1. gzyueqian
      18529173453
      首頁 > 新聞中心 > > 正文

      Linux 環境下串口通信的編程

      更新時間: 2007-05-15 10:29:59來源: 粵嵌教育瀏覽量:1305


        串口設備無論是在工控領域,還是在嵌入式設備領域,應用都非常廣泛。而串口編程也就顯得必不可少。偶然的一次機會,需要使用串口,而且操作系統還要求是Linux,因此,趁著這次機會,綜合別人的代碼,進行了一次整理和封裝。

        具體的封裝格式為C代碼,這樣做是為了很好的移植性,使它可以在C和C++環境下,都可以編譯和使用。代碼的頭文件如下:

      ///////////////////////////////////////////////////////////////////////////////
      //filename:stty.h
      #ifndef __STTY_H__
      #define __STTY_H__

      #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 <pthread.h>
      //
      // 串口設備信息結構
      typedef struct tty_info_t
      {
      int fd; // 串口設備ID
      pthread_mutex_t mt; // 線程同步互斥對象
      char name[24]; // 串口設備名稱,例:"/dev/ttyS0"
      struct termios ntm; // 新的串口設備選項
      struct termios otm; // 舊的串口設備選項
      } TTY_INFO;
      //
      // 串口操作函數
      TTY_INFO *readyTTY(int id);
      int setTTYSpeed(TTY_INFO *ptty, int speed);
      int setTTYParity(TTY_INFO *ptty,int databits,int parity,int stopbits);
      int cleanTTY(TTY_INFO *ptty);
      int sendnTTY(TTY_INFO *ptty,char *pbuf,int size);
      int recvnTTY(TTY_INFO *ptty,char *pbuf,int size);
      int lockTTY(TTY_INFO *ptty);
      int unlockTTY(TTY_INFO *ptty);

      #endif


      從頭文件中的函數定義不難看出,函數的功能,使用過程如下:
      (1) 打開串口設備,調用函數setTTYSpeed();
      (2) 設置串口讀寫的波特率,調用函數setTTYSpeed();
      (3) 設置串口的屬性,包括停止位、校驗位、數據位等,調用函數setTTYParity();
      (4) 向串口寫入數據,調用函數sendnTTY();
      (5) 從串口讀出數據,調用函數recvnTTY();
      (6) 操作完成后,需要調用函數cleanTTY()來釋放申請的串口信息接口;
      其中,lockTTY()和unlockTTY()是為了能夠在多線程中使用。在讀寫操作的前后,需要鎖定和釋放串口資源。
      具體的使用方法,在代碼實現的原文件中,main()函數中進行了演示。下面就是源代碼文件:

      ////////////////////////////////////////////////////////////////////////////////
      //stty.c

      #include <stdio.h>
      #include <sys/ioctl.h>
      #include "stty.h"

      ///////////////////////////////////////////////////////////////////////////////
      // 初始化串口設備并進行原有設置的保存
      TTY_INFO *readyTTY(int id)
      {
      TTY_INFO *ptty;

      ptty = (TTY_INFO *)malloc(sizeof(TTY_INFO));
      if(ptty == NULL)
      return NULL;
      memset(ptty,0,sizeof(TTY_INFO));
      pthread_mutex_init(&ptty->mt,NULL);
      sprintf(ptty->name,"/dev/ttyS%d",id);
      //
      // 打開并且設置串口
      ptty->fd = open(ptty->name, O_RDWR | O_NOCTTY |O_NDELAY);
      if (ptty->fd <0)
      {
      free(ptty);
      return NULL;
      }
      //
      // 取得并且保存原來的設置
      tcgetattr(ptty->fd,&ptty->otm);
      return ptty;
      }

      ///////////////////////////////////////////////////////////////////////////////
      // 清理串口設備資源
      int cleanTTY(TTY_INFO *ptty)
      {
      //
      // 關閉打開的串口設備
      if(ptty->fd>0)
      {
      tcsetattr(ptty->fd,TCSANOW,&ptty->otm);
      close(ptty->fd);
      ptty->fd = -1;
      free(ptty);
      ptty = NULL;
      }

      return 0;
      }


      ///////////////////////////////////////////////////////////////////////////////
      // 設置串口通信速率
      // ptty 參數類型(TTY_INFO *),已經初始化的串口設備信息結構指針
      // speed 參數類型(int),用來設置串口的波特率
      // return 返回值類型(int),函數執行成功返回零值,否則返回大于零的值
      ///////////////////////////////////////////////////////////////////////////////
      int setTTYSpeed(TTY_INFO *ptty, int speed)
      {
      int i;
      //
      // 進行新的串口設置,數據位為8位
      bzero(&ptty->ntm, sizeof(ptty->ntm));
      tcgetattr(ptty->fd,&ptty->ntm);
      ptty->ntm.c_cflag = /*CS8 |*/ CLOCAL | CREAD;

      switch(speed)
      {
      case 300:
      ptty->ntm.c_cflag |= B300;
      break;
      case 1200:
      ptty->ntm.c_cflag |= B1200;
      break;
      case 2400:
      ptty->ntm.c_cflag |= B2400;
      break;
      case 4800:
      ptty->ntm.c_cflag |= B4800;
      break;
      case 9600:
      ptty->ntm.c_cflag |= B9600;
      break;
      case 19200:
      ptty->ntm.c_cflag |= B19200;
      break;
      case 38400:
      ptty->ntm.c_cflag |= B38400;
      break;
      case 115200:
      ptty->ntm.c_cflag |= B115200;
      break;
      }
      ptty->ntm.c_iflag = IGNPAR;
      ptty->ntm.c_oflag = 0;
      //
      //
      tcflush(ptty->fd, TCIFLUSH);
      tcsetattr(ptty->fd,TCSANOW,&ptty->ntm);
      //
      //
      return 0;
      }
      // 設置串口數據位,停止位和效驗位
      // ptty 參數類型(TTY_INFO *),已經初始化的串口設備信息結構指針
      // databits 參數類型(int), 數據位,取值為7或者8
      // stopbits 參數類型(int),停止位,取值為1或者2
      // parity 參數類型(int),效驗類型 取值為N,E,O,,S
      // return 返回值類型(int),函數執行成功返回零值,否則返回大于零的值
      ///////////////////////////////////////////////////////////////////////////////
      int setTTYParity(TTY_INFO *ptty,int databits,int parity,int stopbits)
      {
      //
      // 取得串口設置
      if( tcgetattr(ptty->fd,&ptty->ntm) != 0)
      {
      printf("SetupSerial [%s]\n",ptty->name);
      return 1;
      }

      bzero(&ptty->ntm, sizeof(ptty->ntm));
      ptty->ntm.c_cflag = CS8 | CLOCAL | CREAD;
      ptty->ntm.c_iflag = IGNPAR;
      ptty->ntm.c_oflag = 0;
      //
      // 設置串口的各種參數
      ptty->ntm.c_cflag &= ~CSIZE;
      switch (databits)
      { //設置數據位數
      case 7:
      ptty->ntm.c_cflag |= CS7;
      break;
      case 8:
      ptty->ntm.c_cflag |= CS8;
      break;
      default:
      printf("Unsupported data size\n");
      return 5;
      }
      //
      //
      switch (parity)
      { // 設置奇偶校驗位數
      case 'n':
      case 'N':
      ptty->ntm.c_cflag &= ~PARENB; /* Clear parity enable */
      ptty->ntm.c_iflag &= ~INPCK; /* Enable parity checking */
      break;
      case 'o':
      case 'O':
      ptty->ntm.c_cflag |= (PARODD|PARENB); /* 設置為奇效驗*/
      ptty->ntm.c_iflag |= INPCK; /* Disnable parity checking */
      break;
      case 'e':
      case 'E':
      ptty->ntm.c_cflag |= PARENB; /* Enable parity */
      ptty->ntm.c_cflag &= ~PARODD; /* 轉換為偶效驗*/
      ptty->ntm.c_iflag |= INPCK; /* Disnable parity checking */
      break;
      case 'S':
      case 's': /*as no parity*/
      ptty->ntm.c_cflag &= ~PARENB;
      ptty->ntm.c_cflag &= ~CSTOPB;
      break;
      default:
      printf("Unsupported parity\n");
      return 2;
      }
      //
      // 設置停止位
      switch (stopbits)
      {
      case 1:
      ptty->ntm.c_cflag &= ~CSTOPB;
      break;
      case 2:
      ptty->ntm.c_cflag |= CSTOPB;
      break;
      default:
      printf("Unsupported stop bits\n");
      return 3;
      }
      //
      //
      ptty->ntm.c_lflag = 0;
      ptty->ntm.c_cc[VTIME] = 0; // inter-character timer unused
      ptty->ntm.c_cc[VMIN] = 1; // blocking read until 1 chars received
      tcflush(ptty->fd, TCIFLUSH);
      if (tcsetattr(ptty->fd,TCSANOW,&ptty->ntm) != 0)
      {
      printf("SetupSerial \n");
      return 4;
      }

      return 0;
      }

      int recvnTTY(TTY_INFO *ptty,char *pbuf,int size)
      {
      int ret,left,bytes;

      left = size;

      while(left>0)
      {
      ret = 0;
      bytes = 0;

      pthread_mutex_lock(&ptty->mt);
      ioctl(ptty->fd, FIONREAD, &bytes);
      if(bytes>0)
      {
      ret = read(ptty->fd,pbuf,left);
      }
      pthread_mutex_unlock(&ptty->mt);
      if(ret >0)
      {
      left -= ret;
      pbuf += ret;
      }
      usleep(100);
      }

      return size - left;
      }

      int sendnTTY(TTY_INFO *ptty,char *pbuf,int size)
      {
      int ret,nleft;
      char *ptmp;

      ret = 0;
      nleft = size;
      ptmp = pbuf;

      while(nleft>0)
      {
      pthread_mutex_lock(&ptty->mt);
      ret = write(ptty->fd,ptmp,nleft);
      pthread_mutex_unlock(&ptty->mt);

      if(ret >0)
      {
      nleft -= ret;
      ptmp += ret;
      }
      //usleep(100);
      }

      return size - nleft;
      }

      int lockTTY(TTY_INFO *ptty)
      {
      if(ptty->fd < 0)
      {
      return 1;
      }

      return flock(ptty->fd,LOCK_EX);
      }
      int unlockTTY(TTY_INFO *ptty)
      {
      if(ptty->fd < 0)
      {
      return 1;
      }

      return flock(ptty->fd,LOCK_UN);
      }


      #ifdef LEAF_TTY_TEST
      ///////////////////////////////////////////////////////////////////////////////
      // 接口測試
      int main(int argc,char **argv)
      {
      TTY_INFO *ptty;
      int nbyte,idx;
      unsigned char cc[16];

      ptty = readyTTY(0);
      if(ptty == NULL)
      {
      printf("readyTTY(0) error\n");
      return 1;
      }
      //
      //
      lockTTY(ptty);
      if(setTTYSpeed(ptty,9600)>0)
      {
      printf("setTTYSpeed() error\n");
      return -1;
      }
      if(setTTYParity(ptty,8,'N',1)>0)
      {
      printf("setTTYParity() error\n");
      return -1;
      }
      //
      idx = 0;
      while(1)
      {
      cc[0] = 0xFA;
      sendnTTY(ptty,&cc[0],1);
      nbyte = recvnTTY(ptty,cc,1);
      printf("%d:%02X\n",idx++,cc[0]);
      }

      cleanTTY(ptty);

      }
      #endif

      免費預約試聽課

      亚洲另类欧美综合久久图片区_亚洲中文字幕日产无码2020_欧美日本一区二区三区桃色视频_亚洲AⅤ天堂一区二区三区

      
      

      1. 亚洲国产综合精品二区 | 午夜中文乱码福利 | 一伊香蕉久在播放线视频 | 亚洲国产精品激情一区二区 | 伊人亚洲综合中文字幕 | 亚洲欧美中文字幕图 |