<track id="zxlr8"></track>
<u id="zxlr8"><sub id="zxlr8"></sub></u>
  • <track id="zxlr8"></track>
    1. <ins id="zxlr8"><table id="zxlr8"></table></ins><wbr id="zxlr8"><ins id="zxlr8"></ins></wbr>
      <wbr id="zxlr8"><table id="zxlr8"></table></wbr><u id="zxlr8"><bdo id="zxlr8"></bdo></u>
    2. <video id="zxlr8"></video>
      <rp id="zxlr8"><input id="zxlr8"></input></rp>
    3. <u id="zxlr8"></u>

      嵌入式Linux串口通訊的C++設計

       2010-4-28         

              嵌入式Linux主板EM9160提供了6個標準異步串口:ttyS1——ttyS6,其中ttyS4、ttyS5、ttyS6和GPIO的管腳復用,每個串口都有獨立的中斷模式,使得多個串口能夠同時實時進行數據收發。各個串口的驅動均已經包含在嵌入式Linux操作系統的內核中,EM9160在嵌入式Linux系統啟動完成時,各個串口已作為字符設備完成了注冊加載,用戶的應用程序可以以操作文件的方式對串口進行讀寫,從而實現數據收發的功能。

       

      串口編程接口函數

       

              在嵌入式Linux系統下,所有的設備文件都位于“/dev”目錄下,EM9160上6個串口所對應的設備名依次為“/dev/ttyS1”——“/dev/ttyS6”。

       

              嵌入式Linux下操作設備的方式和操作文件的方式是一樣的:調用open( )打開設備文件,再調用read( )、write( )對串口進行數據讀寫操作。這里需要注意的是打開串口除了設置普通的讀寫之外,還需要設置O_NOCTTY和O_NDLEAY,以避免該串口成為一個控制終端,因為如果作為一個終端有可能會影響到用戶的進程。打開的方式如下:

              sprintf( portname, '/dev/ttyS%d', PortNo ); //PortNo為串口端口號,從1開始
              m_fd = open( portname,O_RDWR | O_NOCTTY | O_NONBLOCK);

       

              作為串口通訊還需要一些通訊參數的配置,包括波特率、數據位、停止位、校驗位等參數。在實際的操作中,主要是通過設置struct termios結構體的各個成員值來實現,一般會用到的函數包括:

              tcgetattr( ) ;
              tcflush( );
              cfsetispeed( );
              cfsetospeed( );
              tcsetattr( );

       

              其中各個函數的具體使用方法這里就不一一介紹了,用戶可以參考嵌入式Linux應用程序開發的相關書籍,也可參看Step2_SerialTest中Serial.cpp模塊中set_port( )函數代碼。

       

      串口應用的C++設計

       

              Step2 _SerialTest是一個支持異步串口數據通訊的示例,該例程采用了面向對象的C++編程,把串口數據通訊作為一個對象進行封裝,用戶調用該對象提供的接口函數即可方便地完成串口通訊的操作。

       

              CSerial類介紹

              利用上一小節中介紹的串口API函數,封裝了一個支持異步讀寫的串口類CSerial,CSerial類中提供了4個公共函數、一個串口數據接收線程以及數據接收用到的數據Buffer。

       

              class CSerial
              {
              private:
                      //通訊線程標識符ID
                      pthread_t m_thread;
                      // 串口數據接收線程
                      static int ReceiveThreadFunc( void* lparam );
              public:
                      CSerial();
                      virtual ~CSerial();

                      int m_fd; // 已打開的串口文件描述符
                      int m_DatLen;
                      char DatBuf[1500];
                      int m_ExitThreadFlag;

                      // 按照指定的串口參數打開串口,并創建串口接收線程
                      int OpenPort( int PortNo, int baudrate, char databits, char stopbits, char parity );
                      // 關閉串口并釋放相關資源
                      int ClosePort( );
                      // 向串口寫數據
                      int WritePort( char* Buf, int len );
                      // 接收串口數據處理函數
                      virtual int PackagePro( char* Buf, int len );
              };

       

              OpenPort函數用于根據輸入串口參數打開串口,并創建串口數據接收線程。在嵌入式Linux環境中是通過函數pthread_create( )創建線程,通過函數pthread_exit( )退出線程。嵌入式Linux線程屬性存在有非分離(缺?。┖头蛛x兩種,在非分離情況下,當一個線程結束時,它所占用的系統資源并沒有被釋放,也就是沒有真正的終止;只有調用pthread_join( )函數返回時,創建的線程才能釋放自己占有的資源。在分離屬性下,一個線程結束時立即釋放所占用的系統資源?;谶@個原因,在我們提供的例程中通過相關函數將數據接收線程的屬性設置為分離屬性。如:

              // 設置線程綁定屬性
              res = pthread_attr_setscope( &attr, PTHREAD_SCOPE_SYSTEM );
              // 設置線程分離屬性
              res += pthread_attr_setdetachstate( &attr, THREAD_CREATE_DETACHED );

       

              ReceiveThreadFunc函數是串口數據接收和處理的主要核心代碼,在該函數中調用select( ),阻塞等待串口數據的到來。對于接收到的數據處理也是在該函數中實現,在本例程中處理為簡單的數據回發,用戶可結合實際的應用修改此處代碼,修改PackagePro( )函數即可。流程如下:

       

      串口通訊嵌入式Linux應用程序流程

       

              int CSerial::ReceiveThreadFunc(void* lparam)
              {
                      CSerial *pSer = (CSerial*)lparam; 

                      //定義讀事件集合
                      fd_set fdRead;
                      int ret;
                      struct timeval aTime;

                      while( 1 )
                      {
                              //收到退出事件,結束線程
                              if( pSer->m_ExitThreadFlag )
                              {
                                      break;
                              }
                              FD_ZERO(&fdRead);
                              FD_SET(pSer->m_fd,&fdRead);
                              aTime.tv_sec = 0;
                              aTime.tv_usec = 300000;
                              ret = select( pSer->m_fd+1,&fdRead,NULL,NULL,&aTime );
                              if (ret < 0 )
                              {
                                      //關閉串口
                                      pSer->ClosePort( ); 
                                      break;
                              } 
                              if (ret > 0)
                              {
                                      //判斷是否讀事件
                                      if (FD_ISSET(pSer->m_fd,&fdRead))
                                      {
                                              //data available, so get it!
                                              pSer->m_DatLen = read( pSer->m_fd, pSer->DatBuf, 1500 );
                                              // 對接收的數據進行處理,這里為簡單的數據回發
                                              if( pSer->m_DatLen > 0 )
                                              { 
                                                      pSer->PackagePro( pSer->DatBuf, pSer->m_DatLen);
                                              }
                                              // 處理完畢
                                      }
                              } 
                      } 
                      printf( 'ReceiveThreadFunc finished\n');
                      pthread_exit( NULL ); 
                      return 0; 
              }

       

              需要注意的是,select( )函數中的時間參數在嵌入式Linux中每次都需要重新賦值,否則會自動歸0。

       

              CSerial類的實現代碼請參見Serial.CPP文件。

       

              CSerial類的調用

              CSerial類的具體使用也比較簡單,主要是對于類中定義的4個公共函數的調用,以下為 Step2_SerialTest.cpp中相關代碼。

       

              class CSerial m_Serial;
              int main( int argc,char* argv[] )
              { 
                      int i1;
                      int portno, baudRate;
                      char cmdline[256];

                      printf( 'Step2_SerialTest V1.0\n' ); 
                      // 解析命令行參數:串口號 波特率
                      if( argc > 1 ) strcpy( cmdline, argv[1] );
                      else portno = 1;
                      if( argc > 2 )
                      { 
                              strcat( cmdline, ' ' );
                              strcat( cmdline, argv[2] );
                              scanf( cmdline, '%d %d', &portno, &baudRate );
                      }
                      else 
                      {
                              baudRate = 115200;
                      }
                      printf( 'port:%d baudrate:%d\n', portno, baudRate);
                      //打開串口相應地啟動了串口數據接收線程
                   
         i1 = m_Serial.OpenPort( portno, baudRate, '8', '1', 'N');
                      if( i1<0 )
                      {
                              printf( 'serial open fail\n');
                              return -1;
                      }
                      //進入主循環,這里每隔1s輸出一個提示信息
                     
      for( i1=0; i1<10000;i1++)
                      {
                              sleep(1);
                              printf( '%d \n', i1+1);
                      }
                      m_Serial.ClosePort( );
                      return 0; 
              }

       

              從上面的代碼可以看出,程序的主循環只需要實現一些管理性的功能,在本例程中僅僅是每隔1s輸出一個提示信息,在實際的應用中,可以把一些定時查詢狀態的操作、看門狗的喂狗等操作放在主循環中,這樣充分利用了嵌入式Linux多任務的編程優勢,利用內核的任務調度機制,將各個應用功能模塊化,以便于程序的設計和管理。這里順便再提一下,在進行多個串口編程時,也可以利用本例程中的CSerial類為基類,根據應用需求派生多個CSerial派生類實例,每一個派生類只是重新實現虛函數PackagePro(…),這樣每個串口都具有一個獨立的串口數據處理線程,利用Linux內核的任務調度機制以實現多串口通訊功能。

      A毛看片免费观看视频视频在线播放,国产a片欧美一级毛 片在线观看,2019午夜75福利不卡片在线,久久精品国产99国产精,最近更新中文字幕免费,久久人人97超碰,中文字幕无码A片久久东京热 亚洲伊人成综合人影院,亚洲国产中文字幕在线视频,天天五月缴情在线观看,97国产在线看片免费人成视频,天干夜天天夜天干天,免费A级毛片高清视频,窝窝午夜色视频国产精品 92福利视频合集100午夜,人人天天夜夜曰曰狠狠狠,免费观看网站 亚洲自国产拍偷拍,国产免费888在线观看,久久天天躁狠狠躁夜夜躁2020,无羞耻肉动漫在线观看 欧美成人电影,日本不卡免费一区二区,老司机精品视频在线观看,快播影院在线观看,无遮挡又色又黄的免费视频,美女一黄色网站,成年无码AV片在线观看,亚洲AVAV天堂Av在线不卡 色就色欧美综合在线影院,亚洲欧美卡通另类丝袜美腿,老司机福利在线观看,夜夜爽8888免费视频,国内自拍99re久久,2018Av天堂在线视频精品观看,少妇无码精品12p 午夜天堂欧美成人在线视频,超碰91自拍国产自拍,激情综合色综合啪啪五月,男人的天堂在线视频,午夜理理伦A级毛片天天看,无码熟妇人妻AV在线偷拍,大量偷拍情侣自拍视频 精品国产自在现线拍在线,无码专区人妻系列日韩,色婷婷色综合缴情网站,猛男操的我高潮连连,国产片av国语在线观看手机版,久久人人97超碰精品,亚洲最大AV网站在线观看
      久久亚洲精品无码爱剪辑,亚洲欧美国产vr在线观,国产真实乱子伦精品视频,日韩精品一区二区中文免费在线观看,在线A亚洲V天堂网2018,免费观看欧美大片毛片不用播放器 日本极品高清不卡AV,亚洲AⅤ天堂AV在线电影猫咪,五月色婷婷综合狠狠爱,碰超79网站,印度女人牲交视频免费播放,va在线看国产免费,狠狠躁夜夜躁人人爽天天古典 免费 在线 av 日本,免费A片在线观看,一本道久在道最新2021,人妻无码不卡中文字幕系列,午夜爽爽爽男女免费观看HD,日本高清视频永久网站www,东京热人妻无码人av 人人插人人莫人人干在线,AV天堂久久天堂AV色综合,欧美A色爱综合网欧美V,亚洲图欧美日韩在线,亚洲中文字幕曰本毛片,中文字幕97超碰大香寡妇蕉,久爱在线 亚洲AV片不卡无码久久,亚洲人成免费观看视频在线,欧洲亚洲偷自拍第一页,av在线播放日韩亚洲欧,一日本道不卡高清A无码,97碰碰碰人妻无码视频,加勒比最新无码AV免费资源 国内精品自线在拍,日韩一区二区三不卡高清,伊人中文字幕无码专区视频在线播放网站,看全黄大色黄大片美女蓝光在线看,无码av高清毛片在线看,人人超人人超碰超国产 小草视频手机在线视频,免费黃色大片,偷欧洲亚洲另类图片AV天堂,久久国产乱子伦,国产乱子伦精品视频,日本高清色本在线视频观看,加勒比一本HEYZO高清视频 AV无码东京热亚洲男人的天堂,315电影网A级毛片,深夜A级毛片视频免费,亚洲日本VA午夜在线电影,日本无码免费不卡AV二区,在线看午夜福利片国产,亚洲中文字幕aⅴ天堂 无码刺激性A片,成上人色爱A∨综合网,午夜性影院在线观看视频播放,手机国产乱子伦精品视频,无码99久热只有精品视频在线,狠狠噜天天噜日日黑人亚洲,在线观看无码不卡 真实国产乱子伦对白视频不卡,国产成人亚洲精品,老司机亚洲精品影院无码,亚洲成av人片在线观看天堂无码,美国一级a片,狠狠狠的在啪线香蕉亚洲,AV男人的天堂在线观看第三区