Linux之UART小结

文章目录

  • Linux Shell 操作
    • 查找串口
    • 串口调试工具
    • 串口与Shell编程
      • 读取串口数据
      • 串口发送数据
  • UART操作流程
  • 重要数据结构
    • c_iflag输入模式标志,控制终端输入方式
    • c_oflag输出模式标志,控制终端输出方式
    • c_cflag控制模式标志,指定终端硬件控制信息
    • c_lflag本地模式标志,控制终端编辑功能
    • c_line行控制
    • c_cc[NCC]控制字符
  • 操作函数
    • tcgetattr()
    • tcsetattr()
    • tcsendbreak()
    • tcdrain()
    • tcflush()
    • tcflow()
    • 波特率函数
  • 终端操作案例

Linux Shell 操作

查找串口

#查看串口中断号,设备路径等信息
dmesg | grep tty*
#查看串口中断号信息
cat /proc/tty/drivers/serial 

串口调试工具

#安装串口调试工具
sudo apt-get install minicom
#界面参数设置,crtl_A Z
#指令打开串口
sudo minicom -D /tty0

串口与Shell编程

stty(set tty)命令用于检查和修改当前注册的终端的通信参数

  • stty -a 查看当前注册端口的设置情况
  • stty -ixon 将流控设置为OFF,而stty ixon则将流控设置为ON
  • stty ixon 9600 设置波特率为9600,并且设置流控为ON
  • stty -F /dev/ttyS0 speed 115200 cs8 -parenb -cstopb time 100 设置波特率115200、数据位8位、无校验位、1位停止位、等待超时10秒
  • stty -F /dev/ttyTHS2
$stty -F /dev/ttyTHS2
speed 9600 baud; line = 0;
-brkint -imaxbel
stty --help
Usage: stty [-F DEVICE | --file=DEVICE] [SETTING]...
  or:  stty [-F DEVICE | --file=DEVICE] [-a|--all]
  or:  stty [-F DEVICE | --file=DEVICE] [-g|--save]
  
  -a, --all print all current settings in human-readable form
  -g, --save print all current settings in a stty-readable form
  -F, --file=DEVICE open and use the specified DEVICE instead of stdin
  --help display this help and exit
  --version output version information and exit

stty命令用法:https://blog.csdn.net/hxlawf/article/details/103611946

读取串口数据

#读取串口数据,停止在读取的界面上
cat /dev/ttyUSB0
#分批次读取一定之间内的数据
stty -F /dev/ttyUSB0 raw speed 9600 min 0 time 10
#每次读取到的数据存储到一个文件
cat /dev/ttyUSB0 >> “tmpFile”

串口发送数据

echo "hello world" > /dev/ttyUSB0

UART操作流程

Linux之UART小结_第1张图片

重要数据结构

struct termio {
	unsigned short c_iflag;		/* input mode flags */
	unsigned short c_oflag;		/* output mode flags */
	unsigned short c_cflag;		/* control mode flags */
	unsigned short c_lflag;		/* local mode flags */
	unsigned char c_line;		/* line discipline */
	unsigned char c_cc[NCC];	/* control characters */
};

c_iflag输入模式标志,控制终端输入方式

在输入值传给程序之前控制其处理的方式

  • IGNBRK 忽略BREAK键输入
  • BRKINT 如果设置了IGNBRK,BREAK键的输入将被忽略,如果设置
  • BRKINT ,将产生SIGINT中断
  • IGNPAR 忽略奇偶校验错误
  • PARMRK 标识奇偶校验错误
  • INPCK 允许输入奇偶校验
  • ISTRIP 去除字符的第8个比特
  • INLCR 将输入的NL(换行)转换成CR(回车)
  • IGNCR 忽略输入的回车
  • ICRNL 将输入的回车转化成换行(如果IGNCR未设置的情况下)
  • IUCLC 将输入的大写字符转换成小写字符(非POSIX)
  • IXON 允许输入时对XON/XOFF流进行控制
  • IXANY 输入任何字符将重启停止的输出
  • IXOFF 允许输入时对XON/XOFF流进行控制
  • IMAXBEL 当输入队列满的时候开始响铃,Linux在使用该参数而是认为该参数总是已经设置

c_oflag输出模式标志,控制终端输出方式

负责控制输出字元的处理方式

  • OPOST 处理后输出
  • OLCUC 将输入的小写字符转换成大写字符(非POSIX)
  • ONLCR 将输入的NL(换行)转换成CR(回车)及NL(换行)
  • OCRNL 将输入的CR(回车)转换成NL(换行)
  • ONOCR 第一行不输出回车符
  • ONLRET 不输出回车符
  • OFILL 发送填充字符以延迟终端输出
  • OFDEL 以ASCII码的DEL作为填充字符,如果未设置该参数,填充字符将是NUL(‘/0’)(非POSIX)
  • NLDLY 换行输出延时,可以取NL0(不延迟)或NL1(延迟0.1s)
  • CRDLY 回车延迟,取值范围为:CR0、CR1、CR2和 CR3
  • TABDLY 水平制表符输出延迟,取值范围为:TAB0、TAB1、TAB2和TAB3
  • BSDLY 空格输出延迟,可以取BS0或BS1
  • VTDLY 垂直制表符输出延迟,可以取VT0或VT1
  • FFDLY 换页延迟,可以取FF0或FF1

c_cflag控制模式标志,指定终端硬件控制信息

用于控制终端设备的硬件设置

  • CBAUD 波特率(4+1位)(非POSIX)
  • CBAUDEX 附加波特率(1位)(非POSIX)
  • CSIZE 字符长度,取值范围为CS5、CS6、CS7或CS8
  • CSTOPB 设置两个停止位
  • CREAD 使用接收器
  • PARENB 使用奇偶校验
  • PARODD 对输入使用奇偶校验,对输出使用偶校验
  • HUPCL 关闭设备时挂起
  • CLOCAL 忽略调制解调器线路状态
  • CRTSCTS 使用RTS/CTS流控制

c_lflag本地模式标志,控制终端编辑功能

主要用来控制终端设备不同的特色

  • ISIG 当输入INTR、QUIT、SUSP或DSUSP时,产生相应的信号
  • ICANON 使用标准输入模式,允许使用特殊字符 EOF, EOL, EOL2, ERASE, KILL, LNEXT, REPRINT, STATUS, 和 WERASE,以及按行的缓冲
  • XCASE 在ICANON和XCASE同时设置的情况下,终端只使用大写。如果只设置了XCASE,则输入字符将被转换为小写字符,除非字符使用了转义字符(非POSIX,且Linux不支持该参数)
  • ECHO 显示输入字符
  • ECHOE 如果ICANON同时设置,ERASE将删除输入的字符,WERASE将删除输入的单词
  • ECHOK 如果ICANON同时设置,KILL将删除当前行
  • ECHONL 如果ICANON同时设置,即使ECHO没有设置依然显示换行符
  • ECHOPRT 如果ECHO和ICANON同时设置,将删除打印出的字符(非POSIX)
  • TOSTOP 向后台输出发送SIGTTOU信号

c_line行控制

c_cc[NCC]控制字符

  • 提供使用者设定一些特殊的功能, 如Ctrl+C的字元组合。
  • 特殊控制字元主要是利用termios结构里c_cc的阵列成员来做设定。
  • c_cc阵列主要用于正规与非正规两种环境,但要注意的是正规与非正规不可混为一谈。

符号下标 (初始值) 和意义(即c_cc[]数组对应下标的数值对应含义,如c_cc[VMIN] = 3):

  • VINTR:(003, ETX, Ctrl-C, or also 0177, DEL, rubout) 中断字符。发出 SIGINT 信号。当设置 ISIG 时可被识别,不再作为输入传递。
  • VQUIT :(034, FS, Ctrl-) 退出字符。发出 SIGQUIT 信号。当设置 ISIG 时可被识别,不再作为输入传递。
  • VERASE :(0177, DEL, rubout, or 010, BS, Ctrl-H, or also #) 删除字符。删除上一个还没有删掉的字符,但不删除上一个 EOF 或行首。当设置 ICANON 时可被识别,不再作为输入传递。
  • VKILL :(025, NAK, Ctrl-U, or Ctrl-X, or also @) 终止字符。删除自上一个 EOF 或行首以来的输入。当设置 ICANON 时可被识别,不再作为输入传递。
  • VEOF :(004, EOT, Ctrl-D) 文件尾字符。更精确地说,这个字符使得 tty 缓冲中的内容被送到等待输入的用户程序中,而不必等到 EOL。如果它是一行的第一个字符,那么用户程序的 read() 将返回 0,指示读到了 EOF。当设置 ICANON 时可被识别,不再作为输入传递。
  • VMIN :非 canonical 模式读的最小字符数(MIN主要是表示能满足read的最小字元数)。
  • VEOL :(0, NUL) 附加的行尾字符。当设置 ICANON 时可被识别。
  • VTIME :非 canonical 模式读时的延时,以十分之一秒为单位。
  • VEOL2 :(not in POSIX; 0, NUL) 另一个行尾字符。当设置 ICANON 时可被识别。
  • VSWTCH :(not in POSIX; not supported under Linux; 0, NUL) 开关字符。(只为 shl 所用。)
  • VSTART :(021, DC1, Ctrl-Q) 开始字符。重新开始被 Stop 字符中止的输出。当设置 IXON 时可被识别,不再作为输入传递。
  • VSTOP :(023, DC3, Ctrl-S) 停止字符。停止输出,直到键入 Start 字符。当设置 IXON 时可被识别,不再作为输入传递。
  • VSUSP :(032, SUB, Ctrl-Z) 挂起字符。发送 SIGTSTP 信号。当设置 ISIG 时可被识别,不再作为输入传递。
  • VDSUSP :(not in POSIX; not supported under Linux; 031, EM, Ctrl-Y) 延时挂起信号。当用户程序读到这个字符时,发送 SIGTSTP 信号。当设置 IEXTEN 和 ISIG,并且系统支持作业管理时可被识别,不再作为输入传递。
  • VLNEXT :(not in POSIX; 026, SYN, Ctrl-V) 字面上的下一个。引用下一个输入字符,取消它的任何特殊含义。当设置 IEXTEN 时可被识别,不再作为输入传递。
  • VWERASE :(not in POSIX; 027, ETB, Ctrl-W) 删除词。当设置 ICANON 和 IEXTEN 时可被识别,不再作为输入传递。
  • VREPRINT :(not in POSIX; 022, DC2, Ctrl-R) 重新输出未读的字符。当设置 ICANON 和 IEXTEN 时可被识别,不再作为输入传递。
  • VDISCARD :(not in POSIX; not supported under Linux; 017, SI, Ctrl-O) 开关:开始/结束丢弃未完成的输出。当设置 IEXTEN 时可被识别,不再作为输入传递。
  • VSTATUS :(not in POSIX; not supported under Linux; status request: 024, DC4, Ctrl-T).

这些符号下标值是互不相同的,除了 VTIME,VMIN 的值可能分别与 VEOL,VEOF 相同。 (在 non-canonical 模式下,特殊字符的含义更改为延时含义MIN 表示应当被读入的最小字符数。TIME 是以十分之一秒为单位的计时器。如果同时设置了它们,read 将等待直到至少读入一个字符,一旦读入 MIN 个字符或者从上次读入字符开始经过了 TIME 时间就立即返回。如果只设置了 MIN,read 在读入 MIN 个字符之前不会返回。如果只设置了 TIME,read 将在至少读入一个字符,或者计时器超时的时候立即返回。如果都没有设置,read 将立即返回,只给出当前准备好的字符。)

MIN与TIME组合有以下四种:

  • MIN = 0 , TIME =0
    有READ立即回传,否则传回 0 ,不读取任何字元
  • MIN = 0 , TIME >0
    READ 传回读到的字元,或在十分之一秒后传回TIME,若来不及读到任何字元,则传回0
  • MIN > 0 , TIME =0
    READ 会等待,直到MIN字元可读
  • MIN > 0 , TIME > 0
    每一格字元之间计时器即会被启动,READ 会在读到MIN字元,传回值或TIME的字元计时(1/10秒)超过时将值传回

操作函数

tcgetattr()

  • int tcgetattr(int fd,struct termois & termios_p);
    取得终端介质(fd)初始值,并把其值 赋给temios_p;函数可以从后台进程中调用;但是,终端属性可能被后来的前台进程所改变。

tcsetattr()

  • int tcsetattr(int fd,int actions,const struct termios *termios_p);
    设置与终端相关的参数 (除非需要底层支持却无法满足),使用 termios_p 引用的 termios 结构。optional_actions (tcsetattr函数的第二个参数)指定了什么时候改变会起作用:
    TCSANOW:改变立即发生
    TCSADRAIN:改变在所有写入 fd 的输出都被传输后生效。这个函数应当用于修改影响输出的参数时使用。(当前输出完成时将值改变)
    TCSAFLUSH :改变在所有写入 fd 引用的对象的输出都被传输后生效,所有已接受但未读入的输入都在改变发生前丢弃(同TCSADRAIN,但会舍弃当前所有值)。

tcsendbreak()

传送连续的 0 值比特流,持续一段时间,如果终端使用异步串行数据传输的话。如果 duration 是 0,它至少传输 0.25 秒,不会超过 0.5 秒。如果 duration 非零,它发送的时间长度由实现定义。
如果终端并非使用异步串行数据传输,tcsendbreak() 什么都不做。

tcdrain()

等待直到所有写入 fd 引用的对象的输出都被传输。

tcflush()

丢弃要写入 引用的对象,但是尚未传输的数据,或者收到但是尚未读取的数据,取决于 queue_selector 的值:
TCIFLUSH :刷新收到的数据但是不读
TCOFLUSH :刷新写入的数据但是不传送
TCIOFLUSH :同时刷新收到的数据但是不读,并且刷新写入的数据但是不传送

tcflow()

挂起 fd 引用的对象上的数据传输或接收,取决于 action 的值:
TCOOFF :挂起输出
TCOON :重新开始被挂起的输出
TCIOFF :发送一个 STOP 字符,停止终端设备向系统传送数据
TCION :发送一个 START 字符,使终端设备向系统传输数据
打开一个终端设备时的默认设置是输入和输出都没有挂起。

波特率函数

被用来获取和设置 termios 结构中,输入和输出波特率的值。新值不会马上生效,直到成功调用了 tcsetattr() 函数。
设置速度为 B0 使得 modem “挂机”。与 B38400 相应的实际比特率可以用 setserial(8) 调整。
输入和输出波特率被保存于 termios 结构中。
cfmakeraw 设置终端属性如下:
termios_p->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
termios_p->c_oflag &= ~OPOST;
termios_p->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
termios_p->c_cflag &= ~(CSIZE|PARENB);
termios_p->c_cflag |= CS8;
1.cfgetospeed() 返回 termios_p 指向的 termios 结构中存储的输出波特率
2.cfsetospeed() 设置 termios_p 指向的 termios 结构中存储的输出波特率为 speed。取值必须是以下常量之一:
B0 B50 B75 B110 B134 B150 B200 B300 B600 B1200 B1800 B2400 B4800 B9600 B19200 B38400 B57600 B115200 B230400
其中:零值 B0 用来中断连接。如果指定了 B0,不应当再假定存在连接。通常,这样将断开连接。CBAUDEX 是一个掩码,指示高于 POSIX.1 定义的速度的那一些 (57600 及以上)。因此,B57600 & CBAUDEX 为非零。
3.cfgetispeed() 返回 termios 结构中存储的输入波特率。
4.cfsetispeed() 设置 termios 结构中存储的输入波特率为 speed。如果输入波特率被设为0,实际输入波特率将等于输出波特率。
RETURN VALUE 返回值
1.cfgetispeed() 返回 termios 结构中存储的输入波特率。
2.cfgetospeed() 返回 termios 结构中存储的输出波特率。
3.其他函数返回:
(1)0:成功
(2) -1:失败,
并且为 errno 置值来指示错误。
注意 tcsetattr() 返回成功,如果任何所要求的修改可以实现的话。因此,当进行多重修改时,应当在这个函数之后再次调用 tcgetattr() 来检测是否所有修改都成功实现

终端操作案例

#include 
#include    /* File Control Definitions           */
#include  /* POSIX Terminal Control Definitions */
#include   /* UNIX Standard Definitions 	   */
#include    /* ERROR Number Definitions           */
 
int uart_int(void)
{
    int fd;/*File Descriptor*/
    /*------------------------------- Opening the Serial Port -------------------------------*/
    fd = open("/dev/ttyS3", O_RDWR | O_NOCTTY | O_NDELAY);	/* ttyUSB0 is the FT232 based USB2SERIAL Converter  |O_NDELAY */
    /* O_RDWR   - Read/Write access to serial port       */
    /* O_NOCTTY - No terminal will control the process   */
    /* Open in blocking mode,read will wait              */
    if(fd == -1) {
        printf("\n  Error! in Opening ttyUSB0  ");
        return -1;
    }
    /*---------- Setting the Attributes of the serial port using termios structure --------- */
    /*RX init*/
    struct termios SerialPortSettings;	/* Create the structure                          */
    tcgetattr(fd, &SerialPortSettings);	/* Get the current attributes of the Serial port */
    /* Setting the Baud rate */
    cfsetispeed(&SerialPortSettings, B115200); /* Set Read  Speed as 9600*/
    cfsetospeed(&SerialPortSettings, B115200); /* Set Write Speed as 9600*/
    /* 8N1 Mode */
    SerialPortSettings.c_cflag &= ~PARENB;/* Disables the Parity Enable bit(PARENB),So No Parity*/
    SerialPortSettings.c_cflag &= ~CSTOPB;/* CSTOPB = 2 Stop bits,here it is cleared so 1 Stop bit*/
    SerialPortSettings.c_cflag &= ~CSIZE;/* Clears the mask for setting the data size*/
    SerialPortSettings.c_cflag |= CS8;/* Set the data bits = 8*/
    SerialPortSettings.c_cflag &= ~CRTSCTS;/* No Hardware flow Control*/
    SerialPortSettings.c_cflag |= CREAD | CLOCAL; /* Enable receiver,Ignore Modem Control lines*/
    SerialPortSettings.c_iflag &= ~(IXON | IXOFF | IXANY);          /* Disable XON/XOFF flow control both i/p and o/p */
    SerialPortSettings.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);  /* Non Cannonical mode*/
    SerialPortSettings.c_oflag &= ~OPOST;/*No Output Processing   raw  format  output*/
    /* Setting Time outs */
    SerialPortSettings.c_cc[VMIN] = 0; /* Read at least 10 characters */
    SerialPortSettings.c_cc[VTIME] = 1; /* Wait indefinetly */

/* Set the attributes to the termios structure*/
    if((tcsetattr(fd, TCSANOW, &SerialPortSettings)) != 0) 
        printf("\n  ERROR ! in Setting attributes");
    else
        printf("\n  BaudRate = 115200 \n  StopBits = 1 \n  Parity   = none");
 
    /*------------------------------- Read data from serial port -----------------------------*/
    tcflush(fd, TCIFLUSH);/* Discards old data in the rx buffer*/
    close(fd); /* Close the serial port */
    return 0;
 
}
 
int main(void)
{
    int fd;/*File Descriptor*/
    printf("\n +----------------------------------+");
    printf("\n |        Serial Port Read          |");
    printf("\n +----------------------------------+");
    uart_int();
    /*------------------------------- Opening the Serial Port -------------------------------*/
    fd = open("/dev/ttyS3", O_RDWR | O_NOCTTY | O_NDELAY);	/* ttyUSB0 is the FT232 based USB2SERIAL Converter   */
    /* O_RDWR   - Read/Write access to serial port       */
    /* O_NOCTTY - No terminal will control the process   */
    /* Open in blocking mode,read will wait              */
    if(fd == -1)						/* Error Checking */
        printf("\n  Error! in Opening ttyUSB0  ");
    else
        printf("\n  ttyUSB0 Opened Successfully ");
    char read_buffer[32];   /* Buffer to store the data received              */
    int  bytes_read = 0;    /* Number of bytes read by the read() system call */
    int i = 0;
    while(1)
    {
        bytes_read = read(fd, &read_buffer, 32); /* Read the data                   */
        if(bytes_read > 0) {
        	printf("\n\n  Bytes Rxed -%d", bytes_read); /* Print the number of bytes read */
            printf("\n\n  ");
            for(i = 0; i < bytes_read; i++)	 /*printing only the received characters*/
                printf("%c", read_buffer[i]);
 
            int  bytes_written  = 0;  	/* Value for storing the number of bytes written to the port */
            bytes_written = write(fd, read_buffer, bytes_read); /* use write() to send data to port*/
            /* "fd" - file descriptor pointing to the opened serial port */
            /*	"write_buffer" - address of the buffer containing data*/
            /* "sizeof(write_buffer)" - No of bytes to write             */
            printf("\n  %d Bytes written to ttyUSB0", bytes_written);
            printf("\n\n  Bytes Rxed -%d", bytes_read); /* Print the number of bytes read */
            printf("\n\n  ");
            printf("\n +----------------------------------+\n\n\n");
        }
    }
}

你可能感兴趣的:(Linux)