分类:
2010-12-13 09:55:23
串口操作采用UNIX类似的方式,打开/关闭/发送/接收等基本操作采用类似文件系统的方式进行,而一些属性的设置和控制则使用termios来进行。
串口对应的设备文件名为”/dev/ttyS0”。
1. 打开串口
fd = open(“/dev/ttyS0”, O_RDWR);
如果只发送数据,可以使用O_WRONLY, 如果只接收数据,可以设置成O_RDONLY。
2. 关闭串口 close(fd);
3. 接收数据
ret = read(fd, buf, 100);
串口默认的打开方式是非阻塞的,因此本函数只是接收缓冲中的数据,而并非直接操作IO。如果要加入一些IO的属性,请参见”使用超时”和”设置串口属性”。
如果缓冲中有接收到的数据,那么本函数将返回实际接收到的数据长度,当然不会超过指定的100字节。如果缓冲中没有数据,那么将返回0。如果接收失败,那么将返回-1,错误代码放在errno中。
4. 发送数据
ret = write(fd, buf, 100);
返回值表示实际发送的数据长度。
5. 设置串口属性
tcgetattr(int fd, struct termios *termios_p);
tcsetattr(int fd, int optional_actions, struct termios *termios_p);
串口打开后,使用的串口属性实际上是上一次关闭串口前的设置。这个设置也就是一个结构struct termios,其中主要有以下的属性:
tcflag_t c_iflag // 输入属性
tcflag_t c_oflag // 输出属性
tcflag_t c_cflag // 控制属性
tcflag_t c_lflag // 本地属性
cc_t c_cc[NCCS] // 控制字
c_iflag
IGNBRK 忽略接收到的break信号
BRKINT 如果IGNBRK被设置,break信号将被忽略,否则如果BRKINT被设置,接收到break信号将导致输入/输出队列被清空,并且当前控制串口的前 台进程将收到一个SIGINT信号。如果IGNBRK和BRKINT都没有被设置 ,收到的break信号将被接收为
NULL,即{post.content}。但是如果PARMARK被设置,接收到的break信号将被接收为7{post.content} 。
IGNPAR 忽略帧错误或奇偶校验错。
PARMARK 如果没有设置IGNPAR,设置本属性表示在接收到的带有错误的帧格式或奇偶校验的字符将被前缀377{post.content}。如果两者都没有设 置,带有错误的帧格式或奇偶校验的字符将被接收为{post.content}。
INPCK 打开输入数据的奇偶校验。
ISTRIP 滤掉第8位。
INLCR 将接收到的NL(换行)转换成CR(回车)。
IGNCR 忽略接收到的CR。
ICRNL 将收到的CR转换成NL(除非设置了IGNCR)。
IUCLC 将接收到的大写字符转换成小写。
IXON 打开输出的XON/XOFF控制。
IXOFF 打开输入的XON/XOFF控制。
c_oflag
OLCUC 将小写字符转换成大写后输出。
ONLCR 将NL转换成CR-NL后输出。
OCRNL 将CR转换成NL后输出。
ONLRET 不发送CR。
c_cflag
CBAUD 波特率掩码,可以设置为
B2400
B4800
B9600
B19200
B38400
B57600
B115200
CSIZE 字符长度掩码,可以设置为
CS5
CS6
CS7
CS8
CSTOPB 设置为两个停止位。(默认为1个)
CREAD 打开接收功能。
PARENB 打开发送的奇偶校验生成功能和接收的奇偶校验检查功能,默认的是偶校验。
PARODD 使用奇校验。
CLOCAL 忽略modem信号线。
CRTSCTS 打开RTS/CTS硬件流控。
c_lflag
由于使用该类属性不多,因此在此不作介绍。
c_cc
常用的是c_cc[VMIN],表示调用read函数时等待接收的最少字符个数。例如设置为1时,read函数至少要读到1个字符才会返回。
optional_actions
可以设置为
TCSANOW 立即更新当前的设置。
TCSADRAIN 在当前发送缓冲的所由数据发送完毕后再更新当前设置。
TCSAFLUSH 同TCSADRAIN,只是在更新前
所有为被读取的收到的数据将被丢弃。
6. 使用超时
int select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
struct timeval *timeout);
此函数用于控制接收、发送或异常出现之前的超时。
fd_set是句柄的集合,其中的句柄都是被监测的对象。
readfds表示需要监测其中句柄代表的设备是否可以从中读取数据。
writefds表示需要监测其中句柄代表的设备是否可以向其写入数据。
exceptfds表示需要监测其中句柄代表的设备是否出现异常。
timeout是这样一个结构
struct timeval{
long tv_sec; // 秒
long tv_usec; // 微秒
};
n则是所有监测的句柄中的最大值加一。
系统提供一些定义号的操作来操作fd_set:
FD_CLR(int fd, fd_set *fds);
将fd从fds集合中去掉。
FD_ISSET(int fd, fd_set *fds);
检查fd是否在fds集合中。
FD_SET(int fd, fd_set *fds);
将fd加入fds集合中。
FD_ZERO(fd_set *fds);
将fds集合清空。
7. 其它串口操作
int tcdrain(int fd);
等待所有发送缓冲的数据全部发送出去后返回。
int tcflush(int fd, int queue_selector);
queue_selector:
TCIFLUSH
丢弃所有未读取的接收到的数据。
TCOFLUSH
丢弃所有为发送的发送缓冲的数据。
TCIOFLUSH
丢弃上面两种数据。
示例
#include
#include
#include
#include
int main() {
int fd;
struct termios attr;
fd_set fds;
struct timeval tv;
unsigned char buf[1024];
// 打开串口
fd = open(“/dev/ttyS0”, O_RDWR);
if (fd == -1)
return -1;
// 读取串口当前属性
tcgetattr(fd, &attr);
// 设置最少接收字符个数为0
attr.c_cc[VMIN] = 0;
// 不处理iflag、oflag和lflag
attr.c_iflag = 0;
attr.c_oflag = 0;
attr.c_lflag = 0;
// 设置波特率为9600,字符长度为8位,偶校验,允许接收
attr.c_cflag = B9600 | CS8 | PARENB | CLOCAL | CREAD;
// 设置串口属性
tcsetattr(fd, TCSANOW, &attr);
// 发送字符串
write(fd, “12345 ”, 6);
// 清除监测集合
FD_ZERO(&fds);
// 将串口句柄加入到监测集合中
FD_SET(fd, &fds);
// 设置超时为5秒
tv.tv_sec = 5;
tv.tv_usec = 0;
// 监测串口是否有数据接收到,超时为5秒
if (select(fd+1, &fds, NULL, NULL, &tv) <= 0)
return -1;
// 接收最多100个字符
read(fd, buf, 100);
// 关闭串口
close(fd);
return 0;
}