Linux下应用层操作UART的四种方式_天天滚动
串口文件
COM1串口一为/dev/ttyS0
COM2串口2为/dev/ttyS1
或者
【资料图】
COM1串口一为/dev/ttyUSB0
COM2串口2为/dev/ttyUSB1
命令查询串口:
~$ ls /dev/ttyS*/dev/ttyS0 /dev/ttyS12 /dev/ttyS16 /dev/ttyS2 /dev/ttyS23 /dev/ttyS27 /dev/ttyS30 /dev/ttyS6/dev/ttyS1 /dev/ttyS13 /dev/ttyS17 /dev/ttyS20 /dev/ttyS24 /dev/ttyS28 /dev/ttyS31 /dev/ttyS7/dev/ttyS10 /dev/ttyS14 /dev/ttyS18 /dev/ttyS21 /dev/ttyS25 /dev/ttyS29 /dev/ttyS4 /dev/ttyS8/dev/ttyS11 /dev/ttyS15 /dev/ttyS19 /dev/ttyS22 /dev/ttyS26 /dev/ttyS3 /dev/ttyS5 /dev/ttyS9
方法1:轮询
1. 打开串口
fd = open(port, O_RDWR | O_NOCTTY | O_NDELAY);if (fd == -1) { perror("open_port: Unable to open serial port"); return -1;}
2. 配置串口
tcgetattr(fd, &options);cfsetispeed(&options, B115200);cfsetospeed(&options, B115200);options.c_cflag |= (CLOCAL | CREAD);options.c_cflag &= ~PARENB;options.c_cflag &= ~CSTOPB;options.c_cflag &= ~CSIZE;options.c_cflag |= CS8;options.c_cflag &= ~CRTSCTS;tcsetattr(fd, TCSANOW, &options);
其中,tcgetattr 和 tcsetattr 函数用于获取和设置串口参数。cfsetispeed 和 cfsetospeed 函数用于设置串口的输入和输出波特率,这里设置为 115200。options.c_cflag 表示控制标志位,用于配置串口控制参数,具体含义如下:
CLOCAL:忽略调制解调器的状态线,只允许本地使用串口。
CREAD:允许从串口读取数据。
PARENB:启用奇偶校验。&= ~PARENB则为禁用校验。
CSTOPB:使用两个停止位而不是一个。&= ~CSTOPB停止位为1。
CSIZE:表示字符长度的位掩码。在这里设置为 0,表示使用默认的 8 位数据位。
CS8:表示使用 8 位数据位。
CRTSCTS:启用硬件流控制,即使用 RTS 和 CTS 状态线进行流控制。
在示例程序中,我们将 CLOCAL 和 CREAD 标志位置为 1,表示允许本地使用串口,并允许从串口读取数据。我们将 PARENB、CSTOPB 和 CRTSCTS 标志位都设置为 0,表示不启用奇偶校验、使用一个停止位和禁用硬件流控制。最后,我们将 CSIZE 标志位设置为 0,然后将 CS8 标志位设置为 1,以表示使用 8 位数据位。
3. 读写
read(fd, buf, sizeof(buf)); // 返回接收个数write(fd, buf, strlen(buf)); // 返回发送长度,负值表示发送失败
4. 关闭串口
close(fd);
完整示例
int open_port(const char *port){ int fd; struct termios options; // 打开串口设备 fd = open(port, O_RDWR | O_NOCTTY | O_NDELAY); if (fd == -1) { perror("open_port: Unable to open serial port"); return -1; } // 配置串口参数 tcgetattr(fd, &options); cfsetispeed(&options, B115200); cfsetospeed(&options, B115200); options.c_cflag |= (CLOCAL | CREAD); options.c_cflag &= ~PARENB; options.c_cflag &= ~CSTOPB; options.c_cflag &= ~CSIZE; options.c_cflag |= CS8; options.c_cflag &= ~CRTSCTS; tcsetattr(fd, TCSANOW, &options); return fd;}int main(){ int fd; char buf[255]; int n; // 打开串口设备 fd = open_port("/dev/ttyUSB0"); if (fd == -1) { printf("open err\n"); exit(1); } while (1) { // 读取串口数据 n = read(fd, buf, sizeof(buf)); if (n > 0) { printf("Received: %.*s\n", n, buf); } // 发送串口数据 strcpy(buf, "Hello, world!\n"); n = write(fd, buf, strlen(buf)); if (n < 0) { perror("write failed\n"); } usleep(10 * 1000); } // 关闭串口设备 close(fd); printf("close uart\n"); return 0;}
方法2:中断读取示例
以下是一个简单的使用中断方式接收串口数据的示例程序:
#include #include #include #include #include #include int main() { int fd; struct termios options; fd_set rfds; // 打开串口设备 fd = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY); if (fd < 0) { perror("open"); return -1; } // 配置串口参数 tcgetattr(fd, &options); options.c_cflag = B9600 | CS8 | CLOCAL | CREAD; options.c_iflag = IGNPAR; options.c_oflag = 0; options.c_lflag = 0; options.c_cc[VTIME] = 0; options.c_cc[VMIN] = 1; tcsetattr(fd, TCSANOW, &options); while (1) { // 使用 select 函数监听串口文件描述符的可读事件 FD_ZERO(&rfds); FD_SET(fd, &rfds); select(fd + 1, &rfds, NULL, NULL, NULL); // 读取串口数据 char buf[256]; int n = read(fd, buf, sizeof(buf)); if (n > 0) { printf("Received data: %.*s\n", n, buf); } } // 关闭串口设备 close(fd); return 0;}
需要注意的是,在使用中断方式接收串口数据时,需要对串口文件描述符设置为非阻塞模式,以便在 select 函数返回时立即读取串口数据。可以使用 fcntl 函数来设置文件描述符的标志位,如下所示:
// 设置串口文件描述符为非阻塞模式int flags = fcntl(fd, F_GETFL, 0);fcntl(fd, F_SETFL, flags | O_NONBLOCK);
方法3:信号的方式接收数据
#include #include #include #include #include #include int fd;void sigio_handler(int sig) { char buf[256]; int n = read(fd, buf, sizeof(buf)); if (n > 0) { printf("Received data: %.*s\n", n, buf); }}int main() { struct termios options; struct sigaction sa; // 打开串口设备 fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY); if (fd < 0) { perror("open"); return -1; } // 配置串口参数 tcgetattr(fd, &options); options.c_cflag = B9600 | CS8 | CLOCAL | CREAD; options.c_iflag = IGNPAR; options.c_oflag = 0; options.c_lflag = 0; options.c_cc[VTIME] = 0; options.c_cc[VMIN] = 1; tcsetattr(fd, TCSANOW, &options); // 设置串口文件描述符为异步通知模式 /* 将串口文件描述符设置为当前进程的拥有者,从而接收该文件描述符相关的信号。*/ fcntl(fd, F_SETOWN, getpid()); int flags = fcntl(fd, F_GETFL, 0); // 先获取当前配置, 下面只更改O_ASYNC标志 /* 将串口文件描述符设置为非阻塞模式,从而允许该文件描述符异步地接收数据和信号。*/ fcntl(fd, F_SETFL, flags | O_ASYNC); // 设置 SIGIO 信号的处理函数 sa.sa_handler = sigio_handler; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; /* 设置了 SIGIO 信号的处理函数为 sigio_handler,从而在该信号被触发时读取串口数据并进行处理。*/ sigaction(SIGIO, &sa, NULL); while (1) { // 等待 SIGIO 信号 sleep(1); } // 关闭串口设备 close(fd); return 0;}
上述代码中,使用了 fcntl 函数将串口文件描述符设置为异步通知模式,并使用 SIGIO 信号来通知程序串口数据已经可读。当程序接收到 SIGIO 信号时,会调用 sigio_handler 函数来读取并处理串口数据。
方法4:使用线程接收串口数据:
#include #include #include #include #include #include void *read_thread(void *arg) { int fd = *(int *)arg; char buf[256]; int n; while (1) { // 读取串口数据 n = read(fd, buf, sizeof(buf)); if (n > 0) { printf("Received data: %.*s\n", n, buf); } } return NULL;}int main() { int fd; struct termios options; pthread_t tid; // 打开串口设备 fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY); if (fd < 0) { perror("open"); return -1; } // 配置串口参数 tcgetattr(fd, &options); options.c_cflag = B9600 | CS8 | CLOCAL | CREAD; options.c_iflag = IGNPAR; options.c_oflag = 0; options.c_lflag = 0; options.c_cc[VTIME] = 0; options.c_cc[VMIN] = 1; tcsetattr(fd, TCSANOW, &options); // 创建读取线程 if (pthread_create(&tid, NULL, read_thread, &fd) != 0) { perror("pthread_create"); return -1; } while (1) { // 主线程的其他处理逻辑 sleep(1); } // 关闭串口设备 close(fd); return 0;}
上述代码中,创建了一个读取线程,不断读取串口数据并进行处理。主线程可以在读取线程运行的同时进行其他处理逻辑。
来源:一口Linux
关键词:
相关阅读
-
Linux下应用层操作UART的四种方式_天天滚动
串口文件在linux中,针对所有的周边设备都提供了设备文件供用户访问, -
小鹏汽车跌超8%领跌汽车股,本月首18日...
6月23日港股早盘,汽车股回落,截至发稿,$小鹏汽车-W(09868 HK)$跌超8 -
环球新资讯:今年端午假期 高速公路充...
天津北方网讯:记者从国网天津市电力公司了解到,今年端午假期,高速公 -
【天天时快讯】单词详解 | irreverent
irreverent音标:美音: ɪˈrevərənt ,英音: ɪˈrevərənt 听听 -
@所有苏州人 可以坐着地铁去上海啦!|...
西起苏州工业园区唯亭站,东至昆山花桥站,并在花桥站实现与上海轨道交 -
纽约金价23日上涨-全球快资讯
纽约金价23日上涨---新华社芝加哥6月23日电(记者徐静)纽约商品交易所 -
【聚看点】大熊猫“丫丫”最新吃播视频...
北京动物园饲养员为“丫丫”准备了新鲜的竹子和竹笋,“丫丫”负责... -
市妇联守护她健康 巾帼在行动
6月15日,市妇联携手市妇幼保健院、市木兰花综合服务中心,在沙嘴街道 -
卸妆不够彻底?怎么办?-今热点
卸妆是每个美妆爱好者不可避免的步骤,但是有时候只用洗面奶卸妆还不够 -
游戏人生小说_游戏人生第二季什么时候出...
1、剧场版已经出了,原作小说也够出第二季了,依着疯人公司凡是只出第 -
对联的尺寸有讲究吗(对联尺寸是多少)...
对联的尺寸有讲究吗,对联尺寸是多少这个很多人还不知道,现在让我们一 -
中医针灸培训班_中医针灸师报考条件
1、办法实施细则 一、为了贯彻执行国际针灸师资格(水平)考试《考 -
长春一网红打卡地正式开放!|今日关注
经过两个月的试营业,长春电影嘉年华于6月21日正式开街,同时,以净月 -
勇士赚了,奇才亏了!ESPN评级出炉,你...
勇士赚了,奇才亏了!ESPN评级出炉,你还是为自己的狂妄付出代价,勇士, -
今日关注:电脑桌面下边的菜单栏跑到右...
1、首先在任务栏上的空白的地方点击鼠标左键,取消对“锁定任务栏”... -
世界快看点丨菠萝怎么画?4步教你画菠萝
色标▼Step1 调和浅镉黄,加入一点印度黄,从菠萝的侧面画起,颜色画的 -
当前资讯!合康新能拟向美的募资14.73亿...
集微网消息,近日,合康新能发布公告称,公司拟向特定对象发行股票拟募 -
美媒:北约可能明年初向乌克兰交付F-16战机
本文转自【央视新闻客户端】;自俄乌冲突爆发以来,北约国家不断向乌克 -
东软集团怎么样
本文内容是由小编为大家搜集关于东软集团怎么样,以及的资料,整理后发 -
每日热闻!Supercell首席执行官提供手机...
Supercell首席执行官伊尔卡·帕纳宁(IlkkaPaananen)表示,虽然Supercel