久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

Linux下串口通信詳解(上)打開串口和串口初始化詳解

 surfboarder 2017-07-25

Linux下串口通信主要有下面幾個(gè)步驟

Linux串口通信流程

串口通信流程圖

下面我會(huì)一一介紹這幾個(gè)步驟,。

1.打開串口

代碼(串口為ttyUSB0)

  1. //打開串口  
  2. int open_port(void)  
  3. {  
  4.     int fd;  
  5.           
  6.     fd=open("/dev/ttyUSB0",O_RDWR | O_NOCTTY | O_NONBLOCK);//O_NONBLOCK設(shè)置為非阻塞模式,,在read時(shí)不會(huì)阻塞住,在讀的時(shí)候?qū)ead放在while循環(huán)中,,下一節(jié)篇文檔將詳細(xì)講解阻塞和非阻塞  
  7. //  printf("fd=%d\n",fd);  
  8.       
  9.     if(fd==-1)  
  10.     {  
  11.         perror("Can't Open SerialPort");  
  12.     }  
  13.       
  14.     return fd;  
  15. }  
打開串口時(shí)也可以多加一些內(nèi)容,,比如判斷串口為阻塞狀態(tài)、測(cè)試是否為終端設(shè)備等,,這些是必要的,,所以較上面的基本的打開串口的代碼,更加完整健壯一些的代碼流程如下所示:


打開串口較完整流程圖

代碼:

  1. /** 
  2.  * open port 
  3.  * @param  fd 
  4.  * @param  comport 想要打開的串口號(hào) 
  5.  * @return  返回-1為打開失敗 
  6.  */  
  7. int open_port(int fd,int comport)   
  8. {   
  9.     char *dev[]={"/dev/ttyUSB0","/dev/ttyS1","/dev/ttyS2"};  
  10.   
  11.     if (comport==1)//串口1   
  12.     {  
  13.         fd = open( "/dev/ttyUSB0", O_RDWR|O_NOCTTY|O_NDELAY);   
  14.         if (-1 == fd)  
  15.         {   
  16.             perror("Can't Open Serial Port");   
  17.             return(-1);   
  18.         }   
  19.      }   
  20.      else if(comport==2)//串口2   
  21.      {       
  22.         fd = open( "/dev/ttyS1", O_RDWR|O_NOCTTY|O_NDELAY); //沒有設(shè)置<span style="font-family: Arial, Helvetica, sans-serif;">O_NONBLOCK非阻塞模式,,也可以設(shè)置為非阻塞模式,,兩個(gè)模式在下一篇博客中具體說明</span>  
  23.   
  24.         if (-1 == fd)  
  25.         {   
  26.             perror("Can't Open Serial Port");   
  27.             return(-1);   
  28.         }   
  29.      }   
  30.      else if (comport==3)//串口3   
  31.      {   
  32.         fd = open( "/dev/ttyS2", O_RDWR|O_NOCTTY|O_NDELAY);   
  33.         if (-1 == fd)  
  34.         {   
  35.             perror("Can't Open Serial Port");   
  36.             return(-1);   
  37.         }   
  38.      }   
  39.      /*恢復(fù)串口為阻塞狀態(tài)*/   
  40.      if(fcntl(fd, F_SETFL, 0)<0)   
  41.             printf("fcntl failed!\n");   
  42.      else   
  43.         printf("fcntl=%d\n",fcntl(fd, F_SETFL,0));   
  44.      /*測(cè)試是否為終端設(shè)備*/   
  45.      if(isatty(STDIN_FILENO)==0)   
  46.         printf("standard input is not a terminal device\n");   
  47.      else   
  48.         printf("isatty success!\n");   
  49.      printf("fd-open=%d\n",fd);   
  50.      return fd;   
  51. }  

關(guān)鍵函數(shù)解釋:

open

功能描述:用于打開或創(chuàng)建文件,成功則返回文件描述符,,否則返回-1,,open返回的文件描述符一定是最小的未被使用的描述符

  1. #include<fcntl.h>  
  2. int open(const char *pathname, int oflag, ... );  
參數(shù)解釋:

pathname:文件路徑名,串口在linux中被看做是一個(gè)文件

oflag:一些文件模式選擇,,有如下幾個(gè)參數(shù)可以設(shè)置

  • O_RDONLY只讀模式
  • O_WRONLY只寫模式
  • O_RDWR讀寫模式
上面三個(gè)參數(shù)在設(shè)置的時(shí)候必須選擇其中一個(gè)?。?!下面的是可選的

  • O_APPEND每次寫操作都寫入文件的末尾
  • O_CREAT如果指定文件不存在,,則創(chuàng)建這個(gè)文件
  • O_EXCL如果要?jiǎng)?chuàng)建的文件已存在,則返回 -1,,并且修改 errno 的值
  • O_TRUNC如果文件存在,,并且以只寫/讀寫方式打開,則清空文件全部內(nèi)容
  • O_NOCTTY如果路徑名指向終端設(shè)備,,不要把這個(gè)設(shè)備用作控制終端,。
  • O_NONBLOCK如果路徑名指向 FIFO/塊文件/字符文件,則把文件的打開和后繼 I/O設(shè)置為非阻塞模式(nonblocking mode)

下面三個(gè)常量同樣是選用的,,他們用于同步輸入輸出

  • O_DSYNC等待物理 I/O 結(jié)束后再 write,。在不影響讀取新寫入的數(shù)據(jù)的前提下,,不等待文件屬性更新,。
  • O_RSYNC讀(read)等待所有寫入同一區(qū)域的寫操作完成后再進(jìn)行
  • O_SYNC等待物理 I/O 結(jié)束后再 write,包括更新文件屬性的 I/O
對(duì)于串口的打開操作,,必須使用O_NOCTTY參數(shù),,它表示打開的是一個(gè)終端設(shè)備,程序不會(huì)成為該端口的控制終端。如果不使用此標(biāo)志,,任務(wù)的一個(gè)輸入(比如鍵盤終止信號(hào)等)都會(huì)影響進(jìn)程,。

O_NDELAY表示不關(guān)心DCD信號(hào)所處的狀態(tài)(端口的另一端是否激活或者停止)。

fcntl

功能描述:根據(jù)文件描述詞來操作文件的特性,,返回-1代表出錯(cuò)

  1. #include<unistd.h>  
  2. #include<fcntl.h>  
  3. int fcntl(int fd,int cmd);  
  4. int fcntl(int fd,int cmd,long arg);  
  5. int fcntl(int fd,int cmd,struct flock *lock);  
參數(shù)說明:

  • fd:文件描述符
  • cmd:命令參數(shù)
fcntl函數(shù)有5種功能: 
1. 復(fù)制一個(gè)現(xiàn)有的描述符(cmd=F_DUPFD). 
2. 獲得/設(shè)置文件描述符標(biāo)記(cmd=F_GETFD或F_SETFD). 
3. 獲得/設(shè)置文件狀態(tài)標(biāo)記(cmd=F_GETFL或F_SETFL). 
4. 獲得/設(shè)置異步I/O所有權(quán)(cmd=F_GETOWN或F_SETOWN). 
5. 獲得/設(shè)置記錄鎖(cmd=F_GETLK , F_SETLK或F_SETLKW).

isatty
函數(shù)功能,,實(shí)現(xiàn)只使用了一個(gè)終端專用的函數(shù)tcgetattr(如果成功之星,它不改變?nèi)魏螙|西),,并取其返回值,。若為終端設(shè)備返回1,否則返回0,。詳情見http://blog.csdn.net/wangjingyu00711/article/details/41693155

2.串口的初始化

串口初始化工作需要做以下工作:
  1. 設(shè)置波特率
  2. 設(shè)置數(shù)據(jù)流控制
  3. 設(shè)置幀的格式(即數(shù)據(jù)位個(gè)數(shù),,停止位,校驗(yàn)位)
串口初始化
串口初始化
代碼:
  1. int set_opt(int fd,int nSpeed, int nBits, char nEvent, int nStop)   
  2. {   
  3.      struct termios newtio,oldtio;   
  4. /*保存測(cè)試現(xiàn)有串口參數(shù)設(shè)置,,在這里如果串口號(hào)等出錯(cuò),,會(huì)有相關(guān)的出錯(cuò)信息*/   
  5.      if  ( tcgetattr( fd,&oldtio)  !=  0) {    
  6.       perror("SetupSerial 1");  
  7.     printf("tcgetattr( fd,&oldtio) -> %d\n",tcgetattr( fd,&oldtio));   
  8.       return -1;   
  9.      }   
  10.      bzero( &newtio, sizeof( newtio ) );   
  11. /*步驟一,設(shè)置字符大小*/   
  12.      newtio.c_cflag  |=  CLOCAL | CREAD;    
  13.      newtio.c_cflag &= ~CSIZE;    
  14. /*設(shè)置停止位*/   
  15.      switch( nBits )   
  16.      {   
  17.      case 7:   
  18.       newtio.c_cflag |= CS7;   
  19.       break;   
  20.      case 8:   
  21.       newtio.c_cflag |= CS8;   
  22.       break;   
  23.      }   
  24. /*設(shè)置奇偶校驗(yàn)位*/   
  25.      switch( nEvent )   
  26.      {   
  27.      case 'o':  
  28.      case 'O': //奇數(shù)   
  29.       newtio.c_cflag |= PARENB;   
  30.       newtio.c_cflag |= PARODD;   
  31.       newtio.c_iflag |= (INPCK | ISTRIP);   
  32.       break;   
  33.      case 'e':  
  34.      case 'E': //偶數(shù)   
  35.       newtio.c_iflag |= (INPCK | ISTRIP);   
  36.       newtio.c_cflag |= PARENB;   
  37.       newtio.c_cflag &= ~PARODD;   
  38.       break;  
  39.      case 'n':  
  40.      case 'N':  //無奇偶校驗(yàn)位   
  41.       newtio.c_cflag &= ~PARENB;   
  42.       break;  
  43.      default:  
  44.       break;  
  45.      }   
  46.      /*設(shè)置波特率*/   
  47. switch( nSpeed )   
  48.      {   
  49.      case 2400:   
  50.       cfsetispeed(&newtio, B2400);   
  51.       cfsetospeed(&newtio, B2400);   
  52.       break;   
  53.      case 4800:   
  54.       cfsetispeed(&newtio, B4800);   
  55.       cfsetospeed(&newtio, B4800);   
  56.       break;   
  57.      case 9600:   
  58.       cfsetispeed(&newtio, B9600);   
  59.       cfsetospeed(&newtio, B9600);   
  60.       break;   
  61.      case 115200:   
  62.       cfsetispeed(&newtio, B115200);   
  63.       cfsetospeed(&newtio, B115200);   
  64.       break;   
  65.      case 460800:   
  66.       cfsetispeed(&newtio, B460800);   
  67.       cfsetospeed(&newtio, B460800);   
  68.       break;   
  69.      default:   
  70.       cfsetispeed(&newtio, B9600);   
  71.       cfsetospeed(&newtio, B9600);   
  72.      break;   
  73.      }   
  74. /*設(shè)置停止位*/   
  75.      if( nStop == 1 )   
  76.       newtio.c_cflag &=  ~CSTOPB;   
  77.      else if ( nStop == 2 )   
  78.       newtio.c_cflag |=  CSTOPB;   
  79. /*設(shè)置等待時(shí)間和最小接收字符*/   
  80.      newtio.c_cc[VTIME]  = 0;   
  81.      newtio.c_cc[VMIN] = 0;   
  82. /*處理未接收字符*/   
  83.      tcflush(fd,TCIFLUSH);   
  84. /*激活新配置*/   
  85. if((tcsetattr(fd,TCSANOW,&newtio))!=0)   
  86.      {   
  87.       perror("com set error");   
  88.       return -1;   
  89.      }   
  90.      printf("set done!\n");   
  91.      return 0;   
  92. }   
講解這片代碼之前,,我們要先研究一下termios的數(shù)據(jù)結(jié)構(gòu),。最小的termios結(jié)構(gòu)的典型定義如下:
  1. struct termios  
  2. {  
  3.            tcflag_t c_iflag;  
  4.            tcflag_t c_oflag;  
  5.            tcflag_t c_cflag;  
  6.            tcflag_t c_lflag;  
  7.            cc_t           c_cc[NCCS];  
  8. };  
上面五個(gè)結(jié)構(gòu)成員名稱分別代表:
  • c_iflag:輸入模式
  • c_oflag:輸出模式
  • c_cflag:控制模式
  • c_lflag:本地模式
  • c_cc[NCCS]:特殊控制模式
五種模式的參數(shù)說明見博客http://blog.csdn.net/querdaizhi/article/details/7436722
tcgetattr可以初始化一個(gè)終端對(duì)應(yīng)的termios結(jié)構(gòu),tcgetattr函數(shù)原型如下:
  1. #include<termios.h>    
  2. int tcgetattr(int fd, struct termios *termios_p);   
這個(gè)函數(shù)調(diào)用把低昂前終端接口變量的值寫入termios_p參數(shù)指向的結(jié)構(gòu),。如果這些值其后被修改了,,可以通過調(diào)用函數(shù)tcsetattr來重新配置。
tcsetattr函數(shù)原型如下:
  1. #include<termios.h>    
  2. int tcsetattr(int fd , int actions , const struct termios *termios_h);    
參數(shù)actions控制修改方式,,共有三種修改方式,,如下所示:
  1. TCSANOW:立刻對(duì)值進(jìn)行修改
  2. TCSADRAIN:等當(dāng)前的輸出完成后再對(duì)值進(jìn)行修改
  3. TCSAFLUSH:等當(dāng)前的輸出完成之后,再對(duì)值進(jìn)行修改,,但丟棄還未從read調(diào)用返回的當(dāng)前的可用的任何輸入,。
在我們的代碼中,我們?cè)O(shè)置為NOW立即對(duì)值進(jìn)行修改,。
tcflush用于清空中端為完成的輸入/輸出請(qǐng)求及數(shù)據(jù),,它的函數(shù)原型如下:
  1. int tcflush(int fd, int queue_selector);  
其中queue_selector時(shí)控制tcflush的操作,取值可以為如下參數(shù)中的一個(gè):TCIFLUSH清楚正收到的數(shù)據(jù),,且不會(huì)讀出來,;TCOFLUSH清楚正寫入的數(shù)據(jù),且不會(huì)發(fā)送至終端,;TCIOFLUSH清除所有正在發(fā)送的I/O數(shù)據(jù),。
再看我們的代碼,我們修改字符大小的代碼為
  1. newtio.c_cflag  |=  CLOCAL | CREAD;    
  2. newtio.c_cflag &= ~CSIZE;    
c_cflag代表控制模式
  • CLOCAL含義為忽略所有調(diào)制解調(diào)器的狀態(tài)行,,這個(gè)目的是為了保證程序不會(huì)占用串口,。
  • CREAD代表啟用字符接收器,,目的是是的能夠從串口中讀取輸入的數(shù)據(jù)。
  • CS5/6/7/8表示發(fā)送或接收字符時(shí)使用5/6/7/8比特,。
  • CSTOPB表示每個(gè)字符使用兩位停止位,。
  • HUPCL表示關(guān)閉時(shí)掛斷調(diào)制解調(diào)器。
  • PARENB:啟用奇偶校驗(yàn)碼的生成和檢測(cè)功能,。
  • PARODD:只使用奇校驗(yàn)而不使用偶校驗(yàn),。
c_iflag代表輸入模式

  • BRKINT:當(dāng)在輸入行中檢測(cè)到一個(gè)終止?fàn)顟B(tài)時(shí),產(chǎn)生一個(gè)中斷,。
  • TGNBRK:忽略輸入行中的終止?fàn)顟B(tài),。
  • TCRNL:將接受到的回車符轉(zhuǎn)換為新行符。
  • TGNCR:忽略接受到的新行符,。
  • INLCR:將接受到的新行符轉(zhuǎn)換為回車符,。
  • IGNPAR:忽略奇偶校檢錯(cuò)誤的字符。
  • INPCK:對(duì)接收到的字符執(zhí)行奇偶校檢,。
  • PARMRK:對(duì)奇偶校檢錯(cuò)誤作出標(biāo)記,。
  • ISTRIP:將所有接收的字符裁減為7比特。
  • IXOFF:對(duì)輸入啟用軟件流控,。
  • IXON:對(duì)輸出啟用軟件流控,。
c_cc特殊的控制字符

標(biāo)準(zhǔn)模式和非標(biāo)準(zhǔn)模式下,c_cc數(shù)組的下標(biāo)有不同的值:

標(biāo)準(zhǔn)模式:

  • VEOF:EOF字符
  • VEOL:EOF字符
  • VERASE:ERASE字符
  • VINTR:INTR字符
  • VKILL:KILL字符
  • VQUIT:QUIT字符
  • VSTART:START字符 
  • VSTOP:STOP字符

非標(biāo)準(zhǔn)模式:

  • VINTR:INTR字符
  • VMIN:MIN值
  • VQUIT:QUIT字符
  • VSUSP:SUSP字符
  • VTIME:TIME值
  • VSTART:START字符 
  • VSTOP:STOP字符

cfsetispeed和cfsetospeed用來設(shè)置輸入輸出的波特率,函數(shù)模型如下:

  1. int cfsetispeed(struct termios *termptr, speed_t speed);  
  2. int cfsetospeed(struct termios *termptr, speed_t speed);  
參數(shù)說明:

  • struct termios *termptr:指向termios結(jié)構(gòu)的指針
  • speed_t speed:需要設(shè)置的波特率
  • 返回值:成功返回0,,否則返回-1

這樣,,所有的初始化操作我們就完成了。

下一篇文章我會(huì)記錄串口的讀寫及關(guān)閉操作的詳細(xì)步驟,。并且會(huì)把源代碼鏈接給出供大家參考,!

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點(diǎn),。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,,謹(jǐn)防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào),。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多