按照对linux系统的理解,串口编程的顺序无非就是open,read,write,close,而串口有波特率、数据位等重要参数需要设置,因此还应该用到设置函数,那么接下来就带着这几个问题去学习linux下的串口编程。
linux系统通常使用termios结构存储串口参数,该结构在termios.h头文件定义如下:
struct termios
{
//输入模式标志
//输出模式标志
//控制模式标志
//本地模式标志
//行控制
//控制字符
};
串口编程常用到的函数如下:
读取当前参数函数:int tcgetattr(int fd, struct termios *termios_p);
1:fd是open返回的句柄
2:*termios_p是前面介绍的结构体
-在初始化开始调用这个函数
波特率设置函数:int cfsetispeed(const struct termios *termios_p, speed_t speed);
int cfsetospeed(const struct termios *termios_p, speed_t speed);
1:前面介绍的结构体
2:speed波特率
0,失败返回-1
清空串口BUFFER中的数据函数:int tcflush(int fd, int queue_selector);
1:fd是open返回的句柄
2:控制tcflush的操作。
-常用的有三个值,
TCIFLUSH清除正收到的数据,且不会读取出来;
TCOFLUSH清除正写入的数据,且不会发送至终端;
TCIOFLUSH清除所有正在发生的I/O数据
0,失败返回-1
设置串口参数函数:int tcsetattr(int fd, int optional_actions, const struct termios *termios_p);
fd:open返回的文件句柄
optional_actions:参数生效的时间。
-有三个常用的值,
TCSANOW:不等数据传输完毕就立即改变属性;
TCSADRAIN:等待所有数据传输结束才改变属性;
TCSAFLUSH:清空输入输出缓冲区才改变属性;
termios_p:在旧的参数基础上修改的后的参数
-返回值:执行成功返回0,失败返回-1
-一般初始化最后会使用这个函数
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <termios.h>
int uart_set(int fd, int baudrate, int bits, int stop, char parity, char flow)
{
int ret;
speed_t uart_speed;
struct termios termios_uart;
memset(&termios_uart, 0, sizeof(termios_uart));
//读取当前串口参数值
ret = tcgetattr(fd, &termios_uart);
if(ret < 0)
{
perror("tcgetattr error");
return -1;
}
//设置波特率
switch(baudrate)
{
case 9600:
cfsetspeed(&termios_uart, B9600); break;
case 38400:
cfsetspeed(&termios_uart, B38400); break;
case 115200:
cfsetspeed(&termios_uart, B115200); break;
case 230400:
cfsetspeed(&termios_uart, B230400); break;
default:
printf("Baudrate not supported \n"); return -1;
}
//设置数据位
switch(bits)
{
case 6:
termios_uart.c_cflag &= ~CSIZE;
termios_uart.c_cflag |= CS6;
break;
case 7:
termios_uart.c_cflag &= ~CSIZE;
termios_uart.c_cflag |= CS7;
break;
case 8:
termios_uart.c_cflag &= ~CSIZE;
termios_uart.c_cflag |= CS8;
break;
default:
printf("Data bits not supported \n");
return -1;
}
//设置停止位
switch(stop)
{
case 1:
termios_uart.c_cflag &= ~CSTOPB; break;
case 2:
termios_uart.c_cflag |= CSTOPB; break;
default:
printf("Stop bits not supported\n"); return -1;
}
//设置校验位
switch(parity)
{
//无校验
case 'N':
termios_uart.c_cflag &= ~PARENB;
termios_uart.c_iflag &= ~INPCK;
break;
//奇校验
case 'O':
termios_uart.c_cflag |= PARENB;
termios_uart.c_cflag |= PARODD;
termios_uart.c_iflag |= INPCK;
termios_uart.c_iflag |= ISTRIP;
break;
//偶校验
case 'E':
termios_uart.c_cflag |= PARENB;
termios_uart.c_cflag &= ~PARODD;
termios_uart.c_iflag |= INPCK;
termios_uart.c_iflag |= ISTRIP;
break;
default:
printf("Parity not supported\n");
return -1;
}
//设置流控
switch(flow)
{
//无流控
case 'N':
termios_uart.c_cflag &= ~CRTSCTS;
termios_uart.c_iflag &= ~(IXON | IXOFF | IXANY);
break;
//硬件流控
case 'H':
termios_uart.c_cflag |= CRTSCTS;
termios_uart.c_iflag &= ~(IXON | IXOFF | IXANY);
break;
//软件流控
case 'S':
termios_uart.c_cflag &= ~CRTSCTS;
termios_uart.c_iflag |= (IXON | IXOFF | IXANY);
break;
default:
printf("Flow control parameter error\n");
return -1;
}
//其他设置
//忽略modem(调制解调器)控制线
//使能接收
//禁能执行定义(implementation-defined)输出处理,意思就是输出的某些特殊数据会作特殊处理,如果禁能的话那么就按原始数据输出
termios_uart.c_oflag &= ~OPOST;
/*
设置本地模式位原始模式
规范输入模式,如果设置了那么退格等特殊字符会产生实际动作
则将输入字符回送到终端设备
如果ICANON也设置了,那么收到ERASE字符后会从显示字符中擦除一个字符(通俗点理解就是收到退格键后显示内容会往回删一个字符)
使终端产生的信号起作用(比如按ctrl+c可以使程序退出)
*/
termios_uart.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
/*
设置等待时间和最小接收字符
这两个值只有在阻塞模式下有意义,也就是说open的时候不能传入O_NONBLOCK,如果经过了c_cc[VTIME]这么长时间,缓冲区内有数据,但是还没达到c_cc[VMIN]个
数据,read也会返回。而如果当缓冲区内有了c_cc[VMIN]个数据时,无论等待时间是否到了c_cc[VTIME],read都会返回,但返回值可能比c_cc[VMIN]还大。如果将
的值设置为0,那么当经过c_cc[VTIME]时间后read也会返回,返回值为0。如果将c_cc[VTIME]和c_cc[VMIN]都设置为0,那么程序运行的效果与设置
类似,不同的是如果设置了O_NONBLOCK,那么在没有数据时read返回-1,而如果没有设置O_NONBLOCK,那么在没有数据时read返回的是0。
*/
//设置等待时间,单位1/10秒
//最少读取一个字符
//清空读缓冲区
//写入配置
ret = tcsetattr(fd, TCSANOW, &termios_uart);
if(ret == -1)
{
printf("tcsetattr failed\n");
}
return ret;
}
int main(int argc, char *argv[])
{
int fd;
int len;
char *filename;
char buf[512];
char *buffer = "hello lianmeng!\n";
memset(buf, 0, sizeof(buf));
filename = argv[1];
fd = open(filename, O_RDWR | O_NONBLOCK);
if(fd < 0)
{
printf("can't open file %s \r\n", filename);
return -1;
}
uart_set(fd, 115200, 8, 1, 'N', 'N');
while(1)
{
len = read(fd, buf, sizeof(buf));
if(len > 0)
{
write(fd, buf, len);
}
}
close(fd);
}