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波特率的位掩码
BO0波特率(放弃DTR)
B18001800波特率
B24002400波特率
B48004800波特率
B96009600波特率
B3840038400波特率
B5760057600波特率
B115200115200波特率
EXTA外部时钟频率
EXTB外部时钟频率
CSIZE数据位的位掩码
CS55个数据位 (发送和接收时使用5比特)
CS66个数据位 (发送和接收时使用6比特)
CS77个数据位 (发送和接收时使用7比特)
CS88个数据位 (发送和接收时使用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制定了读取每个字符的等待时间
已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页