485测试应用 1. 背景2. 应用层调用串口的流程1. 打开设备节点对于linux来说,操作串口就是操作/dev下的tty节点,应用层需要调用open/close函数来得到该节点的设备描述符,之后使用write/read函数进行读写。 2. 初始化串口设置串口波特率、数据位、停止位等参数。 3. 读写串口调用write/read函数进行读写。 4. 关闭设备节点调用close函数关闭设备节点。 3. 应用常用的几种处理1. 传参校验使用argc和argv进行传参校验,如果传入的参数数量不对,则打印Usage提示输入正确的参数。 int main(int argc, char **argv) { if (argc != 4 ) { printf("Usage:%s dev1_name dev2_name [self_loop_test_string]\n", argv[0]); exit(1); } } 2. open/close函数对于linux来说,操作串口就是操作/dev下的tty节点,应用层需要调用open/close函数来得到该节点的设备描述符,之后使用write/read函数进行读写。 一般情况下,操作正常执行会返回0或者正数,当返回负数表示函数没有正常执行,所以一般会调用open/close等函数时,会通过判断该函数的返回值,确定函数是否正常执行。例如: dev1 = argv[1]; fd1 = open(dev1, O_RDWR | O_NOCTTY | O_NONBLOCK); if (-1 == fd1) { printf("Cannot open %s:%s\n", dev1, strerror(errno)); exit(1); } 4. 串口对测的处理方法两串口测试时,需要一个发,一个收,然后通过对比发出去的内容和收到的内容,来确定串口通信是否正常。 流程如下: 写串口1 >> 清理缓存区 >> 将串口2的数据读入缓存区 >> 对比判断 >> 输出结果 源码如下: /* 写串口 */ do { nwrite = write(fd1, test_string, strlen(test_string)); } while(nwrite <= 0); printf("send %d bytes data.\n", nwrite); /* 清空buffer */ memset(buffer, 0, BUF_SIZE); p_buffer = buffer; nread = 0; /* 读串口 */ do { ret = read(fd2, p_buffer, 64); if (ret > 0) { printf("read %d bytes data:%s\n", ret, p_buffer); p_buffer += ret; nread += ret; } } while(nread < nwrite && i--); printf("all read %d bytes data:%s\n", nread, buffer); printf("------%s >> %s test %s------\n", dev1, dev2, (0 == strcmp(buffer, test_string)) ? "ok!" : "failed!"); 5. 源码源码如下: #include <stdio.h> /*标准输入输出定义*/ #include <stdlib.h> /*标准函数库定义*/ #include <string.h> #include <unistd.h> /*Unix标准函数定义*/ #include <sys/types.h> /**/ #include <sys/stat.h> /**/ #include <fcntl.h> /*文件控制定义*/ #include <termios.h> /*PPSIX终端控制定义*/ #include <errno.h> /*错误号定义*/ #include <sys/time.h> /* * % 0x25 * ; 0x3B * + 0x2B * ? 0x3F */ #define DEF_BAUD 115200 #define SPEED_CNT 5 #define BUF_SIZE 100 /*用来接收轨道数据*/ char buffer[BUF_SIZE]; int speed_arr[SPEED_CNT] = { B9600, B19200, B38400, B57600, B115200 }; int name_arr[SPEED_CNT] = { 9600, 19200, 38400, 57600, 115200 }; /** *@brief 设置串口通信速率 *@param fd 类型 int 打开串口的文件句柄 *@param speed 类型 int 串口速度 *@return 0 success or -1 err */ int set_speed(int fd, int speed) { int i; int status; struct termios opt; tcgetattr(fd, &opt); for (i= 0; i<SPEED_CNT; i++) { if (speed == name_arr[i]) { tcflush(fd, TCIOFLUSH); /* 设置串口的波特率 */ cfsetispeed(&opt, speed_arr[i]); cfsetospeed(&opt, speed_arr[i]); status = tcsetattr(fd, TCSANOW, &opt); if (status != 0) { perror("tcsetattr set_speed"); return -1; } return 0; } /*清空所有正在发生的IO数据*/ tcflush(fd, TCIOFLUSH); } printf("Cannot find suitable speed\n"); return -1; } /** *@brief 设置串口数据位,停止位和效验位 *@param fd 类型 int 打开的串口文件句柄* *@param databits 类型 int 数据位 取值 为 7 或者8* *@param stopbits 类型 int 停止位 取值为 1 或者2* *@param parity 类型 int 效验类型 取值为N,E,O,,S *@return 0 success or -1 err */ int set_parity(int fd, int databits, int stopbits, int parity) { struct termios options; if (tcgetattr(fd, &options) != 0) { perror("tcgetattr"); return -1; } options.c_cflag &= ~CSIZE; switch (databits) /*设置数据位数*/ { case 7: options.c_cflag |= CS7; break; case 8: options.c_cflag |= CS8; break; default: fprintf(stderr, "Unsupported data size\n"); return -1; } switch (parity) { case 'n': case 'N': options.c_cflag &= ~PARENB; /* Clear parity enable */ options.c_iflag &= ~INPCK; /* Enable parity checking */ options.c_iflag &= ~(ICRNL|IGNCR); options.c_lflag &= ~(ICANON ); break; case 'o': case 'O': options.c_cflag |= (PARODD | PARENB); /* 设置为奇效验*/ options.c_iflag |= INPCK; /* Disnable parity checking */ break; case 'e': case 'E': options.c_cflag |= PARENB; /* Enable parity */ options.c_cflag &= ~PARODD; /* 转换为偶效验*/ options.c_iflag |= INPCK; /* Disnable parity checking */ break; case 'S': case 's': /*as no parity*/ options.c_cflag &= ~PARENB; options.c_cflag &= ~CSTOPB; break; default: fprintf(stderr, "Unsupported parity\n"); return -1; } /* 设置停止位*/ switch (stopbits) { case 1: options.c_cflag &= ~CSTOPB; break; case 2: options.c_cflag |= CSTOPB; break; default: fprintf(stderr,"Unsupported stop bits\n"); return -1; } /* Set input parity option */ if ((parity != 'n') || (parity != 'N')) options.c_iflag |= INPCK; /* 若以O_NONBLOCK 方式open,这两个设置没有作用,等同于都为0 */ /* 若非O_NONBLOCK 方式open,具体作用可参考其他博客,关键词linux VTIME */ options.c_cc[VTIME] = 10; // 1s options.c_cc[VMIN] = 0; /* 清空正读的数据,且不会读出 */ tcflush(fd,TCIFLUSH); /*采用原始模式通讯*/ options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); options.c_oflag &= ~OPOST; /*解决发送0x0A的问题*/ // options.c_iflag &= ~(INLCR | ICRNL | IGNCR); // options.c_oflag &= ~(ONLCR | OCRNL | ONOCR | ONLRET); /* Update the options and do it NOW */ if (tcsetattr(fd, TCSANOW, &options) != 0) { perror("SetupSerial 3"); return -1; } return 0; } /** *@breif main() */ int main(int argc, char **argv) { int fd1, fd2; int ret = -1; const char *dev1 = NULL; const char *dev2 = NULL; const char *test_string = NULL; char *p_buffer = NULL; int nread = 0; int nwrite = 0; /* 1、检测传参 */ if (argc != 4 ) { printf("Usage:%s dev1_name dev2_name [self_loop_test_string]\n", argv[0]); exit(1); } dev1 = argv[1]; dev2 = argv[2]; if (NULL != argv[3]) { if (strlen(argv[3]) <= BUF_SIZE) { test_string = argv[3]; } else { printf("self_loop_test_string must be smaller than %d.\n", BUF_SIZE); return 0; } } else{ printf("please input a string!\n"); return 0; } /* 2、打开串口 */ fd1 = open(dev1, O_RDWR | O_NOCTTY | O_NONBLOCK); if (-1 == fd1) { printf("Cannot open %s:%s\n", dev1, strerror(errno)); exit(1); } printf("------open %s success------\n", dev1); fd2 = open(dev2, O_RDWR | O_NOCTTY | O_NONBLOCK); if (-1 == fd2) { printf("Cannot open %s:%s\n", dev2, strerror(errno)); exit(1); } printf("------open %s success------\n", dev2); #if 1 /* 3、初始化设备 */ if (-1 == set_speed(fd1, DEF_BAUD)) { printf("Cannot set baudrate to 115200\n"); close(fd1); exit(1); } if (-1 == set_speed(fd2, DEF_BAUD)) { printf("Cannot set baudrate to 115200\n"); close(fd2); exit(1); } if (-1 == set_parity(fd1, 8, 1, 'N')) { printf("Set Parity Error\n"); close(fd1); exit(1); } if (-1 == set_parity(fd2, 8, 1, 'N')) { printf("Set Parity Error\n"); close(fd2); exit(1); } #endif int i = 30000; if (NULL != test_string) { /*开始自发自收测试*/ /* 写串口 */ do { nwrite = write(fd1, test_string, strlen(test_string)); } while(nwrite <= 0); printf("send %d bytes data.\n", nwrite); /* 清空buffer */ memset(buffer, 0, BUF_SIZE); p_buffer = buffer; nread = 0; /* 读串口 */ do { ret = read(fd2, p_buffer, 64); if (ret > 0) { printf("read %d bytes data:%s\n", ret, p_buffer); p_buffer += ret; nread += ret; } } while(nread < nwrite && i--); printf("all read %d bytes data:%s\n", nread, buffer); printf("------%s >> %s test %s------\n", dev1, dev2, (0 == strcmp(buffer, test_string)) ? "ok!" : "failed!"); close(fd1); close(fd2); return 0; } }
|