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

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

1. 串口通信

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

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

  • 添加DMA
    111

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

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

  • 位置一:串口的初始化函数内
    在这里插入图片描述
    extern byte_t pcUartBufDMA[PC_UART_BUFFER_MAX];
	
	//使能串口接收DMA
    HAL_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.coloradmin.cn/o/1894798.html

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

相关文章

AGI系列(7)Reflection 在 AI agent 中的应用实例

斯坦福大学教授吴恩达一直非常推崇AI Agent,之前他提出过AI Agent的四种工作模式,分别是Reflection(反思)、Tool use(工具使用)、Planning(规划)和Multi-agent collaboration(多智能体协同)。 近日,他又开源了一个翻译 AI Agent, 他认为 AI 智能体机器翻译对改进传…

spring6框架解析(by尚硅谷)

文章目录 spring61. 一些基本的概念、优势2. 入门案例实现maven聚合工程创建步骤分析实现过程 3. IoC&#xff08;Inversion of Control&#xff09;基于xml的bean环境搭建获取bean获取接口创建实现类依赖注入 setter注入 和 构造器注入原生方式的setter注入原生方式的构造器注…

electron-vue自定义标题

1.在主进程background.js或者main.js中主窗口配置frame: false async function createWindow() {Menu.setApplicationMenu(null);// Create the browser window.const win new BrowserWindow({width: 1000,height: 600,resizable: false,frame: false,webPreferences: {nodeI…

Python基础语法(与C++对比)(持续更新ing)

代码块 Python在统一缩进体系内&#xff0c;为同一代码块C{...}内部的为同一代码块 注释 Python 单行注释&#xff1a;#... 多行注释&#xff1a;... C 单行注释&#xff1a;//... 多行注释: /*...*/ 数据类型 1. Python数据类型 Python中支持数字之间使用下划线 _ 分割…

docker容器技术、k8s的原理和常见命令、用k8s部署应用步骤

容器技术 容器借鉴了集装箱的概念&#xff0c;集装箱解决了什么问题呢&#xff1f;无论形状各异的货物&#xff0c;都可以装入集装箱&#xff0c;集装箱与集装箱之间不会互相影响。由于集装箱是标准化的&#xff0c;就可以把集装箱整齐摆放起来&#xff0c;装在一艘大船把他们…

昇思学习打卡-5-基于Mindspore实现BERT对话情绪识别

本章节学习一个基本实践–基于Mindspore实现BERT对话情绪识别 自然语言处理任务的应用很广泛&#xff0c;如预训练语言模型例如问答、自然语言推理、命名实体识别与文本分类、搜索引擎优化、机器翻译、语音识别与合成、情感分析、聊天机器人与虚拟助手、文本摘要与生成、信息抽…

通过 Power Automate 以提升的权限运行 Power Apps 连接

使用Power Apps在Sharepoint列表中新建或编辑项比较简单&#xff0c;就是创建窗体&#xff0c;连接Sharepoint列表&#xff0c;添加个按钮&#xff0c;触发条件为Submit(form)。 填写信息&#xff0c;点击按钮即可新建项 但使用过程中&#xff0c;发现运行此应用的用户&#xf…

朗新天霁eHR GetFunc_code.asmx SQL注入致RCE漏洞复现

0x01 产品简介 朗新天霁人力资源管理系统(LongShine eHR)是一款由北京朗新天霁软件技术有限公司研发的人力资源管理系统,该产品融合了国外先进的人力资源管理理念和国内大量人力资源管理实践经验,是国内功能较为全面、性价比较高的人力资源管理系统之一,系统凭借其集成化…

如何通过IP地址查询地理位置及运营商信息

在数字时代&#xff0c;IP地址&#xff08;Internet Protocol Address&#xff0c;互联网协议地址&#xff09;已经成为我们日常网络活动的重要组成部分。每台连接到互联网的设备都被分配了一个唯一的IP地址&#xff0c;它不仅可以识别设备&#xff0c;还可以揭示设备的地理位置…

以太网协议介绍——UDP

注&#xff1a;需要先了解一些以太网的背景知识&#xff0c;方便更好理解UDP协议、 以太网基础知识一 以太网基础知识二 UDP协议 UDP即用户数据报协议&#xff0c;是一种面向无连接的传输层协议&#xff0c;属于 TCP/IP 协议簇的一种。UDP具有消耗资源少、通信效率高等优点&a…

MySQL 9.0 GA 来了!

2024 年 7 月 2 日&#xff0c;MySQL 9.0 GA 版本正式发布。还记得 MySQL 8.0 版本正式发布于 2018 年 4 月 19 日&#xff0c;中间经过了 6 年之久&#xff0c;MySQL 官方终于发布了大版本号变更得 9.0 版本&#xff0c;接下来由我给大家介绍 MySQL 在 9.0 版本中有哪些新的变…

经典低功耗四通道运算放大器LM324

前言&#xff1a; SOP14封装LM324 这个LM324运放有几十年的历史了吧&#xff1f;很普通&#xff0c;很常用&#xff0c;搞电路的避免不了接触运放&#xff0c;怎么选择运放&#xff0c;是工程师关心的问题吧&#xff1f; 从本文开始&#xff0c;将陆续发一些常用的运放&#xf…

2024 AI工程师世界博览会

6月24日至6月27日在旧金山举行的 AI 工程师世界博览会是AI 从业者和爱好者的首要活动之一。本次年度会议展示了人工智能技术的最新进展&#xff0c;并提供了对行业趋势的宝贵见解。 模型不是壁垒 大型语言模型&#xff08;LLMs&#xff09;的快速发展是会议的中心主题。OpenAI…

单片机软件架构连载(4)-结构体

枚举、指针、结构体&#xff0c;我愿称为C语言"三板斧"。 用人话来讲&#xff0c;几乎所有c语言高阶编程&#xff0c;都离不开这这3个知识点的应用。 今天站在实际产品常用的角度&#xff0c;给大家讲一下结构体。 1.结构体概念 结构体可以用来构建更复杂的数据结…

【病毒分析】假冒游戏陷阱:揭秘MBRlock勒索病毒及其修复方法

1.背景 在公众号文章中看到一篇名为《敲竹杠木马分析&#xff1a;虚假的植物大战僵尸杂交版》的文章&#xff0c;样本来源于某吧&#xff0c;对此我们对样本进行了提取分析。 文章链接&#xff1a;https://mp.weixin.qq.com/s/Up9u4DZtHnVNMiGBIHZzHw 2.恶意文件基础信息 文…

鸿蒙开发设备管理:【@ohos.update (升级)】

升级 说明&#xff1a; 本模块首批接口从API version 6开始支持。后续版本的新增接口&#xff0c;采用上角标单独标记接口的起始版本。开发前请熟悉鸿蒙开发指导文档&#xff1a;gitee.com/li-shizhen-skin/harmony-os/blob/master/README.md点击或者复制转到。 升级范围&…

Build a Large Language Model (From Scratch)附录B(gpt-4o翻译版)

来源&#xff1a;https://github.com/rasbt/LLMs-from-scratch?tabreadme-ov-file https://www.manning.com/books/build-a-large-language-model-from-scratch

上海-灵曼科技(面经)

上海-灵曼科技 hr电话面 个人简介 个人信息的询问 是否知道芋道框架 技术面 算法题 14. 最长公共前缀&#xff08;写出来即可&#xff09; 聊一下Docker Docker核心概念总结Docker实战 聊一下AOP Spring AOP详解 聊一下JWT JWT 基础概念详解JWT 身份认证优缺点分析 Spri…

智能猫砂盆到底哪家好用?自费实测聚宠、糯雪、CEWEY真实反馈!

快到夏天了&#xff0c;是不是还有人因为没挑选到喜欢的智能猫砂盆而苦恼着&#xff1f;太便宜怕不好用&#xff0c;太贵怕质量比不上价格。来来去去拖到现在还没决定&#xff0c;我作为养了四年猫的资深铲屎官&#xff0c;今天就来给大家传授经验&#xff0c;关于我是怎么从好…

记录通过Cloudflare部署属于自己的docker镜像源

引言 由于最近国内无法正常拉取docker镜像&#xff0c;然而找了几个能用的docker镜像源发现拉取回来的docker镜像不是最新的版本&#xff0c;部署到Cloudflare里Workers 和 Pages&#xff0c;拉取docker 镜像成功&#xff0c;故记录部署过程。 部署服务 登录Cloudflare后&…