240 likes | 361 Views
第 12 章. 串行通信. 本章重点. 串行通信编程的流程 串行通信端口的设置 串行通信中相关函数的应用. 12.1 串行通信概述. 串行通信( Serial Communication )一直占据着极其重要的地位。现在的串行通信端口( RS-232 )是计算机上的标准配置。 最为常见的应用是连接调制解调器进行数据传输。 串行通信中使用一条数据线,将数据一位一位地依次传输,每一位数据占据一个固定的时间长度。其只需要少数几条线就可以在系统间交换信息,特别使用于计算机与计算机、计算机与外设之间的远距离通信。
E N D
第 12 章 串行通信
本章重点 • 串行通信编程的流程 • 串行通信端口的设置 • 串行通信中相关函数的应用
12.1串行通信概述 • 串行通信(Serial Communication)一直占据着极其重要的地位。现在的串行通信端口(RS-232)是计算机上的标准配置。 • 最为常见的应用是连接调制解调器进行数据传输。 • 串行通信中使用一条数据线,将数据一位一位地依次传输,每一位数据占据一个固定的时间长度。其只需要少数几条线就可以在系统间交换信息,特别使用于计算机与计算机、计算机与外设之间的远距离通信。 • 串行通信将计算机主机与外设之间以及主机系统与主机系统之间数据的串行传送。使用串口通信时,发送和接收到的每一个字符实际上都是一次一位的传送的,每一位为1或者为0。串行通信可分为同步通信与异步通信。
12.1.1 同步通信 • 同步通信是一种连续串行传送数据的通信方式,一次通信只传送一帧信息。 • 这里的信息帧与异步通信中的字符帧不同,通常含有若干个数据字符。它们均由同步字符、数据字符和校验字符(CRC)组成。 • 同步字符位于帧开头,用于确认数据字符的开始。 • 数据字符在同步字符之后,个数没有限制,由所需传输的数据块长度来决定; • 校验字符有1到2个,用于接收端对接收到的字符序列进行正确性的校验。 • 同步通信的缺点是要求发送时钟和接收时钟保持严格的同步。
12.1.2 异步通信 • 两个比较重要的指标:字符帧格式和波特率。 • 数据通常以字符或者字节为单位组成字符帧传送。 • 字符帧由发送端逐帧发送,通过传输线被接收设备逐帧接收。 • 发送端和接收端可以由各自的时钟来控制数据的发送和接收,这两个时钟源彼此独立,互不同步。 • 接收端检测到传输线上发送过来的低电平逻辑"0"(即字符帧起始位)时,确定发送端已开始发送数据,每当接收端收到字符帧中的停止位时,就知道一帧字符已经发送完毕。
12.1.2 异步通信 • 计算机通常包含COM1和COM2两个串行通信端口。一般计算机的COM端口从外观上看有9个针脚 。 • 在Linux中,所有的设备文件都位于“/dev”下 • COM1、COM2对应的设备名依次为“/dev/ttyS0”、“/dev/ttyS1”。 • Linux对设备的操作方法和对文件的操作方法相同,对串口的读写就可以使用简单的“read”、“write”函数来完成,所不同的是要对串口的一些参数进行配置。 • 注意: • 在终端可用命令 ls /dev -al 查找所有设备或用命令ls /dev ttyS* -al查找以ttyS开头的设备名。 • 要自制两个串口的连接电缆, 你必需要把TxD (传送)及RxD(接收)两线对调。
12.2 串行通信程序的设计 12.2.1 串行通信程序设计流程 • 串行通信程序的设计分为发送端程序设计与接收端程序设计。
12.2.2 打开通信端口 • 在Linux中把串口设备视为普通文件,可使用open()函数来打开串口设备。 • 例12.1 打开PC的COM1串行通信端口。 • 分析 使用open()函数打开COM1端口,设备名称为"/dev/ttyS0"。设置open的打开方式,要求以读写(O_RDWR)、非阻塞(O_NONBLOCK)的方式打开,打开串口设备时不会成为进程的控制终端,此时使用参数O_NOCTTY。 • 步骤1 编辑源程序代码。先建立一个目录12-1,在目录12-1下编辑源程序12-1.c及make文件makefile。 [root@localhost 12-1]#vim 12-1.c
12.2.2 打开通信端口 • 步骤2 编辑makefile文件 [root@localhost 12-1]#vim makefile CC = gcc AR = $(CC)ar EXEC = 12-1 OBJS = 12-1.o all: $(EXEC) $(EXEC): $(OBJS) $(CC) -o $@ $(OBJS) -lm clean: -rm -f $(EXEC) *.elf *.gdb *.o • 编辑好工程文件后,在目录12-1下执行命令make,即可生成可执行文件。 注意:程序中O_RDWR指读写模式。O_NOCTTY标志告诉linux系统,这个程序不会成为对应这个端口的控制终端,如果没有指定这个标志,那么任何一个输入,诸如键盘中止信号等,都将会影响你的进程。O_NONBLOCK标志告诉linux系统这个程序以非阻塞的方式打开。 思考题:要求以只读的模式打开计算机的COM2。
12.2.3 设置串口属性 • 在Linux中若要对串口进行操作,如改变其波特率、字符大小等,就是对结构体struct termios中成员的值进行设置,使用该结构体需要包含“#include<termios.h>头文件”,结构体如下: #include<termios.h> struct termios { tcflag_t c_iflag; /* 输入模式 */ tcflag_t c_oflag; /* 输出模式 */ tcflag_t c_cflag; /* 控制模式 */ tcflag_t c_lflag; /* 本地模式 */ cc_t c_cc[NCCS]; /* 特殊控制模式 */ } ;
12.2.3 设置串口属性 • 输入标志由终端设备驱动程式用来控制输入特性(剥除输入字节的第8位,允许输入奇偶校验等等); • 输出标法则控制输出特性(执行输出处理,将新行映照为CR/LF等),控制标志影响到RS-232串行线(忽略调制解调器的状态线,每个字符的一个或二个停止位等等), • 本地标志影响驱动程式和用户之间的界面(回送的开或关,虚拟的擦除符,允许终端产生的信号,对后台作业输出的控制停止信号等)。 • 类型tcflag-t的长度是以保持每个标志值。他经常被定义为unsigned long。 • c-cc数组包含了任何能够更改的特别字符。NCCS是该数组的长度,其典型值在11-18之间。 在这个结构中最为重要的是c_cflag,通过对它的赋值,用户可以设置波特率、字符大小、数据位、停止位、奇偶校验位和硬件控制等。
12.2.3 设置串口属性 • 结构体成员的含义及用法。 思考题:在设置串口属性时,要求奇偶校验。请写出设置串口的语句。
12.2.4 串口通信程序设计 • 串口通信一般分为接收端和发送端。 • 接收端主要打开端口,设置接收端串口的参数,接收数据; • 发送端主要打开发送数据的端口,设置发送端串口的参数,发送数据。最后关闭发送端和接收端。 1.接收端 (1)打开PC的COM1端口 如果以读写的方式打开COM1端口,语句可写为: fd=open("/dev/ttyS0",O_RDWR | O_NOCTTY); (2)取得当前串口值,并保存至结构体变量oldtio tcgetattr(fd,&oldtio); (3)串口结构体变量newtio清零 bzero(&newtio,sizeof(newtio));
12.2.4 串口通信程序设计 (4)设置串口参数 1)假定设置波特率为BAUDRATE ,8个数据位,忽略任何调制解调器状态,同时启动接受器。 newtio.c_cflag=BAUDRATE |CS8 |CLOCAL|CREAD; 2)忽略奇偶校验错误。 newtio.c_iflag=IGNPAR; 3)设输出模式非标准型,同时不回应。 newtio.c_oflag=0; 4)启用正规模式。 newtio.c_lflag=ICANON; (5)刷新在串口中的输入输出数据 tcflush(fd,TCIFLUSH); 参数TCIFLUSH表示刷新收到的数据,但是不读取
12.2.4 串口通信程序设计 (6)设置当前的串口参数为newtio tcsetattr(fd,TCSANOW,&newtio); 参数TCSANOW表示改变端口配置并立即生效 (7)读取缓存中的数据 read(fd,buf,255); 表示从端口读取255个字符存放到buf中 (8)关闭串口 close(fd); (9)恢复旧的端口参数 tcsetattr(fd,TCSANOW,&oldtio);
12.2.4 串口通信程序设计 2.发送端 (1)打开PC的COM2端口 fd=open("/dev/ttyS1",O_RDWR | O_NOCTTY); (2)取得当前串口值,并保存至oldtio tcgetattr(fd,&oldtio); (3)串口结构体变量newtio清零 bzero(&newtio,sizeof(newtio));
12.2.4 串口通信程序设计 (4)设置串口参数 1)设置波特率为BAUDRATE ,8个数据位,忽略任何调制解调器状态,同时启动接受器。 newtio.c_cflag=BAUDRATE |CS8 |CLOCAL|CREAD; 2)忽略奇偶校验错误。 newtio.c_iflag=IGNPAR; 3)设输出模式非标准型,同时不回应。 newtio.c_oflag=0; 4)启用正规模式。 newtio.c_lflag=ICANON;
12.2.4 串口通信程序设计 (5)刷新在串口中的输入输出数据 tcflush(fd,TCIFLUSH); (6)设置当前的串口为newtio tcsetattr(fd,TCSANOW,&newtio); 参数TCSANOW表示改变端口配置并立即生效 (7)向串口写入数据,储存在缓存中 write(fd,s1,l); 表示向串口写入长度为l的数据s1 (8)关闭串口 close(fd); (9)恢复旧的端口参数 tcsetattr(fd,TCSANOW,&oldtio);/*恢复旧的端口参数*/
12.2.4 串口通信程序设计 • 例12.2 通过计算机的COM1和COM2进行通信,利用RS-232来传送信息,其中COM1为发送端,COM2为接收端,当接收端接收到字符‘@’时,结束传输。RS-232的通信格式为38400,n,8,1(38400表示波特率大小,n表示不进行奇偶校验,8表示数据位,1表示停止位)。 • 分析 先打开串行口,接着设置端口参数,然后进行通信,最后关闭串行端口。 • 步骤1 连线:使用RS-232线连接计算机的COM1和COM2端口。 • 步骤2 编辑源程序代码。 • 设接收端的源文件名为12-2-r.c,发送端的源文件名为12-2-s.c,在接收端打开端口COM2后,COM2口会读取计算机COM1口传来的数据并输出。若COM2口接收到的字符为‘@’,则结束传输。 • [root@localhost root]#vim 12-2-r.c
12.2.4 串口通信程序设计 • 步骤3 用gcc编译程序。 [root@localhost root]#gcc 12-2-r.c –o 12-2-r • 步骤4 编辑发送端源程序代码。 • 发送端COM1,它会把COM1的数据发送给COM2。若COM2接收的字符为‘@’,则结束传输。 • [root@localhost root]#vim 12-2-s.c
12.2.4 串口通信程序设计 • 步骤5 用gcc编译程序。 [root@localhost root]#gcc 12-2-s.c –o 12-2-s • 步骤6 测试运行结果。 1)打开一个终端,运行发送端程序,具体如下: [root@localhost root]#./ 12-2-r 2)打开另一个终端,具体如下: [root@localhost root]#./ 12-2-s start… open… wirte… hello,world! [Enter] @ [Enter] 3)接着会在接收端看到传来的数据,具体如下: [root@localhost root]#./ 12-2-r start… open… reading… res=13 vuf=hello,world! res=2 vuf=@ 结果分析:接收端收到发送端传来的字符(hello,lupa!),并统计出字符数。
12.2.4 串口通信程序设计 • tcgetattr函数说明 • tcsetattr函数说明
12.2.4 串口通信程序设计 • tcflush函数说明 • 思考题 • 分别编写串口通信中发送端与接收端的makefile文件。 • 把例12.2中的RS-232通信格式改为51200,n,8,1,其他设置不变,然后完成实验。 • 参考例12.2,RS-232的通信格式不变,依然是38400,n,8,1,要求发送端先读取文件的内容,然后将其内容发送到接收端,并在屏幕上打印出接收到的内容。
思考与实验 • open(“/dev/ttyS0”,O_RDWR|O_NOCTTY|O_NDELAY);写出这行代码的含义。 • 设置串行口属性参数为:波特率38400并且启用偶校验位。 • 编写一个串口通信程序,要求使用硬件流控制,8位字符大小,以9600的波特率从一台计算机的COM1口发送键盘输入的字符,从另一计算机的COM1口接收,并在屏幕上打印出接收到的字符。 • 查阅相关资料,列举串行通信应用的例子。