linux下使用串口通信总结

第一次接触linux应用编程,需要操作串口,遇到了一些问题,将几个关键点记录一下。
串口配置的文章网上很多,基本都大同小异,这里放几个链接用于参考。

https://blog.csdn.net/wangzhen209/article/details/45246993
https://blog.csdn.net/ywcpig/article/details/92081108
https://blog.csdn.net/m0_38096844/article/details/90716182
https://zhuge.blog.csdn.net/article/details/89039897

总结一下基础的串口配置,主要是串口的波特率,数据位,校验位,停止位,数据流控的配置。需要根据实际要求配置。
在linux下的串口配置中,除了这些基本配置之外,还有一些需要注意的点。

第一点:串口的收发模式。串口属于linux下的终端设备,在输入输出数据时有两种模式。一种是规范模式,一种是原始模式,规范模式下,发送和接收的数据都是做行处理的,我的理解就是会在串口数据里加很多控制字符,比如我输入回车,串口数据才发送之类的;原始模式下,则接收和发送的数据都是不做任何处理的,传感器发给linux主机什么数据,主机就读取什么数据,不像规范模式下,会将一些值识别为特殊控制字符。如果串口是用作终端数据打印时,配置为规范模式;如果串口时用于和其他传感器进行数据通信,则串口要配置为原始模式。

原始模式配置要修改如下标志位。或者调用cfmakeraw()函数可以将终端设置为原始模式

//raw mode
opt.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
opt.c_iflag &= ~(IXON | IXOFF | ICRNL | INLCR | IGNCR);
opt.c_oflag &= ~(OPOST);

第二点:串口的工作模式。串口可以工作在两种工作模式下,一种是非阻塞模式,另一种是阻塞模式。配置工作模式的时候,可以在open串口的时候,添加O_NBLOCK或者O_NDELAY标志位,可以配置为非阻塞模式,不添加则是阻塞模式。还可以通过fcntl()函数进行配置。
首先讲一下阻塞模式,如果配置为阻塞模式,则在串口配置时,VMIN和VTIME配置就会被激活。VMIN和VTIME指定了串口跳出阻塞的规则。
VMIN和VTIME的规则如下:
1)当MIN > 0,TIME > 0时
TIME为接收到第一个字节后允许的数据传输或等待的最长分秒数(1分秒= 0.1秒)。定时器在收到第一个字节后启动,在计时器超时之前,若已收到MIN个字节,则read返回MIN个字节,否则,在计时器超时后返回实际接收到的字节。
注意:因为只有在接收到第一个字节时才启动,所以至少可以返回1个字节。这种情形中,在接到第一个字节之前,调用者阻塞。如果在调用read时数据已经可用,则如同在read后数据立即被接到一样。

2)当MIN > 0,TIME = 0时
MIN个字节完整接收后,read才返回,这可能会造成read无限期地阻塞。

3)当MIN = 0, TIME > 0时
TIME为允许等待的最大时间,计时器在调用read时立即启动,在串口接到1字节数据或者计时器超时后即返回,如果是计时器超时,则返回0。

4)当MIN = 0,TIME = 0时
如果有数据可用,则read最多返回所要求的字节数,如果无数据可用,则read立即返回0。

总的来说,就是VMIN定义了串口跳出阻塞需要满足接收区内有多少字节,串口接收区内有VMIN个字节数据则跳出阻塞。VTIME定义了串口的阻塞时间,阻塞时间超过了VTIME则跳出阻塞。如果VMIN = 0,VTIME != 0,则是收到一个字节,或者超时VTIME则跳出阻塞。如果VMIN != 0,VTIME = 0,则是收到VMIN个字节跳出阻塞,否则永远阻塞。
我一开始在用串口收发数据时,一直以为如果满足VMIN条件跳出阻塞的意思就是串口接收区刚好有VMIN个数据了就跳出阻塞,此时read去读取串口接收区的数据,返回的字节个数就是VMIN个,但是实际并不是这样的,实际上是数据在发送到串口接收区中时,数据大于等于VMIN个字节,串口就会跳出阻塞,此时read读取到的数据,实际是有可能大于VMIN的,read的数据读取上限则是根据read函数中控制读取字节个数的入口参数来配置的。

在编写串口数据接收函数时,可以使用select函数。
代码如下:
timeoutms用来设置select的超时时间,单位是ms。这段接收代码可以接收不定长的串口数据。数据总长别超过SERIAL_BUFFER_SIZE就行。串口可以配置为阻塞,VMIN !=0,VTIME = 0的模式,并且不会永久阻塞,因为read的外层有一个select函数,select超过超时时间后,就会强置跳出阻塞,并输出相应的错误码。
Fd和RecvBuff均定义成了全局变量,在多线程编程的时候要注意加锁。也可以根据需要修改。

int hrt_radar_receive_return_data_once(int timeoutms)
{
    int slaveret = ERROR;
    int selectret = ERROR;
    fd_set readfds;
    struct timeval  selecttime;
    
    memset(RecvBuff,0,SERIAL_BUFFER_SIZE);
    
    selecttime.tv_sec = timeoutms/1000;
    selecttime.tv_usec = (timeoutms%1000)*1000;
    FD_ZERO(&readfds);
    FD_SET(Fd, &readfds);
    
    selectret = select(Fd+1, &readfds, NULL, NULL, &selecttime);
    if (selectret > 0) 
    {
        slaveret = read(Fd, RecvBuff,SERIAL_BUFFER_SIZE);
        if(slaveret <= 0)
        {
            debug("read error\n");
            return ERROR;
        }
        tcflush(Fd,TCIFLUSH);
    }
    else if(selectret == 0)
    {
        debug("select timeout\n");
        return ERROR;
    }
    else
    {
        debug("select error\n");
        return ERROR;
    }
    return slaveret;
}
  • 2
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值