MCU中如何利用串口通信,增加AT指令框架

  • 第一步,通过串口与PC端建立通信
  • 第二步,根据PC端发来的AT指令,MCU执行相应代码
    主要是解析PC端发来的字符串,也就是获取字符串、处理字符串、以及分析字符串。

1. 串口通信

用到的是DMA串口通信,收发字符串数据时,无需占用CPU资源。
首先在cubeMax配置好串口

  • 配置波特率、异步模式等,一般修改波特率即可
    在这里插入图片描述

  • 添加DMA
    111

  • 打开DMA中断
    在这里插入图片描述

配置完成后,点击生成代码后,需要在两个位置添加代码。

  • 位置一:串口的初始化函数内
    在这里插入图片描述
    extern byte_t pcUartBufDMA[PC_UART_BUFFER_MAX];//使能串口接收DMAHAL_UART_Receive_DMA(&huart2, pcUartBufDMA, PC_UART_BUFFER_MAX);//使能IDLE中断__HAL_UART_ENABLE_IT(&huart2, UART_IT_IDLE);//清除空闲标志位,防止中断误入__HAL_UART_CLEAR_IDLEFLAG(&huart2);
  • 位置二:串口的中断处理函数中
    在这里插入图片描述
    经过以上的配置,此时MCU应该可以接收到PC发送的字符串,但PC端不会收到回复,因为MCU只接收了数据,没有处理和分析。

2. 指令解析

  • 首先做一些类型定义
enum
{AT_ERR = -1,                //指令异常AT_OK = 0                   //指令正常
};typedef enum
{QUERY_CMD   = 0x01,          //查询命令SET_CMD     = 0x02,          //设置命令EXECUTE_CMD = 0x03,          //执行命令
} cmd_t;typedef int (*deal_func)(cmd_t opt, int argc, char *argv[]);    //回调函数typedef struct
{char *atCmdStr;                 //AT指令deal_func atFunc;               //AT指令执行函数
} pcAtCmd_t;
  • 可扩展的AT指令表
#define AT_TABLE_SIZE   (sizeof(pcAtTable) / sizeof(pcAtCmd_t))
#define ARGC_LIMIT      0x10    /* 参数限制个数 */const pcAtCmd_t pcAtTable[] =
{{"AT+Z",                pcAtDevReset},{"AT+LOG",         		pcAtLogSw},...
};
  • 指令解析函数
    传入指令字符串pdata和字符串长度size,首先将指令字符转成大写,而后判断指令类型,根据不同类型给函数指针传入相应的参数。
//AT指令解析
int pcAtCmdParse(uint8_t * pdata, uint16_t size)
{int ret  = AT_ERR;uint16_t offset = 0;int index = 0;int argc = ARGC_LIMIT;char *argv[ARGC_LIMIT] = { (char *)0 };char *ptr = NULL;atStringToUpper((char *)pdata);if (strstr((const char *)pdata, "AT") == NULL){ret  = AT_ERR;goto at_end;}//AT\r 测试指令回复if ((pdata[0] == 'A') && (pdata[1] == 'T') && (pdata[2] == '\r')){ret  = AT_OK;goto at_end;}/* 查找匹配的执行指令 */ret = pcAtCmdSearch(pdata, size);if (AT_ERR == ret){goto at_end;}index = ret;/* 定位到指令后内容,即W后面的字符AT+SW=1|*/ptr = strstr((const char *)pdata, pcAtTable[index].atCmdStr) + strlen(pcAtTable[index].atCmdStr);/* AT+SW?\r 是查询命令 */if ((ptr[0] == '?') && (ptr[1] == '\r')){if (NULL != pcAtTable[index].atFunc){ret = pcAtTable[index].atFunc(QUERY_CMD, 0, NULL);}}/* AT+SW=1 是设置命令 */else if (ptr[0] == '=')    {//移动到‘=’后面,计算剩余字符串长度,并分割字符串ptr += 1;offset = ptr - (char *)pdata;argc = atStringSplit((char*)ptr, size - offset, ',', argv, argc);if (NULL != pcAtTable[index].atFunc){ret = pcAtTable[index].atFunc(SET_CMD, argc, argv);}}/* AT+SW 是执行命令 */else if (ptr[0] == '\r'){if (NULL != pcAtTable[index].atFunc){ret = pcAtTable[index].atFunc(EXECUTE_CMD, 0, NULL);}}else{ret = AT_ERR;}at_end:if (AT_ERR == ret){pcAtRespondError();}else{pcAtRespondOk();}return ret;
}
  • 指令解析函数中调用的三个函数
//at小写转大写
static void atStringToUpper(char *strp)
{while ( *strp != '\0'){if (*strp >= 'a' && *strp <= 'z'){*strp -= ('a' - 'A');}strp++;}
}//查找指令表中对应的指令
static int16_t pcAtCmdSearch(uint8_t *pStr, int16_t len)
{int ret = AT_ERR;int16_t index = 0;int16_t n = 0;for (index = 0; index < AT_TABLE_SIZE; index++){n = strlen(pcAtTable[index].atCmdStr);if (!strncmp((char *)pStr, pcAtTable[index].atCmdStr, n)){ret = index;break;}}return ret;
}//at分割字符串  0,1,2
static int atStringSplit(char *strp, uint32_t strsize, char ch, char *argv[], uint32_t argcMax )
{int ch_index = 0;int argc_index = 0;uint8_t splitflag = 0;if ((!strsize) || (!argcMax)){return 0;}//取第一个数据argv[argc_index++] = &strp[ch_index];for (ch_index = 0; ch_index < strsize; ch_index++){if (strp[ch_index] == '\r'){break;}else if (strp[ch_index] == ch){strp[ch_index] = '\0';splitflag = 1;}else if (splitflag == 1){splitflag = 0;argv[argc_index++] = &strp[ch_index];if (argc_index >= argcMax){break;}}else{splitflag = 0;}}return argc_index;
}
  • 还有就是AT指令表中,回调函数的实现了
//指令 设备重启
int pcAtDevReset(cmd_t opt, int argc, char *argv[])
{int ret  = AT_ERR;if (QUERY_CMD == opt)       //查询变量{}else if (SET_CMD == opt)    //设置变量{}else if (EXECUTE_CMD == opt) //执行功能{mcuSoftReset();ret = AT_OK;}return ret;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/40961.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何使用 3D 建模库在 C# 中将 3DS 转换为 USDZ?

USDZ/USD是一种 3D 文件格式&#xff0c;被广泛用于跨平台共享 3D 资产。另一方面&#xff0c;3DS是另一种以块形式存储数据的 3D 文件格式。在某些情况下&#xff0c;您需要将3DS 文件转换为 USDZ/USD文件格式。因此&#xff0c;本篇博文介绍了一个功能丰富的3D 建模库&#x…

【基于R语言群体遗传学】-6-表型计算等位基因频率、最大似然估计方法

到目前为止&#xff0c;我们主要讨论了等位基因和基因型频率&#xff0c;以及我们如何可以从一个推断出另一个。但是&#xff0c;如果我们不知道等位基因频率&#xff0c;只知道种群中存在哪些表型呢&#xff1f;如果我们足够幸运&#xff0c;知道哪些表型对应哪些基因型&#…

一键安装部署,在 Ubuntu 服务器上快速搭建基于 Ghost CMS的网站

我们在上一篇内容中讲过&#xff0c;如何使用 Helm 在 Kubernetes 集群上安装 WordPress&#xff0c;创建高可用性网站。而这次我们将基于另一个流行的内容管理系统 Ghost CMS 在 DigitalOcean 云主机进行建站。 Ghost 也是开源的内容管理系统&#xff08;CMS&#xff09;&…

C#知识|项目的实施过程及通用三级架构的搭建笔记

哈喽,你好啊,我是雷工! 01 项目需求分析 根据与需求方沟通,分析需求,一般都有需求分析师来进行项目需求收集与分析。 根据需求文档进行项目功能设计。 02 框架的选择 ①小项目可以根据需求选择两层或三层结构。 ②中型大型项目,至少需要三层架构和其他架构的组合。 03 框…

Spring学习03-[Spring容器核心技术IOC学习进阶]

IOC学习进阶 Order使用Order改变注入顺序实现Ordered接口&#xff0c;重写getOrder方法来改变自动注入顺序 DependsOn使用 Lazy全局设置-设置所有bean启动时候懒加载 Scopebean是单例的&#xff0c;会不会有线程安全问题 Order 可以改变自动注入的顺序 比如有个animal的接口&a…

NEMU模拟器的gdb调试和指令调试

NEMU模拟器的gdb调试和指令调试 1 通过gdb调试NEMU1.1 编译NEMU1.2 gdb调试 2 通过NEMU调试指令 关于如何编译NEMU&#xff0c;以及编译MySBIBenOS固件&#xff0c;运行等前置知识&#xff0c;可参考 《NEMU模拟器源码编译与使用》。 1 通过gdb调试NEMU 1.1 编译NEMU 当我使…

E2.【C语言】练习:static部分

#include <stdio.h> int sum(int a) {int c 0;static int b 3;c 1;b 2;return (a b c); } int main() {int i;int a 2;for (i 0; i < 5;i){printf("%d ", sum(a));} } 求执行结果 c是auto类变量(普通的局部变量)&#xff0c;自动产生&#xff0c…

Windows 11 操作无法完成(错误 0x00000709)。

这里写自定义目录标题 环境错误一错误二错误三重点 环境 共享端&#xff1a;Win11 专业版 23H2 本地端&#xff1a;Win11 专业版 23H2 错误一 操作无法完成(错误 0x00000709)。 再次检查打印机名称&#xff0c;并确保打印机已连接到网络。 解决&#xff1a; 组策略设置 打开…

sql查询 只取某字段重复数据中的一条

一. 前提条件 某表的主键由两个字段A、B构成&#xff08;或者更多&#xff09;&#xff0c;任何其中一个字段都可能具有重复的数据。 需要只取字段A所有重复数据中的一条构成查询结果&#xff0c;也就是字段A取到所有的可能取值且无重复。 二. 方法一&#xff08;where ... …

Appium环境搭建,华为nova8鸿蒙系统(包括环境安装,环境配置)(一)

1.安装代码工具包 appium python client pip install appium-python-client 2.安装JDK 参考链接: ant+jmeter+jenkins从0实现持续集成(Windows)-CSDN博客 3.下载并安卓SDK 下载地址:AndroidDevTools - Android开发工具 Android SDK下载 Android Studio下载 Gradle下载…

香橙派AIpro初体验:搭建无线随身NAS

文章目录 引言2. 香橙派 AIPro概述3. 开发准备3.0 烧录镜像3.1 需要准备的硬件3.2 需要准备的软件3.3 启动并连接香橙派 AIPro3.3.1 初始化启动香橙派 AIPro3.3.2 无线连接香橙派 AIPro3.3.3.3 VNC连接香橙派 AIPro 3.4 设置固定ip3.4.1 设置开机自动连接WIFI3.4.1 设置香橙派 …

松下Panasonic机器人维修故障原因

松下机器人伺服电机是许多工业自动化设备的关键组成部分。了解如何进行Panasonic工业机械臂电机维修&#xff0c;对于确保设备正常运行至关重要。 【松下焊接机器人维修案例】【松下机器人维修故障排查】 一、常见松下工业机械手伺服电机故障及原因 1. 过热&#xff1a;过热可…

【BUUCTF-PWN】6-jarvisoj_level0

64位&#xff0c;开启了NX保护 运行效果如下&#xff1a; main函数&#xff1a; vulnerable_function()函数 buf变量长度为128&#xff0c;但是read可以读入0x200长度的字符&#xff0c;存在栈溢出&#xff0c;需要覆盖的长度为0x808 寻找后门函数 这里可以直接用栈…

计算机的错误计算(二十一)

摘要 两个不相等数相减&#xff0c;差为0&#xff1a; ? 在计算机的错误计算&#xff08;十九&#xff09;中&#xff0c;高中生小明发现本应为0的算式结果不为0. 今天他又发现对本不为0的算式&#xff0c;计算机的输出为0. 在 Python 中计算 &#xff1a; 则输出为0. 若用 C…

Android-卷积神经网络(Convolutional Neural Network, CNN)

一个复杂且在Android开发中常见的算法是图像处理中的卷积神经网络(Convolutional Neural Network, CNN)。CNN被广泛用于图像识别、物体检测和图像分割等任务,其复杂性在于需要处理大量的图像数据、复杂的神经网络结构和高效的计算。 1. 卷积操作(Convolution) 数学原理:…

CSS学习(三大特性 盒子模型)

目录 Emmet语法 1.快速生成HTML结构语法 2.快速生成CSS样式语法 CSS的复合选择器 后代选择器 子选择器 并集选择器 伪类选择器 链接伪类选择器 focus伪类选择器 CSS的三大特性 层叠性 继承性 优先级 CSS盒子模型 组成 边框 边框 内边距 外边距 块级盒子水…

7_1_SVPWM概述

1、SPWM 正弦脉宽调制法&#xff08;SPWM&#xff09;是将每一正弦周期内的多个脉冲作自然或规则的宽度调制&#xff0c;使其依次调制出相当于正弦函数值的相位角和面积等效于正弦波的脉冲序列&#xff0c;形成等幅不等宽的正弦化电流输出。 通过调整占空比使等效电流近似为正弦…

classin视频下载提取为mp4教程

最近在上classin网课&#xff0c;无奈网课视频要过期了&#xff0c;所以想保存下来&#xff01; 下面介绍提取的教程 我们可以绕过最开始的握手&#xff0c;就是先播放了一段时间后&#xff0c;再打开抓包&#xff0c;回到Classin播放后&#xff0c;就可以获得网课链接了 直接打…

软考-系统架构设计师[九年]上岸感想

2016年就开始参系统架构设计师的考试了&#xff0c;经历七次考试终于成功上岸&#xff0c;分享下自己这么多次考试失败的经验&#xff0c;希望大家可以少踩坑&#xff0c;一次通过考试 重点 如果你不想继续读下去&#xff0c;看完这段就行。 1.一定要知道最新的考试范围&…

Java通过GeoLite2-City.mmdb 进行IP信息查询地理定位和经纬度筛选。

引入依赖 <dependency><groupId>com.maxmind.geoip2</groupId><artifactId>geoip2</artifactId><version>4.2.0</version> </dependency>下载数据文件&#xff1a;https://download.lin2ur.cn/GeoLite2/ package com.cqclo…