串口通讯编程.doc_第1页
串口通讯编程.doc_第2页
串口通讯编程.doc_第3页
串口通讯编程.doc_第4页
串口通讯编程.doc_第5页
已阅读5页,还剩8页未读 继续免费阅读

下载本文档

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

文档简介

Linux Serial Programming HOWTO - 串口通讯编程 (2001-05-02 11:07:12)byPeterH.Baum ann,Peter.Baumanndlr.de 译者:曾元佑 v1.0,22一月1998 - 本文件将叙述如何在Linux环境下撰写序列埠的通讯程式. - - 1.简介 本文是Linux序列埠程式撰写的HOWTO.全篇都在讨论如何在Linux环境下,以序列埠与其他装置/电脑通讯的程式写法.所解释的技术包含:标准的I/O(只具备传送/接收线的),非同步I/O,及等待来自多信号源的输入讯号的写法. 本文不会叙述如何设定序列埠,因为这在GregHankins的Serial-HOWTO已经有说明了. 我必需强调我并非此领域中的专家,而是在专案中曾遇到过这类的通讯问题.在这所提到的例程式是衍生自miniterm的程式码.可在LDP程式设计师指南取得(/pub/Linux/docs/LDP/programmers-guide/lpg-0.4.tar.gz及其他映射站)在例那个目录下. 我开始写这份文件是在1997年六月,现在我已经移转到WinNT以满足客户的需求,以致於我没能学得更深入的知识.如果任何人有什麽意见,我很乐意把它摆进这份文件中(参考回馈那一节).如果有人能接手这份工作并加以改进,请e-mail给我. 所有的例都在i386LinuxKernel2.0.29下测试过. 1.1版权 LinuxSerial-Programming-HOWTO的版权(C)1997是PeterBaumann所有.LinuxHOWTO文件可以完整或部份以实际或电子型式重制或散布,只要版权宣告能保留在所有散布的副本中.商业性的重制散布是许可并被鼓励的;不过,如果以此型式的散布应该告知作者. 所有有关的翻译,衍生的工作,或整合合并任何LinuxHOWTO文件皆必须在此版权宣告规之下.也就是,你不可以自HOWTO所衍生的工作中,散布的文件上附加额外的限制条款.除了这些规则之外皆可在某种条件的授与;请联络LinuxHOWTO协调员:如以下所给的位址. 简而言之,我们希望尽可能得透过各种管道促进这份资讯的流通,不过,我强烈的希望将版权宣告置於HOWTO的文件上,任何想重新散布HOWTO的人,均希望您能知会我们一下. 如果你有问题,请经由email与TimBynum,LinuxHOWTO协调员连络,. 1.2本文最新的版本 Serial-Programming-HOWTO最新的版本将放在 :/pub/Linux/docs/HOWTO/Serial-Programming-HOWTO及其他映设站台.有许多的格式,如PostScript及DVI的版本放在other-formats目录下.Serial-Programming-HOWTO也放在/LDP/HOWTO/Serial-Programming-HOWTO.html并会每个月摆一份到comp.os.linux.answers. 1.3回馈 请把任何修正,问题,意见,建议,或其它附加的题材传送给我.以让我改进这份HOWTO!并详细告诉我哪个部份是您不能了解,或不够清楚的.你可以用email连络我Peter.Baumanndlr.de.请把Serial-Programming-HOWTO的版本号码附上,本文版本号码是0.3. - - 2.开始 2.1侦错 最好的侦错你程式码的方法是建构另一台Linuxbox,并把两台电脑用null-modem缆线连接.用miniterm(可在LDP程式设计师指南取得(/pub/Linux/docs/LDP/programmers-guide/lpg-0.4.tar.gz在例那个目录下)以传送字元到你的Linuxbox.Miniterm很容易编译而它会把所有输入到键盘的字元透过序列埠传送.只有这个宣告定义会被检查#defineMODEMDEVICE/dev/ttyS0.如果是COM1设定为ttyS0,如果是COM2设定为ttyS1等等.先前的测试是必要的,所有的字元都将以raw方式(不经任何处理)直接传送.测试是否连接正确,在两台电脑上都启动miniterm然後随便在键盘上乱按.在其中一台上输入的字元应该会显示在另一台电脑上反之亦同.但输入的字元不会回应到与之相连的萤幕上. 要自制null-modem的电缆,你必需要把TxD(传送)及RxD(接收)两线对调.详细的说明在Serial-HOWTO的第7段. 当然也可以只用一台电脑来作相同的测试,只要电脑上有两个未使用的序列埠.当然你也就要执行两个miniterm来当虚拟控制台.如果你是藉由拔去滑鼠来取得另一个序列埠,记得要把/dev/mouse装置重新导向,如果它存在的话.如果你使用多埠的序列埠控制卡,请确定它已设定正确.当我在我的电脑上测试时也曾经因为设定错误而出过槌.当我连到另一台电脑,通讯埠开始传送字元.就因为刚好这不是完整的非同步式传输,所以可在同一台电脑上执行两个程式. 2.2连接埠设定 /dev/ttyS*装置会被当成连接到你的Linuxbox的终端机,并且在启动後就设定好了.这个观念在你写raw装置的通讯程式时必需记住.也就是说这个连接埠被设定为回应所有自这个装置送出的字元,而用在资料传输时通常这种要改变这种工作模式. 所有的参数可以由一个小程式简单的完成.设定参数被放在一个结构体内structtermios,他的定义档在: #defineNCCS19 structtermios tcflag_tc_iflag;/*输入模式旗标*/ tcflag_tc_oflag;/*输出模式旗标*/ tcflag_tc_cflag;/*控制模式旗标*/ tcflag_tc_lflag;/*区域模式旗标*/ cc_tc_line;/*行控制(linediscipline)*/ cc_tc_ccNCCS;/*控制特性*/ ; 这个档案也包含所有的旗标定义.输入模式旗标在c_iflag掌管所有的输入处理,这就意谓著由装置上传来的字元在还没用read功能读取前可以先处理过.同理c_oflag掌管所有的输出处理.c_cflag包含连接埠的设定,如鲍率,每字元多少位元,停止位元,等等.区域模式旗标放在c_lflag用来侦测字元是否回应,而讯号会送到你的程式,等等.最後c_cc阵列定义了档案终了的控制字元,停止,等等.预设的控制字元值放在.有关旗标的细节摆在使用手册termios(3).termios结构体内的c_line行控制(linediscipline)元素,不能在POSIX相容的系统下使用译者注:这里所说的linediscipline虽然我翻成行控制但还是很难说出那是舍.如果想知道请看看kernel:(. 2.3序列装置的输入观念 有三个输入的观念要说明.按照所要写的应用程式选用适合的观念.尽量避免使用回圈来读取单一的字元再组成字串.我曾这样做过,会掉字元,且对read而言不会显示任何错误. 标准输入程序 这是终端机的标准处理程序,但用来与其他dl型式的以行为单位的输入通讯也很有用,也就是read会传回一整行完整的输入资料.行预设的终止字元是NL(ASCIILF),档案结束符,或行终止字元.预设环境下,CR(是DOS/Windows预设的行终止符)不会终止一行的叙述. 标准的输入处理程序还可以处理清除,删除字,重印字元,及转换CR为NL等等功能. 非标准输入程序 非标准输入程序可以用在需要每次读取固定数量字元的情况,并允许使用字元输入时间的计时器.这种模式可以用在读取固定字元数量的应用程式,或者所连接的装置会突然送出大量字元的状况. 非同步式输入 以上所叙述的两种模式都可以用在非同步与同步的传输模式.预设是在同步的模式下工作,也就是在尚未读取完之前,read的状态会被阻断.而非同步模式下read的状态会直接返回并送出讯号到所叫用的程式直到完成工作.这个讯号可以由讯号的处理程式handler.来接收. 等待来自多个讯号来源的输入 这并不是一个不一样的输入模式.如果你要透过序列埠连接并处理多个装置的话,它是满有用的.在我的应用程式中我必需在几乎同一时间内,透过TCP/IPsocket及序列埠处理来自其他电脑的输入讯号.下面这个例程式将等待来自两个不同输入源的讯号.如果其中一个信号源出现,他就会被处理,而程式会继续等待新的输入讯号. 以下这个方法看起来相当覆杂,但请记住Linux是一个多工的作业系统.select这个系统呼叫并不会在等待输入讯号时把CPU负载加重,而如果你用回圈方式来等待输入讯号将使得其它同时执行的行程被拖慢. - - 3.程式例 所有的例来源自miniterm.c.Thetypeahead暂存器被限制在255个字元,就跟标准输入程序的最大字串长度相同(或). 参考程式码中的注解它会解释不同输入模式的使用.我希望这些程式码都能被了解.标准输入程序的程式例的注解写得最好,其它的例都只在不同於其它例的地方做注解. 叙述不是很完整,但可以激励你对这例做实验,以延生出合於你所需应用程式的最佳解. 别忘记要把序列埠的权限设定正确(也就是:chmoda+rw/dev/ttyS1)! 3.1标准输入程序 #include #include #include #include #include /*鲍率设定被定义在,这在被引入*/ #defineBAUDRATEB38400 /*定义正确的序列埠*/ #defineMODEMDEVICE/dev/ttyS1 #define_POSIX_SOURCE1/*POSIX系统相容*/ #defineFALSE0 #defineTRUE1 volatileintSTOP=FALSE; main() intfd,c,res; structtermiosoldtio,newtio; charbuf255; /* 开启数据机装置以读取并写入而不以控制tty的模式 因为我们不想程式在送出CTRL-C後就被杀掉. */ fd=open(MODEMDEVICE,O_RDWR|O_NOCTTY); if(fd0且TIME=0,MIN设定为满足读取功能的最低字元接收个数.由於TIME是零,所以计时器将不被使用. 如果MIN=0且TIME0,TIME将被当做逾时设定值.满足读取功能的情况为读取到单一字元,或者超过TIME所定义的时间(t=TIME*0.1s).如果超过TIME所定义的时间,则不会传回任何字元. 如果MIN0且TIME0,TIME将被当做一个分割字元组的计时器.满足读取功能的条件为接收到MIN个数的字元,或两个字元的间隔时间超过TIME所定义的值.计时器会在每读到一个字元後重新计时,且只会在第一个字元收到後才会启动. 如果MIN=0且TIME=0,读取功能就马上被满足.目前所存在的字元组个数,或者将回传的字元组个数.根据Antonino(参考贡献)所说,你可以用fcntl(fd,F_SETFL,FNDELAY);在读取前得到相同的结果. 藉由修改newtio.c_ccVTIME及newtio.c_ccVMIN上述的模式就可以测试了. #include #include #include #include #include #defineBAUDRATEB38400 #defineMODEMDEVICE/dev/ttyS1 #define_POSIX_SOURCE1/*POSIX系统相容*/ #defineFALSE0 #defineTRUE1 volatileintSTOP=FALSE; main() intfd,c,res; structtermiosoldtio,newtio; charbuf255; fd=open(MODEMDEVICE,O_RDWR|O_NOCTTY); if(fd0)perror(MODEMDEVICE);exit(-1); tcgetattr(fd,&oldtio);/*储存目前的序列埠设定*/ bzero(&newtio,sizeof(newtio); newtio.c_cflag=BAUDRATE|CRTSCTS|CS8|CLOCAL|CREAD; newtio.c_iflag=IGNPAR; newtio.c_oflag=0; /*设定输入模式(非标准型,不回应,.)*/ newtio.c_lflag=0; newtio.c_ccVTIME=0;/*不使用分割字元组计时器*/ newtio.c_ccVMIN=5;/*在读取到5个字元前先停止*/ tcflush(fd,TCIFLUSH); tcsetattr(fd,TCSANOW,&newtio); while(STOP=FALSE)/*输入回圈*/ res=read(fd,buf,255);/*在输入5个字元後即返回*/ bufres=0;/*所以我们能用printf.*/ printf(:%s:%dn,buf,res); if(buf0=z)STOP=TRUE; tcsetattr(fd,TCSANOW,&oldtio); 3.3非同步式输入 #include #include #include #include #include #include #defineBAUDRATEB38400 #defineMODEMDEVICE/dev/ttyS1 #define_POSIX_SOURCE1/*POSIX系统相容*/ #defineFALSE0 #defineTRUE1 volatileintSTOP=FALSE; voidsignal_handler_IO(intstatus);/*定义讯号处理程序*/ intwait_flag=TRUE;/*没收到讯号的话就会是TRUE*/ main() intfd,c,res; structtermiosoldtio,newtio; structsigactionsaio;/*definitionofsignalaction*/ charbuf255; /*开启装置为non-blocking(读取功能会马上结束返回)*/ fd=open(MODEMDEVICE,O_RDWR|O_NOCTTY|O_NONBLOCK); if(fd0)perror(MODEMDEVICE);exit(-1); /*在使装置非同步化前,安装讯号处理程序*/ saio.sa_handler=signal_handler_IO; saio.sa_mask=0; saio.sa_flags=0; saio.sa_restorer=NULL; sigaction(SIGIO,&saio,NULL); /*允许行程去接收SIGIO讯号*/ fcntl(fd,F_SETOWN,getpid(); /*使档案akethefiledescriptor非同步(使用手册上说只有O_APPEND及 O_NONBLOCK,而F_SETFL也可以用.)*/ fcntl(fd,F_SETFL,FASYNC); tcgetattr(fd,&oldtio);/*储存目前的序列埠设定值*/ /*设定新的序列埠为标准输入程序*/ newtio.c_cflag=BAUDRATE|CRTSCTS|CS8|CLOCAL|CREAD; newtio.c_iflag=IGNPAR|ICRNL; newtio.c_oflag=0; newtio.c_lflag=ICANON; newtio.c_ccVMIN=1; newtio.c_ccVTIME=0; tcflush(fd,TCIFLUSH); tcsetattr(fd,TCSANOW,&newtio); /*等待输入讯号的回圈.很多有用的事我们将在这做*/ while(STOP=FALSE) printf(.n);usleep(100000); /*在收到SIGIO後,wait_flag=FALSE,输入讯号存在则可以被读取*/ if(wait_flag=FALSE) res=read(fd,buf,255); bufres=0; printf(:%s:%dn,buf,res); if(res=1)STOP=TRUE;/*如果只输入CR则停止回圈*/ wait_flag=TRUE;/*等待新的输入讯号*/ /*回存旧的序列埠设定值*/ tcsetattr(fd,TCSANOW,&oldtio); /* *讯号处理程序.设定wait_flag为FALSE,以使上述的回圈能接收字元* */ voidsignal_handler_IO(intstatus) printf(receivedSIGIOsignal.n); wait_flag=FALSE; 3.4等待来自多个讯号来源的输入 这一段很短.它只能被拿来当成写程式时的提示,故例程式也很简短.但这个例不只能用在序列埠上,还可以用在被当成档案来使用的装置上. select呼叫及伴随它所引发的巨集共用fd_set.fd_set则是一个位元阵列,而其中每一个位元代表一个有效的档案叙述结构.select呼叫接受一个有效的档案叙述结构并传回fd_set位元阵列,而该位元阵列中若有某一个位元为1,就表示相对映的档案叙述结构的档案发生了输入,输出或有例外事件.而这些巨集提供了所有处理fd_set的功能.亦可参考手册select(2). #include #include #include main() intfd1,fd2;/*输入源1及2*/ fd_setreadfs;/*档案叙述结构设定*/ intmaxfd;/*最大可用的档案叙述结构*/ intloop=1;/*回圈在TRUE时成立*/ /*open_input_source开启一个装置,正确的设定好序列埠, 并回传回此档案叙述结构体*/ fd1=open_input_source(/dev/ttyS1);/*COM2*/ if(fd10)exit(0); fd2=open_input_source(/dev/ttyS2);/*COM3*/ if(fd20)exit(0); maxfd=MAX(fd1,fd2)+1;/*测试最大位元输入(fd)*/ /*输入回圈*/ while(loop) FD_SET(fd1,&readfs);/*测试输入源1*/ FD_SET(fd2,&readfs);/*测试输入源2*/ /*blockuntilinputbecomesavailable*/ select(maxfd,&readfs,NULL,NULL,NULL); if(FD_ISSET(fd1)/*如果输入源1有讯号*/ handle_input_from_source1(); if(FD_ISSET(fd2)/*如果输入源2有讯号*/ handle_input_from_source2(); 这个例程式在等待输入讯号出现前,不能确定它会停顿下来.如果你需要在输入时加入逾时功能,只需把select呼叫换成: intres; structtimevalTimeout; /*设定输入回圈的逾时值*/ Timeout.tv_usec=0;/*毫秒*/ Timeout.tv_sec=1;/*秒

温馨提示

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

评论

0/150

提交评论