Linux系统串口批量产测工具

1、说明本文针对linux系统上如何对各类串口硬件进行出厂测试进行硬件连接和软件使用说明,提供的软件测试工具wchsertest,适用于usb、pci、pcie转串口设备等、同样也适用于原生ttys串口。
2、串口测试硬件连接在测试前,需要制作单独的硬件治具,按下表连接信号线:
引脚连接示意图:

3、软件使用方法(1)插入待测试usb/pci/pcie转串口设备。
(2)以ch342f(usb转2串口芯片)为例,安装对应vcp厂商驱动程序,进入/dev目录查看出现如下设备节点:

以ch382为例,安装对应vcp厂商驱动程序,进入/dev目录查看出现如下设备节点:

(3)运行软件,输入命令格式:
./[可执行文件] –d [设备节点路径]
实例1(测试ch342的uart0):sudo ./serial_port_test -d /dev/ttych343usb0
实例2(测试ch382的uart0):sudo ./serial_port_test -d /dev/ttywch0
4、测试错误码说明根据输出的错误码和终端输出信息可判断故障信号线,下表为错误码和说明。
错误码错误码说明
0 dtr--dsr线错误
1 dtr--dcd线错误
2 rts--cts线错误
3 rts--ri线错误
4 txd--rxd线错误
5、测试实例(1)测试成功实例
软件分别以2400bps、9600bps、115200bps各测试一次。
​ ​
(2)测试错误实例

根据输出信息可知,dtr—dsr信号通讯存在错误,错误码:0。
6、wchsertest工具源码/* * serial port factory test utility. * * copyright (c) 2023 nanjing qinheng microelectronics co., ltd. * web: http://wch.cn * author: wch #include #include #include #include #include #include #include #include #include #include #include #include #include #define termios asmtermios#include #undef termios#include #define dtr_on 1#define dtr_off 0#define rts_on 1#define rts_off 0#define buf_size 64#define dtr_on_cmd 0x0#define dtr_off_cmd 0x1#define rts_on_cmd 0x2#define rts_off_cmd 0x3extern int ioctl(int d, int request, ...);static const char *device = /dev/ttych343usb0;static int hardflow = 0;static int verbose = 0;static file *fp;static const struct option lopts[] = { { device, required_argument, 0, 'd' }, { null, 0, 0, 0 },};static void print_usage(const char *prog){ printf(usage: %s [-dsvf], prog); puts( -d --device tty device to use); exit(1);}static void parse_opts(int argc, char *argv[]){ int c; while (1) { c = getopt_long(argc, argv, d:s:h, lopts, null); if (c == -1) { break; } switch (c) { case 'd': if (optarg != null) device = optarg; break; case 'h': default: print_usage(argv[0]); break; } }}/** * libtty_setcustombaudrate - set baud rate of tty device * @fd: device handle * @speed: baud rate to set * * the function return 0 if success, or -1 if fail. */static int libtty_setcustombaudrate(int fd, int baudrate){ struct termios2 tio; if (ioctl(fd, tcgets2, &tio)) { perror(tcgets2); return -1; } tio.c_cflag &= ~cbaud; tio.c_cflag |= bother; tio.c_ispeed = baudrate; tio.c_ospeed = baudrate; if (ioctl(fd, tcsets2, &tio)) { perror(tcsets2); return -1; } if (ioctl(fd, tcgets2, &tio)) { perror(tcgets2); return -1; } return 0;}/** * libtty_setopt - config tty device * @fd: device handle * @speed: baud rate to set * @databits: data bits to set * @stopbits: stop bits to set * @parity: parity to set * @hardflow: hardflow to set * * the function return 0 if success, or -1 if fail. */static int libtty_setopt(int fd, int speed, int databits, int stopbits, char parity, char hardflow){ struct termios newtio; struct termios oldtio; int i; bzero(&newtio, sizeof(newtio)); bzero(&oldtio, sizeof(oldtio)); if (tcgetattr(fd, &oldtio) != 0) { perror(tcgetattr); return -1; } newtio.c_cflag |= clocal | cread; newtio.c_cflag &= ~csize; /* set data bits */ switch (databits) { case 5: newtio.c_cflag |= cs5; break; case 6: newtio.c_cflag |= cs6; break; case 7: newtio.c_cflag |= cs7; break; case 8: newtio.c_cflag |= cs8; break; default: fprintf(stderr, unsupported data size); return -1; } /* set parity */ switch (parity) { case 'n': case 'n': newtio.c_cflag &= ~parenb; /* clear parity enable */ newtio.c_iflag &= ~inpck; /* disable input parity check */ break; case 'o': case 'o': newtio.c_cflag |= (parodd | parenb); /* odd parity instead of even */ newtio.c_iflag |= inpck; /* enable input parity check */ break; case 'e': case 'e': newtio.c_cflag |= parenb; /* enable parity */ newtio.c_cflag &= ~parodd; /* even parity instead of odd */ newtio.c_iflag |= inpck; /* enable input parity check */ break; default: fprintf(stderr, unsupported parity); return -1; } /* set stop bits */ switch (stopbits) { case 1: newtio.c_cflag &= ~cstopb; break; case 2: newtio.c_cflag |= cstopb; break; default: perror(unsupported stop bits); return -1; } if (hardflow) newtio.c_cflag |= crtscts; else newtio.c_cflag &= ~crtscts; newtio.c_cc[vtime] = 10; /* time-out value (tenths of a second) [!icanon]. */ newtio.c_cc[vmin] = 64; /* minimum number of bytes read at once [!icanon]. */ tcflush(fd, tcioflush); if (tcsetattr(fd, tcsanow, &newtio) != 0) { perror(tcsetattr); return -1; } /* set tty speed */ if (libtty_setcustombaudrate(fd, speed) != 0) { perror(setbaudrate); return -1; } return 0;}/** * libtty_open - open tty device * @devname: the device name to open * * in this demo device is opened blocked, you could modify it at will. */static int libtty_open(const char *devname){ int fd = open(devname, o_rdwr | o_noctty); int flags = 0; if (fd < 0) { perror(open device failed); return -1; } if (fcntl(fd, f_setfl, 0) < 0) { printf(fcntl failed.); return -1; } if (isatty(fd) == 0) { printf(not tty device.); return -1; } return fd;}/** * libtty_close - close tty device * @fd: the device handle * * the function return 0 if success, others if fail. */static int libtty_close(int fd){ return close(fd);}/** * libtty_tiocmset - modem set * @fd: file descriptor of tty device * @bdtr: 0 on inactive, other on dtr active * @brts: 0 on inactive, other on rts active * * the function return 0 if success, others if fail. */static int libtty_tiocmset(int fd, char bdtr, char brts){ unsigned long controlbits = 0; if (bdtr) controlbits |= tiocm_dtr; if (brts) controlbits |= tiocm_rts; return ioctl(fd, tiocmset, &controlbits);}/** * libtty_tiocmget - modem get * @fd: file descriptor of tty device * @modembits: pointer to modem status * * the function return 0 if success, others if fail. */static int libtty_tiocmget_check(int fd, unsigned long *modembits, int cmd){ int ret = 0; ret = ioctl(fd, tiocmget, modembits); if (ret == 0) { switch (cmd) { case dtr_off_cmd: // dtr--dsr/dcd if ((*modembits & tiocm_dsr) != 0) { printf([error code: %d] dtr--dsr error, 0); ret = -1; } if ((*modembits & tiocm_cd) != 0) { printf([error code: %d] dtr--dcd error, 1); ret = -1; } break; case dtr_on_cmd: if ((*modembits & tiocm_dsr) == 0) { printf([error code: %d] dtr--dsr error, 0); ret = -1; } if ((*modembits & tiocm_cd) == 0) { printf([error code: %d] dtr--dcd error, 1); ret = -1; } break; case rts_off_cmd: // rts--cts/ri if ((*modembits & tiocm_cts) != 0) { printf([error code: %d] rts--cts error, 2); ret = -1; } if ((*modembits & tiocm_ri) != 0) { printf([error code: %d] rts--ri error, 3); ret = -1; } break; case rts_on_cmd: if ((*modembits & tiocm_cts) == 0) { printf([error code: %d] rts--cts error, 2); ret = -1; } if ((*modembits & tiocm_ri) == 0) { printf([error code: %d] rts--ri error, 3); ret = -1; } break; default: break; } } return ret;}static void sig_handler(int signo){ printf(capture sign no:%d, signo); if (fp != null) { fflush(fp); fsync(fileno(fp)); fclose(fp); } exit(0);}void start_test(int fd){ int ret, i, times, num, nwrite, nread, len; int len_w, pos_w, ret1, ret2, ret3; int total = 0, off_w, off_r; char c; unsigned long modemstatus; unsigned char buf_write[buf_size]; unsigned char buf_read[buf_size]; memset(buf_write, 0x00, buf_size); memset(buf_read, 0x00, buf_size); for (times = 0; times < 64; times++) { for (i = 0; i 0) { nwrite = write(fd, buf_write + off_w, len); if (nwrite 0) { nread = read(fd, buf_read + off_r, nwrite); if (nread < 0) { printf(read error!); exit(1); } off_r += nread; nwrite -= nread; } total += nread; /* compare the buffer contents */ if (memcmp(buf_read, buf_write, buf_size) != 0) { printf([error code: %d] txd/rxd test error, 4); goto exit; } } printf(txd/rxd test passed); /* set dtr invalid */ if (libtty_tiocmset(fd, dtr_off, rts_off) != 0) goto exit; usleep(10000); ret1 = libtty_tiocmget_check(fd, &modemstatus, dtr_off_cmd); /* set dtr valid */ if (libtty_tiocmset(fd, dtr_on, rts_off) != 0) goto exit; usleep(10000); ret2 = libtty_tiocmget_check(fd, &modemstatus, dtr_on_cmd); /* set rts valid */ if (libtty_tiocmset(fd, dtr_off, rts_on) != 0) goto exit; usleep(10000); ret3 = libtty_tiocmget_check(fd, &modemstatus, rts_on_cmd); if ((ret1 || ret2 || ret3) == 0) printf(dtr/rts/dsr/cts/dcd/ri test passed); printf();exit: return;}int main(int argc, char *argv[]){ int fd, ret, i, num, nwrite, nread; int len_w, pos_w, ret1, ret2, ret3, ret4; int total = 0, off = 0; char c; unsigned long modemstatus; unsigned char buf_write[buf_size]; unsigned char buf_read[buf_size]; parse_opts(argc, argv); signal(sigint, sig_handler); fd = libtty_open(device); if (fd < 0) { printf(libtty_open: %s error., device); exit(0); } /* 2400bps test */ ret = libtty_setopt(fd, 2400, 8, 1, 'n', hardflow); if (ret != 0) { printf(libtty_setopt error.); exit(0); } start_test(fd); /* 9600bps test */ ret = libtty_setopt(fd, 9600, 8, 1, 'n', hardflow); if (ret != 0) { printf(libtty_setopt error.); exit(0); } start_test(fd); /* 115200bps test */ ret = libtty_setopt(fd, 115200, 8, 1, 'n', hardflow); if (ret != 0) { printf(libtty_setopt error.); exit(0); } start_test(fd); ret = libtty_close(fd); if (ret != 0) { printf(libtty_close error.); exit(0); } return 0;}​

在PLC中保护电源就相当于保护PLC的命脉
详解PWM开关稳压电源尖峰干扰
新的科学突破:智能手机摄像头竟可以定量检测新冠病毒RNA
哪一些企业被评为人工智能领航企业
南方电网公司的智能电网发展目标全面分析
Linux系统串口批量产测工具
苹果为5G新款iPhone 12自行设计手机天线
5G智慧医疗健康行业拥有非常好的发展前景
GPRS的ARM7嵌入式单片机视频报警系统
信号发生器如何设置双窄脉冲同步输出?
智能压力变送器特点
新型节能综合基站解决方案
GlobalCom上市暖白色荧光灯型LED照明灯
音圈电机模组有哪些优点
电路板进行散热处理十分重要
垂直单极天线介绍
谱析光晶完成Pre-B轮融资,进一步完善碳化硅生产基地建设
用于PCB品质验证的时域串扰测量法分析
写Verilog,FPGA和ASIC如何选择?
dfrobot12V直流减速电机 专用适配器介绍