Linux下串口程序开发_第1页
Linux下串口程序开发_第2页
Linux下串口程序开发_第3页
Linux下串口程序开发_第4页
Linux下串口程序开发_第5页
已阅读5页,还剩12页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、Linux下串口程序开发串行口是计算机一种常用的接口,具有连接线少,通讯简单,得到广泛的 使用。常用的串口是 RS-232-C接口(又称EIA RS-232-C)它是在1970年由美国电 子工业协会(EIA)联合贝尔系统、调制解调器厂家及计算机终端生产厂家共同制 定的用于串行通讯的标准。它的全名是数据终端设备(DTE)和数据通讯设备(DCE)之间串行二进制数据交换接口技术标准 该标准规定采用一个 25个脚的 DB25连接器,对连接器的每个引脚的信号内容加以规定,还对各种信号的电平 加以规定。传输距离在码元畸变小于 4%的情况下,传输电缆长度应为 50英尺。在linux文件中,所有的设备文件一般

2、都位于/dev下,其中串口一、串口二 分别对应的设备名依次为“ /dev/ttyS0”、“/dev/ttyS1”,可以查看在/dev下的文件 以确认。在linux下面对于串口的读写就可以通过简单的 read write函数来完成, 所不同的是只是需要对串口的其他参数另坐配置。1. 串口编程需要用到的头文件#include /标准输入输岀定义#include #include /文件控制定义,主要完成串口通信中对文件的读写操作#include / linux标准函数定义#include #include / POSIX终端控制定义#include #include 2. 串口终端函数2.1打开串

3、口设备int fd ;char *device = /dev/tts/0;/设备路径,初始使用UART0for(t=1;t (t+1)device = argvt+1;if(!strcmp(device,/dev/tts/1)/ 不允许使用 UART1,因为它已和 PC相连printf(can not use /dev/tts/1n);return -1;fd = open(device, O_RDWR);/ 打开设备if (fd 0)/设备打开失败printf(open device errorn);return -1;2.2设置串口最基本的串口设置包括波特率设置,校验位和停止位设置。实际上

4、串口的设置只要是设置Struct termios()结构体中各成员的值。struct termiounsigned shortc_iflag;/*输入模式标志*/unsigned shortc_oflag;/*输岀模式标志 */unsigned shortc_cflag;/*控制模式标志*/unsigned shortc_lflag;/* local mode flags */unsigned charc_line;/* line discipline */unsigned char;c_ccNCC;/* control characters */2.2.1波特率设置struct termio

5、s Opt; tcgetattr(fd, & Opt); cfsetispeed(&Opt,B192OO); cfsetospeed(&Opt,B19200); tcsetattr(fd,TCANOW, &Opt);/得到当前串口的参数/* 设置为 19200Bps*/激活新配置设置波特率的例子函数:*brief 设置串口通信速率*param fd 类型int 打开串口的文件句柄*paramspeed类型 int 串口速度*returnvoid*/int speed_arr = B38400, B19200, B9600, B4800, B2400, B1200, B300, B38400,

6、B19200, B9600, B4800, B2400, B1200, B300, ;300, 38400,int name_arr = 38400,19200,9600,4800,2400,1200,19200,9600, 4800, 2400, 1200,300, ;void set_speed(int fd, int speed)inti;intstatus;struct termiosOpt;tcgetattr(fd, & Opt);for ( i= 0; i sizeof(speed_arr) / sizeof(int);i+) if (speed = name_arri) tcfl

7、ush(fd, TCIOFLUSH); cfsetispeed(&Opt, speed_arri); cfsetospeed(&Opt, speed_arri);status = tcsetattr(fd1, TCSANOW, & Opt);if (status != 0) perror(tcsetattr fd1);return;tcflush(fd,TCIOFLUSH);2.2.2校验位和停止位设置*brief设置串口数据位,停止位和效验位*paramfd类型 int打开的串口文件句柄*paramdatabits类型int数据位取值为7或者8*paramstopbits类型 int停止位取

8、值为1或者2*paramparity类型 int效验类型取值为N,E,O,S*/int set_Parity(int fd,int databits,int stopbits,int parity)struct termios options;if ( tcgetattr( fd,&options)!=0) / 得到当前串口的参数perror(SetupSerial 1); return(FALSE);/设置字符大小options.c_cflag &=CSIZE;switch (databits) /*设置数据位数 */case 7:options.c_cflag |= CS7;break;c

9、ase 8:options.c_cflag |= CS8;break;default:fprintf(stderr,Unsupported data sizen); return (FALSE);/设置奇偶校验位switch (parity)case n:/无奇偶校验位case N:/* Clear parity enable */options.c_cflag &=PARENB; break;case o:case O:options.c_cflag |= (PARODD | PARENB); /*options.c_iflag |= INPCK; break;case e:case E:o

10、ptions.c_cflag |= PARENB; options.c_cflag &=PARODD; options.c_iflag |= INPCK; break;case S:/ Space 校验case s:/*as no parity*/options.c_cflag &=PARENB; options.c_cflag &=CSTOPB;设置为奇效验*/ INPCK:奇偶校验使能/* Enable parity */*转换为偶效验*/* Disnable parity checking */options.c_iflag |= INPCK; break;default:fprintf

11、(stderr,Unsupported parityn);return (FALSE);/设置停止位switch (stopbits)case 1:options.c_cflag &=CSTOPB;/ 1 个停止位break;case 2:options.c_cflag |= CSTOPB;/ 2 个停止位break;default:fprintf(stderr,Unsupported stop bitsn);return (FALSE);/处理未接收的字符tcflush(fd,TCIFLUSH);/设置等待时间和最小接收字符options.c_ccVTIME = 150; /*设置超时 15

12、 seconds*/options.c_ccVMIN = 0; /* Update the options and do it NOW */激活新配置if (tcsetattr(fd,TCSANOW,&options) != 0)perror(SetupSerial 3);return (FALSE);return (TRUE);2.2.3模式设置需要注意的是,如果不是开发终端之类的,只是串口传输数据,而不需要 串口来处理,那么使用原始模式(Raw Mode)方式来通信。newtio.c_lflag &=(ICANON | ECHO | ECHOE | ISIG); /原始数据输入newtio

13、.c_oflag &=(OPOST); /原始数据输出224串口配置实例void init_ttyS(int fd)struct termios newtio;bzero (&newtio, sizeof(newtio);/得到当前串口的参数tcgetattr(fd, &newtio);/将输入波特率设为19200/将输出波特率设为19200cfsetispeed(&newtio, B19200); cfsetospeed(&newtio, B19200);/使能接收并使能本地状态newtio.c_cflag |= (CLOCAL | CREAD);/无校验8位数据位1位停止位newtio.c

14、_cflag &=PARENB;newtio.c_cflag &=CSTOPB;newtio.c_cflag &=CSIZE;/ 8个数据位newtio.c_cflag |= CS8;/原始数据输入newtio.c_lflag &=(ICANON | ECHO | ECHOE | ISIG); newtio.c_oflag &=(OPOST);/设置等待时间和最小接收字符数newtio.c_ccVTIME= 0;newtio.c_ccVMIN= 0;/处理未接收的字符tcflush(fd, TCIFLUSH);/激活新配置tcsetattr(fd,TCSANOW,&newtio);2.3读串口

15、读取串口数据使用文件操作read函数读取,如果设置为原始模式(Raw Mode)传输数据,那么read函数返回的字符数是实际串口收到的字符数char buff1024;int Len;int readByte = read(fd,buff,Len);可以使用操作文件的函数来实现异步读取,如fcntl,或者select等来操作void SERIAL_RX(void)/ read(fd, RXBUF , RX_len);#if 1int ret,n,pos,retval;fd_set rfds;struct timeval tv ;pos = 0;/指向接收缓冲for(n = 0; n RX_le

16、n; n+)RXBUFn = 0xFF;FD_ZERO(&rfds);清空串口接收端口集FD_SET(fd,&rfds);设置串口接收端口集tv.tv_sec = 2;tv.tv_usec = 0;while(FD_ISSET(fd,& rfds) /检测串口是否有读写动作/每次循环都要清空,否则不会检测到有变化FD_ZERO(&rfds);清空串口接收端口集FD_SET(fd,&rfds);设置串口接收端口集retval = select(fd+1,&rfds,NULL,NULL, &tv);if(retval = -1)perror(select();break;else if(retva

17、l)/判断是否还有数据sleep( 2);ret = read(fd, RXBUF, RX_len);pos += ret;printf(ret = %d n,ret);if(RXBUFpos-2 = r) & (RXBUFpos-1 = n) /确实接收到了数据,并打印岀来FD_ZERO (&rfds);FD_SET(fd,&rfds);retval = select(fd+1,&rfds,NULL,NULL, &tv);if(!retval)/no datasbreak;elsebreak;Linux下直接用read读串口可能会造成堵塞,或数据读出错误。然而用select 先查询com 口

18、,再用read去读就可以避免,并且当com 口延时时,程序可以退 出,这样就不至于由于com 口堵塞,程序就死了。Select的函数格式(我所说的是Unix系统下的伯克利socket编程,和windows下的有区别,一会儿说明):struct fd_set可以理解为一个集合,这个集合中存放的是文件描述符(file descriptor),即文件句柄,这可以是我们所说的普通意义的文件,当然Unix下任何设备、管道、FIFO等都是文件形式,全部包括在内,所以毫无疑问一个socket就是一个文件, socket句柄就是一个文件描述符。fd_set集合可以通过一些宏由人为来操作,比 如:? FD_ZE

19、RO(fd_set *set):清除一个文件描述符集;? FD_SET(i nt fd, fd_set *set):将一个文件描述符加入文件描述符集中;? FD_CLR(i nt fd, fd_set *set):将一个文件描述符从文件描述符集中清除;? FD_ISSET(int fd, fd_set *set):检查集合中指定的文件描述符是否可以 读写。一会儿举例说明。struct timeval是一个大家常用的结构,用来代表时间值,有两个成员,一个是秒数,另 一个是毫秒数。struct timevallong tv_sec;long tv_unsec;具体解释select的参数:int m

20、axfdp是一个整数值,是指集合中所有文件描述符的范围,即所有文件描述符的 最大值加1,不能错!在 Windows中这个参数的值无所谓,可以设置不正确。fd_set *readfds是指向fd_set结构的指针,这个集合中应该包括文件描述符,我们是要监 视这些文件描述符的读变化的,即我们关心是否可以从这些文件中读取数据了, 如果这个集合中有一个文件可读,select就会返回一个大于0的值,表示有文件 可读,如果没有可读的文件,则根据timeout参数再判断是否超时,若超出timeout 的时间,select返回0,若发生错误返回负值。可以传入NULL值,表示不关心任何文件的读变化。fd_set

21、 *writefds是指向fd_set结构的指针,这个集合中应该包括文件描述符,我们是要监 视这些文件描述符的写变化的,即我们关心是否可以向这些文件中写入数据了, 如果这个集合中有一个文件可写,select就会返回一个大于0的值,表示有文件 可写,如果没有可写的文件,则根据timeout参数再判断是否超时,若超出timeout 的时间,select返回0,若发生错误返回负值。可以传入NULL值,表示不关心任何文件的写变化。fd set *errorfds同上面两个参数的意图,用来监视文件错误异常struct timeval* timeout是select的超时时间,这个参数至关重要,它可以使

22、select处于三种状态, 第一,若将NULL以形参传入,即不传入时间结构,就是将select置于阻塞状态, 一定等到监视文件描述符集合中某个文件描述符发生变化为止;第二,若将时间值设为0秒0毫秒,就变成一个纯粹的非阻塞函数,不管文件描述符是否有变化, 都立刻返回继续执行,文件无变化返回 0,有变化返回一个正值;第三,timeout 的值大于0,这就是等待的超时时间,即select在timeout时间内阻塞,超时时间 之内有事件到来就返回了,否则在超时后不管怎样一定返回,返回值同上述。返回值:负值:select错误 正值:某些文件可读写或出错 0:等待超时,没有可读 写或错误的文件在有了 se

23、lect后可以写出像样的网络程序来!举个简单的例子,就是从网络 上接受数据写入一个文件中。一般来说,在使用select函数之前,首先使用FD_ZERO和FD_SET来初始 化文件描述符集,在使用了 select函数时,可循环使用FD_ISSET测试描述符集, 在执行完对相关的文件描述符后,使用 FD_CLR来清除描述符集。2.4写串口读写串口设置好串口之后,读写串口就很容易了,把串口当作文件读写就 是。发送数据:char buffer1024;intLength;intnByte;nByte = write(fd, buffer Length);2.5关闭串口close ( fd);3. 具体

24、应用实例#include #include #include #include #include #include #include#include #include #include /#include COMM.h#define ACK_SUCCESS#define ACK_FAIL#define ACK_FULL#define ACK_NOUSER#define ACK_USER_EXIST#define ACK_TIMEOUT#define ACK_COUNT0x00/操作成功0x01/操作失败0x04/Full0x05/无此用户0x07/用户已存在0x08/采集超时0x3/发生错误时

25、候,重试次数extern unsigned char TXBUF9900;extern unsigned char RXBUF9900;extern unsigned char rev_ok;extern unsigned intTX_len;extern unsigned intRX_len;extern unsigned char one_onecontrast(unsigned char user_number_h,unsigned char user_number_l);extern unsigned char one_morecontrast(void);extern unsigne

26、d char Get_UserNumber_Right(void);extern unsigned char set_addmode(unsigned char yn_repeat);extern unsigned char add_Fingerprint(unsigned char time_number,unsigned char user_number_h,unsigned char user_number_l,unsigned charuser_right);extern unsigned char del_alluser(void);extern unsigned char del_

27、oneuser(unsigned char user_number_h,unsigned char user_number_l);extern unsigned char read_usernumber(void);int fd;unsigned char USER_NUMBER_H;unsigned char USER_NUMBER_L;unsigned char USER_RIGHT;unsigned char FEATURE_BUFFER512;unsigned char FEATURE_LEN;/用户号高8位/用户号低8位/用户权限/要下传的指纹特征值数据/要下传的指纹特征值的长度un

28、signed char CharToHex(unsigned char ch); unsigned char select_one_onecontrast(void); void select_Get_Usernumber_right(void);*name:SERIAL_TXfunc:发生数据到指纹模块串口para:noneret:nonemodify:comment:*/int SERIAL_TX(void)int ret;ret = write(fd, TXBUF, TX_len);/ 试图从串口发送数 据if(ret = -1)/确实接收到了数据,并打印出来/ *(rcv_buf+re

29、t)=O:printf( Write device error!n);return -1;/ ret = 0;return 0;*n ame:SERIAL_RX* func:从指纹模块串口接收数据* para:none* ret:none* modify:* comment:*/void SERIAL_RX(void)/ read(fd, RXBUF , RX_len);#if 1int ret,n,pos,retval;fd_set rfds;struct timeval tv ;pos = 0;/指向接收缓冲tv.tv_sec = 2;tv.tv_usec = 0;for(n = 0; n

30、 RX_len; n+)RXBUFn = 0xFF;/检测串口是否有读写动作while(FD_ISSET(fd,&uart_r)|FD_ISSET(fd,&uart_w);while(1) /检测串口是否有读写动作FD_ZERO(&rfds);FD_SET(fd,&rfds);/清空串口接收端口集设置串口接收端口集retval = select(fd+1,&rfds,NULL,NULL, &tv);if(retval = -1)perror(select();break;else if(retval)/判断是否还有数据/sleep( 2);ret = read(fd, RXBUF, RX_le

31、n);pos += ret;/printf(ret = %d n,ret);/确实if(RXBUFpos-2 = r) & (RXBUFpos-1 = n)接收到了数据,并打印岀来FD_ZERO(&rfds);FD_SET(fd,&rfds);retval = select(fd+1,&rfds,NULL,NULL, &tv); if(!retval)/no datasbreak;elsebreak;void init_ttyS(int fd)struct termios newtio;bzero (&newtio, sizeof(newtio); tcgetattr(fd, &newtio);cfsetispeed(&newtio, B19200); cfsetospeed(&newtio, B19200); newtio.c_cflag |= (CLOCAL | CREAD); newtio.c_cflag &=PARENB; newtio.c_cflag &=CSTOPB; ne

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论