Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1743353
  • 博文数量: 143
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 1462
  • 用 户 组: 普通用户
  • 注册时间: 2016-08-23 11:14
文章分类

全部博文(143)

文章存档

2022年(3)

2021年(13)

2020年(21)

2019年(8)

2018年(28)

2017年(7)

2016年(63)

我的朋友

分类: 嵌入式

2016-09-22 19:19:14

背景介绍:因项目需要在ICETEK OMAPL138开发板上实现:能通过uart脚本控制ICETEK OMAPL138的spi1口,来读写AD/DA器件的寄存器,类似于华为的qshell。很明显,首先需要在ICETEK OMAPL138上实现:接受串口字符串,以及解析字符串,发送字符串到串口等等功能的uart应用程序。
  而通常情况下,开发板自带的光盘中会有uart收发应用程序的例程,ICETEK OMAPL138开发板的uart收发应用程序路径:/usr/local/Omapl138kba/projects/examples/app/comtest/。但是,此例程和网上绝大部分例子一样代码看着不够清晰,所以本文想先从最最最简单的uart收发应用程序开始,介绍一下uart收发应用程序的实现步骤,再把网上常出现的优化后的代码也贴上来以供参考。
  参考代码选自作者bg2bkk的两篇文章:Linux串口编程 和 Linux系统串口接收数据编程
1. 最简单uart收发程序

点击(此处)折叠或打开

  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. #include<fcntl.h>
  4. #include<unistd.h>
  5. #include<errno.h>
  6. #include<termios.h>
  7. #include<sys/types.h>
  8. #include<sys/stat.h>
  9. int main()
  10. {
  11.     printf("COM1 test program\n");
  12.     int fd;
  13.     fd = open("/dev/ttyS2",O_RDWR | O_NDELAY);
  14.     if(fd == -1)
  15.     {
  16.         perror("serialport error\n");
  17.     }
  18.     else{
  19.         printf("open %s succesfully\n", ttyname(fd));
  20.     }

  21.     struct termios Opt;
  22.     int status;
  23.     
  24.     tcgetattr(fd, &Opt);
  25.     //set speed
  26.     cfsetispeed(&Opt, B115200);
  27.     cfsetospeed(&Opt, B115200);
  28.     //set databits
  29.     Opt.c_cflag &= ~CSIZE;
  30.     Opt.c_cflag |= CS8;
  31.     //set parity
  32.     Opt.c_cflag &= ~PARENB;
  33.     Opt.c_iflag &= ~INPCK;
  34.     //set stopbits
  35.     Opt.c_cflag &= ~CSTOPB;
  36.     tcsetattr(fd, TCSANOW, &Opt);
  37.     status = tcsetattr(fd, TCSANOW, &Opt);
  38.     if(status != 0)
  39.     {
  40.         perror("tcsetattr fd1");
  41.         return;
  42.     }

  43.     //write
  44.     char wrbuff[] = {'h', 'e', 'l', 'l', 'o', '5', 'a', '\n', 'a', 'a', '5', '5', '\0', 'w', 'o', 'r', 'l', 'd', '!'};
  45.     write(fd, wrbuff, sizeof(wrbuff));//the intervening '\0' will not be printed to UART.

  46.     //read
  47.     char rdbuff[512];
  48.     int rdlen;
  49.     while(1)
  50.     {
  51.         if((rdlen = read(fd, rdbuff, sizeof(rdbuff)))>0)//'\n' will also be received as 0x0a.
  52.         {
  53.             rdbuff[rdlen] = '\0';
  54.             printf("receive len:%d receice data:%s", rdlen, rdbuff);
  55.         }
  56.     }

  57.     close(fd);
  58.     return 0;
  59. }
  很明显,要对串口进行收发要经过以下几个步骤:
1.1 打开串口
  Linux与其他的关于设备编程的方法一样,串口编程也是通过操作其设备文件进行的。串口的设备文件是/dev/ttyS0或/dev/ttyS1等。因此要读写串口,我们首先要打开串口。
  需要注意的是,open设备文件时的参数:
O_RDWR:读写打开
O_NOCTTY:如果pathname指的是终端设备(tty),则不将此设备分配作为此进程的控制终端
O_NONELAY:如果pathname指的是一个FIFO、一个块特殊文件或一个字符特殊文件,则此选择项为此文件的本次打开操作和后续的I/O操作设置为非阻塞方式
  其中,O_NONELAY一定要使用,否则串口因一直被shell占用而不能被此应用程序使用。
1.2 使用tcgetattr函数与tcsetattr函数控制终端
  为了便于通过程序来获得和修改终端参数,Linux还提供了tcgetattr函数和tcsetattr函数。tcgetattr用于获取终端的相关参数,而tcsetattr函数用于设置终端参数

1.3 设置串口通信参数
  串口通信参数指的是波特率、数据位、奇偶校验位和停止位,这些参数保存在结构体termios中。
1.3.1 设置波特率
  先用tcgetattr获得termios中的相关参数,再用cfsetispeed和cfsetospeed设置termios中存储的输入/输出波特率最后用tcsetattr将termios中的参数重新设置下去。一般情况下,输入和输出波特率是相等的。
1.3.2 设置数据位、奇偶校验位和停止位
  先用tcgetattr获得termios中的相关参数,再通过修改termios中c_cflag成员来实现设置数据位、奇偶校验位和停止位,最后用tcsetattr将termios中的参数重新设置下去。

1.4 串口收发
  通过以上设置了串口的基本信息后,就可以用read和write读写串口数据,实现串口的收发功能。
2常见用的uart收发程序
  然而,我们常见的且也经常用的串口收发程序,是对设置串口通信参数做了函数封装,然后再循环调用read和write读写串口数据。
  另外,如果我们把这种循环read的方式称为循环读取数据,但这种方式会一直占用当前串口而不能在后台运行,所以我们另外再介绍两种方式:通过signal机制读取数据、通过select系统调用进行io多路切换实现异步读取串口数据,此两种方式都能用来后台读取数据,值得学习。后两种方式博主并未亲自验证,有兴趣的同学可以试试。
2.1 循环读取数据

点击(此处)折叠或打开

  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. #include<unistd.h>
  4. #include<sys/types.h>
  5. #include<sys/stat.h>
  6. #include<fcntl.h>
  7. #include<termios.h>
  8. #include<errno.h>

  9. #define FALSE -1
  10. #define TRUE 0

  11. int speed_arr[] = { B38400, B19200, B9600, B4800, B2400, B1200, B300,B38400, B19200, B9600, B4800, B2400, B1200, B300, };
  12. int name_arr[] = {38400, 19200, 9600, 4800, 2400, 1200, 300, 38400, 19200, 9600, 4800, 2400, 1200, 300, };
  13. void set_speed(int fd, int speed){
  14.   int i;
  15.   int status;
  16.   struct termios Opt;
  17.   tcgetattr(fd, &Opt);
  18.   for ( i= 0; i < sizeof(speed_arr) / sizeof(int); i++) {
  19.     if (speed == name_arr[i]) {
  20.       tcflush(fd, TCIOFLUSH);
  21.       cfsetispeed(&Opt, speed_arr[i]);
  22.       cfsetospeed(&Opt, speed_arr[i]);
  23.       status = tcsetattr(fd, TCSANOW, &Opt);
  24.       if (status != 0) {
  25.         perror("tcsetattr fd1");
  26.         return;
  27.       }
  28.       tcflush(fd,TCIOFLUSH);
  29.     }
  30.   }
  31. }

  32. int set_Parity(int fd,int databits,int stopbits,int parity)
  33. {
  34.     struct termios options;
  35.     if ( tcgetattr( fd,&options) != 0) {
  36.         perror("SetupSerial 1");
  37.         return(FALSE);
  38.     }
  39.     options.c_cflag &= ~CSIZE;
  40.     switch (databits)
  41.     {
  42.     case 7:        
  43.         options.c_cflag |= CS7;
  44.         break;
  45.     case 8:
  46.         options.c_cflag |= CS8;
  47.         break;
  48.     default:
  49.         fprintf(stderr,"Unsupported data size\n"); return (FALSE);
  50.     }
  51.     switch (parity)
  52.     {
  53.         case 'n':
  54.         case 'N':
  55.             options.c_cflag &= ~PARENB; /* Clear parity enable */
  56.             options.c_iflag &= ~INPCK; /* Enable parity checking */
  57.             break;
  58.         case 'o':
  59.         case 'O':
  60.             options.c_cflag |= (PARODD | PARENB);
  61.             options.c_iflag |= INPCK; /* Disnable parity checking */
  62.             break;
  63.         case 'e':
  64.         case 'E':
  65.             options.c_cflag |= PARENB; /* Enable parity */
  66.             options.c_cflag &= ~PARODD;
  67.             options.c_iflag |= INPCK; /* Disnable parity checking */
  68.             break;
  69.         case 'S':
  70.         case 's': /*as no parity*/
  71.          options.c_cflag &= ~PARENB;
  72.             options.c_cflag &= ~CSTOPB;break;
  73.         default:
  74.             fprintf(stderr,"Unsupported parity\n");
  75.             return (FALSE);
  76.         }
  77.     
  78.     switch (stopbits)
  79.     {
  80.         case 1:
  81.             options.c_cflag &= ~CSTOPB;
  82.             break;
  83.         case 2:
  84.             options.c_cflag |= CSTOPB;
  85.          break;
  86.         default:
  87.              fprintf(stderr,"Unsupported stop bits\n");
  88.              return (FALSE);
  89.     }
  90.     /* Set input parity option */
  91.     if (parity != 'n')
  92.         options.c_iflag |= INPCK;
  93.     tcflush(fd,TCIFLUSH);
  94.     options.c_cc[VTIME] = 150;
  95.     options.c_cc[VMIN] = 0; /* Update the options and do it NOW */
  96.     if (tcsetattr(fd,TCSANOW,&options) != 0)
  97.     {
  98.         perror("SetupSerial 3");
  99.         return (FALSE);
  100.     }
  101.     return (TRUE);
  102. }

  103. int main()
  104. {
  105.     printf("This program updates last time at %s %s\n",__TIME__,__DATE__);
  106.     printf("STDIO COM1\n");
  107.     int fd;
  108.     fd = open("/dev/ttyS0",O_RDWR | O_NDELAY);
  109.     if(fd == -1)
  110.     {
  111.         perror("serialport error\n");
  112.     }
  113.     else
  114.     {
  115.         printf("open ");
  116.         printf("%s",ttyname(fd));
  117.         printf(" succesfully\n");
  118.     }

  119.     set_speed(fd,115200);
  120.     if (set_Parity(fd,8,1,'N') == FALSE) {
  121.         printf("Set Parity Error\n");
  122.         exit (0);
  123.     }

  124.     //write
  125.     char wrbuff[] = {'h', 'e', 'l', 'l', 'o', '5', 'a', '\n', 'a', 'a', '5', '5', '\0', 'w', 'o', 'r', 'l', 'd', '!'};
  126.     write(fd, wrbuff, sizeof(wrbuff));//the intervening '\0' will not be printed to UART.

  127.     //read
  128.     char rdbuff[512];
  129.     int rdlen;
  130.     while(1)
  131.     {
  132.         if((rdlen = read(fd, rdbuff, sizeof(rdbuff)))>0)//'\n' will also be received as 0x0a.
  133.         {
  134.             rdbuff[rdlen] = '\0';
  135.             printf("receive len:%d receice data:%s", rdlen, rdbuff);
  136.         }
  137.     }
  138.     
  139.     close(fd);
  140.     return 0;
  141. }
2.2 通过signal机制读取数据---
  此方式是在用户层通过用信号signal机制模拟软中断,来读取串口数据。

点击(此处)折叠或打开

  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. #include<unistd.h>
  4. #include<sys/types.h>
  5. #include<sys/stat.h>
  6. #include<sys/signal.h>
  7. #include<fcntl.h>
  8. #include<termios.h>
  9. #include<errno.h>

  10. #define FALSE -1
  11. #define TRUE 0
  12. #define flag 1
  13. #define noflag 0

  14. int wait_flag = noflag;
  15. int STOP = 0;
  16. int res;

  17. int speed_arr[] =
  18.   { B38400, B19200, B9600, B4800, B2400, B1200, B300, B38400, B19200, B9600,
  19. B4800, B2400, B1200, B300, };
  20. int name_arr[] =
  21.   { 38400, 19200, 9600, 4800, 2400, 1200, 300, 38400, 19200, 9600, 4800, 2400,
  22. 1200, 300, };
  23. void
  24. set_speed (int fd, int speed)
  25. {
  26.   int i;
  27.   int status;
  28.   struct termios Opt;
  29.   tcgetattr (fd, &Opt);
  30.   for (i = 0; i < sizeof (speed_arr) / sizeof (int); i++)
  31.     {
  32.       if (speed == name_arr[i])
  33.     {
  34.      tcflush (fd, TCIOFLUSH);
  35.      cfsetispeed (&Opt, speed_arr[i]);
  36.      cfsetospeed (&Opt, speed_arr[i]);
  37.      status = tcsetattr (fd, TCSANOW, &Opt);
  38.      if (status != 0)
  39.      {
  40.      perror ("tcsetattr fd1");
  41.      return;
  42.      }
  43.      tcflush (fd, TCIOFLUSH);
  44.     }
  45.     }
  46. }

  47. int
  48. set_Parity (int fd, int databits, int stopbits, int parity)
  49. {
  50.   struct termios options;
  51.   if (tcgetattr (fd, &options) != 0)
  52.     {
  53.       perror ("SetupSerial 1");
  54.       return (FALSE);
  55.     }
  56.   options.c_cflag &= ~CSIZE;
  57.   switch (databits)
  58.     {
  59.     case 7:
  60.       options.c_cflag |= CS7;
  61.       break;
  62.     case 8:
  63.       options.c_cflag |= CS8;
  64.       break;
  65.     default:
  66.       fprintf (stderr, "Unsupported data size\n");
  67.       return (FALSE);
  68.     }
  69.   switch (parity)
  70.     {
  71.     case 'n':
  72.     case 'N':
  73.       options.c_cflag &= ~PARENB;    /* Clear parity enable */
  74.       options.c_iflag &= ~INPCK;    /* Enable parity checking */
  75.       break;
  76.     case 'o':
  77.     case 'O':
  78.       options.c_cflag |= (PARODD | PARENB);
  79.       options.c_iflag |= INPCK;    /* Disnable parity checking */
  80.       break;
  81.     case 'e':
  82.     case 'E':
  83.       options.c_cflag |= PARENB;    /* Enable parity */
  84.       options.c_cflag &= ~PARODD;
  85.       options.c_iflag |= INPCK;    /* Disnable parity checking */
  86.       break;
  87.     case 'S':
  88.     case 's':            /*as no parity */
  89.       options.c_cflag &= ~PARENB;
  90.       options.c_cflag &= ~CSTOPB;
  91.       break;
  92.     default:
  93.       fprintf (stderr, "Unsupported parity\n");
  94.       return (FALSE);
  95.     }

  96.   switch (stopbits)
  97.     {
  98.     case 1:
  99.       options.c_cflag &= ~CSTOPB;
  100.       break;
  101.     case 2:
  102.       options.c_cflag |= CSTOPB;
  103.       break;
  104.     default:
  105.       fprintf (stderr, "Unsupported stop bits\n");
  106.       return (FALSE);
  107.     }
  108.   /* Set input parity option */
  109.   if (parity != 'n')
  110.     options.c_iflag |= INPCK;
  111.   tcflush (fd, TCIFLUSH);
  112.   options.c_cc[VTIME] = 150;
  113.   options.c_cc[VMIN] = 0;    /* Update the options and do it NOW */
  114.   if (tcsetattr (fd, TCSANOW, &options) != 0)
  115.     {
  116.       perror ("SetupSerial 3");
  117.       return (FALSE);
  118.     }
  119.   return (TRUE);
  120. }

  121. void
  122. signal_handler_IO (int status)
  123. {
  124.   printf ("received SIGIO signale.\n");
  125.   wait_flag = noflag;
  126. }

  127. int
  128. main ()
  129. {
  130.   printf ("This program updates last time at %s %s\n", __TIME__, __DATE__);
  131.   printf ("STDIO COM1\n");
  132.   int fd;
  133.   struct sigaction saio;
  134.   fd = open ("/dev/ttyUSB0", O_RDWR);
  135.   if (fd == -1)
  136.     {
  137.       perror ("serialport error\n");
  138.     }
  139.   else
  140.     {
  141.       printf ("open ");
  142.       printf ("%s", ttyname (fd));
  143.       printf (" succesfully\n");
  144.     }

  145.   saio.sa_handler = signal_handler_IO;
  146.   sigemptyset (&saio.sa_mask);
  147.   saio.sa_flags = 0;
  148.   saio.sa_restorer = NULL;
  149.   sigaction (SIGIO, &saio, NULL);

  150.   //allow the process to receive SIGIO
  151.   fcntl (fd, F_SETOWN, getpid ());
  152.   //make the file descriptor asynchronous
  153.   fcntl (fd, F_SETFL, FASYNC);

  154.   set_speed (fd, 115200);
  155.   if (set_Parity (fd, 8, 1, 'N') == FALSE)
  156.     {
  157.       printf ("Set Parity Error\n");
  158.       exit (0);
  159.     }

  160.   char buf[255];
  161. while (STOP == 0)
  162.     {
  163.       usleep (100000);
  164.       /* after receving SIGIO ,wait_flag = FALSE,input is availabe and can be read */
  165.       if (wait_flag == 0)
  166.     {
  167.      memset (buf, 0, sizeof(buf));
  168.      res = read (fd, buf, 255);
  169.      printf ("nread=%d,%s\n", res, buf);
  170. //     if (res ==1)
  171. //     STOP = 1;        /*stop loop if only a CR was input */
  172.      wait_flag = flag;    /*wait for new input */
  173.     }
  174.     }


  175.   close (fd);
  176.   return 0;
  177. }
2.3 通过select系统调用进行io多路切换实现异步读取串口数据---
  此方式是通过select系统调用,在没有数据时阻塞进程,串口有数据需要读时唤醒进程。

点击(此处)折叠或打开

  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. #include<unistd.h>
  4. #include<sys/types.h>
  5. #include<sys/stat.h>
  6. #include<sys/signal.h>
  7. #include<fcntl.h>
  8. #include<termios.h>
  9. #include<errno.h>

  10. #define FALSE -1
  11. #define TRUE 0
  12. #define flag 1
  13. #define noflag 0

  14. int wait_flag = noflag;
  15. int STOP = 0;
  16. int res;

  17. int speed_arr[] =
  18.   { B38400, B19200, B9600, B4800, B2400, B1200, B300, B38400, B19200, B9600,
  19. B4800, B2400, B1200, B300, };
  20. int name_arr[] =
  21.   { 38400, 19200, 9600, 4800, 2400, 1200, 300, 38400, 19200, 9600, 4800, 2400,
  22. 1200, 300, };
  23. void
  24. set_speed (int fd, int speed)
  25. {
  26.   int i;
  27.   int status;
  28.   struct termios Opt;
  29.   tcgetattr (fd, &Opt);
  30.   for (i = 0; i < sizeof (speed_arr) / sizeof (int); i++)
  31.     {
  32.       if (speed == name_arr[i])
  33.     {
  34.      tcflush (fd, TCIOFLUSH);
  35.      cfsetispeed (&Opt, speed_arr[i]);
  36.      cfsetospeed (&Opt, speed_arr[i]);
  37.      status = tcsetattr (fd, TCSANOW, &Opt);
  38.      if (status != 0)
  39.      {
  40.      perror ("tcsetattr fd1");
  41.      return;
  42.      }
  43.      tcflush (fd, TCIOFLUSH);
  44.     }
  45.     }
  46. }

  47. int
  48. set_Parity (int fd, int databits, int stopbits, int parity)
  49. {
  50.   struct termios options;
  51.   if (tcgetattr (fd, &options) != 0)
  52.     {
  53.       perror ("SetupSerial 1");
  54.       return (FALSE);
  55.     }
  56.   options.c_cflag &= ~CSIZE;
  57.   switch (databits)
  58.     {
  59.     case 7:
  60.       options.c_cflag |= CS7;
  61.       break;
  62.     case 8:
  63.       options.c_cflag |= CS8;
  64.       break;
  65.     default:
  66.       fprintf (stderr, "Unsupported data size\n");
  67.       return (FALSE);
  68.     }
  69.   switch (parity)
  70.     {
  71.     case 'n':
  72.     case 'N':
  73.       options.c_cflag &= ~PARENB;    /* Clear parity enable */
  74.       options.c_iflag &= ~INPCK;    /* Enable parity checking */
  75.       break;
  76.     case 'o':
  77.     case 'O':
  78.       options.c_cflag |= (PARODD | PARENB);
  79.       options.c_iflag |= INPCK;    /* Disnable parity checking */
  80.       break;
  81.     case 'e':
  82.     case 'E':
  83.       options.c_cflag |= PARENB;    /* Enable parity */
  84.       options.c_cflag &= ~PARODD;
  85.       options.c_iflag |= INPCK;    /* Disnable parity checking */
  86.       break;
  87.     case 'S':
  88.     case 's':            /*as no parity */
  89.       options.c_cflag &= ~PARENB;
  90.       options.c_cflag &= ~CSTOPB;
  91.       break;
  92.     default:
  93.       fprintf (stderr, "Unsupported parity\n");
  94.       return (FALSE);
  95.     }

  96.   switch (stopbits)
  97.     {
  98.     case 1:
  99.       options.c_cflag &= ~CSTOPB;
  100.       break;
  101.     case 2:
  102.       options.c_cflag |= CSTOPB;
  103.       break;
  104.     default:
  105.       fprintf (stderr, "Unsupported stop bits\n");
  106.       return (FALSE);
  107.     }
  108.   /* Set input parity option */
  109.   if (parity != 'n')
  110.     options.c_iflag |= INPCK;
  111.   tcflush (fd, TCIFLUSH);
  112.   options.c_cc[VTIME] = 150;
  113.   options.c_cc[VMIN] = 0;    /* Update the options and do it NOW */
  114.   if (tcsetattr (fd, TCSANOW, &options) != 0)
  115.     {
  116.       perror ("SetupSerial 3");
  117.       return (FALSE);
  118.     }
  119.   return (TRUE);
  120. }

  121. void
  122. signal_handler_IO (int status)
  123. {
  124.   printf ("received SIGIO signale.\n");
  125.   wait_flag = noflag;
  126. }

  127. int
  128. main ()
  129. {
  130.   printf ("This program updates last time at %s %s\n", __TIME__, __DATE__);
  131.   printf ("STDIO COM1\n");
  132.   int fd;
  133.   fd = open ("/dev/ttyUSB0", O_RDWR);
  134.   if (fd == -1)
  135.     {
  136.       perror ("serialport error\n");
  137.     }
  138.   else
  139.     {
  140.       printf ("open ");
  141.       printf ("%s", ttyname (fd));
  142.       printf (" succesfully\n");
  143.     }

  144.   set_speed (fd, 115200);
  145.   if (set_Parity (fd, 8, 1, 'N') == FALSE)
  146.     {
  147.       printf ("Set Parity Error\n");
  148.       exit (0);
  149.     }

  150.   char buf[255];
  151.   fd_set rd;
  152.   int nread = 0;
  153.   while(1)
  154.   {
  155.       FD_ZERO(&rd);
  156.     FD_SET(fd, &rd);
  157.     while(FD_ISSET(fd, &rd))
  158.     {
  159.         if(select(fd+1, &rd, NULL,NULL,NULL) < 0)
  160.         {
  161.             perror("select error\n");
  162.         }
  163.         else
  164.         {
  165.             while((nread = read(fd, buf, sizeof(buf))) > 0)
  166.             {
  167.                 printf("nread = %d,%s\n",nread, buf);
  168.                 printf("test\n");
  169.                 memset(buf, 0 , sizeof(buf));
  170.             }
  171.         }
  172.     }
  173.   }
  174.   close (fd);
  175.   return 0;
  176. }

阅读(3164) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~