戰(zhàn):AT命令、串口異步接收與GPRS應(yīng)用開發(fā))
簡(jiǎn)介面向嵌入式與物聯(lián)網(wǎng)開發(fā)者STM32F103驅(qū)動(dòng)SIM800C模塊的HAL庫工程適合需要快速實(shí)現(xiàn)短信收發(fā)、語音通話、GPRS數(shù)據(jù)通信和藍(lán)牙交互的場(chǎng)景代碼基于UART串口通信完整覆蓋AT指令的構(gòu)建、發(fā)送與響應(yīng)解析可直接適配STM32F1系列控制器。資源共1680個(gè)文件主要是870個(gè).h頭文件與730個(gè).c源文件并包含uvprojx/uvoptx工程配置、啟動(dòng)文件、hex固件及調(diào)試配置等壓縮包僅10.96MB目錄組織清晰方便對(duì)照閱讀和二次開發(fā)。目前已有803人學(xué)習(xí)/下載適合正在學(xué)習(xí)HAL庫、串口中斷、AT指令集或物聯(lián)網(wǎng)無線通信終端開發(fā)的工程師與學(xué)生作為參考。工程內(nèi)不僅實(shí)現(xiàn)了短信收發(fā)ATCMGF/CMGS/CMGR、撥號(hào)與掛斷ATD/ATH、GPRS網(wǎng)絡(luò)接入及TCP/IP收發(fā)還提供藍(lán)牙配對(duì)連接與數(shù)據(jù)透?jìng)魇纠瑫r(shí)包含電源管理、超時(shí)重試和異常恢復(fù)等實(shí)用處理代碼注釋詳盡是構(gòu)建STM32通信終端的良好起點(diǎn)。1. STM32F103 最小系統(tǒng) SIM800C先認(rèn)清它是 AT 語音機(jī)而不是傳感器用 STM32F103 最小系統(tǒng)板點(diǎn) OLED、讀 DHT11幾行 HAL 代碼就能收工輪到 SIM800C 時(shí)這套經(jīng)驗(yàn)會(huì)失效。SIM800C 內(nèi)部跑著完整的 GSM/GPRS 協(xié)議棧和藍(lán)牙協(xié)議棧主控不讀寄存器只通過串口一行行發(fā) AT 文本命令。更反直覺的是模塊會(huì)主動(dòng)上報(bào)事件新短信到達(dá)時(shí)隨時(shí)插入一條CMTI打亂原本線性的收發(fā)流程。下面按落地順序展開先講硬件與電平再搭 HAL 串口的異步接收框架然后短信電話、GPRS TCP 會(huì)話最后落在藍(lán)牙調(diào)試與整機(jī)自檢上。適合手里只有一塊 STM32F103 最小系統(tǒng)板、想做短信告警或低吞吐量數(shù)據(jù)上報(bào)的工程師也適合從標(biāo)準(zhǔn)庫 V3.5 遷移到 HAL 后想重建串口接收模型的人。核心認(rèn)知只有一個(gè)SIM800C 不是外設(shè)是一臺(tái)等文本命令的“AT 語音機(jī)”。2. 硬件接線與 HAL 串口異步接收框架SIM800C 的響應(yīng)永遠(yuǎn)不定長2.1 引腳接線與電平邊界先給出一張最小接線表主串口用 USART2把 PA2/PA3 留給模塊避免和調(diào)試打印的 USART1 搶線。STM32F103 引腳方向SIM800C 引腳說明PA2USART2_TX→SIM800_RXDF103 輸出 3.3VSIM800C 是 2.8V TTL 邏輯建議串 510Ω1kΩ 電阻PA3USART2_RX←SIM800_TXD2.8V 輸出對(duì) F103 的輸入高電平閾值 2.31V 有余量可直連GND—GND兩端必須共地這是所有怪問題的頭號(hào)來源5V/2A 電源→VBAT 或 5V 輸入GSM 突發(fā)發(fā)射時(shí)模塊瞬時(shí)電流接近 2A不能用 3.3V LDO 供電PB0推挽輸出→PWRKEY多數(shù)模塊上電即開機(jī)也有模塊需要拉低 PWRKEY 約 500ms 完成開機(jī)電源是所有新手最容易栽的地方。STMF103 最小系統(tǒng)板上的 AMS1117-3.3V 只能撐幾十毫安級(jí)別的負(fù)載SIM800C 一入網(wǎng)發(fā)射電壓就被拉垮表現(xiàn)是ATCSQ永遠(yuǎn)返回 99或者模塊反復(fù)重啟。常見做法是模塊用獨(dú)立的 5V/2A 適配器或鋰電池供電主控板單獨(dú)供電只在 GND 處單點(diǎn)相接。信號(hào)線暫且不管先把地接好、把電源喂飽再談 AT 命令。還有一個(gè)細(xì)節(jié)SIM800C 的串口電平是 2.8V不是 5V。F103 的 TX 輸出 3.3V高電平略超規(guī)格但絕大多數(shù)模塊能接受穩(wěn)妥做法是在 TX 線上串一個(gè) 510Ω 到 1kΩ 的電阻限流如果項(xiàng)目要過認(rèn)證或批量生產(chǎn)建議加 TXS0102 這類電平轉(zhuǎn)換芯片。SIM800_TXD 到 PA3 這段可以直接連因?yàn)?2.8V 高于 F103 識(shí)別高電平的最低 2.31V可靠性足夠。2.2 CubeMX 串口配置115200 8N1 開中斷在 STM32CubeMX 里選 USART2置為 Asynchronous波特率 1152008 位數(shù)據(jù)、無校驗(yàn)、1 停止位。NVIC 設(shè)置里勾選 USART2 global interrupt。CubeMX 生成的代碼不需要大改只需要在main()里確認(rèn)調(diào)用了MX_USART2_UART_Init()。一個(gè)容易被忽略的點(diǎn)SIM800C 出廠波特率不一定是 115200很多模塊默認(rèn) 9600 或 115200取決于固件版本和出廠配置。上電后先用 USB-TTL 轉(zhuǎn)串口單獨(dú)連模塊一個(gè)個(gè)波特率試過去看到AT回OK才算找到正確速率。正常情況下模塊上電后會(huì)有幾秒初始化等板載 NETLIGHT 燈開始慢閃再發(fā)命令。F1 系列里 F103C8T6 只有 3 個(gè) USARTF105/F107 有 5 個(gè)這套工程只占一個(gè)串口換型號(hào)時(shí)只需改串口句柄和中斷回調(diào)應(yīng)用層代碼不用動(dòng)。2.3 環(huán)形緩沖區(qū)HAL 串口逐字節(jié)接收的正確姿勢(shì)SIM800C 響應(yīng)不定長ATCMGL可以一次回幾百字節(jié)新短信 URC 只有十幾個(gè)字節(jié)阻塞式HAL_UART_Receive等固定長度必然卡死。所以串口接收層要用環(huán)形緩沖區(qū)配合中斷每收到一個(gè)字節(jié)先存起來主循環(huán)再按行取走。// sim_rx.cSIM800C 串口接收環(huán)形緩沖 #define SIM_RX_SIZE 512 static uint8_t sim_rx_buf[SIM_RX_SIZE]; static volatile uint16_t sim_rx_head 0; static volatile uint16_t sim_rx_tail 0; static uint8_t sim_rx_byte; // 中斷回調(diào)逐字節(jié)寫入環(huán)形緩沖 void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { if (huart-Instance USART2) { sim_rx_buf[sim_rx_head] sim_rx_byte; sim_rx_head (sim_rx_head 1) % SIM_RX_SIZE; HAL_UART_Receive_IT(huart2, sim_rx_byte, 1); } } // 主循環(huán)或任務(wù)里取一行完整響應(yīng)返回行長度無整行返回 0 int sim_get_line(char *line, int max_len) { int len 0; while (sim_rx_head ! sim_rx_tail) { uint8_t c sim_rx_buf[sim_rx_tail]; sim_rx_tail (sim_rx_tail 1) % SIM_RX_SIZE; if (c \n len 0) { line[len] \0; return len; } if (len max_len - 1) line[len] c; } return 0; }這段代碼的核心是HAL_UART_Receive_IT的一次性掛接和重新掛接。每次收到一個(gè)字節(jié)進(jìn)入中斷回調(diào)把字節(jié)寫入環(huán)形緩沖后立刻再調(diào)用一次HAL_UART_Receive_IT準(zhǔn)備收下一個(gè)字節(jié)。sim_rx_head在中斷里寫sim_rx_tail在主循環(huán)里讀兩者都在中斷和主循環(huán)之間共享必須加volatile。緩沖區(qū) 512 字節(jié)對(duì) GPRS 場(chǎng)景足夠如果頻繁用ATCMGLALL拉全量短信建議加大到 2048并在入緩沖時(shí)加滿判斷。sim_get_line以\n作為行結(jié)束符自動(dòng)忽略\r這樣應(yīng)用層拿到的就是OK、ERROR、CMTI: SM,3這類干凈文本。注意 AT 命令的響應(yīng)不一定只有一行比如ATCLCC會(huì)回多行調(diào)用方要做“收集所有行直到出現(xiàn) OK”的邏輯而不是取到一行就返回。提示如果工程里跑了 FreeRTOS這套環(huán)形緩沖不用改把sim_get_line和后續(xù)狀態(tài)解析放進(jìn)獨(dú)立的 SIM800C 任務(wù)即可裸機(jī)工程就在主循環(huán)里輪詢。2.4 異步事件與狀態(tài)機(jī)CMTI 為什么不請(qǐng)自來SIM800C 會(huì)隨時(shí)產(chǎn)生 URC即模塊主動(dòng)上報(bào)的消息。最常見的場(chǎng)景是開啟新短信指示后來短信時(shí)模塊會(huì)在任何命令間隙插入一行CMTI: SM,3。如果此時(shí)程序正堵在HAL_UART_Receive等一個(gè)固定長度的響應(yīng)這行 URC 要么被吞掉要么被當(dāng)成響應(yīng)的一部分短信永遠(yuǎn)讀不出來。所以應(yīng)用層不能只寫“發(fā)一條命令等一條響應(yīng)”的線性代碼要維護(hù)一個(gè)狀態(tài)機(jī)發(fā)送命令前記錄當(dāng)前期望的關(guān)鍵字收到行后先判斷是不是 URC是 URC 就走異步處理分支不是 URC 再和當(dāng)前期望匹配。后面第 3 章會(huì)給出行解析函數(shù)這里先記住一個(gè)原則任何等待響應(yīng)的循環(huán)里都要能跳過非目標(biāo)行不能因?yàn)橐恍蠧MTI就認(rèn)為命令失敗了。3. 短信與電話文本模式、呼叫命令與一個(gè)能用的發(fā)送函數(shù)3.1 開機(jī)自檢命令鏈每塊新模塊上電后先按順序跑一遍下面這張表。這五條命令能覆蓋 90% 的“模塊不工作”問題。命令典型返回說明ATOK模塊活著、串口波特率正確ATE0OK關(guān)閉命令回顯讓后續(xù)解析更干凈ATCPIN?CPIN: READYSIM 卡未插或方向反了會(huì)返回 ERRORATCSQCSQ: 22,0第一個(gè)數(shù)是信號(hào)等級(jí) 0~3199 表示天線未接或射頻異常ATCREG?CREG: 0,1第二個(gè)數(shù) 1 表示已注冊(cè)本地網(wǎng)3 表示被拒絕ATCSQ返回的 22 不是百分比而是一個(gè)對(duì)數(shù)映射等級(jí)。22 以上基本是滿信號(hào)12 以下就要檢查天線和供電。如果ATCSQ一直返回 99別急著查軟件先看天線座是否擰緊、模塊的射頻天線是否被金屬外殼罩住。SIM 卡接觸不良也常見表現(xiàn)為ATCPIN?返回 ERROR重新插拔能解決大半。3.2 文本模式短信收發(fā)0x1A 才是正文結(jié)束符文本模式下收發(fā)短信有三條規(guī)則。第一ATCMGF1切到文本模式否則ATCMGS會(huì)走 PDU 模式命令格式完全不同。第二ATCMGS號(hào)碼輸入回車后模塊會(huì)回提示符這個(gè)提示符不帶回車換行所以用sim_get_line按行等待永遠(yuǎn)等不到。第三短信正文必須以 0x1AASCII 的 Ctrl-Z結(jié)束模塊收到 0x1A 才真正提交短信然后回OK或ERROR。下面這段代碼是短信發(fā)送的最小實(shí)現(xiàn)依賴前文的sim_get_line和環(huán)形緩沖// 等待模塊發(fā)出 提示符該字符不帶回車換行必須按字節(jié)等 static int sim_wait_prompt(uint32_t timeout_ms) { uint32_t start HAL_GetTick(); while (HAL_GetTick() - start timeout_ms) { if (sim_rx_head ! sim_rx_tail) { uint8_t c sim_rx_buf[sim_rx_tail]; sim_rx_tail (sim_rx_tail 1) % SIM_RX_SIZE; if (c ) return 0; } } return -1; } // 發(fā)送命令并等待響應(yīng)子串遇到 ERROR 提前失敗 static int sim_expect(const char *cmd, const char *resp, uint32_t timeout_ms) { char line[160]; if (cmd ! NULL cmd[0] ! \0) { HAL_UART_Transmit(huart2, (uint8_t *)cmd, strlen(cmd), 200); HAL_UART_Transmit(huart2, (uint8_t *)\r, 1, 200); } uint32_t start HAL_GetTick(); while (HAL_GetTick() - start timeout_ms) { if (sim_get_line(line, sizeof(line)) 0) { if (strstr(line, resp) ! NULL) return 0; if (strstr(line, ERROR) ! NULL) return -1; } } return -2; } // 發(fā)送一條文本短信 static int sim_send_sms(const char *number, const char *text) { char cmd[64]; if (sim_expect(ATCMGF1, OK, 1000) ! 0) return -1; // 文本模式切換失敗 snprintf(cmd, sizeof(cmd), ATCMGS\%s\, number); HAL_UART_Transmit(huart2, (uint8_t *)cmd, strlen(cmd), 200); HAL_UART_Transmit(huart2, (uint8_t *)\r, 1, 200); if (sim_wait_prompt(5000) ! 0) return -2; // 模塊沒回 HAL_UART_Transmit(huart2, (uint8_t *)text, strlen(text), 300); uint8_t ctrl_z 0x1A; // 短信正文結(jié)束符 HAL_UART_Transmit(huart2, ctrl_z, 1, 200); if (sim_expect(, OK, 10000) ! 0) return -3; // 短信提交失敗 return 0; }代碼里最值得注意的兩個(gè)細(xì)節(jié)sim_wait_prompt是字節(jié)級(jí)讀取它不經(jīng)過sim_get_line因?yàn)楹竺鏇]有換行sim_expect的第一個(gè)參數(shù)如果傳空串就只等待不發(fā)送這樣能復(fù)用同一套超時(shí)和行解析邏輯。0x1A是 ASCII 的 Ctrl-Z不要用\r或\n替代否則短信正文會(huì)停留在編輯態(tài)模塊既不回 OK 也不回 ERROR。短信接收方面讀取用ATCMGLALL或ATCMGRindex刪除用ATCMGDindex。主動(dòng)接收新短信必須先開ATCNMI2,1開啟后模塊會(huì)在新短信到達(dá)時(shí)上報(bào)CMTI: SM,index。程序拿到 index 后再用ATCMGRindex取內(nèi)容。讀取后要及時(shí)刪除SIM 卡存儲(chǔ)區(qū)滿了之后新短信會(huì)寫不進(jìn)去。下面是 URC 行解析函數(shù)放在主循環(huán)的取行邏輯里// 收到一行識(shí)別 URC 并返回事件類型 int sim_process_line(const char *line) { if (strncmp(line, CMTI:, 6) 0) { int index 0; sscanf(line, CMTI: \SM\,%d, index); new_sms_index index; // 通知主狀態(tài)機(jī)去讀短信 return 1; } if (strcmp(line, RING) 0) { // 來電主程序執(zhí)行 ATCLCC 查詢主叫號(hào)碼 return 2; } return 0; }用strncmp而不是strstr判斷前綴是為了避免普通響應(yīng)里恰好包含同樣文本時(shí)誤觸發(fā)。sscanf的格式串里%d前要寫清楚引號(hào)和逗號(hào)解析失敗時(shí)返回 0。3.3 電話功能ATD 后面的分號(hào)不能省打電話的命令本身很簡(jiǎn)單ATD13800138000;。分號(hào)必須跟在號(hào)碼最后面表示這是語音呼叫沒有分號(hào)模塊會(huì)按數(shù)據(jù)呼叫處理行為完全不同。發(fā)完ATD...后模塊回OK之后主叫方接聽前不會(huì)再有額外狀態(tài)上報(bào)。掛斷用ATH。來電檢測(cè)需要先執(zhí)行ATCLIP1開啟主叫號(hào)碼顯示來電時(shí)模塊上報(bào)CLIP: 13800138000,129,,0同時(shí)上報(bào)一行RING。如果在通話中想查詢當(dāng)前呼叫狀態(tài)ATCLCC會(huì)返回一行或多行CLCC: 1,0,0,0,0,13800138000,129其中第二個(gè)字段是呼叫方向第三個(gè)字段是呼叫狀態(tài)。工程上外呼一般由按鍵或 Modbus 寄存器觸發(fā)主控發(fā)完ATD后起一個(gè)軟件定時(shí)器到時(shí)間就發(fā)ATH不要用阻塞延時(shí)等通話結(jié)束。3.4 狀態(tài)機(jī)不要寫成 sleep短信、電話和 GPRS 共用同一個(gè)串口任何長時(shí)間 sleep 都會(huì)造成 URC 丟失。常見做法是維護(hù)一個(gè)狀態(tài)變量和一張“當(dāng)前等待關(guān)鍵字”的表主循環(huán)每輪只做三件事從環(huán)形緩沖取行、用sim_process_line判斷是不是 URC、不是則和當(dāng)前期望關(guān)鍵字做匹配。FreeRTOS 移植過來也一樣把這三步放進(jìn)一個(gè)獨(dú)立任務(wù)其它任務(wù)通過隊(duì)列發(fā)命令索引。4. GPRS 數(shù)據(jù)業(yè)務(wù)APN 配置、TCP 會(huì)話與異步行處理4.1 APN 與 PDP 上下文先激活再接服務(wù)器GPRS 的完整會(huì)話不是一條命令而是一組命令。先配置 PDP 上下文再附著網(wǎng)絡(luò)再激活上下文最后才能建 TCP 連接。國內(nèi)卡常見默認(rèn) APN中國移動(dòng)cmnet、聯(lián)通3gnet、電信ctnet。企業(yè)卡和物聯(lián)網(wǎng)卡要用卡商提供的專用 APN用戶名密碼可能也要填。命令典型返回說明ATCGDCONT1,IP,cmnetOK配置 PDP 上下文APN 拼錯(cuò)會(huì)在這里埋雷ATCGATT1OK附著 GPRS 網(wǎng)絡(luò)ATCGACT1,1OK激活 PDP 上下文失敗多為 APN 或卡沒開數(shù)據(jù)套餐ATCIPSTARTTCP,120.55.8.9,8080CONNECT OK建立 TCP 連接ATCIPSEND進(jìn)入發(fā)送窗口等待提示符業(yè)務(wù)數(shù)據(jù) 0x1ASEND OK數(shù)據(jù)幀已交給遠(yuǎn)端服務(wù)器ATCIPCLOSECLOSE OK關(guān)閉本次活動(dòng)連接ATCIPSHUTSHUT OK關(guān)閉移動(dòng)場(chǎng)景釋放 PDP激活失敗先查ATCGACT?看當(dāng)前上下文狀態(tài)返回 0 說明沒激活成功。另一個(gè)容易忽略的點(diǎn)整個(gè)會(huì)話只有一個(gè)活動(dòng) socketSIM800C 的 TCP/IP 應(yīng)用同一時(shí)刻只能跑一條 TCP 連接。業(yè)務(wù)設(shè)計(jì)必須串行發(fā)完一幀等SEND OK再發(fā)下一幀不能開兩個(gè)線程同時(shí)發(fā)。4.2 發(fā)一幀 TCP 數(shù)據(jù)的完整函數(shù)下面這段代碼直接復(fù)用第 3 章的sim_expect和sim_wait_prompt完成一次完整的 TCP 數(shù)據(jù)發(fā)送。// sim_tcp.c建鏈、發(fā)一幀數(shù)據(jù)、等待確認(rèn) static int sim_tcp_send(const char *host, uint16_t port, const uint8_t *data, uint16_t len) { char cmd[96]; snprintf(cmd, sizeof(cmd), ATCIPSTART\TCP\,\%s\,%u, host, port); if (sim_expect(cmd, CONNECT OK, 15000) ! 0) return -1; // 建鏈?zhǔn)z查 IP 端口和網(wǎng)絡(luò) if (sim_wait_prompt(2000) ! 0) // CIPSEND 的 也沒有換行 return -2; HAL_UART_Transmit(huart2, data, len, 500); uint8_t end 0x1A; // 通知模塊這一幀結(jié)束 HAL_UART_Transmit(huart2, end, 1, 200); if (sim_expect(, SEND OK, 10000) ! 0) return -3; // 發(fā)送失敗需要重建連接 return 0; }這段代碼的邏輯說明sim_expect(cmd, CONNECT OK, 15000)負(fù)責(zé)發(fā)送建鏈命令超時(shí) 15 秒是因?yàn)?GPRS 建鏈?zhǔn)芫W(wǎng)絡(luò)影響很大可能要等幾秒才回CONNECT OK如果中途收到ERRORsim_expect會(huì)提前返回。ATCIPSEND的提示符同樣沒有換行所以復(fù)用sim_wait_prompt。數(shù)據(jù)長度建議控制在 1024 字節(jié)以內(nèi)超過 MTU 時(shí)模塊雖然能內(nèi)部封包但長包失敗率會(huì)明顯上升實(shí)際工程里把業(yè)務(wù)幀拆成小塊更穩(wěn)。發(fā)送后如果等到ERROR不要直接重發(fā)先把連接關(guān)掉執(zhí)行ATCIPCLOSE必要時(shí)再執(zhí)行ATCIPSHUT重建整個(gè) TCP/IP 場(chǎng)景。sim_expect(, SEND OK, 10000)在等待期間如果收到CMTI這類 URC 行會(huì)正常跳過繼續(xù)等不會(huì)誤判失敗。等待響應(yīng)的循環(huán)里能忽略非目標(biāo)行這是第 2 章說的異步模型帶來的直接好處。如果CIPSTART里寫的是域名而不是 IP部分固件可能解析失敗。遇到這種情況先換成對(duì)端公網(wǎng) IP 測(cè)試能連上說明域名解析鏈路有問題再查ATCDNSCFG的 DNS 配置。4.3 下行數(shù)據(jù) IPD 的粘包處理TCP 對(duì)端主動(dòng)下發(fā)的數(shù)據(jù)模塊會(huì)以IPD,len:data的行格式上報(bào)例如IPD,12:hello world!。解析時(shí)先找IPD,前綴取出逗號(hào)后面的長度再從數(shù)據(jù)區(qū)切出對(duì)應(yīng)字節(jié)。注意 payload 可能很長模塊會(huì)把數(shù)據(jù)和后續(xù) URC 拼接在一起不能假設(shè)“一行就是一個(gè)完整包”。處理粘包的辦法是維護(hù)一個(gè)累積區(qū)先解析出 len如果當(dāng)前行剩余字節(jié)不夠 len就把剩余數(shù)據(jù)暫存繼續(xù)等環(huán)形緩沖里的后續(xù)字節(jié)直到湊滿 len。解析完成后檢查緩沖區(qū)里是否還有剩余內(nèi)容再做下一輪。這塊邏輯和串口協(xié)議解析是同一套路建議獨(dú)立成sim_ipd_handler不要在sim_get_line里直接處理否則行邊界和包邊界會(huì)互相污染。5. SIM800C 藍(lán)牙通信的驗(yàn)證技巧ATCLAC、SPP 會(huì)話與整機(jī)自檢5.1 先確認(rèn)固件支持哪些命令SIM800C 的藍(lán)牙命令在不同固件上子集不完全一樣驗(yàn)證前先執(zhí)行ATCLAC模塊會(huì)把支持的全部命令列出來。看到以BT開頭的條目就說明固件帶藍(lán)牙協(xié)議棧。這一步值得認(rèn)真做因?yàn)楹芏嗄K出廠固件精簡(jiǎn)過藍(lán)牙功能憑記憶敲命令只會(huì)得到一片 ERROR。5.2 打開藍(lán)牙并建立 SPP 會(huì)話藍(lán)牙在 SIM800C 上默認(rèn)為關(guān)閉狀態(tài)需要先執(zhí)行ATBTPOWER1打開。如果這條命令返回 ERROR去ATCLAC的輸出里找藍(lán)牙相關(guān)的實(shí)際命令名。打開后手機(jī)安裝藍(lán)牙串口助手按模塊標(biāo)簽上的 PIN 配對(duì)常見是 0000 或 1234。配對(duì)成功后手機(jī)與模塊之間的 SPP 通道就建立了。這里要分清架構(gòu)SPP 數(shù)據(jù)進(jìn)入模塊后是否需要主 UART 轉(zhuǎn)發(fā)取決于固件對(duì)藍(lán)牙數(shù)據(jù)的路由方式。我一般把藍(lán)牙當(dāng)近場(chǎng)調(diào)試口而不是業(yè)務(wù)主鏈路STM32 繼續(xù)走主 UART 發(fā) AT手機(jī)端發(fā)的內(nèi)容被當(dāng)作遠(yuǎn)端調(diào)試指令注入模塊藍(lán)牙是否透?jìng)鳌⑼競(jìng)髂J较略趺赐顺鲆允謨?cè)為準(zhǔn)。不要同時(shí)從藍(lán)牙和主 UART 發(fā)起 AT兩個(gè)口搶命令會(huì)讓模塊響應(yīng)變得不可預(yù)期。5.3 整機(jī)自檢序列一小時(shí)排除硬件問題拿到新模塊后按順序執(zhí)行下面這張表能快速判斷問題出在哪一層。步驟命令預(yù)期失敗先查1ATOK串口交叉、波特率2ATE0OK—3ATCPIN?CPIN: READYSIM 卡方向、金屬觸點(diǎn)4ATCSQ信號(hào)等級(jí) ≥ 12天線、供電99 是天線或射頻異常5ATCREG?注冊(cè)成功欠費(fèi)、卡未開通網(wǎng)絡(luò)6ATCMGF1OK固件異常7ATCIPSTARTCONNECT OK對(duì)端 IP 端口、APN 配置最后補(bǔ)一個(gè)具體技巧如果調(diào)試時(shí)用 DAP 下載失敗先把 SIM800C 供電斷開再確認(rèn)最小系統(tǒng)板的 BOOT0 處于 Flash 啟動(dòng)檔位。大多數(shù)情況下是模塊瞬態(tài)電流把共地電源拖垮而不是程序問題另一類是把 BOOT0 撥到了系統(tǒng)存儲(chǔ)區(qū)啟動(dòng)重新?lián)芑?Flash 檔即可。自檢時(shí)每一條命令都盯兩秒回顯別同時(shí)掛著串口助手和單片機(jī)搶發(fā)否則你看到的亂碼多半來自自己。本文還有配套的精品資源點(diǎn)擊獲取