Linux终端设备之串口通信设置

前言

1、串口属于终端设备,其接口属性用termios结构描述 2、为了便于通过程序来获得和修改终端参数,Linux还提供了tcgetattr函数和tcsetattr函数。tcgetattr用于获取终端的相关参数,而tcsetattr函数用于设置终端参数 3、需要头文件:#include

文章目录

  • 前言
  • 一、串口是什么?
  • 二、struct termios 结构体
    • 1.c_iflag 参数表
    • 2.c_oflag 参数表
    • 3.c_cflag 参数表
    • 4.c_lflag 参数表
    • 5.c_cc[NCCS] 参数表
  • 三、串口属性设置
    • 1. tcgetattr获取termios结构属性
    • 2.设置串口输入/输出波特率函数
    • 3.设置数据位
    • 4.设置奇偶校验
      • ①无奇偶校验(8N1):
      • ②7位数据位奇偶校验(7E1):
      • ③奇校验(7O1):
    • 5.tcsetattr设置串口termios结构属性
  • 四 、Demo
    • 1.简单串口设置例子
    • 2.设置串口波特率
    • 3. 设置串口数据位、停止位、校验位、流控


一、串口是什么?

  1. 串行接口是一种可以将接收来自CPU的并行数据字符转换为连续的串行数据流发送出去,同时可将接收的串行数据流转换为并行的数据字符供给CPU的器件。一般完成这种功能的电路,我们称为串行接口电路。

  2. 串口通信(Serial Communications)的概念非常简单,串口按位(bit)发送和接收字节的通信方式。

二、struct termios 结构体

struct termios {
    tcflag_t  c_iflag; 		/* 输入标志*/
    tcflag_t  c_oflag; 		/* 输出标志*/
    tcflag_t  c_cflag; 		/* 控制标志*/
    tcflag_t  c_lflag; 		/* 本地标志*/
    tcflag_t  c_cc[NCCS];	/* 控制字符*/
};

1.c_iflag 参数表

c_iflag:输入模式标志,控制终端输入方式,具体参数如下表所示。

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

2.c_oflag 参数表

c_oflag:输出模式标志,控制终端输出方式,具体参数如下表所示。

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

3.c_cflag 参数表

  1. c_cflag成员控制着波特率、数据位、奇偶校验、停止位以及流控制。
  2. c_cflag成员的CREAD和CLOCAL选项通常是要启用的,这两个选项使驱动程序启动接收字符装置,同时忽略串口信号线的状态。
  3. 控制模式标志,指定终端硬件控制信息,具体参数如下表所示。
标志 说明
CBAUD 波特率(4+1位)(非POSIX)
CBAUDEX 附加波特率(1位)(非POSIX)
CSIZE 字符长度,取值范围为CS5、CS6、CS7或CS8
CSTOPB 设置两个停止位
CREAD 使用接收器
PARENB 使用奇偶校验
PARODD 对输入使用奇偶校验,对输出使用偶校验
HUPCL 关闭设备时挂起
CLOCAL 忽略调制解调器线路状态
CRTSCTS 使用RTS/CTS流控制

4.c_lflag 参数表

c_lflag:本地模式标志,控制终端编辑功能,具体参数如下表所示。

标志 说明
ISIG 当输入INTR、QUIT、SUSP或DSUSP时,产生相应的信号
ICANON 使用标准输入模式
XCASE 在ICANON和XCASE同时设置的情况下,终端只使用大写。
ECHO 显示输入字符
ECHOE 如果ICANON同时设置,ERASE将删除输入的字符
ECHOK 如果ICANON同时设置,KILL将删除当前行
ECHONL 如果ICANON同时设置,即使ECHO没有设置依然显示换行符
ECHOPRT 如果ECHO和ICANON同时设置,将删除打印出的字符(非POSIX)
TOSTOP 向后台输出发送SIGTTOU信号

5.c_cc[NCCS] 参数表

c_cc[NCCS]:控制字符,用于保存终端驱动程序中的特殊字符,如输入结束符等。c_cc中定义了如下表所示的控制字符。

说 明
VINTR Interrupt字符
VEOL 附加的End-of-file字符
VQUIT Quit字符
VTIME 非规范模式读取时的超时时间
VERASE Erase字符
VSTOP Stop字符
VKILL Kill字符
VSTART Start字符
VEOF End-of-file字符
VSUSP Suspend字符
VMIN 非规范模式读取时的最小字符数

三、串口属性设置

说明:使用函数tcgetattr和tcsetattr可以获取和设置串口termios结构属性。

1. tcgetattr获取termios结构属性

int tcgetattr(int fd, struct termios *termptr);

 1. fd:串口设备文件描述符。
 2. termptr:在tcgetattr函数中是用于获取串口的termios结构体。
 3. 返回值:成功则返回0,若出错则返回-1

2.设置串口输入/输出波特率函数


 1. int cfsetispeed(struct termios *termptr, speed_t speed);//设置串口输入波特率
 2. int cfsetospeed(struct termios *termptr, speed_t speed);//设置串口输出波特率
 3. int tcflush(int fd,int );
   TCIFLUSH   刷新收到的数据但是不读
  TCOFLUSH  	刷新写入的数据但是不传送
  TCIOFLUSH  同时刷新收到的数据但是不读,并且刷新写入的数据但是不传送
	输出缓冲器清空,输入缓冲区清空。清空缓冲区里的数据。

3.设置数据位

termptr.c_cflag &= ~CSIZE;/* 先把数据位清零*/
termptr.c_cflag |= CS8;/* 把数据位设置为8位*/

4.设置奇偶校验

①无奇偶校验(8N1):

termptr.c_cflag &= ~PARENB;
termptr.c_cflag &= ~CSTOPB;
termptr.c_cflag &= ~CSIZE;
termptr.c_cflag |= CS8;

②7位数据位奇偶校验(7E1):

termptr.c_cflag |= PARENB;
termptr.c_cflag &= ~PARODD;
termptr.c_cflag &= ~CSTOPB;
termptr.c_cflag &= ~CSIZE;
termptr.c_cflag |= CS7;

③奇校验(7O1):

termptr.c_cflag|= PARENB;
termptr.c_cflag |= PARODD;
termptr.c_cflag &= ~CSTOPB;
termptr.c_cflag &= ~CSIZE;
termptr.c_cflag |= CS7;

5.tcsetattr设置串口termios结构属性

int tcsetattr(int fd, int opt, const struct termios *termptr);

1. fd为串口设备文件描述符。
2. opt是整形变量,使用方法如下:
	TCSANOW:更改立即发生;
	TCSADRAIN:发送了所有输出后更改才发生,若更改输出参数则应用此选项;
	TCSAFLUSH:发送了所有输出后更改才发生,更进一步,在更改发生时未读的所有输入数据被删除(Flush)。
	参数opt说明:
		在串口驱动程序里,有输入缓冲区和输出缓冲区。在改变串口属性时,缓冲区中的数据可能还存在,这时需要考虑到更改后的属性什么时候起作用。tcsetattr的参数opt可以指定在什么时候启动新的串口属性。
3. termptr参数在tcgetattr函数中是用于存放串口设置的termios结构体。
4. 返回值:成功则返回0,若出错则返回-1

四 、Demo

1.简单串口设置例子

#include
#include
#include
#include
#include
#include 

#define DATA_LEN 5

static int UART2_init(void)
{
   
 	//打开串口
    int fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY);            
    if(fd < 0) 
    {
        perror("提示错误!");
        return -1;
    }
 	struct termios opt; //终端属性结构体
    tcgetattr(fd, &opt);     //获取串口属性结构体对象
    cfsetispeed(&opt, B115200);    //设置输入波特率
    cfsetospeed(&opt, B115200);    //设置输出波特率
 
    /* raw mode */   //偶校验
    opt.c_lflag   &=   ~(ECHO | ICANON | IEXTEN |ISIG); //设置本地标志:不进行回送,关闭规范输入,关闭扩充输入字符处理,关闭终端产生的信号
    opt.c_iflag   &=  ~(IXON | ISTRIP);       // 关闭输出流控制, 不剥除第8位
    opt.c_iflag   |= (ICRNL | BRKINT | INPCK);// 将输入的CR转换为NL,使得输入和输出队列被刷新 ,打开奇偶校验
    opt.c_oflag   &=   ~(OPOST);              // 设置输出标志:不执行输出处理
    opt.c_cflag   &=   ~(PARODD | CSIZE);     // 关闭输入输出是奇校验 ,使用屏蔽位
    opt.c_cflag   |=   (CS8 | CLOCAL | CREAD | PARENB);//8位数据位,保证程序不会占用串口,能够从串口读取输入数据,允许输出产生奇偶信息以及输入的奇偶校验
 
    /*'DATA_LEN' bytes can be read by serial*/
    opt.c_cc[VMIN]   =   DATA_LEN;   //读取字符的最少个                                   
    opt.c_cc[VTIME]  =   1;        //读取一个字符等待1*(1/10)s
 
    tcflush(fd,TCIOFLUSH);  //清空所有正在发生的IO数据
 
    if (tcsetattr(fd, TCSANOW, &opt) < 0) //激活配置(将修改后的termios数据设置到串口)
    {
        return   -1;
    }

    return fd;
}
int main()
{
    UART2_init();    
    return 0;
}      

2.设置串口波特率

/***********************************************************
Description:
    设置串口波特率
************************************************************/
static int tc_set_speed(int fd,int baud_rate)
{
    int status;
    int i;
    struct termios opt;

    int speed_arr[] = { B115200, B57600, B38400, B19200, B9600, B4800, B2400, B1200, B300 };
    int name_arr[]  = { 115200, 57600, 38400,  19200,  9600,  4800,  2400,  1200,  300 };

    if(fd == -1)
        return 1;

    //set baud_rate
    if (tcgetattr(fd, &opt) != 0)
    {
        printf("tc_set_speed fail !\n");
        return 0 ;
    }
    for (i=0; i < sizeof(speed_arr)/sizeof(int); i++)
    {
        if (baud_rate == name_arr[i])
        {
            cfsetispeed(&opt, speed_arr[i]);
            cfsetospeed(&opt, speed_arr[i]);
            tcflush(fd,TCIOFLUSH);
            status = tcsetattr(fd, TCSANOW, &opt);
            if  (status != 0)
            {
                 printf("tcsetattr fail\n");
                return 0;
            }
            break;
        }
    }

    return 1;
}

3. 设置串口数据位、停止位、校验位、流控


/***********************************************************
Description:
  设置串口数据位、停止位、校验位、流控
************************************************************/
static int tc_set_parity(int fd, int databits,int stopbits,int parity,int flowctrl)
{
    struct termios options;

    if(fd == -1)
        return 1;

    if (tcgetattr(fd,&options)  !=  0)
    {
         printf("tcgetattr ERROR");
        return 0 ;
    }
    /*set flow control*/
    switch (flowctrl)
    {
        case 0: /* 无流控制 */
            options.c_cflag &= ~CRTSCTS;
            options.c_iflag &= ~(IXON | IXOFF | IXANY );
            break;
        case 1: /* 硬件流控制 */
            options.c_cflag |= CRTSCTS; /* also called CRTSCTS */
            options.c_iflag &= ~(IXON | IXOFF | IXANY );
            break;
        case 2: /* 软件流控制 */
            options.c_iflag |= (IXON | IXOFF | IXANY );
            options.c_cflag &= ~CRTSCTS;
            break;
        default: /* 无流控制 */
            options.c_cflag &= ~CRTSCTS;
            options.c_iflag &= ~(IXON | IXOFF | IXANY );
             printf("Default No flow control");
            break;
    }

    options.c_cflag &= ~CSIZE;
    /*set databit*/
    switch (databits)
    {
        case 7:
            options.c_cflag |= CS7;
            break;
        case 8:
            options.c_cflag |= CS8;
            break;
        default:
             printf("Unsupported data size");
            return 0;
    }

    /*set parity*/
    switch (parity)
    {
        case 'n':
        case 'N':
            options.c_cflag &= ~PARENB;   /* Clear parity enable */
            options.c_iflag &= ~INPCK;     /* Enable parity checking */
            break;
        case 'o':
        case 'O':
            options.c_cflag |= (PARODD | PARENB); /* 设置为奇效验*/
            options.c_iflag |= INPCK;             /* Disnable parity checking */
            break;
        case 'e':
        case 'E':
            options.c_cflag |= PARENB;     /* Enable parity */
            options.c_cflag &= ~PARODD;   /* 转换为偶效验*/
            options.c_iflag |= INPCK;       /* Disnable parity checking */
            break;
        case 'S':
        case 's':  /*as no parity*/
            options.c_cflag &= ~PARENB;
            options.c_cflag &= ~CSTOPB;
            break;
        default:
            printf("Unsupported parity");
            return  0;
    }

    /*set stopbits*/
    switch (stopbits)
    {
        case 1:
            options.c_cflag &= ~CSTOPB;
            break;
        case 2:
            options.c_cflag |= CSTOPB;
            break;
        default:
            printf("Unsupported stop bits");
            return 0 ;
    }

    /* Set input parity option */
    options.c_cc[VTIME] = 150; /* 设置超时15 seconds*/
    options.c_cc[VMIN] = 0; /* Update the options and do it NOW */

    //RAM MODE
#ifdef _BSD_SOURCE
    cfmakeraw( &options );
#else
    options.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP
                    | INLCR | IGNCR | ICRNL | IXON);
    options.c_oflag &= ~OPOST;
    options.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
#endif

    tcflush(fd,TCIFLUSH);
    if (tcsetattr(fd,TCSANOW,&options) != 0)
    {
        printf("tcsetattr ERROR");
        return 0;
    }
    
    return 1;
}

你可能感兴趣的:(Linux,驱动,通信,嵌入式,linux,串口通信)