Toybrick

uart串口COM双机通讯测试程序范例

jax_fong

新手上路

积分
14
楼主
发表于 2019-1-11 19:45:37    查看: 6983|回复: 2 | [复制链接]    打印 | 只看该作者
本帖最后由 qiu 于 2020-8-7 17:18 编辑

以下代码为比较通用的uart双机通讯测试程序, 可作参考

  1. //串口相关的头文件  

  2. #include<stdio.h>      /*标准输入输出定义*/  

  3. #include<stdlib.h>     /*标准函数库定义*/  

  4. #include<unistd.h>     /*Unix 标准函数定义*/  

  5. #include<sys/types.h>   

  6. #include<sys/stat.h>     

  7. #include<fcntl.h>      /*文件控制定义*/  

  8. #include<termios.h>    /*PPSIX 终端控制定义*/  

  9. #include<errno.h>      /*错误号定义*/  

  10. #include<string.h>  

  11.    

  12.    

  13. //宏定义  

  14. #define FALSE  -1  

  15. #define TRUE   0  

  16.    

  17. /*******************************************************************

  18. * 名称:                  UART0_Open

  19. * 功能:                打开串口并返回串口设备文件描述

  20. * 入口参数:        fd    :文件描述符     port :串口号(ttyS0,ttyS1,ttyS2)

  21. * 出口参数:        正确返回为1,错误返回为0

  22. *******************************************************************/  

  23. int UART0_Open(int fd,char* port)  

  24. {  

  25.      

  26.         fd = open( port, O_RDWR|O_NOCTTY|O_NDELAY);  

  27.         if (FALSE == fd)  

  28.         {  

  29.                 perror("Can't Open Serial Port");  

  30.                 return(FALSE);  

  31.         }  

  32.         //恢复串口为阻塞状态                                 

  33.         if(fcntl(fd, F_SETFL, 0) < 0)  

  34.         {  

  35.                 printf("fcntl failed!\n");  

  36.                 return(FALSE);  

  37.         }      

  38.         else  

  39.         {  

  40.                 printf("fcntl=%d\n",fcntl(fd, F_SETFL,0));  

  41.         }  

  42.         //测试是否为终端设备      

  43.         if(0 == isatty(STDIN_FILENO))  

  44.         {  

  45.                 printf("standard input is not a terminal device\n");  

  46.                 return(FALSE);  

  47.         }  

  48.         else  

  49.         {  

  50.                 printf("isatty success!\n");  

  51.         }               

  52.         printf("fd->open=%d\n",fd);  

  53.         return fd;  

  54. }  

  55. /*******************************************************************

  56. * 名称:                UART0_Close

  57. * 功能:                关闭串口并返回串口设备文件描述

  58. * 入口参数:        fd    :文件描述符     port :串口号(ttyS0,ttyS1,ttyS2)

  59. * 出口参数:        void

  60. *******************************************************************/  

  61.    

  62. void UART0_Close(int fd)  

  63. {  

  64.         close(fd);  

  65. }  

  66.    

  67. /*******************************************************************

  68. * 名称:                UART0_Set

  69. * 功能:                设置串口数据位,停止位和效验位

  70. * 入口参数:        fd        串口文件描述符

  71. *                              speed     串口速度

  72. *                              flow_ctrl   数据流控制

  73. *                           databits   数据位   取值为 7 或者8

  74. *                           stopbits   停止位   取值为 1 或者2

  75. *                           parity     效验类型 取值为N,E,O,,S

  76. *出口参数:          正确返回为1,错误返回为0

  77. *******************************************************************/  

  78. int UART0_Set(int fd,int speed,int flow_ctrl,int databits,int stopbits,int parity)  

  79. {  

  80.      

  81.         int   i;  

  82.         int   status;  

  83.         int   speed_arr[] = { B115200, B19200, B9600, B4800, B2400, B1200, B300};  

  84.         int   name_arr[] = {115200,  19200,  9600,  4800,  2400,  1200,  300};  

  85.            

  86.         struct termios options;  

  87.      

  88.         /*tcgetattr(fd,&options)得到与fd指向对象的相关参数,并将它们保存于options,该函数还可以测试配置是否正确,该串口是否可用等。若调用成功,函数返回值为0,若调用失败,函数返回值为1.

  89.     */  

  90.         if( tcgetattr( fd,&options)  !=  0)  

  91.         {  

  92.                 perror("SetupSerial 1");      

  93.                 return(FALSE);   

  94.         }  

  95.    

  96.     //设置串口输入波特率和输出波特率  

  97.         for ( i= 0;  i < sizeof(speed_arr) / sizeof(int);  i++)  

  98.         {  

  99.                 if  (speed == name_arr[i])  

  100.                 {               

  101.                         cfsetispeed(&options, speed_arr[i]);   

  102.                         cfsetospeed(&options, speed_arr[i]);   

  103.                 }  

  104.         }      

  105.      

  106.     //修改控制模式,保证程序不会占用串口  

  107.     options.c_cflag |= CLOCAL;  

  108.     //修改控制模式,使得能够从串口中读取输入数据  

  109.     options.c_cflag |= CREAD;  

  110.    

  111.     //设置数据流控制  

  112.     switch(flow_ctrl)  

  113.     {  

  114.         

  115.                 case 0 ://不使用流控制  

  116.               options.c_cflag &= ~CRTSCTS;  

  117.               break;     

  118.         

  119.                 case 1 ://使用硬件流控制  

  120.               options.c_cflag |= CRTSCTS;  

  121.               break;  

  122.                 case 2 ://使用软件流控制  

  123.               options.c_cflag |= IXON | IXOFF | IXANY;  

  124.               break;  

  125.     }  

  126.     //设置数据位  

  127.     //屏蔽其他标志位  

  128.     options.c_cflag &= ~CSIZE;  

  129.     switch (databits)  

  130.     {   

  131.                 case 5    :  

  132.                      options.c_cflag |= CS5;  

  133.                      break;  

  134.                 case 6    :  

  135.                      options.c_cflag |= CS6;  

  136.                      break;  

  137.                 case 7    :      

  138.                  options.c_cflag |= CS7;  

  139.                  break;  

  140.                 case 8:      

  141.                  options.c_cflag |= CS8;  

  142.                  break;   

  143.                 default:     

  144.                  fprintf(stderr,"Unsupported data size\n");  

  145.                  return (FALSE);   

  146.     }  

  147.     //设置校验位  

  148.     switch (parity)  

  149.     {   

  150.                 case 'n':  

  151.                 case 'N': //无奇偶校验位。  

  152.                  options.c_cflag &= ~PARENB;   

  153.                  options.c_iflag &= ~INPCK;      

  154.                  break;   

  155.                 case 'o':   

  156.                 case 'O'://设置为奇校验      

  157.                  options.c_cflag |= (PARODD | PARENB);   

  158.                  options.c_iflag |= INPCK;               

  159.                  break;   

  160.                 case 'e':   

  161.                 case 'E'://设置为偶校验   

  162.                  options.c_cflag |= PARENB;         

  163.                  options.c_cflag &= ~PARODD;         

  164.                  options.c_iflag |= INPCK;        

  165.                  break;  

  166.                 case 's':  

  167.                 case 'S': //设置为空格   

  168.                  options.c_cflag &= ~PARENB;  

  169.                  options.c_cflag &= ~CSTOPB;  

  170.                  break;   

  171.         default:   

  172.                  fprintf(stderr,"Unsupported parity\n");      

  173.                  return (FALSE);   

  174.     }   

  175.     // 设置停止位   

  176.     switch (stopbits)  

  177.     {   

  178.                 case 1:     

  179.                  options.c_cflag &= ~CSTOPB; break;   

  180.                 case 2:     

  181.                  options.c_cflag |= CSTOPB; break;  

  182.                 default:     

  183.                        fprintf(stderr,"Unsupported stop bits\n");   

  184.                        return (FALSE);  

  185.     }  

  186.      

  187.         //修改输出模式,原始数据输出  

  188.         options.c_oflag &= ~OPOST;  

  189.    

  190.         options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);  

  191.         //options.c_lflag &= ~(ISIG | ICANON);  

  192.      

  193.     //设置等待时间和最小接收字符  

  194.     options.c_cc[VTIME] = 1; /* 读取一个字符等待1*(1/10)s */   

  195.     options.c_cc[VMIN] = 1; /* 读取字符的最少个数为1 */  

  196.      

  197.     //如果发生数据溢出,接收数据,但是不再读取 刷新收到的数据但是不读  

  198.     tcflush(fd,TCIFLUSH);  

  199.      

  200.     //激活配置 (将修改后的termios数据设置到串口中)  

  201.     if (tcsetattr(fd,TCSANOW,&options) != 0)   

  202.         {  

  203.                 perror("com set error!\n");   

  204.                 return (FALSE);   

  205.         }  

  206.     return (TRUE);   

  207. }  

  208. /*******************************************************************

  209. * 名称:                UART0_Init()

  210. * 功能:                串口初始化

  211. * 入口参数:        fd       :  文件描述符   

  212. *               speed  :  串口速度

  213. *                              flow_ctrl  数据流控制

  214. *               databits   数据位   取值为 7 或者8

  215. *                           stopbits   停止位   取值为 1 或者2

  216. *                           parity     效验类型 取值为N,E,O,,S

  217. *                       

  218. * 出口参数:        正确返回为1,错误返回为0

  219. *******************************************************************/  

  220. int UART0_Init(int fd, int speed,int flow_ctrl,int databits,int stopbits,int parity)  

  221. {  

  222.     int err;  

  223.     //设置串口数据帧格式  

  224.     if (UART0_Set(fd,9600,0,8,1,'N') == FALSE)  

  225.         {                                                           

  226.                 return FALSE;  

  227.         }  

  228.     else  

  229.         {  

  230.                 return  TRUE;  

  231.         }  

  232. }  

  233.    

  234. /*******************************************************************

  235. * 名称:                  UART0_Recv

  236. * 功能:                接收串口数据

  237. * 入口参数:        fd                  :文件描述符     

  238. *                              rcv_buf     :接收串口中数据存入rcv_buf缓冲区中

  239. *                              data_len    :一帧数据的长度

  240. * 出口参数:        正确返回为1,错误返回为0

  241. *******************************************************************/  

  242. int UART0_Recv(int fd, char *rcv_buf,int data_len)  

  243. {  

  244.         int len,fs_sel;  

  245.     fd_set fs_read;  

  246.      

  247.     struct timeval time;  

  248.      

  249.     FD_ZERO(&fs_read);  

  250.     FD_SET(fd,&fs_read);  

  251.      

  252.     time.tv_sec = 10;  

  253.     time.tv_usec = 0;  

  254.      

  255.     //使用select实现串口的多路通信  

  256.     fs_sel = select(fd+1,&fs_read,NULL,NULL,&time);  

  257.     printf("fs_sel = %d\n",fs_sel);  

  258.     if(fs_sel)  

  259.         {  

  260.                 len = read(fd,rcv_buf,data_len);  

  261.                 printf("I am right!(version1.2) len = %d fs_sel = %d\n",len,fs_sel);  

  262.                 return len;  

  263.         }  

  264.     else  

  265.         {  

  266.                 printf("Sorry,I am wrong!");  

  267.                 return FALSE;  

  268.         }      

  269. }  

  270. /********************************************************************

  271. * 名称:                  UART0_Send

  272. * 功能:                发送数据

  273. * 入口参数:        fd                  :文件描述符     

  274. *                              send_buf    :存放串口发送数据

  275. *                              data_len    :一帧数据的个数

  276. * 出口参数:        正确返回为1,错误返回为0

  277. *******************************************************************/  

  278. int UART0_Send(int fd, char *send_buf,int data_len)  

  279. {  

  280.     int len = 0;  

  281.      

  282.     len = write(fd,send_buf,data_len);  

  283.     if (len == data_len )  

  284.         {  

  285.                 printf("send data is %s\n",send_buf);

  286.                 return len;  

  287.         }      

  288.     else     

  289.         {  

  290.                  

  291.                 tcflush(fd,TCOFLUSH);  

  292.                 return FALSE;  

  293.         }  

  294.      

  295. }  

  296.    

  297.    

  298. int main(int argc, char **argv)  

  299. {  

  300.     int fd;                            //文件描述符  

  301.     int err;                           //返回调用函数的状态  

  302.     int len;                          

  303.     int i;  

  304.     char rcv_buf[100];         

  305.     //char send_buf[20]="tiger john";  

  306.     char send_buf[20]="tiger john";

  307.     if(argc != 3)  

  308.         {  

  309.                 printf("Usage: %s /dev/ttySn tx(send data) / rx(receive data) \n",argv[0]);  

  310.                 return FALSE;  

  311.         }  

  312.     fd = UART0_Open(fd,argv[1]); //打开串口,返回文件描述符  

  313.     do

  314.         {  

  315.                 err = UART0_Init(fd,9600,0,8,1,'N');  

  316.                 printf("Set Port Exactly!\n");  

  317.         }while(FALSE == err || FALSE == fd);  

  318.      

  319.     if(0 == strcmp(argv[2],"tx"))  

  320.         {  

  321.                 for(i = 0;i < 10;i++)  

  322.                 {  

  323.                          len = UART0_Send(fd,send_buf,10);  

  324.                         if(len > 0)  

  325.                                 printf(" %d time send %d data successful\n",i,len);  

  326.                         else  

  327.                                 printf("send data failed!\n");  

  328.                            

  329.                         sleep(2);  

  330.                 }  

  331.                 UART0_Close(fd);               

  332.         }  

  333.     else  

  334.         {                                       

  335.                 while (1) //循环读取数据  

  336.                 {   

  337.                         len = UART0_Recv(fd, rcv_buf,99);  

  338.                           if(len > 0)  

  339.                         {  

  340.                                 rcv_buf[len] = '\0';  

  341.                                 printf("receive data is %s\n",rcv_buf);  

  342.                                 printf("len = %d\n",len);  

  343.                         }  

  344.                         else  

  345.                         {  

  346.                                 printf("cannot receive data\n");  

  347.                         }  

  348.                         sleep(2);  

  349.                 }              

  350.                 UART0_Close(fd);   

  351.         }  

  352. }  

复制代码


回复

使用道具 举报

piccolo

中级会员

积分
316
沙发
发表于 2019-2-19 11:15:48 | 只看该作者
正好要用到 十分有用!
回复

使用道具 举报

tanggou

注册会员

积分
179
板凳
发表于 2020-7-20 17:56:05 | 只看该作者
测试产生乱码,读取到的数据显示不出来。
打印如下:
[root@localhost test]# ./uart /dev/ttyS4 rx
fcntl=0
isatty success!
fd->open=3
Set Port Exactly!
fs_sel = 1
I am right!(version1.2) len = 99 fs_sel = 1
receive data is
len = 99
fs_sel = 1
I am right!(version1.2) len = 99 fs_sel = 1
receive data is ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ
len = 99
fs_sel = 1
I am right!(version1.2) len = 99 fs_sel = 1
receive data is ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ
len = 99
fs_sel = 1
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

产品中心 购买渠道 开源社区 Wiki教程 资料下载 关于Toybrick


快速回复 返回顶部 返回列表