本文共 2697 字,大约阅读时间需要 8 分钟。
参考文章:
和其他设备一样,Linux也是通过设备文件来提供访问串口的功能。当需要访问串口的时候,你只需要open相应的文件。Linux系统上一般有一个或者多个串口,一般串口设备在dev文件夹中的名称为ttyS0、ttyS1之类的,S表示的是Serial的意思。使用系统调用open函数打开对应的串口设备之后就可以进行读写操作,但是在读写操作之前还需要进行串口的设置,否则使用的是默认的串口配置。配置的方法下面将会介绍。
打开串口连接的时候,程序在open函数中除了Read+Write模式以外还指定了两个选项;
fd = open(“/dev/ttyS0”, O_RDWR | O_NOCTTY | O_NDELAY); 标志O_NOCTTY可以告诉UNIX这个程序不会成为这个端口上的“控制终端”。如果不这样做的话,所有的输入,比如键盘上过来的Ctrl+C中止信号等等,会影响到你的进程。而有些程序比如getty(1M/8)则会在打开登录进程的时候使用这个特性,但是通常情况下,用户程序不会使用这个行为。 O_NDELAY标志则是告诉UNIX,这个程序并不关心DCD信号线的状态——也就是不关心端口另一端是否已经连接。如果不指定这个标志的话,除非DCD信号线上有space电压否则这个程序会一直睡眠。打开串口设备之后要做的第一步工作就是配置串口的参数例如波特率、数据位长度、停止位数量、流控等等。很多系统都支持POSIX终端(串口)接口。程序可以利用这个接口来改变终端的参数,与串口操作相关的最重要的两个POSIX函数可能就是tcgetattr(3)和tcsetattr(3)。顾名思义,这两个函数分别用来取得设设置终端的属性。调用这两个函数的时候,你需要提供一个包含着所有串口选项的termios结构体:
struct termios { tcflag_t c_iflag; //input flags tcflag_t c_oflag; //output flags tcflag_t c_cflag; //control flags tcflag_t c_lflag; //local flags cc_t c_cc[NCCS]; //control characters };
串口配置流程
1>保存原先串口配置,用tcgetattr(fd,&oldtio)函数 struct termios newtio,oldtio; tcgetattr(fd,&oldtio); 2>激活选项有CLOCAL和CREAD,用于本地连接和接收使用 newtio.c_cflag | = CLOCAL | CREAD; 3>设置波特率,使用函数cfsetispeed、cfsetospeed cfsetispeed(&newtio,B115200); cfsetospeed(&newtio,B115200); 4>设置数据位,需使用掩码设置 newtio.c_cflag &= ~CSIZE; newtio.c_cflag |= CS8; 5>设置奇偶校验位,使用c_cflag和c_iflag. 设置奇校验: newtio.c_cflag |= PARENB; newtio.c_cflag |= PARODD; newtio.c_iflag |= (INPCK | ISTRIP); 设置偶校验: newtio.c_iflag |= (INPCK|ISTRIP); newtio.c_cflag |= PARENB; newtio.c_cflag |= ~PARODD; 6>设置停止位,通过激活c_cflag中的CSTOPB实现。若停止位为1,则清除CSTOPB,若停止位为2,则激活CSTOPB。 newtio.c_cflag &= ~CSTOPB; 7>设置最少字符和等待时间,对于接收字符和等待时间没有特别的要求时,可设为0: newtio.c_cc[VTIME] = 0; newtio.c_cc[VMIN] = 0; 8>处理要写入的引用对象,tcflush函数刷新(抛弃)输入缓存(终端驱动程序已接收到,但用户程序尚未读)或输出缓存(用户程序已经写,但尚未发送). int tcflush(int filedes,int quene) quene数应当是下列三个常数之一: *TCIFLUSH 刷清输入队列 *TCOFLUSH 刷清输出队列 *TCIOFLUSH 刷清输入、输出队列 例如:tcflush(fd,TCIFLUSH); 9>激活配置。在完成配置后,需要激活配置使其生效。使用tcsetattr()函数: int tcsetattr(int filedes,int opt,const struct termios *termptr); opt使我们可以指定在什么时候新的终端属性才起作用, *TCSANOW:更改立即发生 *TCSADRAIN:发送了所有输出后更改才发生。若更改输出参数则应使用此选项 *TCSAFLUSH:发送了所有输出后更改才发生。更进一步,在更改发生时未读的 所有输入数据都被删除(刷清). 例如: tcsetattr(fd,TCSANOW,&newtio);写数据到串口时使用write函数例如:
n = write(fd, “tangquan\r\n”, 10); 表示写10个字节的数据到文件描述符fd描述的文件中去。从串口上读取数据的时候就得耍花招了。因为,如果你在原数据模式(raw data mode)操作端口的话,每个read(2)系统调用都会返回从串口输入缓冲区中实际得到的字符的个数。在不能得到数据的情况下,read(2)系统调用就会一直等着,只到有端口上新的字符可以读取或者发生超时或者错误的情况发生。如果需要read(2)函数迅速返回的话,你可以使用下面这个方式: fcntl(fd, F_SETFL, FNDELAY); 标志FNDELAY可以保证read(2)函数在端口上读不到字符的时候返回0。需要回到正常(阻塞)模式的时候,需要再次在不带FNDELAY标志的情况下调用fcntl(2)函数: fcntl(fd, F_SETFL, 0); 当然,如果你最初就是以O_NDELAY标志打开串口的,你也可在之后使用这个方法改变读取的行为方式。 程序退出或者关闭串口的时候调用close函数关闭设备文件的文件描述符。转载地址:http://bhzh.baihongyu.com/