Linux下串口编程基础
一、串口概述
串行口是计算机一种常用的接口,具有连接线少,通讯简单,得到广泛的使用。常用的串口是 RS-232-C 接口(又称 EIA RS-232-C)它是在 1970 年由美国电子工业协会(EIA)联合贝尔系统、 调制解调器厂家及计算机终端生产厂家共同制定的用于串行通讯的标准。它的全名是"数据终端设备(DTE)和数据通讯设备(DCE)之间串行二进制数据交换接口技术标准"该标准规定采用一个 25 个脚的 DB25 连接器,对连接器的每个引脚的信号内容加以规定,还对各种信号的电平加以规定。传输距离在码元畸变小于 4% 的情况下,传输电缆长度应为 50 英尺。
如果想对串口通讯编程有更深的了解,可以参考《Serial Programming Guide for POSIX Operating Systems》
二、串口编程
1. 串口需要的头文件
1: #include <stdio.h> /*标准输入输出定义*/
2: #include <stdlib.h> /*标准函数库定义*/
3: #include <unistd.h> /*Unix 标准函数定义*/
4: #include <sys/types.h>
5: #include <sys/stat.h>
6: #include <fcntl.h> /*文件控制定义*/
7: #include <termios.h> /*POSIX 终端控制定义*/
8: #include <errno.h> /*错误号定义*/
2. 打开关闭串口
对于串口设备文件的操作与其他文件操作基本相同。可以使用系统调用open(), close()打开或关闭串口。
在Linux下串口文件是在/dev下的,例如串口一为/dev/ttyS0,串口二为/dev/ttyS1。
open(),close()系统调用的原型
1: #include <fcntl.h>
2: #include <sys/types.h>
3: #include <sys/stat.h>
4: int open(const char *path, int oflags);
5: int open(const char *path, int oflags, mode_t mode);
6: #include <unistd.h>
7: int close(int fildes);
8: 实例:打开串口ttyS0。
9: int fd;
10: /*以读写方式打开串口*/
11: fd = open( "/dev/ttyS0", O_RDWR);
12: if (-1 == fd){
13: /* 不能打开串口一*/
14: perror("open serial port error");
15: }
3. 设置串口
设置串口包括波特率设置、校验位、停止位设置。在串口设置中主要是设置struct termios结构体成员的值。
struct termios结构如下
1: #include <termios.h>
2: struct termio
3: {
4: unsigned short c_iflag; /* input options输入模式标志 */
5: unsigned short c_oflag; /* output options输出模式标志 */
6: unsigned short c_cflag; /* control options控制模式标志*/
7: unsigned short c_lflag; /* local mode flags */
8: unsigned char c_line; /* line discipline */
9: unsigned char c_cc[NCC]; /* control characters */
10: };
l 波特率的设置
波特率:每秒钟传送的二进制位数,用 b / s 表示(b表示bit)。
设置波特率需要对c_cflag进行操作。c_cflag支持的波特率设置项如下:
Constant |
Description |
CBAUD |
Bit mask for baud rate |
B0 |
0 baud (drop DTR) |
B50 |
50 baud |
B75 |
75 baud |
B110 |
110 baud |
B134 |
134.5 baud |
B150 |
150 baud |
B200 |
200 baud |
B300 |
300 baud |
B600 |
600 baud |
B1200 |
1200 baud |
B1800 |
1800 baud |
B2400 |
2400 baud |
B4800 |
4800 baud |
B9600 |
9600 baud |
B19200 |
19200 baud |
B38400 |
38400 baud |
B57600 |
57,600 baud |
B76800 |
76,800 baud |
B115200 |
115,200 baud |
设置c_cflag需要激活两个选项,CLOCAL和CREAD,它们分别为本地连接和串口接收使能。
波特率的设置并不能直接对c_cflag进行赋值操作,Linux提供系统调用cfsetospeed()和cfsetispeed()来设置波特率。
原型:
1: int cfsetospeed(struct termios *termptr, speed_t speed);
2: int cfsetispeed(struct termios *termptr, speed_t speed);
参数中termptr为指向termios结构体的指针,speed为要设置的波特率。如果成功返回0,否则返回-1。
在波特率设置完成后调用tcsetattr()来激活设置。
原型:
1: #include <termios.h>
2: int tcsetattr(int fd, int actions, const struct termios *termios_p);
参数中actions控制如何对串口设置进行改变,可选项为:
TCSANOW: 立即对值进行修改。
TCSADRAIN: 在当前输出完成后再对值进行修改。
TCSAFLUSH: 在当前输出完成后再对值进行修改,但还要丢弃当前的可用输入数据和尚未从 read 调用的返回值。
实例:设置波特率
1: struct termios options;
2: /*
3: * 得到当前串口设置,保存在options中
4: */
5: tcgetattr(fd, &options);
6: /*
7: * 设置波特率为19200
8: */
9: cfsetispeed(&options, B19200);
10: cfsetospeed(&options, B19200);
11: /*
12: * 本地连接和接收使能
13: */
14: options.c_cflag |= (CLOCAL | CREAD);
15: /*
16: * 应用设置(立即应用)
17: */
18: tcsetattr(fd, TCSANOW, &options);
l 数据位、校验位与停止位的设置
对于数据位的设置没有专用的系统调用,你可以使用位掩码的操作来设置数据位。
实例:选择8位数据位
1: options.c_cflag &= ~CSIZE; /* 清除数据位掩码Mask the character size bits */
2: options.c_cflag |= CS8; /* 选择8位数据位Select 8 data bits */
校验位需要设置c_cflag和c_iflag。首先要激活c_cflag的校验位使能标志PARENB(parity enable),选择是否使用偶校验PARODD,然后激活c_iflag中奇偶校验使能位(INPACK enable parity check | ISTRIP strip parity bits)。
实例:
选择奇校验
1: options.c_cflag |= PARENB;
2: options.c_cflag |= PARODD;
3: options.c_iflag |= (INPACK|ISTRIP);
选择偶校验
1: options.c_cflag |= PARENB;
2: options.c_cflag &= ~PARODD;
3: options.c_iflag |= (INPACK|ISTRIP);
停止位的设置是通过激活c_cflag中的CSTOPB实现的,停止位为1,清除CSTOPB,停止位为0,激活CSTOPB。
实例: 设置停止位为1。
1: options.c_cflag &= ~CSTOPB;
l 最少字符和等待时间的设置
设置c_cc成员数组中的VTIME和VMIN分别设置等待时间和最少字符。VTIME和VMIN的值决定串口的等待时间和接收的最少字符,在此之前,会堵塞串口直到到达设置的时间或者字符个数。
实例:将最少字符和等待时间设置为0
1: options.c_cc[VTIME] = 0;
2: options.c_cc[VMIN] = 0;
4. 读写串口
读写串口和普通的文件操作相同,分别使用read()和write()。
原型:
1: #include <unistd.h>
2: size_t read(int fields, void *buf, size_t nbytes);
3: size_t write(int fildes, const void *buf, size_t nbytes);
实例:写串口
1: char buffer[] = “hello world”;
2: int length = 11;
3: int nByte;
4: nByte = write(fd, buffer, length);