嵌入式系统原理与技术资料:linux串口编程-1.doc
- 【下载声明】
1. 本站全部试题类文档,若标题没写含答案,则无答案;标题注明含答案的文档,主观题也可能无答案。请谨慎下单,一旦售出,不予退换。
2. 本站全部PPT文档均不含视频和音频,PPT中出现的音频或视频标识(或文字)仅表示流程,实际无音频或视频文件。请谨慎下单,一旦售出,不予退换。
3. 本页资料《嵌入式系统原理与技术资料:linux串口编程-1.doc》由用户(罗嗣辉)主动上传,其收益全归该用户。163文库仅提供信息存储空间,仅对该用户上传内容的表现方式做保护处理,对上传内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知163文库(点击联系客服),我们立即给予删除!
4. 请根据预览情况,自愿下载本文。本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
5. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007及以上版本和PDF阅读器,压缩文件请下载最新的WinRAR软件解压。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 嵌入式 系统 原理 技术 资料 linux 串口 编程
- 资源描述:
-
1、linux 串口编程http:/ Linux 中,串口是一个字设备,访问具体的串行端口的编程与读写文件的操作类似,只需打开相应的设备文件即可操作。串口编程特殊在于串口通信时相关参数与属性的设置。嵌入式 Linux 的串口编程时应注意,若在根文件中没有串口设备文件,应使用mknod 命令创建,这这里假设串口设备是/dev/ttyS0,介绍一下串口的编程过程。mknod /dev/ttyS0 c 4 641、打开串口打开串口设备文件的操作与普通文件的操作类似,都采用标准的 I/O 操作函数 open()。fd = open(/dev/ttyS0,O_RDWR|O_NDELAY|O_NOCTTY);
2、open()函数有两个参数,第一个参数是要打开的文件名(此处为串口设备文件/dev/ttyS0);第二个参数设置打开的方式,O_RDWR表示打开的文件可读/写,O_NDELAY 表示以非阻塞方式打开,ONOCTTY 表示若打开的文件为终端设备,则不会将终端作为进程控制终端。2、设置串口属性串口通信时的属性设置是串口编程的关键问题,许多串口通信时的错误都与串口的设置相关,所以编程时应特别注意这些设置,最常见的设置包括波特率、奇偶校验和停止位以及流控制等。在 Linux 中,串口被作为终端 I/O,它的参数设置需要使用 struct termios 结构体,这个结构体在 termio.h 文件中定
3、义,且应在程序中包含这个头文件。typedef unsigned charcc_t ;typedef unsigned intspeed_t ;typedef unsigned inttcflag_t ;struct termiostcflag_tc_iflag ;/*输入模式标志*/tcflag_tc_oflag ;/*输出模式标志*/tcflag_tc_cflag ;/*控制模式标志*/tcflag_tc_lflag ;/*本地模式标志*/tcflag_tc_line ;/*行规程类型,一般应用程序不使用*/cc_tc_ccNCC;/*控制字符*/speed_tc_ispeed ;/*输入
4、数据波特率*/speed_tc_ospeed ;/*输出数据波特率*/;串口的设置主要是设置这个结构体的各成员值,然后利用该结构体将参数传给硬件驱动程序。在 Linux 中,串口以串行终端的方式进行处理,因而,可以使用 tcgetattr()/tcsetattr()函数获取/设置串口的参数。int tcgetattr( int fd, struct termios *termios_p );int tcsetattr( int fd, int optional_actions , struct termios *termios_p );这两个参数都有一个批向 termios 结构体的指针作为参
5、数, 用于返回当前终端的属性或设置该终端的属性。 参数 fd 就是用 open()函数打开的终端文件句柄,而串口就是用 open()打开的串口设备文件句柄。tcsetattr()函数的 optional_action 参数用于指定新设定的参数起作用的时间,其设定值可以为:TCSANOW改变立即生效TCSADRAIN在所有的输出都被传输后改变生效,适用于更改影响输出参数的情况。TCSAFLUSH在所有输出都被传输后改变生效,丢弃所有末读入的输入(清空输入缓存)。(1)设置波特率使用 cfsetospeed()/cfsetispeed()函数设置波特率, 它们分别用于在 termios 结构体中设
6、置输出和输入的波特率。 设置波特率可以使用波特率常数,其定义为字母“B速率”,如 B19200 就是波特率为 19200bps,B115200 就是波特率为 115200bps。int cfsetispeed( struct termios *termios_p, speed_t speed );/speed 为波特率常数int cfsetospeed( struct termios *termios_p, speed_t speed );例 :cfsetispeed( ttys0_opt, B115200 );cfsetospeed( ttys0_opt, B115200 );(2)设置控制
7、模式标志控制模式标志 c_cflag 主要用于设置串口对 DCD 信号状态检测、 硬件流控制、 字符位宽、 停止位和奇偶校验等, 常用标志位如下:CLOCAL忽略 DCD 信号,若不使用 MODEM,或没有串口没有 CD 脚就设置此标志CREAD启用接收装置,可以接收字符CRTSCTS 启用硬件流控制,对于许多三线制的串不应使用,需设置CRTCTSCSIZE字符位数掩码,常用 CS8CSTOPB使用两个停止位,若用一位应设置CSTOPBPARENB启用奇偶校验例如, 下面的代码将串口设置为忽略 DCD 信号, 启用接收装置, 关闭硬件流控制, 传输数据时使用 8 位数据位和一位停止位 (8N1
8、) ,不使用奇偶校验。struct temios ttys0ttyso_opt.c_cflag |= CLOCAL | CREAD ;/将 CLOCAL 与 CREAD 位设置为 1ttys0_opt.c_cflag &= CRTSCTS ;/将硬件流控制位 CRTSCTS 清 0,其他位不变ttys0_opt.c_cflag & CSIZE ;/清除数据位掩码ttys0_opt.c_cflag |= CS8 ;/设置 8 位数据位标志 CS8ttys0_opt.c_cflag &= (PARENB|CSTOPB);/使用 1 位停止位,停用奇偶校验(3)设置本地模式标志本地模式标志 c_lf
9、lag 主要用于设置终端与用户的交互方式, 常见的设置标志位有 ICANON, ECHO 和 ECHOE 等。 其中, ICANON标志位用于实现规范输入,即 read()读到行结束符后返回,常用于终端的处理;若串口用于发送/接收数据,则应清除此标志,使用非规范模式(raw mode)。非规范模式中,输入数据不组成行,不处规范模式中的特殊字符。在规范模式中,当设置 ECHO 标志位时,用户向终端输入的字符将被回传给用户;当设置 ECHOE 标志位时,用户输入退格键时,则回传“退格空格退格”序列给用户,使得退格键覆盖的字符从显示中消失,这样更符合用户的习惯(若未设置此标志,输入退格键时,则光标回
10、退一个字符,但原有的字符未从显示中消失)。(4)设置输入模式标志输入模式标志 c_iflag 主要用于控制串口的输入特性,常用的设置有 IXOFF 和 IXON,分别用于软件流控制。其中,IXOFF 用于防止输入缓冲区溢出;IXON 则是在输入数据中识别软件流控制标志。由于许多嵌入式系统无法使用硬件流控制,因此,只能使用软件流控制数据传输的速度,但是,它可能降低串口数据传输效率。启用软件流控制的代码如下:ttys0_opt.c_iflag |= IXOFF|IXON ;(5)设置输出模式标志输出模式标志 c_oflag 主要用于对串口在规范模式时输出的特殊字符处理,而对非规范模式无效。(6)设
11、置控制字符在非规范模式中,控制字符数组 c_cc中的变量 c_ccVMIN和 c_ccVTIME用于设置 read()返回前读到的最少字节数和读超时时间,其值分为四种情况:(a)c_ccVMIN0,c_ccVTIME0读到一个字节后,启动定时器,其超时时间为 c_ccVTIME,read()返回的条件为至少读到 c_ccVMIN个字符或定时器超期。(b)c_ccVMIN0, c_ccVTIME =0只要读到数据的字节数大于等于 c_ccVMIN,则 read()返回;否则,将无限期阻塞等待。(c)c_ccVMIN = 0, c_ccVTIME0只要读到数据,则 read()返回;若定时器超期(
12、定时时间 c_ccVTIME)却未读到数据,则 read()返回 0;(d)c_ccVMIN = 0, c_ccVTIME = 0若有数据,则 read()读取指定数量的数据后返回;若没有数据,则 read()返回 0;在 termios 结构体中填写完这些参数后,接下来就可以使用 tcsetattr()函数设置串口的属性。tcsetattr( fd, &old_opt );/将原有的设置保存到 old_opt,以便程序结束后恢复tcsetattr( fd, TCSANOW, &ttsy0_opt );3、清空发送/接收缓冲区为保证读/写操作不被串口缓冲区中原有的数据干拢,可以在读/写数据前用
13、 tcflush()函数清空串口发送/接收缓冲区。tcflush()函数的参数可为:TCIFLUSH清空输入队列TCOFLUSH清空输出队列TCIOFLUSH同时清空输入和输出队列4、从串口读写数据串口的数据读/写与普通文件的读/写一样,都是使用 read()/write()函数实现。n = write( fd, buf, len );/将 buf 中 len 个字节的数据从串口输出,返回输出的字节数n = read( fd, buf, len );/从串口读入 len 个字节的数据并放入 buf, 返回读取的字节数5、关闭串口关闭串口的操作很简单,将打开的串口设备文件句柄关闭即可。close
14、(fd);Linux 串口读写串口读写(二二)例子下面是一个简单的读取串口数据的例子,使用了上面定义的一些函数和头文件/* 代码说明:使用串口二测试的,发送的数据是字符,但是没有发送字符串结束符号,* 所以接收到后, 后面加上了结束符号。 我测试使用的是单片机发送数据到第二个串口, 测试通过。*/#define FALSE-1#define TRUE0/*/int OpenDev(char *Dev)/Dev 就是设备,设备就是文件,就是给出该设备文件的路径int fd = open(Dev, O_RDWR ); /| O_NOCTTY | O_NDELAYif (-1 = fd)perror
15、(Cant Open Serial Port);return -1;elsereturn fd;int main(int argc, char *argv)int fd;int nread;char buff512;char *dev = /dev/ttyS1; /串口二fd = OpenDev(dev);set_speed(fd, 19200);if (set_Parity(fd, 8, 1, N) = FALSE)printf(Set Parity Errorn);exit (0);while (1) /循环读取数据while (nread = read(fd, buff, 512)0)p
16、rintf(nLen %dn, nread);buffnread+1 = 0;printf(n%s, buff);/close(fd);/ exit (0);1、虚拟机下使用串口的方法使用 vmwave,默认串口设备是没有添加的,通过 vmwave 将设备加入即可正常使用串口。虚拟机串口打开后,可能会占用 windows 下的串口。另外,虚拟机的串口收发比正常的速度的确要慢许多。2、消除 Linux 串口收发的一些规则Linux 串口收发有许多模式,如:(1) 接收返回模式: 如果串口没有接收到数据,read()函数不返回。(2) 数据接收n 才返回接收的数据,否则 read()函数返回 0(
17、3) 特殊字符解析问题,部分特殊字符接收/发送时,会被屏蔽或者转义。如发送 0 x0A 接收变为0 x0A 0 x0A ,0 x0D 被屏蔽等。(4) 接收反馈:如串口接收到数据,立即将该数据发送出去。3、解决问题的方法是,消除这些默认规则,关键是 struct termios 的参数影响。struct termiostcflag_t c_iflag;/*/* 输入模式旗标 */tcflag_t c_oflag;/*/* 输出模式旗标 */tcflag_t c_cflag;/*/* 控制模式旗标 */tcflag_t c_lflag;/*/* 区域模式旗标 */cc_t c_line;/*/*
18、 行控制 (line discipline) */cc_t c_ccNCCS;/*/* 控制特性 */;可如下处理的struct termios options;串口打开方式:open (dev/ttyS0 , O_RDWR|O_NOCTTY| O_NDELAY );消除收发模式规则:options.c_lflag= 0;options.c_oflag= 0;options.c_iflag= 0;消除字符屏蔽规则:options.c_ccVINTR= 0;/*/* Ctrl-c */options.c_ccVQUIT= 0;/*/* Ctrl- */options.c_ccVERASE= 0;
19、/*/* del */options.c_ccVKILL= 0;/*/* */options.c_ccVEOF= 0;/*/* Ctrl-d */options.c_ccVTIME= 1;/*/*/options.c_ccVMIN= 0;/*/*/options.c_ccVSWTC= 0;/*/* */options.c_ccVSTART= 0;/*/* Ctrl-q */options.c_ccVSTOP= 0;/*/* Ctrl-s */options.c_ccVSUSP= 0;/*/* Ctrl-z */options.c_ccVEOL= 0;/*/* */options.c_ccVRE
20、PRINT = 0;/*/* Ctrl-r */options.c_ccVDISCARD = 0;/*/* Ctrl-u */options.c_ccVWERASE= 0;/*/* Ctrl-w */options.c_ccVLNEXT= 0;/*/* Ctrl-v */options.c_ccVEOL2= 0;/*/* */以上设置,在其它参数串口设置前执行,如果你需要保留部分参数,请参阅= = = = = = = = = = = 非阻塞 read= = = = = = = = = = =Q:在调用串口 read(fd,buff,len);时,如果串口没有数据,会停在 read 处,请问有没
21、有办法让这个read 动作中止?A:使用非阻塞方式 select 函数(I/O 多工机制)或者 open 的时候加 O_NONBLOCK 参数。int select(int n,fd_set * readfds,fd_set * writefds,fd_set *exceptfds,struct timeval * timeout);关于这个函数的使用我会在下篇 blog 中整理。= = = = = = = = = = = 串口收发源码= = = = = = = = = = = = = = = = receive.c= = = = = =#include#include#include#inc
22、lude#include#include#include#include#include#define TRUE 1/初始化串口选项:void setTermios(struct termios * pNewtio, int uBaudRate)bzero(pNewtio, sizeof(struct termios); /* clear struct for new portsettings */8N1pNewtio-c_cflag = uBaudRate | CS8 | CREAD | CLOCAL;pNewtio-c_iflag = IGNPAR;pNewtio-c_oflag = 0;
23、pNewtio-c_lflag = 0; /non ICANON/*initialize all control charactersdefault values can be found in /usr/include/termios.h, andare given in the comments, but we dont need them here*/pNewtio-c_ccVINTR = 0; /* Ctrl-c */pNewtio-c_ccVQUIT = 0; /* Ctrl- */pNewtio-c_ccVERASE = 0; /* del */pNewtio-c_ccVKILL
24、= 0; /* */pNewtio-c_ccVEOF = 4; /* Ctrl-d */pNewtio-c_ccVTIME = 5; /* inter-character timer, timeout VTIME*0.1*/pNewtio-c_ccVMIN = 0; /* blocking read until VMIN character arrives*/pNewtio-c_ccVSWTC = 0; /* 0 */pNewtio-c_ccVSTART = 0; /* Ctrl-q */pNewtio-c_ccVSTOP = 0; /* Ctrl-s */pNewtio-c_ccVSUSP
25、= 0; /* Ctrl-z */pNewtio-c_ccVEOL = 0; /* 0 */pNewtio-c_ccVREPRINT = 0; /* Ctrl-r */pNewtio-c_ccVDISCARD = 0; /* Ctrl-u */pNewtio-c_ccVWERASE = 0; /* Ctrl-w */pNewtio-c_ccVLNEXT = 0; /* Ctrl-v */pNewtio-c_ccVEOL2 = 0; /* 0 */#define BUFSIZE 512int main(int argc, char *argv)int fd;int nread;char buff
展开阅读全文