欢迎来到淘文阁 - 分享文档赚钱的网站! | 帮助中心 好文档才是您的得力助手!
淘文阁 - 分享文档赚钱的网站
全部分类
  • 研究报告>
  • 管理文献>
  • 标准材料>
  • 技术资料>
  • 教育专区>
  • 应用文书>
  • 生活休闲>
  • 考试试题>
  • pptx模板>
  • 工商注册>
  • 期刊短文>
  • 图片设计>
  • ImageVerifierCode 换一换

    linux串口编程.doc

    • 资源ID:70344529       资源大小:156.50KB        全文页数:42页
    • 资源格式: DOC        下载积分:15金币
    快捷下载 游客一键下载
    会员登录下载
    微信登录下载
    三方登录下载: 微信开放平台登录   QQ登录  
    二维码
    微信扫一扫登录
    下载资源需要15金币
    邮箱/手机:
    温馨提示:
    快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。
    如填写123,账号就是123,密码也是123。
    支付方式: 支付宝    微信支付   
    验证码:   换一换

     
    账号:
    密码:
    验证码:   换一换
      忘记密码?
        
    友情提示
    2、PDF文件下载后,可能会被浏览器默认打开,此种情况可以点击浏览器菜单,保存网页到桌面,就可以正常下载了。
    3、本站不支持迅雷下载,请使用电脑自带的IE浏览器,或者360浏览器、谷歌浏览器下载即可。
    4、本站资源下载后的文档和图纸-无水印,预览文档经过压缩,下载后原文更清晰。
    5、试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。

    linux串口编程.doc

    linux 串口编程在嵌入式Linux中,串口是一个字设备,访问具体的串行端口的编程与读写文件的操作类似,只需打开相应的设备文件即可操作。串口编程特殊在于串口通信时相关参数与属性的设置。嵌入式Linux的串口编程时应注意,若在根文件中没有串口设备文件,应使用mknod命令创建,这这里假设串口设备是/dev/ttyS0,介绍一下串口的编程过程。mknod /dev/ttyS0 c 4 641、打开串口       打开串口设备文件的操作与普通文件的操作类似,都采用标准的I/O操作函数open()。       fd = open("/dev/ttyS0",O_RDWR|O_NDELAY|O_NOCTTY);    open()函数有两个参数,第一个参数是要打开的文件名(此处为串口设备文件/dev/ttyS0);第二个参数设置打开的方式,O_RDWR表示打开的文件可读/写,O_NDELAY表示以非阻塞方式打开,ONOCTTY表示若打开的文件为终端设备,则不会将终端作为进程控制终端。2、设置串口属性     串口通信时的属性设置是串口编程的关键问题,许多串口通信时的错误都与串口的设置相关,所以编程时应特别注意这些设置,最常见的设置包括波特率、奇偶校验和停止位以及流控制等。    在Linux中,串口被作为终端I/O,它的参数设置需要使用struct termios结构体,这个结构体在termio.h文件中定义,且应在程序中包含这个头文件。          typedef unsigned char         cc_t ;          typedef unsigned int            speed_t ;          typedef unsigned int            tcflag_t ;          struct termios                       tcflag_t      c_iflag ;          /*输入模式标志*/              tcflag_t      c_oflag ;         /*输出模式标志*/             tcflag_t      c_cflag ;            /*控制模式标志*/             tcflag_t      c_lflag ;            /*本地模式标志*/             tcflag_t      c_line ;            /*行规程类型,一般应用程序不使用*/             cc_t         c_ccNCC;      /*控制字符*/             speed_t      c_ispeed ;      /*输入数据波特率*/             speed_t      c_ospeed ;      /*输出数据波特率*/       ;       串口的设置主要是设置这个结构体的各成员值,然后利用该结构体将参数传给硬件驱动程序。在Linux中,串口以串行终端的方式进行处理,因而,可以使用tcgetattr()/tcsetattr()函数获取/设置串口的参数。       int tcgetattr( int fd, struct termios *termios_p );       int tcsetattr( int fd, int optional_actions , struct termios *termios_p );       这两个参数都有一个批向termios结构体的指针作为参数,用于返回当前终端的属性或设置该终端的属性。参数fd就是用open()函数打开的终端文件句柄,而串口就是用open()打开的串口设备文件句柄。tcsetattr()函数的optional_action参数用于指定新设定的参数起作用的时间,其设定值可以为:       TCSANOW         改变立即生效       TCSADRAIN      在所有的输出都被传输后改变生效,适用于更改影响输出参数的情况。       TCSAFLUSH    在所有输出都被传输后改变生效,丢弃所有末读入的输入(清空输入缓                                存)。(1)设置波特率       使用cfsetospeed()/cfsetispeed()函数设置波特率,它们分别用于在termios结构体中设置输出和输入的波特率。设置波特率可以使用波特率常数,其定义为字母“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)设置控制模式标志       控制模式标志c_cflag主要用于设置串口对DCD信号状态检测、硬件流控制、字符位宽、停止位和奇偶校验等,常用标志位如下:CLOCAL   忽略DCD信号,若不使用MODEM,或没有串口没有CD脚就设置此标志CREAD    启用接收装置,可以接收字符CRTSCTS启用硬件流控制,对于许多三线制的串不应使用,需设置CRTCTSCSIZE      字符位数掩码,常用CS8CSTOPB   使用两个停止位,若用一位应设置CSTOPBPARENB   启用奇偶校验       例如,下面的代码将串口设置为忽略DCD信号,启用接收装置,关闭硬件流控制,传输数据时使用8位数据位和一位停止位(8N1),不使用奇偶校验。       struct temios ttys0       ttyso_opt.c_cflag |= CLOCAL | CREAD ;      /将CLOCAL与CREAD位设置为1       ttys0_opt.c_cflag &= CRTSCTS ;               /将硬件流控制位CRTSCTS清0,其他位不变       ttys0_opt.c_cflag & CSIZE ;               /清除数据位掩码       ttys0_opt.c_cflag |= CS8 ;                           /设置8位数据位标志CS8       ttys0_opt.c_cflag &= (PARENB|CSTOPB);/使用1位停止位,停用奇偶校验(3)设置本地模式标志       本地模式标志c_lflag主要用于设置终端与用户的交互方式,常见的设置标志位有ICANON,ECHO和ECHOE等。其中,ICANON标志位用于实现规范输入,即read()读到行结束符后返回,常用于终端的处理;若串口用于发送/接收数据,则应清除此标志,使用非规范模式(raw mode)。非规范模式中,输入数据不组成行,不处规范模式中的特殊字符。在规范模式中,当设置ECHO标志位时,用户向终端输入的字符将被回传给用户;当设置ECHOE标志位时,用户输入退格键时,则回传“退格空格退格”序列给用户,使得退格键覆盖的字符从显示中消失,这样更符合用户的习惯(若未设置此标志,输入退格键时,则光标回退一个字符,但原有的字符未从显示中消失)。(4)设置输入模式标志       输入模式标志c_iflag主要用于控制串口的输入特性,常用的设置有IXOFF和IXON,分别用于软件流控制。其中,IXOFF用于防止输入缓冲区溢出;IXON则是在输入数据中识别软件流控制标志。由于许多嵌入式系统无法使用硬件流控制,因此,只能使用软件流控制数据传输的速度,但是,它可能降低串口数据传输效率。启用软件流控制的代码如下:       ttys0_opt.c_iflag |= IXOFF|IXON ;(5)设置输出模式标志       输出模式标志c_oflag主要用于对串口在规范模式时输出的特殊字符处理,而对非规范模式无效。(6)设置控制字符       在非规范模式中,控制字符数组c_cc中的变量c_ccVMIN和c_ccVTIME用于设置read()返回前读到的最少字节数和读超时时间,其值分为四种情况:    (a)c_ccVMIN0,c_ccVTIME>0          读到一个字节后,启动定时器,其超时时间为c_ccVTIME,read()返回的条件为至少读到c_ccVMIN个字符或定时器超期。    (b)c_ccVMIN>0, c_ccVTIME =0          只要读到数据的字节数大于等于c_ccVMIN,则read()返回;否则,将无限期阻塞等待。      (c)c_ccVMIN = 0, c_ccVTIME>0          只要读到数据,则read()返回;若定时器超期(定时时间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、清空发送/接收缓冲区       为保证读/写操作不被串口缓冲区中原有的数据干拢,可以在读/写数据前用tcflush()函数清空串口发送/接收缓冲区。tcflush()函数的参数可为:        TCIFLUSH      清空输入队列        TCOFLUSH   清空输出队列        TCIOFLUSH   同时清空输入和输出队列4、从串口读写数据        串口的数据读/写与普通文件的读/写一样,都是使用read()/write()函数实现。        n = write( fd, buf, len );         /将buf中len个字节的数据从串口输出,返回输出的字节数        n = read( fd, buf, len );         /从串口读入len个字节的数据并放入buf, 返回读取的字节数5、关闭串口    关闭串口的操作很简单,将打开的串口设备文件句柄关闭即可。    close(fd);Linux 串口读写(二) 例子 下面是一个简单的读取串口数据的例子,使用了上面定义的一些函数和头文件 /*  * 代码说明:使用串口二测试的,发送的数据是字符,但是没有发送字符串结束符号,  * 所以接收到后,后面加上了结束符号。我测试使用的是单片机发送数据到第二个串口,测试通过。  */ #define FALSE  -1 #define TRUE   0 /*/ int OpenDev(char *Dev)     /Dev 就是设备,设备就是文件,就是给出该设备文件的路径     int fd = open(Dev, O_RDWR ); /| O_NOCTTY | O_NDELAY     if (-1 = fd)            perror("Can't Open Serial Port");        return -1;         else        return 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)                   printf("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 (3) 特殊字符解析问题,部分特殊字符接收/发送时,会被屏蔽或者转义。如发送0x0A 接收变为0x0A 0x0A ,0x0D被屏蔽等。 (4) 接收反馈:如串口接收到数据,立即将该数据发送出去。 (上面是我遇到的一些问题,可能表述不很清楚,呵呵。如果用于收发txt文件,一般不大注意。)  3、解决问题的方法是,消除这些默认规则,关键是struct termios 的参数影响。 struct termios         tcflag_t c_iflag;               /*/* 输入模式旗标 */         tcflag_t c_oflag;               /*/* 输出模式旗标 */         tcflag_t c_cflag;               /*/* 控制模式旗标 */         tcflag_t c_lflag;               /*/* 区域模式旗标 */         cc_t c_line;                    /*/* 行控制 (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;   /*/* 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_ccVREPRINT = 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;   /*/* '' */  以上设置,在其它参数串口设置前执行,如果你需要保留部分参数,请参阅在RedHat Feroda 4 下编译通过  = = = = = = = = = = = 非阻塞read= = = = = = = = = = = Q:在调用串口read(fd,   buff,   len);时,如果串口没有数据,会停在read处,请问有没有办法让这个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中整理。 = = = = = = = = = = = 串口收发源码= = = = = = = = = = =        一下代码已经经过我测试,没有问题。开发环境Redhat9,运行环境s3c2410 = = = = = = receive.c= = = = = = #include   <stdio.h>      #include   <stdlib.h>    #include   <unistd.h>      #include   <sys/types.h>  #include   <sys/stat.h>   #include   <fcntl.h>     #include   <termios.h>   #include   <errno.h>     #include   <string.h>  #define TRUE 1 /初始化串口选项:   void setTermios(struct termios * pNewtio, int uBaudRate)     bzero(pNewtio, sizeof(struct termios); /* clear struct for new port settings */      /8N1     pNewtio->c_cflag = uBaudRate | CS8 | CREAD | CLOCAL;     pNewtio->c_iflag = IGNPAR;      pNewtio->c_oflag = 0;     pNewtio->c_lflag = 0; /non ICANON     /*      initialize all control characters      default values can be found in /usr/include/termios.h, and      are given in the comments, but we don't need them here      */     pNewtio->c_ccVINTR = 0; /* Ctrl-c */     pNewtio->c_ccVQUIT = 0; /* Ctrl- */     pNewtio->c_ccVERASE = 0; /* del */     pNewtio->c_ccVKILL = 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 = 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 512 int main(int argc, char *argv)     int fd;     int nread;     char buffBUFSIZE;     struct termios oldtio, newtio;     struct timeval tv;     char *dev ="/dev/ttyS1"     fd_set rfds;      if (fd = open(dev, O_RDWR | O_NOCTTY)<0)            printf("err: can't open serial port!n");        return -1;          tcgetattr(fd, &oldtio); /* save current serial port settings */     setTermios(&newtio, B115200);      tcflush(fd, TCIFLUSH);     tcsetattr(fd, TCSANOW, &newtio);      tv.tv_sec=30;     tv.tv_usec=0;     while (TRUE)            printf("wait.n");        FD_ZERO(&rfds);        FD_SET(fd, &rfds);        if (select(1+fd, &rfds, NULL, NULL, &tv)>0)                   if (FD_ISSET(fd, &rfds)                          nread=read(fd, buff, BUFSIZE);               printf("readlength=%dn", nread);               buffnread='0'               printf("%sn", buff);                           tcsetattr(fd, TCSANOW, &oldtio);     close(fd);  = = = = = send.c= = = = = = #include   <stdio.h>      #include   <stdlib.h>    #include   <unistd.h>      #include   <sys/types.h>  #include   <sys/stat.h>   #include   <fcntl.h>     #include   <termios.h>   #include   <errno.h>     #include   <string.h>  /初始化串口选项:   void setTermios(struct termios * pNewtio, int uBaudRate)     bzero(pNewtio, sizeof(struct termios); /* clear struct for new port settings */      /8N1     pNewtio->c_cflag = uBaudRate | CS8 | CREAD | CLOCAL;     pNewtio->c_iflag = IGNPAR;      pNewtio->c_oflag = 0;     pNewtio->c_lflag = 0; /non ICANON     /*      initialize all control characters      default values can be found in /usr/include/termios.h, and      are given in the comments, but we don't need them here      */     pNewtio->c_ccVINTR = 0; /* Ctrl-c */     pNewtio->c_ccVQUIT = 0; /* Ctrl- */     pNewtio->c_ccVERASE = 0; /* del */     pNewtio->c_ccVKILL = 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 = 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' */  int main(int argc, char *argv)     int fd;     int nCount, nTotal, i;     struct termios oldtio, newtio;     char *dev ="/dev/ttyS1"      if (argc!=3) | (sscanf(argv1, "%d", &nTotal) != 1)            printf("err: need tow arg!n");        return -1;          if (fd = open(dev, O_RDWR | O_NOCTTY)<0)            printf("err: can't open serial port!n");        return -1;          tcgetattr(fd, &oldtio); /* save current serial port settings */     setTermios(&newtio, B115200);      tcflush(fd, TCIFLUSH);     tcsetattr(fd, TCSANOW, &newtio);      for (i=0; i<nTotal; i+)            nCount=write(fd, argv2, strlen(argv2);        printf("send datan");        sleep(1);         tcsetattr(fd, TCSANOW, &oldtio);     close(fd);     return 0;  = = = = = =.makefile= = = = = = CC = /usr/local/arm/2.95.3/bin/arm-linux-gcc all:receive send receive: receive.c     $(CC) receive.c -o  receive send: send.c     $(CC) send.c -o  send clean:     -rm -rf testCOM receive send  到此基本就结束了,可能代码注释比较少些,写的太着急了,等有时间整理一下。最好再看看上一篇blog这样能更好的理解串口。 #include#include#include#define STDIN 0 /* file descriptor for standard input */ main() struct timeval tv; fd_set readfds; tv.tv_sec = 2; tv.tv_usec = 500000; FD_ZERO(&readfds); FD_SET(STDIN,&readfds); /* don&apost care about writefds and exceptfds: */ select(STDIN+1,&readfds, NULL, NULL,&tv); if (FD_ISSET(STDIN,&readfds) printf("A key was pressed!n"); else printf("Timed out.n"); 如果你是在一个 line buffered 终端上,那么你敲的键应该是回车 (RETURN),否则无论如何它都会超时。现在,你可能回认为这就是在数据报套接字上等待数据的方式-你是对 的:它可能是。有些 Unix 系统可以按这种方式,而另外一些则不能。你 在尝试以前可能要先看看本系统的 man page 了。最后一件关于 select() 的事情:如果你有一个正在侦听 (listen() 的套 接字,你可以通过将该套接字的文件描述符加入到 readfds 集合中来看是 否有新的连接。这就是我关于函数select() 要讲的所有的东西。深入UNIX编程:一个简单聊天室的两种实现 (fcntl 和 select)-

    注意事项

    本文(linux串口编程.doc)为本站会员(asd****56)主动上传,淘文阁 - 分享文档赚钱的网站仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知淘文阁 - 分享文档赚钱的网站(点击联系客服),我们立即给予删除!

    温馨提示:如果因为网速或其他原因下载失败请重新下载,重复下载不扣分。




    关于淘文阁 - 版权申诉 - 用户使用规则 - 积分规则 - 联系我们

    本站为文档C TO C交易模式,本站只提供存储空间、用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。本站仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知淘文阁网,我们立即给予删除!客服QQ:136780468 微信:18945177775 电话:18904686070

    工信部备案号:黑ICP备15003705号 © 2020-2023 www.taowenge.com 淘文阁 

    收起
    展开