一.程序功能讲解:
功能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(); }
浙公网安备 33010602011771号