Linux下串口是比较常用的通讯接口,有直接用串口通讯的,也有用USB转串口通讯的,还有其它方式转串口的,但不管是以什么方式,以为在linux下可以说一切皆文件,操作文件设备基本都是一样的,都是使用open,read,write,ioctrl这几个函数进行操作,串口的应用编程也不例外,本例程中的串口程序是一个比较完善的串口模块,封装了比较丰富的API,包括串口波特率、数据位、校验位、停止位等参数设置的API,方便串口端口初始化以及读写参数,开发应用可以直接使用!
如下所示:输入 ls /dev/tty 然后table键补全,会出现诸多tty设备,其中
/dev/ttyn是虚拟控制台
/dev/ttySn是串行端口(串口)
/dev/ttyUSB0是USB到串口的转换器
而本例中使用的就是USB到串口的转换器,所以需要操作的就是这个设备文件
1、首先打开该文件设备:
//后面可跟参数:O_NONBLOCK(非阻塞),O_RDWR(可读可写) //O_WRONLY(只写),O_RDONLY(只读),O_NOCTTY(非控制终端) int fd = open("/dev/ttyUSB0", O_RDWR|O_NOCTTY);//以可读可写方式打开,默认阻塞模式
2、 设置串口通讯速率:
/** *@brief 设置串口通信速率 *@param fd 类型 int 打开串口的文件句柄 *@param speed 类型 int 串口速度 *@return void */ int set_speed(int fd, int speed) { int i; int status; struct termios Opt; tcgetattr(fd, &Opt); for ( i= 0; i < sizeof(spd_arr) / sizeof(int); i++) { if(speed == name_arr[i]) { tcflush(fd, TCIOFLUSH); cfsetispeed(&Opt, spd_arr[i]); cfsetospeed(&Opt, spd_arr[i]); status = tcsetattr(fd, TCSANOW, &Opt); if (status != 0) { printf("tcsetattr failed"); return 1; } tcflush(fd,TCIOFLUSH); } } printf("set_speed\n"); return 0; }
3、设置串口的数据位,停止位和效验位:
/** *@brief 设置串口数据位,停止位和效验位 *@param fd 类型 int 打开的串口文件句柄 *@param databits 类型 int 数据位 取值为 7 或者8 *@param stopbits 类型 int 停止位 取值为 1 或者2 *@param parity 类型 int 效验类型 取值为N,E,O,,S */ int set_Parity(int fd, int databits, int parity, int stopbits, int RTSCTS) { struct termios options; if ( tcgetattr( fd,&options) != 0) { perror("SetupSerial 1"); return -1; } options.c_cflag &= ~CSIZE; switch (databits) /*设置数据位数*/ { case 7: options.c_cflag |= CS7; break; case 8: options.c_cflag |= CS8; break; default: fprintf(stderr,"Unsupported data size\n"); return -1; } options.c_iflag |= INPCK; cfmakeraw(&options); //options.c_lflag |= (ICANON | ECHO | ECHOE); //options.c_lflag &= ~(ICANON | ECHO | ECHOE); //options.c_iflag &= ~(IXON | IXOFF); 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); /* 设置为奇效验*/ break; case 'e': case 'E': options.c_cflag |= PARENB; /* Enable parity */ options.c_cflag &= ~PARODD; /* 转换为偶效验*/ break; case 'S': case 's': /*as no parity*/ options.c_cflag &= ~PARENB; options.c_cflag &= ~CSTOPB; break; default: fprintf(stderr,"Unsupported parity\n"); return -1; } /* 设置停止位*/ switch (stopbits) { case 1: options.c_cflag &= ~CSTOPB; break; case 2: options.c_cflag |= CSTOPB; break; default: fprintf(stderr,"Unsupported stop bits\n"); return -1; } /* Set rts/cts */ if (RTSCTS) { printf("Set rts/cts"); options.c_cflag |= CRTSCTS; } tcflush(fd,TCIFLUSH); options.c_cc[VTIME] = 150; /* 设置超时15 seconds*/ options.c_cc[VMIN] = 0; /* Update the options and do it NOW */ if (tcsetattr(fd,TCSANOW,&options) != 0) { printf("SetupSerial failed"); return -1; } printf("set_Parity\n"); return 0; }
到这里串口初始化过程就结束了,就可以编写代码进行串口通讯测试了
串口通讯测试main.c代码如下,过程就是通过串口模块部分提供的api,初始化一个串口,然后对串口数据进行读取,读取不到数据的时候会阻塞,因为open设备文件的时候默认是阻塞模式。
#include "uart.h" int main(int argc, char **argv) { char buff[512]; //打开串口0,波特率为1500000 int fd = serial_def_init(0, 1500000); if(fd < 0) return 0; while(1) { serial_read(fd, buff, sizeof(buff)); printf("read:%s\n", buff); } close(fd);//关闭串口 return 0; }
然后编译:gcc -o app main.c uart.c
我们看到编译后生成了app的文件,然后./app执行发现打开串口失败,这是因为我们的用户权限不够,一般打开硬件设备文件都需要root权限,所以我们可以以root用户权限去执行这个文件,如:sudo ./app
于是就正常执行了这个程序,能从串口成功读取到数据!
完整的串口模块程序链接:linux下串口模块程序-Linux文档类资源-CSDN下载