Linux下串口编程
参考:
1. POSIX操作系统串口编程指南 2. UNIX环境高级编程
在Linux下,标准的串口设备节点名为/dev/ttyS*,如果是USB转串口,则为/dev/ttyUSB*,其中'*'代表0、1...这类数字。
一、访问串口 1 打开串口
打开串口使用open系统调用,例如: #include
* 'open_port()' - Open serial port 1. *
* Returns the file descriptor on sueess or -1 on error. */ int
open_port(void) {
int fd; /* File descriptor for the port */
fd = open(\if (fd == -1) {
/*
* Could not open the port.
/* Standard input/output definitions */ /* String function definitions */ /* UNIX standard function definitions */ /* File control definitions */ /* Error number definitions */
#include
}
} else
*/
perror(\
fcntl(fd, F_SETFL, 0);
return (fd);
在上面的open系统调用中,除了O_RDWR标志外,还使用了O_NOCTTY和O_NDELAY这两个标志。 O_NOCTTY:
O_NOCTTY这个标志用于告知UNIX该程序不想作为该端口的”控制终端“,如果没有指定该标志那么所有的输入(例如键盘的终止信号(Ctrl + c)等等)将会影响你的程序。而像gettty(1M/8)这类程序会使用这个特性来启动一个登录进程,通常情况下用户不需要这个特性(也就是说要使用O_NOCTTY这个标志)。
O_NDELAY:
O_NDELAY这个标志用于告知UNIX该程序不需要关心DCD信号的状态,也就是说不需要关心端口的另一端是否已经连接。如果不指定这个标志的话,那么程序将会一直休眠直到DCD信号线上检测到有space电压。
2 写数据到端口
写数据使用write系统调用,例如: n = write(fd, \if (n < 0)
write系统调用返回已发送的字节数或者发生错误时返回-1。
3 从端口读取数据
当端口在raw data mode操作模式下,那么read系统调用将返回从串口输入缓冲区中实际得到的字节数,如果没有数据可读,那么该系统调用将会被阻塞(block)直到有数据为止,如果超过一定时间仍然没有数据可读,那么将返回
fputs(\
一个错误(读错误)。read函数也可以立即返回(即在没有数据可读的情况下也能立即返回,而不是被阻塞),需要做如下工作: fcntl(fd, F_SETFL, FNDELAY);
FNDELAY选项的意思是read函数在没有数据可读的情况下立即返回0。需要重新回到阻塞模式(blocking)下,那么在调用fcntl()的时候不要加上FNDELAY这个选项:
fcntl(fd, F_SETFL, 0);
4 关闭串口
关闭串口使用close系统调用,例如: close(fd);
二、串口配置
需要包含
struct termios结构至少包含以下成员:
1 c_cflag
c_cflag成员用于控制串口波特率、数据位、校验位、停止位以及硬件流控制等等,位成员有: CBAUD
B0 B50 B75 B110 B134 B150 B200 B300
波特率掩码位
tcflag_t c_iflag; tcflag_t c_oflag; tcflag_t c_cflag; tcflag_t c_lflag; cc_t
c_cc[NCCS];
/* input modes */ /* output modes */ /* control modes */ /* local modes */ /* control chars */
EXTA EXTB
B600 B1200 B2400 B4800 B9600 B19200 B38400 B57600 B76800 B115200 CS5 CS6 CS7 CS8
2位停止位 接收使能 奇偶校验使能 使用奇校验 忽略终端状态行 硬件流控制使能位
外部时钟 外部时钟 数据位掩码位
CSIZE
CSTOPB CREAD PARENB PARODD CLOCAL CRTSCTS
通常情况下,CLOCAL和CREAD这两个选项应该应该总是被打开的。
1.1 设置波特率
波特率的存储位置依赖于操作系统,在比较老接口上波特率存储在c_cflag成员中,在后来的接口中提供了c_ispeed和c_ospeed这两个成员来存储实际的波特率值,所以在设置波特率时应该使用cfsetospeed和cfsetispeed这两个函数(而不是直接赋值的方式)。例如: struct termios options; /*
* Get the current options for the port...
*/
tcgetattr(fd, &options); /*
* Set the baud rates to 19200... */
cfsetispeed(&options, B19200); cfsetospeed(&options, B19200); /*
* Enable the receiver and set local mode... */
options.c_cflag |= (CLOCAL | CREAD); /*
* Set the new options for the port... */
tcsetattr(fd, TCSANOW, &options);
其中用到了tcgetattr和tcsetattr这两个函数用于获取和设置串口的属性。 tcgetattr函数原型如下:
int tcgetattr(int fd, struct termios *termios_p);
tcgetattr用于获取当前的串口设置到它的参数termios_p中,而要修改串口设置则使用tcsetattr函数,原型如下:
int tcsetattr(int fd, int optional_actions,
const struct termios *termios_p);
立即修改设置
等待所有数据传输完成后才修改设置
同样需要等待,但是它是立即刷新输入、输出缓冲区,然后才
其中options_actions有几个选项值: TCSANOW TCSADRAIN TCSAFLUSH 修改设置。
而cfsetispeed和cfsetospeed函数是专门用于设置串口波特率的,函数原型如下: