linux串口编程:LINUX串口简明解析[修正版][0919]

09-14
上周的时候,发了篇文章,关于linux串口的【当然程序师转别人的(还是发布在IBM开发者社区的嘞)】,
虽然当时能跑的通,但这周在用的时候却发现不行了,于是决定仔细研究下linux下串口这东西!
当然那个程序有问题,就要自己重新写啦。。。。。。OTZ 。。。。饿。。。我向来比较懒。。。。

当然研究过程中还是明白了不少东西的
1,解决minicom启动后才能正常读取数据的问题
2.  解决读取数据缺失的问题
3.  学习使用select函式检测串口状态信息
。。。。。。。。。。。。。。。。。。。。。。



当然这次顺带加点自己的分析
串口的配置一般也就是波特率,数据格式这些东西,而linux环境下则通过一名为termios的结构体对其进行配置
其成员如下

                     Termios Structure Members

Member Description

c_cflag

Control options

c_lflag

Line options

c_iflag

Input options

c_oflag

Output options

c_cc

Control characters

c_ispeed

Input baud (new interface)

c_ospeed

Output baud (new interface)


看英文就很容易明白了,所以我也不多说啥了。
这个结构体其实很简单,但其中每一项的配置却要复杂的多,实际上我也没有逐项的学习
只是捡有用的看了下,而下面就是关于这些知识的记录。

1.打开串口

Code
打开时一般可以用O_RDWR ,O_NOCTTY , O_NDELAY这三个参数的组合
分别代表读写[当然有对应只读,只写的,猜都猜到了],第二个告诉系统该串口不被用来作控制终端【没弄明白,反正一般我是不用,见过跟modem通信的程序会用到】
最后那个就是不要等的意思啦。。。。。。

2.配置串口
下面的漏了个枚举量,先不上
typedef 
enum 
{
    SERIAL_8N1=0,
    SERIAL_7E1=1,
    SERIAL_7O1=2,
    SERIAL_7S1=3
}serial_format;
Code


speed_set那个自然是用来设置波特率的
tc***attr那个参数用来获取和设置termios的信息【中间的***,自己猜吧。。。XD】
TCSANOW那个参数当然是指立即更新参数的意思
其中对speed设置具体到了输入和输出,也就意味着可以使不同的速率,另外要说的就是如果要设置9600的波特率
上面的程序中要传入的参数是B9600,他是一个被定义的数值,不是9600

format_set则是配置串口的数据格式
上面程序中配置了最常见的几种类型
比如8位数据无校验,7位数据的奇校验,偶校验以及空格校验,
下面仅分析8位无校验的最常见情形
//校验除能
options.c_cflag &= ~PARENB;
//此位除能代表一位停止位,反之代表两位停止位
options.c_cflag &= ~CSTOPB;
//清空数据宽度度屏蔽位,以便设置
options.c_cflag &= ~CSIZE;
//设置8位数据宽度 options.c_cflag |= CS8;
//相应的,对于输入的数据也除能校验使能,并且不清除第八位 options.c_iflag &= ~(INPCK | ISTRIP);







上次发的文章中的程序有问题和下面这段代码关系密切
Code

注释其实写的很明白了,因为linux版的slickedit对中文支持不是很好【配置很麻烦,还容易卡死】,所以用英文了
这里面只说一句,就是
 options.c_lflag &=~(ICANON | ECHO | ECHOE | ISIG);
它代表为原始数据传输,而与之相对的则是标准数据传输
其实我也没弄明白到底啥区别,反正就按上面的写才能接收到数据



      

其实基本的操作都已经罗列完了,但是测试时总会出现这样那样的问题
如果直接用read读取,可能因为种种原因,独到的数据和我们期待的不一致
多半是时序上的问题,
比如你去读时数据还没准备好。。。。



      
而解决的办法,下面举一例
就是利用ioctl来获取当前串口缓冲中的信息
int wait=0;
do
{
                     
      ioctl(fd, FIONREAD, &bytes);

}
while( wait++,bytes!=bytes_needed);
而有些时候若长时间没有相应,我们还要做超时处理
这就要借用select函式了




      
fd_set         input;
struct timeval timeout;

/* Initialize the input set */
FD_ZERO(&input);
FD_SET(fd, &input);



/* Initialize the timeout structure */
timeout.tv_sec  = 10;
timeout.tv_usec = 0;

/* Do the select */
n = select(fd, input, NULL, NULL,&timeout) ;

/* See if there was an error */
if (n<0)
  perror("select failed");
else if (n == 0)
  puts("TIMEOUT");
else
{
  /* We have input */
  if (FD_ISSET(fd, input))
    process_fd();

}
这里要说明的是,超时时间中的usecond对应的是微秒,也就是microsecond
而毫秒的英文是millisecond
另外
FD_ZERO(&input);
FD_SET(fd, &input);
则分别清空了input信号集,并把fd描述符添加至该信号集




      
哎,别的不多说了,下面给出完整的回传数据测试代码
这次肯定没问题了,因为是自己写的。。。吼吼。。。。OTZ
Code














      







 
实际测试截图,截取自linux版slickedit的output窗口



串口接法图【使用跳线帽】
 
 
Tags:  linux串口设置 linux串口驱动 linux串口 linux串口编程

延伸阅读

最新评论

发表评论