Linux串口编程进阶
在《Linux串口编程》编程一文中介绍了串口应用中常用的基本操作,如:串口打开关闭、串口设置、数据收发等。本篇文章主要基于常规串口操作进行了扩充,主要介绍如下操作:
- Linux系统使用非标准波特率
- 同步方式串口发送
- select I/O复用串口数据读写
- 串口参数VTIME和VMIN的作用
- RS485串口功能应用
- 串口同步等待Modem信号变化
与上一篇文章类似,为方便用户使用我们将以上串口操作均封装成了独立的函数,可以极大的节约开发时间。
1、Linux系统使用非标准波特率
/**
* libtty_setcustombaudrate - set baud rate of tty device
* @fd: device handle
* @speed: baud rate to set
*
* The function return 0 if success, or -1 if fail.
*/
static int libtty_setcustombaudrate(int fd, int baudrate)
{
struct termios2 tio;
if (ioctl(fd, TCGETS2, &tio)) {
perror("TCGETS2");
return -1;
}
tio.c_cflag &= ~CBAUD;
tio.c_cflag |= BOTHER;
tio.c_ispeed = baudrate;
tio.c_ospeed = baudrate;
if (ioctl(fd, TCSETS2, &tio)) {
perror("TCSETS2");
return -1;
}
if (ioctl(fd, TCGETS2, &tio)) {
perror("TCGETS2");
return -1;
}
return 0;
}
Note:
- 使用cfsetspeed函数集无法设置非标准波特率的主要原因主要是因为系统中缺少相关的宏定义。glibc中均是通过波特率宏和实际波特率之间进行转换。
- 如上设置波特率的方法主要是使用了termios2结构体,将相应标志位BOTHER置为有效,然后通过ioctl传递给驱动的tty核心层。
2、同步方式串口发送
直接使用write函数完成串口数据的发送时,在该函数返回时实际上只是把write缓冲区的数据拷贝至tty内核层的缓冲区中,当缓冲区满时write才会阻塞,此过程中串口驱动并未执行真正的发送动作。在有些场景下,我们希望等待串口发送物理上真正完成了再执行后续的操作。那么此时需要使用的函数为:
/**
* tcdrain() waits until all output written to the object referred to by fd has been
* transmitted.
*/
int tcdrain(int fd);
3、select I/O复用串口数据读写
使用select函数实现的I/O多路转接模型,在select操作期间,I/O可以进行其他操作。在对多个设备同时使用的应用场景中应用较为普遍。比如多个串口设备,或者网络通讯中处理多个客户端。select可以具体设置每个文件描述符的条件、等待时间等,这样在函数返回时可以知道具体哪个设备已经准备好读写。
/**
* libtty_selectread - read data from uart
* @fd: device handle
* @buffer: pointer to read buffer
* @count: read length
*
* The function return actual read length if success, 0 if timeout, -1 if fail.
*/
static int libtty_selectread(int fd, char *buffer, int count)
{
int ret;
fd_set rd;
struct timeval tv;
FD_ZERO(&rd);
FD_SET(fd, &rd);
tv.tv_sec = 5;
tv.tv_usec = 0;
ret = select(fd + 1, &rd, NULL, NULL, &tv);
if (ret == -1) {
perror("select(): ");
}
else if (ret)
return read(fd, buffer, count);
else {
printf("select timeout.\n");
}
return ret;
}
4、串口参数VTIME和VMIN的作用
VTIME和VMIN常规情况下,设置为0。但是很多应用场景我们需要将二者结合起来共同控制对串口的读取行为,参数组合说明如下:
- VMIN = 0 和 VTIME = 0 :在这种情况下,read 调用总是立刻返回。如果有等待处理的字符,read 就会立刻返回;如果没有字符等待处理,read 调用返回0,并且不读取任何字符;
- VMIN = 0 和 VTIME > 0 :在这种情况下,只要有字符可以处理或者是经过 VTIME 个十分之一秒的时间间隔,read 调用就返回。如果因为超时而未读到任何字符,read 返回0,否则 read 返回读取的字符数目。
- VMIN > 0 和 VTIME = 0 :在这种情况下,read 调用将一直等待,直到有 MIN 个字符可以读取时才返回,返回值是读取的字符数量。到达文件尾时返回0。
- VMIN > 0 和 VTIME > 0 :在这种情况下,当 read 被调用时,它会等待接收一个字符。在接收到第一个字符及后续的每个字符后,一个字符间隔定时器被启动(如果定时器已经运行,则重启它)。当有 MIN 个字符可读或两个字符之间的时间间隔超过 TIME 个十分之一秒时,read 调用返回。这个功能可用于区分是单独按下了 Escape 键还是按下一个 Escape 键开始的功能组合键。但要注意的是,网络通信或处理器的高负载将使得类似这样的定时器失去作用。
5、RS485串口功能应用
部分使用RS485的应用场景或者针对特定的串口硬件,需要通过串口应用程序主动调用RS485功能开启的相关API。用法如下:
/**
* libtty_rs485set - rs485 set
* @fd: file descriptor of tty device
* @enable: 0 on disable, other on enable
*
* The function return 0 if success, others if fail.
*/
int libtty_rs485set(int fd, char enable)
{
struct serial_rs485 rs485conf;
if (enable)
rs485conf.flags |= SER_RS485_ENABLED;
else
rs485conf.flags &= ~SER_RS485_ENABLED;
return ioctl(fd, TIOCSRS485, &rs485conf);
}
6、 串口同步等待Modem信号变化
同步等待串口Modem信号变化是指,应用程序可以调用接口函数进入等待,直到程序中设定的Modem输入信号DCD/RI/CTS/DCD的信号变化才退出等待。常用于设备状态与特定仪器的操作同步场景。
/**
* libtty_tiocmwait - wiat for modem signal to changed
* @fd: file descriptor of tty device
*
* The function return 0 if success, others if fail.
*/
static int libtty_tiocmwait(int fd)
{
unsigned long modembits = TIOCM_DSR | TIOCM_CTS | TIOCM_CD | TIOCM_RI;
return ioctl(fd, TIOCMIWAIT, modembits);
}
如以上代码所示,设置等待的modem信号为所有输入信号DSR、CTS、DCD和RI,只要任意一路串口信号发生改变,则API退出。
关于Linux串口编程的介绍就到这里了,关于更多更实用的串口用法可以随时交流讨论哈~
Linux串口编程进阶的更多相关文章
- storysnail的Linux串口编程笔记
storysnail的Linux串口编程笔记 作者 He YiJun – storysnail<at>gmail.com 团队 ls 版权 转载请保留本声明! 本文档包含的原创代码根据Ge ...
- Linux串口编程详解(转)
串口本身,标准和硬件 † 串口是计算机上的串行通讯的物理接口.计算机历史上,串口曾经被广泛用于连接计算机和终端设备和各种外部设备.虽然以太网接口和USB接口也是以一个串行流进行数据传送的,但是串口连接 ...
- linux串口编程总结
串口本身.标准和硬件 † 串口是计算机上的串行通讯的物理接口.计算机历史上,串口以前被广泛用于连接计算机和终端设备和各种外部设备.尽管以太网接口和USB接口也是以一个串行流进行数据传送的.可是串口连接 ...
- linux串口编程参数配置详解(转)
1.linux串口编程需要的头文件 #include <stdio.h> //标准输入输出定义#include <stdlib.h> //标准函数 ...
- linux串口编程参数配置详解
1.linux串口编程需要的头文件 #include <stdio.h> //标准输入输出定义 #include <stdlib.h> //标准函 ...
- linux串口编程
按照对linux系统的理解,串口编程的顺序无非就是open,read,write,close,而串口有波特率.数据位等重要参数需要设置,因此还应该用到设置函数,那么接下来就带着这几个问题去学习linu ...
- Linux串口编程(转载)
在嵌入式Linux中,串口是一个字设备,访问具体的串行端口的编程与读/写文件 的操作类似,只需打开相应的设备文件即可操作.串口编程特殊在于串 口通信时相关参数与属性的设置.嵌入式Linux的串口编程时 ...
- linux串口编程设置(转载)
(转载)在嵌入式Linux中,串口是一个字设备,访问具体的串行端口的编程与读/写文件 的操作类似,只需打开相应的设备文件即可操作.串口编程特殊在于串 口通信时相关参数与属性的设置.嵌入式Linux的串 ...
- Linux 串口编程
今天对应用层串口编程进行了验证.程序来源于以下参考链接,自己进行了一些注释和更改,记录于此. Tony Liu, 2016-6-17, Shenzhen 参考链接 https://www.ibm.co ...
随机推荐
- Linux强制用户首次登录修改密码
一个执着于技术的公众号 地方 前言 Linux强制用户首次登陆修改密码,这应该是RHCE认证中用户管理部分, 属于很基础的内容了.可是我忘记了,所以就有了下面的记录~ 实验过程 1.创建用户并设置登录 ...
- 基于SqlSugar的开发框架循序渐进介绍(2)-- 基于中间表的查询处理
在前面介绍的SqlSugar的相关查询处理操作中,我们主要以单表的方式生成相关的实体类,并在查询的时候,对单表的字段进行条件的对比处理,从而返回对应的数据记录.本篇随笔介绍在一些外键或者中间表的处理中 ...
- Redis 的数据过期了就会马上删除么?
码哥,当 key 达到过期时间,Redis 就会马上删除么? 先说结论,并不会立马删除,Redis 有两种删除过期数据的策略: 定期选取部分数据删除: 惰性删除: 该命令在 Redis 2.4 版本, ...
- 『忘了再学』Shell基础 — 13、环境变量(一)
目录 1.用户自定义的环境变量 (1)环境变量设置 (2)查询自定义环境变量 (3)删除自定义环境变量 2.系统自带的环境变量--PATH环境变量 (1)PATH环境变量 (2)PATH环境变量的作用 ...
- DirectX11--CPU与GPU计时器
前言 GAMES104的王希说过: 游戏引擎的世界里,它的核心是靠Tick()函数把这个世界驱动起来. 本来单是一个CPU的计时器是不至于为其写一篇博客的,但把GPU计时器功能加上后就不一样了.在这一 ...
- CentOS7软件环境
一.软件环境 1.1 centos7 [root@centos7 ~]# cat /etc/redhat-release CentOS Linux release 7.4.1708 (Core) [r ...
- 04 Springboot 格式化LocalDateTime
Springboot 格式化LocalDateTime 我们知道在springboot中有默认的json解析器,Spring Boot 中默认使用的 Json 解析技术框架是 jackson.我们点开 ...
- vuex+Es6语法补充-Promise
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式,采用 集中式存储管理 单页面的状态管理/多页面状态管理 使用步骤: // 1.导入 import Vuex from 'vuex' // ...
- 《HelloGitHub》第 74 期
兴趣是最好的老师,HelloGitHub 让你对编程感兴趣! 简介 HelloGitHub 分享 GitHub 上有趣.入门级的开源项目. https://github.com/521xueweiha ...
- PostgreSQL 的窗口函数 OVER, WINDOW, PARTITION BY, RANGE
最近在数据处理中用到了窗函数, 把使用方法记录一下, 暂时只有分组排序和滑动时间窗口的例子, 以后再逐步添加 场景 在SQL查询时, 会遇到有两类需要分组统计的场景, 在之前的SQL语法中是不方便实现 ...