串口助手可以从这里下载:https://docs.ai-thinker.com/%E5%BC%80%E5%8F%91%E5%B7%A5%E5%85%B72
内容摘自网络:
要实现AT指令的发送与接收,第一步先实现相关的串口通信接口:
/****************************** 实现linux环境中端口的打开,关闭 ********************************/ //#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> #include "linux_interface.h" int serial_port_open(char *dev) { //const char * dev = "/dev/ttyUSB1"; int fd; //O_RDWR读写模式 //O_NOCTTY如果路径名指向终端设备,不要把这个设备用作控制终端。 //O_NONBLOCK如果路径名指向FIFO/块文件/字符文件,则把文件的打开和后继I/O fd = open(dev, O_RDWR | O_NOCTTY | O_NONBLOCK); if(fd == -1) { printf("open AT com error. \n"); return -1; } //如果非阻塞,如果文件为空,不会阻塞,直接返回结果,非阻塞针对设备,网络文件 //设置fd为阻塞状态,设备文件,网络文件时用 if(fcntl(fd, F_SETFL, 0) < 0) { printf("fcntl error. \n"); }else { printf("fcntl=%d\n",fcntl(fd, F_SETFL, 0)); } //STDIN_FILENO 标准输入 if(isatty(STDIN_FILENO)==0) printf("standard input is not a terminal device\n"); else printf("isatty success!\n"); return fd; } void serial_port_close(int fd) { close(fd); } /***************************************************** 入口参数: fd 打开设备的fd speed 串口速率 flow_ctrl 数据流控制,一般不控制 0 databits 数据位,取值7或者8 stopbits 停止位 取值为 1 或者2 parity 效验类型 取值为N,E,O,,S *****************************************************/ int serial_port_config(int fd, int speed, int flow_ctrl, int databits, int stopbits, int parity) { int speed_arr[] = { B115200, B19200, B9600, B4800, B2400, B1200, B300}; int name_arr[] = {115200, 19200, 9600, 4800, 2400, 1200, 300}; struct termios options; //获取到fd中对应的参数 bzero( &options, sizeof(options)); if(tcgetattr(fd, &options) != 0) { printf("get serial port config error.\n"); return -1; } //根据speed 设置输入波特率和输出波特率 for(int i=0; i<sizeof(speed_arr)/sizeof(int); i++) { if(name_arr[i] == speed) { 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; } //设置字符长度掩码,取值为 CS5, CS6, CS7, 或 CS8。 //屏蔽其他标志位 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: printf("unsupported data size \n"); return -1; } //设置停止位 switch(stopbits) { case 1: options.c_cflag &= ~CSTOPB; break; case 2: options.c_cflag |= CSTOPB; break; default: printf("unsupported stop bit. \n"); return -1; } //设置校验位 switch(parity) //int类型和char类型的默认互转 { 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: printf("unsupported parity.\n"); return -1; } //设置输出模式 原始数据输出 options.c_oflag &= ~OPOST; options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); //设置等待时间和最小接收字符 ==》这里应该为0吧 options.c_cc[VTIME] = 1; /* 读取一个字符等待1*(1/10)s */ options.c_cc[VMIN] = 1; /* 读取字符的最少个数为1 */ //如果发生数据溢出,接收数据,且不再读取 刷新收到的数据但是不读 //清空终端未完成的输入/输出请求及数据 tcflush(fd,TCIFLUSH); if (tcsetattr(fd,TCSANOW,&options) != 0) { printf("com set error!\n"); return -1; } return 0; } //发送的接口 调用write接口 int linux_serial_port_send(int fd, char* send_buf, int data_len) { int len = 0; data_len = (strlen(send_buf) > data_len)? data_len:strlen(send_buf); len = write(fd, send_buf, data_len); if(len == data_len) { printf("send buff [%s] success. \n", send_buf); return len; }else { tcflush(fd,TCOFLUSH); return -1; } } int linux_serial_port_read(int fd, char* recv_buf, int data_len) { return read(fd, recv_buf, data_len); } //接收的接口 int linux_serial_port_recv(int fd, char* recv_buf, int data_len) { //把fd添加到select的集合中 fd_set fs_read,fd_temp; FD_ZERO(&fs_read); FD_SET(fd, &fs_read); //设置fd,然后设置select参数 struct timeval time; time.tv_sec = 10; time.tv_usec = 0; //使用select实现多路复用 int result; while(1) { fd_temp = fs_read; result = select(fd +1, &fd_temp, (fd_set *)0, (fd_set *)0, &time);/*(struct timeval *) 0);*/ int len; for(int i=0; i<fd+1; i++) { if(FD_ISSET(i, &fd_temp)) { //开始接收数据并进行打印 len = read(fd, recv_buf, data_len); if(len > 0) { recv_buf[len] = '\0'; printf("recv buff: %s \n", recv_buf); }else { printf("not recv some buff, wait... \n"); } } } sleep(1); } return 0; } //按照一定的设置打开 COM口,这里的com口请传参传入,传入是发送还是接收的标志 int linux_serial_port_init(char * dev_port, int speed, int flow_ctrl, int databits, int stopbits, int parity) { //打开端口 int fd; if((fd = serial_port_open(dev_port)) == -1) { return -1; } //设置端口 int err; do{ // err = serial_port_config(fd, 115200, 0, 8, 1, 'N'); err = serial_port_config(fd, speed, flow_ctrl, databits, stopbits, parity); // printf("set Port Exactly! \n"); if(err != 0) { printf(" set Port config error. \n"); }else { printf(" set Port config success. \n"); break; } sleep(1); }while(err == -1); if(err == -1) { close(fd); } return fd; //关闭端口 } //根据入参,实现发送和接收不同逻辑的处理 int linux_serial_execute_send_or_recv(char * dev_port, int flag) { int fd; fd = linux_serial_port_init(dev_port, 115200, 0, 8, 1, 'N'); if(fd == -1) { printf("open serial port error. \n"); return -1; } int len; char send_buf[256]; char recv_buf[256]; //flag 为0,则发送, 为1,则接收 if(flag == 0) { //输入内容,最大不超过160字节,fgets能吸收回车符,这样pc收到的数据就能自动换行 fgets(send_buf,256,stdin); for(int i=0; i<3; i++) { //从send_buf中发送 len = linux_serial_port_send(fd, send_buf, 160); if(len > 0) { printf(" %d time send %d data successful\n",i,len); }else { printf("send data error!\n"); } sleep(1); } serial_port_close(fd); return 0; } //循环一直从串口中读数据 if(flag == 1) { //接收放在接口里 这里后两个参数不用了 linux_serial_port_recv(fd, recv_buf, sizeof(recv_buf)); serial_port_close(fd); return 0; } } // int main(int argc, char *argv[]) // { // if(argc != 3) // { // printf("Usage: %s /dev/ttySn 0 #(send data)\n",argv[0]); // printf("Usage: %s /dev/ttySn 1 #1(receive data)\n",argv[0]); // printf("open failure : %s\n", strerror(errno)); // return -1; // } // if(0 == strcmp(argv[2],"0")) // { // linux_serial_execute_send_or_recv(argv[1], 0); // } // if(1 == strcmp(argv[2],"1")) // { // linux_serial_execute_send_or_recv(argv[1], 1); // } // printf("Usage: %s /dev/ttySn 0/1 #1(receive data)\n",argv[0]); // return 0; // }