一.程序功能講解:
功能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號