首页 > 其他分享 >STM32/GD32/AT32 通过AT命令解析工具

STM32/GD32/AT32 通过AT命令解析工具

时间:2024-11-21 23:09:09浏览次数:1  
标签:char const STM32 命令 command MP3 GD32 printf AT32

  • 这是一个针对 STM32/GD32/AT32 等芯片的 AT 命令解析工具。其主要功能是从串口接收以 “\r\n” 结尾的命令数据,并将其解析为对应的命令,然后根据命令映射表调用相应的处理函数来执行特定操作。

1. 使用方式

  1. 将串口的数据放入 bsp_parseCommand 函数,并且传入数组和数据长度,此函数会自动保存传入的数据,所以不需要一次传入一包完整的数据。如果数据超出缓冲区大小,会自动清零。

  2. 修改命令映射表,将需要解析的命令字符串和命令的回调函数传入,在匹配到字符串之后就会自动调用回调函数

    CommandMapping commandMap[MAX_COMMAND_COUNT] = {
        {"AT+COMMAND1", handleATCommand1},
        {"AT+COMMAND2", handleATCommand2},
        {"AT+RESET", handleATReset},
        // 查看固件信息和重启原因
        {"AT+FirmwareInfo", PrintFirmwareInfoC},
        // 查看任务信息
        {"AT+TaskInfo", PrintTaskInfo},
        {NULL, NULL} // 结束标记
    };
    
  3. 如果需要修改命令长度的缓冲区,请修改 MAX_COMMAND_LENGTH 的定义

  4. 如果需要修改命令映射表数组的大小,请修改 MAX_COMMAND_COUNT

  5. 可以在匹配的字符串后添加参数,在回调中可自行解析。具体看下方代码

2. 运行流程

  • 数据接收函数
    • 进入条件:从串口接收到字符数据。
    • 状态判断:每次接收到一个字符后,会进行判断。
      • 如果接收到的字符是 \n 或者 \r,且缓冲区索引 bufferIndex 大于 0,意味着接收到了可能完整的命令(以 \r\n 结尾),此时进入 “命令解析执行状态”。
      • 如果接收到的字符不是 \r\n,并且缓冲区索引 bufferIndex 小于 MAX_COMMAND_LENGTH - 1,则将该字符存入命令缓冲区 commandBuffer,并将 bufferIndex 加 1,继续保持在 “数据接收状态” 等待下一个字符输入。
      • 如果接收到的字符不是 \r\n,但缓冲区索引 bufferIndex 已经达到 MAX_COMMAND_LENGTH - 1,表示命令缓冲区即将溢出,此时输出 “Command buffer overflow” 提示信息,然后将 bufferIndex 重置为 0,继续等待新的字符输入,仍处于 “数据接收状态”。
  • 命令解析函数:
    • 进入条件:在 “数据接收状态” 下接收到 \n 或者 \r 且缓冲区有有效数据(bufferIndex > 0)。
    • 状态描述
      • 首先将命令缓冲区 commandBuffer 中的字符序列以 \0 结尾,形成完整的字符串形式的命令。
      • 然后通过 parseAndExecuteCommand 函数遍历命令映射表 commandMap,对比接收到的命令字符串与映射表中的命令。
        • 如果找到匹配的命令,输出 “Executing command: [具体命令]” 信息,并调用对应的处理函数执行相关操作,之后进入 “初始状态”,等待下一轮的串口数据输入。
        • 如果遍历完整个命令映射表都没有找到匹配的命令,输出 “Unknown command: [具体命令]” 信息,然后进入 “初始状态”,继续等待新的串口数据输入。

3. 代码例程

/*************************************************************************************************************************
 * CopyRight:           PlayerPencil FreeRtos通用库/不使用操作系统也可以使用  
 * Filename:            bsp_command.c
 * ContentIntroduction:   
 *                      该文件实现了从串口接收 \r\n 结尾的命令,并根据命令调用相应的处理函数
 *                      CommandMapping commandMap[MAX_COMMAND_COUNT],为命令映射表,用于存储命令和处理函数的映射关系
 *                      在调用命令之后,也会把匹配到的字符串传入,可以匹配后面的参数。如:
 *                      const char *volumeStr = command + strlen("AT+MP3Volume=");
 *                      uint8_t volume = atoi(volumeStr);volume就为需要的值
 *                      用户调用bsp_parseCommand,可以传入1个或者多个字符,当检测到 \r\n 时,会调用相应的处理函数。里面有一个缓冲区
 *                      根据 MAX_COMMAND_LENGTH 来设定,MAX_COMMAND_COUNT为最大的命令数量-1.
 *                     
 *                      
 *  FileHistory:
 *   VersionNumber      Date:           Author:             Content:
 *       01a           2024-11-17       PlayerPencil         创建了该文件,完成了基础功能的测试
 *      
 * 
 * 
 * 
 *****************************************************************************************************************************/

#include "bsp_command.h"
#include <string.h>
#include "MP3_Player.h"

#define MAX_COMMAND_LENGTH          20
#define MAX_COMMAND_COUNT           15

// 命令缓冲区
static char commandBuffer[MAX_COMMAND_LENGTH];
static uint8_t bufferIndex = 0;


void handleATCommand1(const char *command) {
    printf("Handling AT+COMMAND1: %s\n", command);
}

void handleATCommand2(const char *command) {
    printf("Handling AT+COMMAND1: %s\n", command);
}

void handleATReset(const char *command) {
    // 系统复位
    printf("Handling AT+RESET: %s\n", command);
    NVIC_SystemReset();
}

void PrintTaskInfo(const char *command) {
    // 动态分配内存
    char *taskListBuffer = (char *)pvPortMalloc(512);
    printf("\r\n");
    printf("\r\n*************** Task Information ***************\r\n");
    if (taskListBuffer == NULL) {
        printf("Failed to allocate memory for task list buffer\n");
        return;
    }
    size_t freeHeapSize = xPortGetFreeHeapSize();
    size_t minEverFreeHeapSize = xPortGetMinimumEverFreeHeapSize();
    vTaskList(taskListBuffer);
    printf("TaskName   TaskState   Priority  stack    TaskNum\r\n");
    printf("%s", taskListBuffer);
    printf("\r\n");
    DEBUG_PRINTF(LEVEL_DEBUG, "Current free heap size: %u bytes\n", (unsigned int)freeHeapSize);
    DEBUG_PRINTF(LEVEL_DEBUG, "Minimum ever free heap size: %u bytes\n", (unsigned int)minEverFreeHeapSize);
    printf("*************** Task Information ***************\r\n");
    printf("\r\n");
    vPortFree(taskListBuffer);
}

void PrintFirmwareInfoC(const char *command)
{
    PrintFirmwareInfo();
}

void handleATMP3Command(const char *command) {
    // 提取歌曲名
    const char *songName = command + strlen("AT+MP3=");
    // printf("Playing song: %s\n", songName);
    // 在这里添加播放歌曲的代码
    // playSong(songName);
    if (!MP3_Play(songName)) {
        // printf("Failed to play song: %s\n", songName);
        DEBUG_PRINTF(LEVEL_ERROR, "Failed to play song: %s\n", songName);
    }else{
        // printf("Playing song: %s\n", songName);
        DEBUG_PRINTF(LEVEL_INFO, "Playing song: %s\n", songName);
    }
}

void handleATMP3_Pause(const char *command) {
    DEBUG_PRINTF(LEVEL_INFO, "MP3 Pause\n");
    MP3_Pause();
}

void handleATMP3_Resume(const char *command) {
    DEBUG_PRINTF(LEVEL_INFO, "MP3 Resume\n");
    MP3_Resume();
}


void handleATMP3_Stop(const char *command) {
    DEBUG_PRINTF(LEVEL_INFO, "MP3 Stop\n");
    MP3_Stop();
}

void handleATMP3Time(const char *command) {
    uint16_t time = MP3_GetTime();
    DEBUG_PRINTF(LEVEL_INFO, "Current play time: %d seconds\n", time);
}

void handleATMP3Volume(const char *command) {
    // 提取音量值
    const char *volumeStr = command + strlen("AT+MP3Volume=");
    DEBUG_PRINTF(LEVEL_INFO, "Setting volume to: %s\n", volumeStr);
    uint8_t volume = atoi(volumeStr);
    DEBUG_PRINTF(LEVEL_INFO, "Setting volume to: %d\n", volume);
    MP3_Pause();
    VS1053_SetVolume(255-volume, 255-volume);
    MP3_Resume();
}

// 定义命令映射表
CommandMapping commandMap[MAX_COMMAND_COUNT] = {
    {"AT+COMMAND1", handleATCommand1},
    {"AT+COMMAND2", handleATCommand2},
    {"AT+RESET", handleATReset},
    // 查看固件信息和重启原因
    {"AT+FirmwareInfo", PrintFirmwareInfoC},
    // 查看任务信息
    {"AT+TaskInfo", PrintTaskInfo},
    // 播放MP3
    {"AT+MP3=", handleATMP3Command},
    // MP3 暂停播放
    {"AT+MP3Pause", handleATMP3_Pause},
    // MP3 继续播放
    {"AT+MP3Resume", handleATMP3_Resume},
    // MP3 停止播放
    {"AT+MP3Stop", handleATMP3_Stop},
    // 查看当前播放时间
    {"AT+MP3Time", handleATMP3Time},
    // 设定播放音量
    {"AT+MP3Volume=", handleATMP3Volume},
    {NULL, NULL} // 结束标记
};


// 解析并执行命令
void parseAndExecuteCommand(const char *command) {
    for (int i = 0; commandMap[i].command != NULL; i++) {
        if (strncmp(command, commandMap[i].command, strlen(commandMap[i].command)) == 0) {
            printf("Executing command: %s\n", command);
            commandMap[i].handler(command);
            return;
        }
    }
    printf("Unknown command: %s\n", command);
}

// 处理逐字符或多字符输入
void bsp_parseCommand(const uint8_t *input, uint8_t length) {
    for (uint8_t i = 0; i < length; i++) {
        if (input[i] == '\n' || input[i] == '\r') {
            // 命令结束,解析命令
            if (bufferIndex > 0) {
                commandBuffer[bufferIndex] = '\0'; // 终止字符串
                parseAndExecuteCommand(commandBuffer);
                bufferIndex = 0; // 重置缓冲区索引
            }
        } else if (bufferIndex < MAX_COMMAND_LENGTH - 1) {
            // 存储字符到缓冲区
            commandBuffer[bufferIndex++] = input[i];
        } else {
            // 缓冲区溢出处理
            printf("Command buffer overflow\n");
            bufferIndex = 0; // 重置缓冲区索引
            break;
        }
    }
}

/*************************************************************************************************************************
 * CopyRight:           PlayerPencil FreeRtos通用库  
 * Filename:            bsp_command.h
 * ContentIntroduction:   
 *                      该文件实现了从串口接收 \r\n 结尾的命令,并根据命令调用相应的处理函数
 *                      CommandMapping commandMap[MAX_COMMAND_COUNT],为命令映射表,用于存储命令和处理函数的映射关系
 *                      在调用命令之后,也会把匹配到的字符串传入,可以匹配后面的参数。如:
 *                      const char *volumeStr = command + strlen("AT+MP3Volume=");
 *                      uint8_t volume = atoi(volumeStr);volume就为需要的值
 *                     
 *                      
 *  FileHistory:
 *   VersionNumber      Date:           Author:             Content:
 *       01a           2024-11-17       PlayerPencil         创建了该文件,完成了基础功能的测试
 *      
 * 
 * 
 * 
 * 
 *****************************************************************************************************************************/
#ifndef __BSP_COMMAND_H
#define __BSP_COMMAND_H
#include "bsp.h"


typedef void (*CommandHandler)(const char *command);

typedef struct {
    const char *command;
    CommandHandler handler;
} CommandMapping;


void bsp_parseCommand(const uint8_t *input, uint8_t length);
#endif // !__BSP_COMMAND_H

标签:char,const,STM32,命令,command,MP3,GD32,printf,AT32
From: https://www.cnblogs.com/PlayerPencil/p/18561762

相关文章

  • AT32F403a/407开启RAM扩展,增加RAM到224K字节
    打开artery的AN0026应用笔记(AN0026_Extending_SRAM_in_User's_Program_ZH_V2.0.0.pdf),可以看到AT32的出厂预设的SRAM的大小为96K字节,可以修改EOPB0扩展到224K字节。EOPB0的寄存器设置如下,根据下方可知需要将EOPB0的0-7位设置位0xFE。但是在设置EOPB0之后,必须执行系统复位的命......
  • STM32相关知识——DMA的基本概念与工作原理详解
    STM32相关知识——DMA的基本概念与工作原理详解目录什么是DMADMA的作用DMA与CPU的区别DMA的工作原理DMA控制器数据传输流程DMA传输模式优先级和通道管理STM32中DMA的应用外设与内存之间的数据传输内存与内存的数据传输示例应用场景数学公式数据传输速率计算总线带宽......
  • STM32定时器知识——看门狗详解
    STM32定时器知识——看门狗详解目录引言STM32看门狗概述看门狗的工作原理看门狗的主要组成4.1独立看门狗(IWDG)4.2窗口看门狗(WWDG)看门狗的主要参数5.1时钟源5.2预分频器5.3重载值看门狗的配置步骤6.1配置独立看门狗(IWDG)6.2配置窗口看门狗(WWDG)看门狗的数学公式......
  • STM32F103嵌套向量中断控制器
    一、STM32F103中断介绍1.1什么是中断中断:打断CPU执行正常的程序,转而处理紧急程序,然后返回原暂停的程序继续运行;举例:当你正在写作业时,做到一半又去吃饭,吃完饭后又回来接着原来的作业继续完成。对于单片机来说,中断是指CPU正在处理某个事件A,发生了另一件事件B,请求CPU迅速去处理......
  • STM32(hal库)中HAL_ADC_PollForConversion 是 如何执行的?
    HAL_ADC_PollForConversion 是STM32HAL库中的一个函数,用于轮询(poll)ADC(模数转换器)的转换完成状态。这个函数会阻塞调用它的线程,直到ADC转换完成。以下是该函数的工作原理和执行步骤的详细解释:函数原型c复制代码HAL_StatusTypeDefHAL_ADC_PollForConversion(ADC_HandleT......
  • STM32 HAL 库硬件 I2C 驱动 MPU6050
    MPU6050简介驱动文件mpu6050.h#ifndefINC_MPU6050_H_#defineINC_MPU6050_H_#include"i2c.h"//I2C通道配置#definehI2C&hi2c2//设备地址配置#defineMPU6050_ADDRESS_Write 0xD0//0x68左移一位补0#defineMPU6050_ADDRESS_Read0xD1//0x68左移一位补1......
  • stm32f4 使用FreeRTOS例程
    文章目录引言开发环境搭建配置STM32CubeMX编写FreeRTOS任务代码编译与调试结论stm32f4使用FreeRTOS例程引言随着物联网(IoT)和嵌入式系统的发展,实时操作系统(RTOS)在资源受限的嵌入式设备上得到了广泛应用。FreeRTOS作为一种开源的、可裁剪的RTOS,因其轻量级、高可靠......
  • STM32F103系统时钟配置
    时钟是单片机运行的基础,时钟信号推动单片机内各个部分执行相应的指令。时钟系统就是CPU的脉搏,决定CPU速率,像人的心跳一样只有有了心跳,人才能做其他的事情,而单片机有了时钟,才能够运行执行指令,才能够做其他的处理(点灯,串口,ADC),时钟的重要性不言而喻。一、STM32F103时钟介绍STM32......
  • 基于STM32的独立按键控制LED灯Proteus仿真设计(仿真+程序+设计报告+讲解视频)
    基于STM32的独立按键控制LED灯Proteus仿真设计(仿真+程序+设计报告+讲解视频)仿真图proteus8.9程序编译器:keil5编程语言:C语言设计编号:C00951.主要功能1.使用Proteus仿真软件和STM32F103系列芯片设按键扫描电路。2.开始仿真后LED1和LED2点亮,按键控制熄灭/点亮3.使用......
  • STM32(hal库)中,为什么DMA没有MSP函数?
            在STM32HAL库中,DMA(直接存储器访问)并没有像其他某些外设(如USART、SPI等)那样拥有专门的MSP(MCUServicesPackage)初始化函数,这主要是由于DMA的特性和HAL库的设计哲学所决定的。        首先,需要明确的是,MSP函数通常是由STM32CubeMX工具为特定的外设生成......