com串口通信测试代码

简介: com串口通信测试代码

串口助手可以从这里下载: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;
// }
目录
相关文章
|
11月前
|
数据采集 机器学习/深度学习 大数据
行为检测代码(一):超详细介绍C3D架构训练+测试步骤
这篇文章详细介绍了C3D架构在行为检测领域的应用,包括训练和测试步骤,使用UCF101数据集进行演示。
339 1
行为检测代码(一):超详细介绍C3D架构训练+测试步骤
|
1月前
|
算法 IDE Java
Java 项目实战之实际代码实现与测试调试全过程详解
本文详细讲解了Java项目的实战开发流程,涵盖项目创建、代码实现(如计算器与汉诺塔问题)、单元测试(使用JUnit)及调试技巧(如断点调试与异常排查),帮助开发者掌握从编码到测试调试的完整技能,提升Java开发实战能力。
223 0
|
2月前
|
安全 Java 测试技术
Java 项目实战中现代技术栈下代码实现与测试调试的完整流程
本文介绍基于Java 17和Spring技术栈的现代化项目开发实践。项目采用Gradle构建工具,实现模块化DDD分层架构,结合Spring WebFlux开发响应式API,并应用Record、Sealed Class等新特性。测试策略涵盖JUnit单元测试和Testcontainers集成测试,通过JFR和OpenTelemetry实现性能监控。部署阶段采用Docker容器化和Kubernetes编排,同时展示异步处理和反应式编程的性能优化。整套方案体现了现代Java开发的最佳实践,包括代码实现、测试调试
118 0
|
5月前
|
存储 jenkins 测试技术
Apipost自动化测试:零代码!3步搞定!
传统手动测试耗时低效且易遗漏,全球Top 10科技公司中90%已转向自动化测试。Apipost无需代码,三步实现全流程自动化测试,支持小白快速上手。功能涵盖接口测试、性能压测与数据驱动,并提供动态数据提取、CICD集成等优势,助力高效测试全场景覆盖。通过拖拽编排、一键CLI生成,无缝对接Jenkins、GitHub Actions,提升测试效率与准确性。
391 11
|
5月前
|
人工智能 自然语言处理 测试技术
自然语言生成代码一键搞定!Codex CLI:OpenAI开源终端AI编程助手,代码重构+测试全自动
Codex CLI是OpenAI推出的轻量级AI编程智能体,基于自然语言指令帮助开发者高效生成代码、执行文件操作和进行版本控制,支持代码生成、重构、测试及数据库迁移等功能。
772 0
自然语言生成代码一键搞定!Codex CLI:OpenAI开源终端AI编程助手,代码重构+测试全自动
|
11月前
|
机器学习/深度学习 人工智能 监控
提升软件质量的关键路径:高效测试策略与实践在软件开发的宇宙中,每一行代码都如同星辰般璀璨,而将这些星辰编织成星系的过程,则依赖于严谨而高效的测试策略。本文将引领读者探索软件测试的奥秘,揭示如何通过精心设计的测试方案,不仅提升软件的性能与稳定性,还能加速产品上市的步伐,最终实现质量与效率的双重飞跃。
在软件工程的浩瀚星海中,测试不仅是发现缺陷的放大镜,更是保障软件质量的坚固防线。本文旨在探讨一种高效且创新的软件测试策略框架,它融合了传统方法的精髓与现代技术的突破,旨在为软件开发团队提供一套系统化、可执行性强的测试指引。我们将从测试规划的起点出发,沿着测试设计、执行、反馈再到持续优化的轨迹,逐步展开论述。每一步都强调实用性与前瞻性相结合,确保测试活动能够紧跟软件开发的步伐,及时适应变化,有效应对各种挑战。
|
7月前
|
人工智能 自然语言处理 测试技术
Potpie.ai:比Copilot更狠!这个AI直接接管项目代码,自动Debug+测试+开发全搞定
Potpie.ai 是一个基于 AI 技术的开源平台,能够为代码库创建定制化的工程代理,自动化代码分析、测试和开发任务。
560 19
Potpie.ai:比Copilot更狠!这个AI直接接管项目代码,自动Debug+测试+开发全搞定
|
8月前
|
前端开发 JavaScript 测试技术
使用ChatGPT生成登录产品代码的测试用例和测试脚本
使用ChatGPT生成登录产品代码的测试用例和测试脚本
214 35
|
12月前
|
Web App开发 JavaScript 前端开发
添加浮动按钮点击滚动到网页底部的纯JavaScript演示代码 IE9、11,Maxthon 1.6.7,Firefox30、31,360极速浏览器7.5.3.308下测试正常
添加浮动按钮点击滚动到网页底部的纯JavaScript演示代码 IE9、11,Maxthon 1.6.7,Firefox30、31,360极速浏览器7.5.3.308下测试正常
|
8月前
|
JavaScript 前端开发 Java
使用ChatGPT生成关于登录产品代码的单元测试代码
使用ChatGPT生成关于登录产品代码的单元测试代码
115 16