Linux系统编程:串口编程
Linux下的串口概述
常见的数据通信的基本方式分为并行通信和串行通信。
1.并行通信:利用多条数据传输线将一个资料的各位同事传送。特点是速度快,通信距离近。
2.串行通信:利用一条传输线将数据一位一位地顺序传输。特点是通信线路简单,利用简单线缆就可以实现通信,降低成本,适合远距离通信但传输速度慢的应用场合。
串行通信是计算机一种常见的接口,具有连接线少、通信简单的特点,得到了广泛的使用。因为不是每个电脑上都有DB25针的RS232接口,所以常用的串口是USB转RS232接口。
Linux中,串口文件位于/dev路径下,查看当前串口命令如下:
ls -l /dev/ttyUSB*
一般为:/dev/ttyUSB0
Linux串口编程
#include<termios.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#define USBCOM "/dev/ttyUSB0"
int main()
{
//open
int fd = open(USBCOM, O_WRONLY);
if(fd == -1)
{
perror("open error!");
exit(-1);
}
//set attr
//1.save the old data of attr oldtms
struct termios newtms, oldtms;
bzero(&newtms, sizeof(struct termios));
if( tcgetattr(fd, &oldtms) == -1)
{
perror("tegetattr error!");
exit(-1);
}
//2.set CREAD and CLOCAL
newtms.c_cflag |= CREAD;
newtms.c_cflag |= CLOCAL;
//3.set bound
if(cfsetispeed(&newtms, B115200) == -1)
{
perror("cfsetispeed error!");
exit(-1);
}
if(cfsetospeed(&newtms, B115200) == -1)
{
perror("cfsetospeed error!");
exit(-1);
}
//4.set CSIZE
newtms.c_cflag &= ~CSIZE;
newtms.c_cflag |= CS8;
//5.set PARENB
newtms.c_cflag &= ~PARENB;
//6.set CSTOPB
newtms.c_cflag &= ~CSTOPB;
//7.set wait time and min of char
newtms.c_cc[VTIME] = 0;
newtms.c_cc[VMIN] = 0;
//8.引用对象
if(tcflush(fd, TCIOFLUSH) == -1)
{
perror("tcflush error!");
exit(-1);
}
//9.激活设置
if(tcsetattr(fd, TCSANOW, &newtms) == -1)
{
perror("tcsetattr error!");
exit(-1);
}
// read or write
char buf[512];
int ir = 0;
while(1)
{
//清除buf中数据,包括'\0'
bzero(&buf,512);
if(ir = read(STDIN_FILENO, buf, 512) >0)
{
if(write(fd, buf, 512) == -1)
{
perror("write error!");
exit(-1);
}
}else{
perror("read error!");
exit(-1);
}
}
//close
close(fd);
return 0;
}
代码解析
1.为了安全起见和以后调试程序方便,可以先保存原先串口的配置,在这里可以使用函数tcgetattr(fd, &oldtms)。函数得到与fd指向对象的相关参数,并将它们保存于oldtms一用的termios结构体中,该函数可以测试配置是否正确,该串口是否可用等。若调用成功,函数返回值为0,若调用失败,函数返回-1.
2.CREAD和CLOCAL用于本地连接和接收使能,因此首先要通过掩码的方式激活这两项。
newtms.c_cflag | = CREAD | CLOCAL;
3.设置波特率:
cfsetispeed(&newtms, B115200); //设置输入波特率为115200
cfsetospeed(&newtms, B115200); //设置输出波特率为115200
4.设置字符大小
newtms.c_cflag &= ~CSIZE;
newtms.c_cflag |= CS8; //8个数据位
5.设置为无奇偶校验位。
6.设置停止位为1。
7.在接收字符和等待时间没有特殊要求的情况下,可以将最少字符和等待时间设置为0。
8.处理要写入的引用对象
由于串口在重新设置之后,在此之前写入的引用对象要重新处理,这时就可以调用函数tcflush(fd, queue_selector) 来处理要写入引用的对象。对于肠胃传输的数据,或者接收到但事尚未读取的数据,处理方式取决于queue_selector的值。
queue_selector可能的取值有一下几种:
TCIFLUSH:刷新收到的数据但是不读;
TCOFLUSH:刷新写入的数据但是不传送;
TCIOFLUSH:同事刷新收到的数据但是不读,并刷新写入的数据但是不传送。
9.激活配置
在完成全部串口配置之后,要激活刚才的配置并使配置生效,这里用到的函数是 setattr (fd, OPTION, &newtms);成功返货0,失败返回-1.
OPTION可能的取值有一下3种:
TCSANOW:改变的位置立即生效;
TCSADRAIN:改变的配置在所有写入fd的输出都结束后生效;
TCSAFLUSH:改变的配置在所有写入fd引用对象的输出都被结束后生效,所有已接受但未读入的输入都在改变发生前丢弃。
编译和测试
gcc -o usart usart.c
编译完生成可执行文件 usart
通过两个usb转串口链接两台电脑,一台linux运行本代码,一台linux或者windows运行一个串口调试助手,设置好波特率和8个数据位一个停止位,无奇偶校验,来测试。
在终端中输入:
./usart
程序运行起来之后,终端中输入要发送的数据,在另一台电脑观察是否接收到。接收到相同数据即为成功。
代码中的常量介绍
1.f_cflag:
符号 | 定义 |
---|---|
CBAUD | 波特率的位掩码 |
BO | 0波特率(放弃DTR) |
B1800 | 1800波特率 |
B2400 | 2400波特率 |
B4800 | 4800波特率 |
B9600 | 9600波特率 |
B38400 | 38400波特率 |
B57600 | 57600波特率 |
B115200 | 115200波特率 |
EXTA | 外部时钟频率 |
EXTB | 外部时钟频率 |
CSIZE | 数据位的位掩码 |
CS5 | 5个数据位 (发送和接收时使用5比特) |
CS6 | 6个数据位 (发送和接收时使用6比特) |
CS7 | 7个数据位 (发送和接收时使用7比特) |
CS8 | 8个数据位 (发送和接收时使用8比特) |
CSTOPB | 连个停止位 (不设则是一个停止位) |
CREAD | 接收使能 |
PARENB PARODD | 校验位使能使用奇校验而不使用偶校验 |
HUPCL | 最后关闭时挂线 (放气DTR) |
CLOCAL | 本地连接 (不改变端口所有者) |
LOBLK | 块作业控制输出 |
CNET_ CTSRTS | 硬件流控制使能 |
2.c_iflag:
符号 | 定义 |
---|---|
INPCK | 奇偶校验使能 |
IGNPAR | 忽略奇偶校验错误的字符 |
PARMRK | 对奇偶校验错误做出标记 |
ISTRIP | 去掉第8位,将所有接收到的字符剪裁位7比特 |
IXON | 启动出口硬件流控 |
IXOFF | 启动入口硬件 |
IXANY | 允许字符重新启动流控 |
IGNBRK | 忽略中断情况 |
BRKINT | 当发生中断时发送SIGINT信号 |
INLCR | 将NL映射到CR (新行符→回车符) |
IGNCR | 忽略CR (忽略回车符) |
ICRNL | 将CR映射到NL(新行符→回车符) |
IUCLC | 将高位情况映射到低位情况 |
IMAXBEL | 当输入太长时恢复ECHO |
3.c_cc:
符号 | 定义 |
---|---|
VINTR | 中断控制,对应键为Ctrl + C |
VQUIT | 退出操作,对应键为Ctrl + Z |
VERASE | 删除操作,对应键为Backspace (BS) |
VKILL | 删除行,对应键为 Ctrl + U |
VEOF | 位于文件结尾,对应键为 Ctrl + D |
VEOL | 位于行尾,对硬件为Carriage return (CR) |
VEOL2 | 位于第二行尾,对应键为Line feed (LF) |
VMIN | 指定了最少读取的字符数 |
VTIME | 制定了读取每个字符的等待时间 |