Linux串口应用编程

1.串口概述

常见的数据通信的基本方式可分为并行通信与串行通信两种。

1.并行通信是指利用多条数据传输线将一个字数据的各比特位同时传送。它的特点是传输速度快,适用于传输距离短且传输速度较高的通信。
2.串行通信是指利用一条传输线将数据以比特位为单位顺序传送。特点是通信 线路简单,利用简单的线缆就可实现通信,降低成本,适用于传输距离长且 传输速度较慢的通信。

2.串口设置详解

串口的设置主要是设置 struct termios 结构体的各成员值

#include<termios.h> 
struct termios
{
    unsigned short  c_iflag;        /* 输入模式标志 */ 
    unsigned short  c_oflag;        /* 输出模式标志 */
    unsigned short  c_cflag;        /* 控制模式标志*/
    unsigned short  c_lflag;        /* 本地模式标志 */
    unsigned char   c_line;     /* 线路规程 */ 
    unsigned char   c_cc[NCC];  /* 控制特性 */
    speed_t c_ispeed;           /* 输入速度 */
    speed_t c_ospeed;       /* 输出速度 */
};

termios 是在 POSIX 规范中定义的标准接口,表示终端设备(包括虚拟终端、串 口等)。口是一种终端设备,一般通过终端编程接口对其进行配置和控制。在具体讲 解串口相关编程之前,先了解一下终端相关知识。
终端 有 3 种 工 作 模 式 ,分 别为 规 范模 式 ( canonical mode )、 非规 范模 式
(non-canonical mode)和原始模式(raw mode)。

在 非规 范模 式 下, 对 参 数 MIN ( c_cc[VMIN] )和 TIME(c_cc[VTIME])的设置决定 read()函数的调用方式。设置可以有 4 种不同的情况。

MIN = 0 和 TIME = 0:read()函数立即返回。若有可读数据,则读取数据并 返回被读取的字节数,否则读取失败并返回 0。
MIN > 0 和 TIME = 0:read()函数会被阻塞直到 MIN 个字节数据可被读取。
MIN = 0 和 TIME > 0:只要有数据可读或者经过 TIME 个十分之一秒的时间, read()函数则立即返回,返回值为被读取的字节数。如果超时并且未读到数 据,则 read()函数返回 0。
MIN > 0 和 TIME > 0:当有 MIN 个字节可读或者两个输入字符之间的时间 间隔超过 TIME 个十分之一秒时,read()函数才返回。因为在输入第一个字符 之后系统才会启动定时器,所以在这种情况下,read()函数至少读取一个字 节之后才返回。

按照严格意义来讲,原始模式是一种特殊的非规范模式。在原始模式下,所有的 输入数据以字节为单位被处理。在这个模式下,终端是不可回显的,而且所有特定的 终端输入/输出控制处理不可用。通过调用 cfmakeraw()函数可以将终端设置为原始模 式。

设置串口中最基本的包括波特率设置,校验位和 停止位设置。在这个结构中最为重要的是 c_cflag,通过对它的赋值,用户可以设置波 特率、字符大小、数据位、停止位、奇偶校验位和硬软流控等。在这里,不能直接对 c_cflag 成员初始化,而要将其通过“与”、“或”操作使用 其中的某些选项。

3.设置串口属性的基本流程

1) 保存原先串口配置

首先,为了安全起见和以后调试程序方便,可以先保存原先串口的配置,在这里 可以使用函数 tcgetattr(fd, &old_cfg)。该函数得到 fd 指向的终端的配置参数,并将它 们保存于 termios 结构变量 old_cfg 中。该函数还可以测试配置是否正确、该串口是否 可用等。若调用成功,函数返回值为 0,若调用失败,函数返回值为-1,其使用如下 所示:

if(tcgetattr(fd, &old_cfg) != 0)
{
    perror("tcgetattr"); 
    return -1;
}

2) 激活选项

CLOCAL 和 CREAD 分别用于本地连接和接受使能,因此,首先要通过位掩码的
方式激活这两个选项。

 newtio.c_cflag  |=  CLOCAL | CREAD;

调用 cfmakeraw()函数可以将终端设置为原始模式,在后面的实例中,采用原始
模式进行串口数据通信。其原型cfmakeraw(&new_cfg);

3) 设置波特率

设置波特率有专门的函数,用户不能直接通过位掩码来操作。设置波特率的主要
函数有:cfsetispeed()和 cfsetospeed()。这两个函数的使用很简单,如下所示:

cfsetispeed(&new_cfg, B115200); 
cfsetospeed(&new_cfg, B115200);

一般地,用户需将终端的输入和输出波特率设置成一样的。这几个函数在成功时
返回 0,失败时返回-1。

4) 设置字符大小

与设置波特率不同,设置字符大小并没有现成可用的函数,需要用位掩码。一般 首先去除数据位中的位掩码,再重新按要求设置。如下所示:

new_cfg.c_cflag &= ~CSIZE; /* 用数据位掩码清空数据位设置 */
new_cfg.c_cflag |= CS8;

5) 设置奇偶校验位

设置奇偶校验位需要用到 termios 中的两个成员:c_cflag 和 c_iflag。首先要激活 c_cflag 中的校验位使能标志 PARENB 和是否要进行偶校验,同时还要激活 c_iflag 中 的对于输入数据的奇偶校验使能(INPCK)。无校验位,代码如下:

new_cfg.c_cflag &= ~PARENB;

如使能奇校验时,代码如下所示:

new_cfg.c_cflag |= (PARODD | PARENB);
new_cfg.c_iflag |= INPCK; 

而使能偶校验时,代码如下所示:

new_cfg.c_cflag |= PARENB;
new_cfg.c_cflag &= ~PARODD;    /* 清除偶校验标志,则配置为奇校验*/ 
new_cfg.c_iflag |= INPCK;

6) 设置停止位

设置停止位是通过激活 c_cflag 中的 CSTOPB 而实现的。若停止位为一个,则清除
CSTOPB,若停止位为两个,则激活 CSTOPB。以下分别是停止位为一个和两个比特时
的代码:

new_cfg.c_cflag &= ~CSTOPB; /* 将停止位设置为一个比特 */
new_cfg.c_cflag |= CSTOPB; /* 将停止位设置为两个比特 */

7) 设置最少字符和等待时间

在一般的情况下,可以设置设置为阻塞等待,直read到数据才返回

termios_new.c_cc[VTIME] = 0;
termios_new.c_cc[VMIN]   = 4;

8) 清除串口缓冲

由于串口在重新设置之后,需要对当前的串口设备进行适当的处理,这时就可调用在<termios.h>中声明的tcdrain()、tcflow()、tcflush()等函数来处理目前串口缓冲中的数据,它们的格式如下所示。

int tcdrain(int fd); /* 使程序阻塞,直到输出缓冲区的数据全部发送完毕*/
int tcflow(int fd, int action) ; /* 用于暂停或重新开始输出 */
int tcflush(int fd, int queue_selector); /* 用于清空输入/输出缓冲区*/

本实例中使用 tcflush()函数,对于在缓冲区中的尚未传输的数据,或者收到的
但是尚未读取的数据,其处理方法取决于 queue_selector 的值,它可能的取值有以下几种。

TCIFLUSH:对接收到而未被读取的数据进行清空处理。
TCOFLUSH:对尚未传送成功的输出数据进行清空处理。
TCIOFLUSH:包括前两种功能,即对尚未处理的输入输出数据进行清空处理。

9) 激活配置

在完成全部串口配置之后,要激活刚才的配置并使配置生效。这里用到的函数是tcsetattr(),
它的函数原型是:

tcsetattr(int fd, int optional_actions, const struct termios*termios_p);

其中参数 termios_p 是 termios 类型的新配置变量。
参数 optional_actions 可能的取值有以下 3 种:

TCSANOW:配置的修改立即生效。
TCSADRAIN:配置的修改在所有写入 fd 的输出都传输完毕之后生效。
TCSAFLUSH:所有已接受但未读入的输入都将在修改生效之前被丢弃。

该函数若调用成功则返回 0,若失败则返回-1,代码如下所示:

if ((tcsetattr(fd, TCSANOW, &new_cfg)) != 0)
{
    perror("tcsetattr");
    return -1;
}

4.串口使用详解

在配置完串口的相关属性后,就可以对串口进行打开和读写操作了。它所使用的函数和普通文件的读写函数一样,都是 open()、write()和 read()。它们之间的区别的只是串口是一个终端设备,因此在选择函数的具体参数时会有一些区别。另外,这里会用到一些附加的函数,用于测试终端设备的连接情况等。下面将对其进行具体讲解。

1) 打开串口

打开串口和打开普通文件一样,都是使用 open()函数,如下所示:

fd = open( "/dev/ttyS0", O_RDWR|O_NOCTTY);

可以看到,这里除了普通的读写参数外,还有参数 O_NOCTTY 。O_NOCTTY 标志用于通知 Linux 系统,该参数不会使打开的文件成为这个进程的控制终端。如果没有指定这个标志,那么任何一个输入(诸如键盘中止信号等)都将会影响用户的进程

2) 配置串口

3) 读写串口

读写串口操作和读写普通文件一样,使用 read()和 write()函数即可,如下所示:

write(fd, buff, strlen(buff));
read(fd, buff, BUFFER_SIZE)

具体应用代码下载请点击:
http://download.csdn.net/download/xiebaocheng12138/9957765

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值