一.程序功能讲解:

功能1:开关广播

AT+ADVEN=1   开启广播 正确设置返回OK/r/n

AT+ADVEN=0   关闭广播 正确设置返回OK/r/n

AT+ADVEN=123  当参数长度不是1时返回ERROR:1(长度错误)

AT+ADVEN=2   当参数不是0和1是返回ERROR:2(参数错误)

功能2:设置广播名称

AT+ADVDATA=WCH 正确设置广播内容返回OK/r/n

名字内容最长29字节,超过29字节返回ERROR:1(长度错误)

功能3:设置配对密码

AT+PASS=123456 正确设置密码返回OK/r/n

密码必须是6位,非6位时返回ERROR:1(长度错误)

密码必须是纯数字,包含非数字内容返回ERROR:2(参数错误)

未知指令返回ERROR:3

缓冲区溢出返回ERROR:4

二.程序详细讲解:

1.串口初始化:

cmd_uart_init

2.串口中断接收:

UART_IRQHandler

3.串口指令处理:

Cmd_Process

4.指令细节处理:

CommandStatus HandleAdvertisingEnable和CommandStatus HandleAdvertisingData和HandlePasskey

ble_cmd.c:

#include "CONFIG.h"
#include "HAL.h"
#include "gattprofile.h"
#include "peripheral.h"
#include "stdlib.h"
#include "ble_adv.h"

// 硬件与缓冲区配置(确保触发阈值与读取长度一致)
#define TRIGGER_BYTE_COUNT 6       // 与UART_7BYTE_TRIG匹配为触发FIFO-1
#define RX_BUFFER_SIZE     64      // 缓冲区大小
#define MAX_ADVDATA_LENGTH 31      // 最大广播数据长度

/**
 * UART初始化:配置引脚、中断模式
 */
void cmd_uart_init(){
    GPIOA_SetBits(bTXD_0);
    GPIOA_ModeCfg(bTXD_0, GPIO_ModeOut_PP_5mA);  // TXD推挽输出(先置高)
    UART_Remap(ENABLE, UART_TX_REMAP_PA3, UART_RX_REMAP_PA2);  // 引脚重映射
    UART_DefInit();  // 默认初始化

#if 1  // 中断模式:接收数据后处理
    UART_ByteTrigCfg(UART_7BYTE_TRIG);  // 7字节触发中断(与TRIGGER_BYTE_COUNT一致)
    UART_INTCfg(ENABLE, RB_IER_RECV_RDY | RB_IER_LINE_STAT);  // 使能接收就绪和线路状态中断
    PFIC_EnableIRQ(UART_IRQn);  // 使能UART中断
#endif
}

// 错误码定义(明确错误类型)
typedef enum {
    CMD_SUCCESS = 0,             // 成功
    CMD_ERROR_LENGTH,            // 长度错误
    CMD_ERROR_PARAM,             // 参数错误
    CMD_ERROR_UNKNOWN,           // 未知指令
    CMD_ERROR_BUFFER_OVERFLOW    // 缓冲区溢出
} CommandStatus;

// 指令结构:前缀、长度、处理函数
typedef struct {
    const char* prefix;          // 指令前缀(如"AT+ADVEN=")
    uint8_t prefixLength;        // 前缀长度
    CommandStatus (*handler)(const uint8_t* data, uint8_t length);  // 处理函数
} CommandDefinition;

// 全局变量(volatile确保中断与主循环可见性)
uint8_t RxBuff[RX_BUFFER_SIZE];          // 接收缓冲区
volatile uint8_t uart_end_flag = 0;      // 接收完成标志
volatile uint8_t uart_len = 0;           // 当前接收长度
volatile uint8_t buffer_overflow_flag=0; // 缓冲区溢出标志

// 指令处理函数声明
static CommandStatus HandleAdvertisingEnable(const uint8_t* data, uint8_t length);
static CommandStatus HandleAdvertisingData(const uint8_t* data, uint8_t length);
static CommandStatus HandlePasskey(const uint8_t* data, uint8_t length);

// 指令表(便于扩展新指令)
static const CommandDefinition commands[] = {
    {"AT+ADVEN=", sizeof("AT+ADVEN=") - 1, HandleAdvertisingEnable},  // 使能/禁用广播
    {"AT+ADVDATA=", sizeof("AT+ADVDATA=") - 1, HandleAdvertisingData}, // 设置广播数据
    {"AT+PASS=", sizeof("AT+PASS=") - 1, HandlePasskey},              // 设置配对密码
    {NULL, 0, NULL} // 结束标记
};

/**
 * 发送错误响应
 * @param status 错误码
 */
static void SendErrorResponse(CommandStatus status) {
    switch (status) {
        case CMD_ERROR_LENGTH:
            UART_SendString("ERROR:1\r\n", 9);  // 长度错误
            break;
        case CMD_ERROR_PARAM:
            UART_SendString("ERROR:2\r\n", 9);  // 参数错误
            break;
        case CMD_ERROR_UNKNOWN:
            UART_SendString("ERROR:3\r\n", 9);  // 未知指令
            break;
        case CMD_ERROR_BUFFER_OVERFLOW:
            UART_SendString("ERROR:4\r\n", 9);  // 缓冲区溢出
            break;
        default:
            break;
    }
}

/**
 * 发送成功响应
 */
static void SendSuccessResponse() {
    UART_SendString("OK\r\n", 4);
}

/**
 * 指令处理主函数(在主循环中调用)
 */
__HIGH_CODE
void Cmd_Process() {
    if (uart_end_flag) {
        uart_end_flag = 0;  // 清除标志

        CommandStatus status = CMD_ERROR_UNKNOWN;  // 默认未知指令

        // 遍历指令表,查找匹配的指令
        for (int i = 0; commands[i].prefix != NULL; i++) {
            // 检查长度是否足够,且前缀匹配(tmos_memcmp返回1表示相等)
            if (uart_len >= commands[i].prefixLength &&
                tmos_memcmp(commands[i].prefix, RxBuff, commands[i].prefixLength)) {

                const uint8_t* cmdData = &RxBuff[commands[i].prefixLength];  // 指令参数
                uint8_t cmdLength = uart_len - commands[i].prefixLength;     // 参数长度
                status = commands[i].handler(cmdData, cmdLength);            // 调用处理函数
                break;
            }
        }

        // 发送响应
        if (status == CMD_SUCCESS) {
            SendSuccessResponse();
        } else {
            SendErrorResponse(status);
        }

        // 清理缓冲区
        uart_len = 0;
        tmos_memset(RxBuff, 0, RX_BUFFER_SIZE);
    }
}

/**
 * 处理AT+ADVEN指令(使能/禁用广播)
 * 格式:AT+ADVEN=0(禁用)或1(使能)
 */
static CommandStatus HandleAdvertisingEnable(const uint8_t* data, uint8_t length) {
    // 检查参数长度(必须为1字节)
    if (length != 1) {
        return CMD_ERROR_LENGTH;
    }

    // 检查参数合法性(必须是'0'或'1')
    if (data[0] != '0' && data[0] != '1') {
        return CMD_ERROR_PARAM;
    }

    // 设置广播使能状态
    uint8_t enable = (data[0] == '1');
    GAPRole_SetParameter(GAPROLE_ADVERT_ENABLED, sizeof(uint8_t), &enable);
    return CMD_SUCCESS;
}

/**
 * 处理AT+ADVDATA指令(设置广播数据)
 * 格式:AT+ADVDATA=xxx(xxx为广播内容,长度≤29)
 */
static CommandStatus HandleAdvertisingData(const uint8_t* data, uint8_t length) {
    // 检查长度(广播数据总长度=参数长度+2≤31,故参数长度≤29)
    if (length > MAX_ADVDATA_LENGTH - 2) {
        return CMD_ERROR_LENGTH;
    }

    uint8_t advData[MAX_ADVDATA_LENGTH];
    uint8_t ble_sta = 0xff;  // BLE当前状态

    // 构建广播数据(符合BLE规范:长度+类型+内容)
    advData[0] = length + 1;  // 长度字段(类型+内容总长度)
    advData[1] = 0x09;        // 类型字段(0x09表示完整本地名称)
    tmos_memcpy(&advData[2], data, length);  // 复制内容

    // 根据当前BLE状态更新广播数据
    GAPRole_GetParameter(GAPROLE_STATE, &ble_sta);
    if (ble_sta == 2) {  // 广播状态:实时更新
        GAP_UpdateAdvertisingData(Peripheral_TaskID, TRUE, length+2, advData);
    } else {  // 非广播状态:预设置
        GAPRole_SetParameter(GAPROLE_ADVERT_DATA, length+2, advData);
    }

    return CMD_SUCCESS;
}

/**
 * 处理AT+PASS指令(设置配对密码)
 * 格式:AT+PASS=xxxxxx(6位数字)
 */
static CommandStatus HandlePasskey(const uint8_t* data, uint8_t length) {
    // 检查长度(必须为6字节)
    if (length != 6) {
        return CMD_ERROR_LENGTH;
    }

    // 检查是否为数字
    for (uint8_t i = 0; i < length; i++) {
        if (data[i] < '0' || data[i] > '9') {
            return CMD_ERROR_PARAM;
        }
    }

    // 转换为数字(忽略前导零)
    uint32_t passkey = 0;
    uint8_t startIdx = 0;
    // 找到第一个非零数字的位置
    while (startIdx < 6 && data[startIdx] == '0') {
        startIdx++;
    }
    // 计算密码(若全为零,结果为0)
    for (uint8_t i = startIdx; i < 6; i++) {
        passkey = passkey * 10 + (data[i] - '0');
    }

    // 设置配对密码
    GAPBondMgr_SetParameter(GAPBOND_PERI_DEFAULT_PASSCODE, sizeof(uint32_t), &passkey);
    return CMD_SUCCESS;
}

/**
 * 处理缓冲区溢出(统一逻辑,避免重复代码)
 */
__HIGH_CODE
static void handleBufferOverflow(void) {
    uart_len = 0;
    tmos_memset(RxBuff, 0, RX_BUFFER_SIZE);
    buffer_overflow_flag = 1;
    SendErrorResponse(CMD_ERROR_BUFFER_OVERFLOW);
}

/**
 * UART中断处理函数(高优先级)
 * 功能:处理UART接收中断,将数据存入缓冲区并标记完成
 * 注意:采用中断驱动,快速处理后返回,避免阻塞
 */
__INTERRUPT
__HIGH_CODE
void UART_IRQHandler(void)
{
    switch (UART_GetITFlag()) {
        case UART_II_LINE_STAT: // 线路状态错误(帧错误、奇偶校验等)
            uint8_t LineSta=UART_GetLinSTA();    // 读取状态寄存器以清除中断
            break;

        case UART_II_RECV_RDY:  // 接收缓冲区达到触发阈值(UART_7BYTE_TRIG)只收6个字节确保代码进超时中断
            // 安全检查:确保缓冲区有足够空间接收触发字节数
            if (uart_len <= (RX_BUFFER_SIZE - TRIGGER_BYTE_COUNT)) {
                // 批量读取触发字节数减1的数据
                for (uint8_t i = 0; i < TRIGGER_BYTE_COUNT; i++) {
                    RxBuff[uart_len + i] = UART_RecvByte();
                }
                uart_len += TRIGGER_BYTE_COUNT;  // 更新缓冲区指针
            } else {
                handleBufferOverflow();  // 缓冲区即将溢出,执行清理
            }
            break;

        case UART_II_RECV_TOUT:  // 接收超时(数据传输暂停,一帧结束)
            // 安全检查:计算剩余空间是否足够接收当前FIFO中的数据
            if ((uart_len + R8_UART_RFC) <= RX_BUFFER_SIZE) {
                // 读取剩余数据(注意:此处假设UART_RecvString为读取剩余全部数据)
                uint8_t bytesRead = UART_RecvString(&RxBuff[uart_len]);

                // 处理历史溢出标志:若之前发生过溢出,丢弃当前数据
                if (buffer_overflow_flag) {
                    buffer_overflow_flag = 0;        // 清除溢出标志
                    uart_len = 0;                    // 重置缓冲区
                    tmos_memset(RxBuff, 0, RX_BUFFER_SIZE);  // 清空缓冲区
                } else {
                    // 正常接收:更新长度并标记接收完成
                    uart_len += bytesRead;
                    uart_end_flag = 1;  // 通知主循环有完整命令待处理
                }
            } else {
                // 剩余空间不足,触发溢出处理
                handleBufferOverflow();
            }
            break;

        case UART_II_THR_EMPTY:  // 发送缓冲区空(当前未使用此功能)
            break;

        default:
            break;
    }
}

头文件:

#ifndef INCLUDE_BLE_ADV_H_
#define INCLUDE_BLE_ADV_H_

extern  uint8_t Peripheral_TaskID;

extern void cmd_uart_init();

extern void Cmd_Process();

#endif /* INCLUDE_BLE_ADV_H_ */

main.c

#include "CONFIG.h"
#include "HAL.h"
#include "gattprofile.h"
#include "peripheral.h"
#include "ble_adv.h"

__attribute__((aligned(4))) uint32_t MEM_BUF[BLE_MEMHEAP_SIZE / 4];

#if(defined(BLE_MAC)) && (BLE_MAC == TRUE)
const uint8_t MacAddr[6] = {0x84, 0xC2, 0xE4, 0x03, 0x55 ,0xAA};
#endif

 * @fn      Main_Circulation
 *
 * @brief   主循环
 *
 * @return  none
 */
__HIGH_CODE
__attribute__((noinline))
void Main_Circulation()
{
    while(1)
    {
        TMOS_SystemProcess();
        Cmd_Process();
    }
}

/*********************************************************************
 * @fn      main
 *
 * @brief   主函数
 *
 * @return  none
 */
int main(void)
{
    HSECFG_Capacitance(HSECap_18p);
    SetSysClock(CLK_SOURCE_HSE_PLL_100MHz);
#if(defined(HAL_SLEEP)) && (HAL_SLEEP == TRUE)
    GPIOA_ModeCfg(GPIO_Pin_All, GPIO_ModeIN_PU);
#endif
#ifdef DEBUG
    GPIOA_SetBits(bTXD_0);
    GPIOA_ModeCfg(bTXD_0, GPIO_ModeOut_PP_5mA); // TXD-配置推挽输出,注意先让IO口输出高电平
    UART_Remap(ENABLE, UART_TX_REMAP_PA3, UART_RX_REMAP_PA2);
    UART_DefInit();
#endif
    cmd_uart_init();
    PRINT("%s\n", VER_LIB);
    CH57x_BLEInit();
    HAL_Init();
    GAPRole_PeripheralInit();
    Peripheral_Init();
    Main_Circulation();
}

 

posted on 2025-10-09 13:59  WCH蓝牙应用分享  阅读(257)  评论(0)    收藏  举报