我是老溫,一名熱愛學(xué)習(xí)的嵌入式工程師。關(guān)注我,一起變得更加優(yōu)秀!
為了可以讓嵌入式Linux產(chǎn)品方便地對接AT指令通信模組,我們在設(shè)計嵌入式應(yīng)用程序的時候,可以用 C/C++ 設(shè)計一個通用的AT指令解析器,這個AT指令解析器具有以下特性:
2、AT指令容易擴(kuò)展,提供處理函數(shù)的注冊接口。
3、通過隊列進(jìn)行指令管理,發(fā)送、接收、處理、多線程同步互斥。
4、具有超時重發(fā)機(jī)制,可設(shè)置超時時間與重發(fā)次數(shù)。
5、面向?qū)ο笤O(shè)計,高內(nèi)聚,容易移植使用。
前段時間,小熊派官方發(fā)布了星閃核心板 H2821-Pico 的AT指令固件,并且支持 1 對 8 組網(wǎng)通信,有了豐富的AT指令集,單片機(jī)或者其他MPU芯片就可以很容易地通過星閃網(wǎng)絡(luò)進(jìn)行互聯(lián)通信。
關(guān)于星閃 AT 固件的詳情,可以查看之前的文章進(jìn)行回顧:開啟星閃互聯(lián),組建一對多小型網(wǎng)絡(luò)!
這個通用的 AT 指令解析器主要由以下兩部分組成:串口通信模塊 serial_port,AT指令解析器模塊 at_cmd_paeser,以下是解析器的具體設(shè)計過程。
1、頭文件 serial_port.h 主要提供底層串口硬件的操作接口,包括配置串口,打開或關(guān)閉串口,數(shù)據(jù)發(fā)送和接口,以及判斷串口是否已經(jīng)打開,具體代碼如下圖所示。
2、源文件 serial_port.cpp 主要是實(shí)現(xiàn)底層串口硬件的操作邏輯,相關(guān)的操作都通過 termios 提供的接口進(jìn)行實(shí)現(xiàn),串口硬件在配置或者數(shù)據(jù)收發(fā)時,要先判斷 is_port_opened 是否置位,串口成功打開后才能進(jìn)行相關(guān)的操作。
3、頭文件 at_cmd_parser.h 主要是把AT 指令解析器抽象成一個類 class at_cmd_parser,這個類提供了AT指令和處理函數(shù)的注冊接口,解析器的啟停,AT指令發(fā)送,三個線程,數(shù)據(jù)收發(fā)隊列,互斥鎖與條件變量,等等。
4、源文件 at_cmd_parser.cpp 主要是對解析器類的接口實(shí)現(xiàn),構(gòu)造函數(shù)主要是打開和配置串口,start() 和 stop() 函數(shù)主要是啟動和停止三大線程,代碼實(shí)現(xiàn)如下圖所示。
5、函數(shù) add_command_handler() 主要是把AT指令和處理函數(shù)進(jìn)行注冊綁定,把處理函數(shù)用一個哈希表 command_handler 進(jìn)行管理,AT指令的字符串是鍵key,具體的處理函數(shù)是健對應(yīng)的值value。
6、調(diào)用 send_at_cmd() 函數(shù)發(fā)送 AT 指令,在這個函數(shù)里面,主要是把待發(fā)送的AT指令放入隊列 send_queue,入隊列采用互斥鎖保護(hù),然后調(diào)用 send_cv 事件喚醒發(fā)送線程 send_thread() 進(jìn)行指令發(fā)送。
7、在發(fā)送線程 send_thread() 里面,先獲取 send_mtx 互斥鎖,然后等待send_cv信號的到達(dá),使用for循環(huán)不斷從send_queue里面取出 struct at_command 類型的數(shù)據(jù),然后調(diào)用 serial.send_data() 進(jìn)行發(fā)送。
在發(fā)送AT指令之前,先記錄發(fā)送前的時間點(diǎn),超過一定時間之后還沒有收到當(dāng)前AT指令的正確回復(fù),則會繼續(xù)重新發(fā)送并記錄重發(fā)次數(shù),達(dá)到最大重發(fā)次數(shù)后,丟棄該條AT指令。
8、在數(shù)據(jù)接收線程 receiving_thread() 里面,每隔100ms輪詢讀取串口緩沖區(qū),如果讀取到數(shù)據(jù),先嘗試獲取互斥鎖,并把數(shù)據(jù)存入 recv_queue 接收隊列,然后發(fā)送 recv_cv 事件喚醒數(shù)據(jù)處理線程 processing_thread()
9、在數(shù)據(jù)處理線程 proessing_thread() 里面,獲取數(shù)據(jù)接收互斥鎖,然后等待收到 recv_cv 事件后,從數(shù)據(jù)接收隊列 revv_queue 里面取出數(shù)據(jù),不斷從 command_handler 哈希表里進(jìn)行鍵值匹配,執(zhí)行對應(yīng)的注冊函數(shù),執(zhí)行成功后,把該條AT指令從發(fā)送隊列里面刪除。
10、把星閃核心板 Bearpi-Pico H2821 通過USB接口連接到Linux開發(fā)板上面,開發(fā)板的內(nèi)核需要支持CH34x驅(qū)動,會在/dev 目錄下生成 ttyUSB0 節(jié)點(diǎn),我們可以做一個簡單的界面來進(jìn)行指令發(fā)送,點(diǎn)擊【指令:AT】按鈕,可以看到調(diào)試終端輸出打印信息,AT指令解析器可以在開發(fā)板上面順利運(yùn)行。
下一步,我們將會基于這個通用的 AT 指令解析器,把星閃核心板BearPi-Pico H2821的 AT 指令都集成到一個模塊組件里面,通過這個組件,就可以讓嵌入式 Linux 開發(fā)板輕松獲得星閃通信功能。