首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > 编程 >

6 linux串口编程

2013-02-05 
六 linux串口编程一.结构体1.termiosstruct termios {tcflag_t c_iflag/* 输入模式标志 */tcflag_t c_ofl

六 linux串口编程

一.结构体

1.termios

struct termios {tcflag_t c_iflag;/* 输入模式标志 */tcflag_t c_oflag;/* 输出模式标志 */tcflag_t c_cflag;/* 控制模式标志 */tcflag_t c_lflag;/* 本地模式标志 */cc_t c_line;/* 线路规程 */cc_t c_cc[NCCS];/* 控制字符 */};

二.定义

1.类型定义

typedef unsigned charcc_t;typedef unsigned intspeed_t;typedef unsigned inttcflag_t;

2.c_cc

#define VINTR 0//中断 Ctrl-C#define VQUIT 1//退出 Ctrl-Z#define VERASE 2//擦除 空格BS#define VKILL 3//删行 Ctrl-U#define VEOF 4//文件结尾 Ctrl-D#define VTIME 5//等待时间#define VMIN 6//读取的最小字符数#define VSWTC 7//#define VSTART 8//软件流开始#define VSTOP 9//软件流停止#define VSUSP 10//#define VEOL 11//行结尾 回车CR#define VREPRINT 12//#define VDISCARD 13//#define VWERASE 14//#define VLNEXT 15//#define VEOL2 16//第二行结尾 进行LF

3.c_iflag

#define IGNBRK0000001//忽略任何中断条件#define BRKINT0000002//传送SIGINT,当检测到中断#define IGNPAR0000004//忽略校验错误#define PARMRK0000010//标记校验错误#define INPCK0000020//校验有效#define ISTRIP0000040//剥离校验位#define INLCR0000100//映射NL到CR#define IGNCR0000200//忽略CR#define ICRNL0000400//映射CR到NL#define IUCLC0001000//映射大写到小写#define IXON0002000//软件流控制输出作用#define IXANY0004000//允许任何字符再次启动流#define IXOFF0010000//软件流控制输入作用#define IMAXBEL0020000//在输入线上回显BEL过长#define IUTF80040000

4.c_oflag

#define OPOST0000001//输出后处理(不设置=行式输出)#define OLCUC0000002//映射小写到大写#define ONLCR0000004//映射NL到CR-NL#define OCRNL0000010//映射CR到NL#define ONOCR0000020//#define ONLRET0000040//NL实现CR功能#define OFILL0000100//对于延时用填充字符#define OFDEL0000200//填充字符DEL#define NLDLY0000400//在行之间,需要掩蔽延时#define NL00000000//NL没有延时#define NL10000400//在换行后,新的输出前延时100ms#define CRDLY0003000//回车到左边,需要掩蔽的延时#define  CR00000000//CR没有延时#define  CR10001000//CR后的延时,依赖于当前的列位置#define  CR20002000//CR后延时100ms#define  CR30003000//CR后延时150ms#define TABDLY0014000//TAB后需要延时#define  TAB00000000//TAB后没有延时#define  TAB10004000//TAB后的延时根据当前的列位置#define  TAB20010000//TAB后延时100ms#define  TAB30014000//TAB扩展为空格#define  XTABS0014000//#define BSDLY0020000//BS后需要延时掩蔽#define  BS00000000//BS后无延时#define  BS10020000//BS后延时50ms#define VTDLY0040000//VT后需要延时掩蔽#define  VT00000000//VT后无延时#define  VT10040000//VT后延时2秒#define FFDLY0100000//FF后需要延时掩蔽#define FF00000000//FF后无延时#define  FF10100000//FF后延时2秒

5.c_cflag

#define CBAUD0010017//波特率掩码#define  B00000000//挂起#define  B500000001//50 b/s#define  B750000002//75 b/s#define  B1100000003//110 b/s#define  B1340000004//134.5 b/s#define  B1500000005//150 b/s#define  B2000000006//200 b/s#define  B3000000007//300 b/s#define  B6000000010//600 b/s#define  B12000000011//1200 b/s#define  B18000000012//1800 b/s#define  B24000000013//2400 b/s#define  B48000000014//4800 b/s#define  B96000000015//9600 b/s#define  B192000000016//19200 b/s#define  B384000000017//38400 b/s#define EXTA B19200//外部时钟A#define EXTB B38400//外部时钟B#define CSIZE0000060//位数据位掩码#define CS50000000//5位数据位#define CS60000020//6位数据位#define CS70000040//7位数据位#define CS80000060//8位数据位#define CSTOPB0000100//2位停止位#define CREAD0000200//接收有效#define PARENB0000400//校验位有效#define PARODD0001000//奇偶校验#define HUPCL0002000//最后关闭后,挂起#define CLOCAL0004000//本地线-不 改变端口的"拥有者"#define CBAUDEX 0010000//#define BOTHER 0010000//#define B57600 0010001//57600 b/s#define B115200 0010002//115200 b/s#define B230400 0010003//230400 b/s#define B460800 0010004//460800 b/s#define B500000 0010005//500000 b/s#define B576000 0010006//576000 b/s#define B921600 0010007//921600 b/s#define  B1000000 0010010//1000000 b/s#define  B1152000 0010011//1152000 b/s#define  B1500000 0010012//1500000 b/s#define  B2000000 0010013//2000000 b/s#define  B2500000 0010014//2500000 b/s#define  B3000000 0010015//3000000 b/s#define  B3500000 0010016//3500000 b/s#define  B4000000 0010017//4000000 b/s#define CIBAUD002003600000//输入波特率#define CMSPAR  010000000000/* mark or space (stick) parity */#define CRTSCTS020000000000/* flow control */#define IBSHIFT   16

6.c_lflag

#define ISIG0000001//使SIGINTR,SIGSUSP,SIGDSUSP,SIGQUIT等信号作用#define ICANON0000002//设定规范canonical(或行式raw)#define XCASE0000004//map uppercase\lowercase(废除)#define ECHO0000010//回显输入字符#define ECHOE0000020//回显擦除字符 BS-SP-BS#define ECHOK0000040//在删除字符后,回显NL#define ECHONL0000100//回显NL#define NOFLSH0000200//不在中断后退出字符后刷新输入缓冲#define TOSTOP0000400//传送SIGTTOU信号作为背景#define ECHOCTL0001000//以^char方式回显控制字符和以~?方式显示删除字符#define ECHOPRT0002000//回显提示有删除字符#define ECHOKE0004000//BS-SP-BS整行,在有行删除时#define FLUSHO0010000//刷新输出#define PENDIN0040000//在下次读或输入时,将未决字符重打#define IEXTEN0100000#define EXTPROC0200000

 7.其他

/* tcflow() and TCXONC use these */#defineTCOOFF0#defineTCOON1#defineTCIOFF2#defineTCION3/* tcflush() and TCFLSH use these */#defineTCIFLUSH0#defineTCOFLUSH1#defineTCIOFLUSH2/* tcsetattr 使用到这些参数*/#defineTCSANOW0//立即改变,不等待数据结束#defineTCSADRAIN1//等待直到所有的都传完#defineTCSAFLUSH2//刷新输入输出缓冲,然后改变


 

三.API函数

1.基本操作

打开串口 O_NOCTTY表示不是系统终端,这样就不会受键盘Ctrl-C等操作影响

fd = open("/dev/ttyXXX", O_RDWR | O_NOCTTY | O_NDELAY);

write(unsigned int fd,const char __user * buf,size_t count)

fcntl(unsigned int fd,F_SETFL,0)

关闭串口

close(unsigned int fd)

2.其他

int tcgetattr(int fildes, struct termios *termios_p);//获取串口参数int tcsetattr(int fildes, int optional_actions,const struct termios *termios_p);//设置串口参数speed_t cfgetispeed(const struct termios *termios_p);//获取输入波特率int cfsetispeed(struct termios *termios_p, speed_t speed);//设置输入波特率speed_t cfgetospeed(const struct termios *termios_p);//获取输出波特率int cfsetospeed(struct termios *termios_p, speed_tspeed);//设置输出波特率int tcflow(int fildes, int action);//软件流控制int tcflush(int fildes, int queue_selector);//丢弃要写入引用的对象,但是尚未传输的数据,或者收到但是尚未读取的数据int tcdrain(int fildes);//等待直到所有写入int tcsendbreak(int fildes, int duration);//传送连续的0值比特流,持续一段时间


四.例子

网上找来个好的例子

/************************Copyright(c)******************************* **                       西安邮电学院 **                       graduate school **                       XNMS项目组 **                       WebSite :blog.csdn.net/tigerjb **------------------------------------------FileInfo------------------------------------------------------- ** File name:                 main.c ** Last modified Date:  2011-01-31 ** Last Version:              1.0 ** Descriptions:             **------------------------------------------------------------------ ** Created by:               冀博 ** Created date:            2011-01-31 ** Version:                            1.0 ** Descriptions:             The original version **------------------------------------------------------------------ ** Modified by: ** Modified date: ** Version: ** Descriptions: *******************************************************************/        //串口相关的头文件   #include<stdio.h>      /*标准输入输出定义*/   #include<stdlib.h>     /*标准函数库定义*/   #include<unistd.h>     /*Unix 标准函数定义*/   #include<sys/types.h>    #include<sys/stat.h>      #include<fcntl.h>      /*文件控制定义*/   #include<termios.h>    /*PPSIX 终端控制定义*/   #include<errno.h>      /*错误号定义*/   #include<string.h>      //宏定义   #define FALSE  -1   #define TRUE   0      /******************************************************************* * 名称:                  UART0_Open * 功能:                打开串口并返回串口设备文件描述 * 入口参数:        fd    :文件描述符     port :串口号(ttyS0,ttyS1,ttyS2) * 出口参数:        正确返回为1,错误返回为0 *******************************************************************/  int UART0_Open(int fd,char* port)  {  fd = open( port, O_RDWR|O_NOCTTY|O_NDELAY);  if(FALSE == fd){  perror("Can't Open Serial Port");  return(FALSE);  }  //恢复串口为阻塞状态                                  if(fcntl(fd, F_SETFL, 0) < 0){  printf("fcntl failed!\n");  return(FALSE);  }       else{  printf("fcntl=%d\n",fcntl(fd, F_SETFL,0));  }  //测试是否为终端设备       if(0 == isatty(STDIN_FILENO)){  printf("standard input is not a terminal device\n");  return(FALSE);  }  else{  printf("isatty success!\n");  }                printf("fd->open=%d\n",fd);  return fd;  }  /******************************************************************* * 名称:                UART0_Close * 功能:                关闭串口并返回串口设备文件描述 * 入口参数:        fd    :文件描述符     port :串口号(ttyS0,ttyS1,ttyS2) * 出口参数:        void *******************************************************************/     void UART0_Close(int fd)  {  close(fd);  }     /******************************************************************* * 名称:                UART0_Set * 功能:               设置串口数据位,停止位和效验位 * 入口参数:fd       串口文件描述符 * speed     串口速度 *        flow_ctrl 数据流控制 0不使用 1硬件流控制 2软件流控制*        databits   数据位   取值为 7 或者8 *        stopbits   停止位   取值为 1 或者2 *        parity     效验类型 取值为N,E,O,,S *出口参数:   正确返回为1,错误返回为0 *******************************************************************/  int UART0_Set(int fd,int speed,int flow_ctrl,int databits,int stopbits,int parity)  {  int   i;  int   status;  int   speed_arr[] = { B115200, B19200, B9600, B4800, B2400, B1200, B300};  int   name_arr[] = {115200,  19200,  9600,  4800,  2400,  1200,  300};      struct termios options;  /*tcgetattr(fd,&options)得到与fd指向对象的相关参数,并将其保存于options,该函数还可以测试配置是否正确,该串口是否可用等。若调用成功,函数返回值为0,若调用失败,函数返回值为1*/  if (tcgetattr( fd,&options)!= 0){  perror("SetupSerial 1");      return(FALSE);   }          //设置串口输入波特率和输出波特率   for ( i= 0;  i < sizeof(speed_arr) / sizeof(int);  i++){  if(speed == name_arr[i]){               cfsetispeed(&options, speed_arr[i]);   cfsetospeed(&options, speed_arr[i]);    }  }                //修改控制模式,保证程序不会占用串口   options.c_cflag |= CLOCAL;      //修改控制模式,使得能够从串口中读取输入数据   options.c_cflag |= CREAD;          //设置数据流控制   switch(flow_ctrl)      {      case 0://不使用流控制   options.c_cflag &= ~CRTSCTS;  break;             case 1://使用硬件流控制   options.c_cflag |= CRTSCTS;  break;  case 2://使用软件流控制   options.c_cflag |= IXON | IXOFF | IXANY;  break;      }      //设置数据位       //屏蔽其他标志位       options.c_cflag &= ~CSIZE;      switch (databits)      {    case 5:  options.c_cflag |= CS5;  break;  case 6:  options.c_cflag |= CS6;  break;  case 7:      options.c_cflag |= CS7;  break;  case 8:      options.c_cflag |= CS8;  break;    default:     fprintf(stderr,"Unsupported data size\n");  return (FALSE);       }      //设置校验位       switch (parity)      {    case 'n':  case 'N': //无奇偶校验位。   options.c_cflag &= ~PARENB;   options.c_iflag &= ~INPCK;      break;   case 'o':    case 'O'://设置为奇校验       options.c_cflag |= (PARODD | PARENB);   options.c_iflag |= INPCK;               break;   case 'e':   case 'E'://设置为偶校验     options.c_cflag |= PARENB;         options.c_cflag &= ~PARODD;         options.c_iflag |= INPCK;        break;  case 's':  case 'S': //设置为空格    options.c_cflag &= ~PARENB;  options.c_cflag &= ~CSTOPB;  break;   default:    fprintf(stderr,"Unsupported parity\n");      return (FALSE);       }       // 设置停止位    switch (stopbits)      {    case 1:     options.c_cflag &= ~CSTOPB; break;   case 2:     options.c_cflag |= CSTOPB; break;  default:     fprintf(stderr,"Unsupported stop bits\n");   return (FALSE);      }       //修改输出模式,原始数据输出   options.c_oflag &= ~OPOST;      options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);//我加的   //options.c_lflag &= ~(ISIG | ICANON);            //设置等待时间和最小接收字符       options.c_cc[VTIME] = 1; /* 读取一个字符等待1*(1/10)s */        options.c_cc[VMIN] = 1; /* 读取字符的最少个数为1 */           //如果发生数据溢出,接收数据,但是不再读取 刷新收到的数据但是不读       tcflush(fd,TCIFLUSH);           //激活配置 (将修改后的termios数据设置到串口中)       if (tcsetattr(fd,TCSANOW,&options) != 0){  perror("com set error!\n");    return (FALSE);   }      return (TRUE);   }  /******************************************************************* * 名称:UART0_Init() * 功能:串口初始化 * 入口参数:fd:  文件描述符    *speed  :  串口速度 *flow_ctrl  数据流控制 *databits   数据位   取值为 7 或者8 *stopbits   停止位   取值为 1 或者2 *parity     效验类型 取值为N,E,O,,S *                       * 出口参数:        正确返回为1,错误返回为0 *******************************************************************/  int UART0_Init(int fd, int speed,int flow_ctrl,int databits,int stopbits,int parity)  {      int err;      //设置串口数据帧格式       if (UART0_Set(fd,19200,0,8,1,'N') == FALSE){                                                           return FALSE;  }      else{  return  TRUE;  }  }     /******************************************************************* * 名称:UART0_Recv * 功能:接收串口数据 * 入口参数:fd:文件描述符     *rcv_buf:接收串口中数据存入rcv_buf缓冲区中 *data_len:一帧数据的长度 * 出口参数:正确返回为1,错误返回为0 *******************************************************************/  int UART0_Recv(int fd, char *rcv_buf,int data_len)  {      int len,fs_sel;      fd_set fs_read;           struct timeval time;           FD_ZERO(&fs_read);      FD_SET(fd,&fs_read);           time.tv_sec = 10;      time.tv_usec = 0;           //使用select实现串口的多路通信       fs_sel = select(fd+1,&fs_read,NULL,NULL,&time);      if(fs_sel){  len = read(fd,rcv_buf,data_len);  printf("I am right!(version1.2) len = %d fs_sel = %d\n",len,fs_sel);  return len;  }      else{  printf("Sorry,I am wrong!");  return FALSE;  }       }  /******************************************************************** * 名称:UART0_Send * 功能:发送数据 * 入口参数:fd:文件描述符     *send_buf :存放串口发送数据 *data_len :一帧数据的个数 * 出口参数:正确返回为1,错误返回为0 *******************************************************************/  int UART0_Send(int fd, char *send_buf,int data_len)  {      int len = 0;           len = write(fd,send_buf,data_len);      if (len == data_len )                {                       return len;                }           else             {                                   tcflush(fd,TCOFLUSH);                  return FALSE;          }       }     int main(int argc, char **argv)  {      int fd;//文件描述符       int err;//返回调用函数的状态       int len;                              int i;      char rcv_buf[100];             char send_buf[20]="tiger john";      if(argc != 3){  printf("Usage: %s /dev/ttySn 0(send data)/1 (receive data) \n",argv[0]);  return FALSE;  }      fd = UART0_Open(fd,argv[1]); //打开串口,返回文件描述符       do{  err = UART0_Init(fd,19200,0,8,1,'N');  printf("Set Port Exactly!\n");  }while(FALSE == err || FALSE == fd);           if(0 == strcmp(argv[2],"0")){  for(i = 0;i < 10;i++){  len = UART0_Send(fd,send_buf,10);  if(len > 0)  printf(" %d send data successful\n",i);  else  printf("send data failed!\n");  sleep(2);  }  UART0_Close(fd);               }      else{  while (1){    //循环读取数据 len = UART0_Recv(fd, rcv_buf,9);  if(len > 0){  rcv_buf[len] = '\0';  printf("receive data is %s\n",rcv_buf);  printf("len = %d\n",len);  }  else{  printf("cannot receive data\n");  }  sleep(2);  }              UART0_Close(fd);   }  }      /*********************************************************************                            End Of File                          *********************************************************************/  


 

必须的表

 6 linux串口编程

热点排行