一、SPI通信基礎(chǔ)知識
SPI(Serial Peripheral Interface)是一種同步串行通信協(xié)議,常用于 MCU 與外設(shè)之間的高速通信。
SPI 通信通常包含以下信號線:
在本方案中:
CW32 作為 SPI 主機
PAN3031 作為 SPI 從機
SPI 通信由 CW32 主動發(fā)起
SCK(Serial Clock):由主機產(chǎn)生的時鐘信號
MOSI(Master Out Slave In):主機發(fā)送數(shù)據(jù)給從機
MISO(Master In Slave Out):從機發(fā)送數(shù)據(jù)給主機
CS/SS(Chip Select):片選信號,用于選擇通信的從機
二、IQR外部中斷知識
IRQ(Interrupt Request)是外設(shè)向 MCU 發(fā)出的中斷請求信號。
PAN3031 通過 IRQ 引腳向 CW32 通知以下事件(示例):
有數(shù)據(jù)可讀取
狀態(tài)發(fā)生變化
需要 MCU 處理的事件發(fā)生
MCU 在檢測到 IRQ 觸發(fā)后,會進(jìn)入中斷服務(wù)函數(shù)(ISR),通常只做:
事件標(biāo)志位設(shè)置
簡單狀態(tài)記錄
不建議在中斷中直接進(jìn)行 SPI 通信,而應(yīng)在主循環(huán)或任務(wù)中處理。
三、CW32與PAN3031的通信整體流程
CW32 與 PAN3031 的通信方式為:
以兩塊 CW32 搭配兩塊 PAN3031 為例:
主機端(Master):
A1: 第一塊 CW32(大腦/指揮官)
A2: 第一塊 PAN3031(嘴巴和耳朵/無線網(wǎng)卡)
從機端(Slave):
B1: 第二塊 CW32(大腦/指揮官)
B2: 第二塊 PAN3031(嘴巴和耳朵/無線網(wǎng)卡)
通信全過程分為兩部分:
第一段路:大腦指揮網(wǎng)卡 (板級有線通信 - SPI)
A1 與 A2 之間(以及 B1 與 B2 之間)是通過 SPI 接口 連接的。 這就像是老板(CW32)通過內(nèi)線電話指揮秘書(PAN3031)。
物理連接:它們之間用杜邦線線連接(CSN、SCK、MOSI、MISO)。
通信方式:
A1 (CW32) 發(fā)送指令:通過 MOSI 線告訴 A2 “把數(shù)據(jù)發(fā)出去”或者“把配置改一下”。
A2 (PAN3031) 反饋數(shù)據(jù):通過 MISO 線把收到的無線數(shù)據(jù)傳回給 A1。
通知機制 (IRQ):當(dāng) A2 收到無線數(shù)據(jù)或者發(fā)完數(shù)據(jù)時,它會拉動 IRQ 引腳(按門鈴),告訴 A1 “有情況,快來處理”。
第二段路:網(wǎng)卡隔空對話 (板間無線通信 - 2.4G RF)
A2 與 B2 之間是通過 2.4GHz 無線射頻信號 連接的。 這就像是兩個拿著對講機的人在隔空喊話。
物理連接:沒有導(dǎo)線,靠天線發(fā)射電磁波。
通信方式:
調(diào)制 (Tx):A2 把 A1 給它的數(shù)字信號(0101...)轉(zhuǎn)換成高頻無線電波發(fā)射出去。
解調(diào) (Rx):B2 的天線捕捉到這些電波,把它還原成數(shù)字信號(0101...)。
特點:這是半雙工的,也就是說 A2 在說的時候,B2 必須在聽;不能兩個人同時說話,否則信號會打架(同頻干擾)。
完整的數(shù)據(jù)傳輸接力跑 (以主機發(fā)送 "kunkun" 為例)
整個通信過程就像一次接力賽,數(shù)據(jù)是從 A1 的內(nèi)存 跑到 B1 的內(nèi)存:
打包 (A1):主機 CW32 (A1) 把字符串 "kunkun" 準(zhǔn)備好。
下達(dá)指令 (A1 -> A2):A1 通過 SPI 接口,把數(shù)據(jù)寫入 A2 的發(fā)送緩沖區(qū),并命令 A2:“發(fā)射!”
發(fā)射 (A2 -> 空中):A2 啟動射頻電路,把數(shù)據(jù)變成無線電波發(fā)向空中。
接收 (空中 -> B2):從機 PAN3031 (B2) 的天線捕捉到信號,解析出 "kunkun",存入自己的接收緩沖區(qū)。
按門鈴 (B2 -> B1):B2 拉高 IRQ 引腳,觸發(fā) B1 的外部中斷。
讀取 (B1 -> B2):從機 CW32 (B1) 收到中斷后,通過 SPI 接口 讀取 B2 緩沖區(qū)里的數(shù)據(jù)。
處理 (B1):B1 拿到了 "kunkun"。
四、SPI硬件連接說明
SPI 硬件連接如下(示例):
| CW32 引腳 | PAN3031 引腳 | 說明 |
| SCK | SCK | SPI 時鐘 |
| MOSI | MOSI | 主發(fā)從收 |
| MISO | MISO | 從發(fā)主收 |
| GPIOx | CS | SPI 片選 |
| GPIOy | IRQ | 外部中斷 |
CS 信號通常為 低電平有效,需由軟件控制。
五、SPI工作模式說明
SPI 通信就像兩個人跳繩,必須在同一個節(jié)奏點上起跳才不會絆倒。為了讓 CW32(主機)能正確讀寫 PAN3031(從機),雙方的配置必須完全一致。
PAN3031 使用的是標(biāo)準(zhǔn)的 SPI Mode 0,CW32 初始化 SPI 時必須嚴(yán)格按照以下參數(shù)配置:
SPI 模式:Mode 0
時鐘極性 (CPOL) = 0:
表示 SCLK 時鐘線在空閑狀態(tài)(沒有傳輸數(shù)據(jù)時)保持 低電平 (Low Level)。
時鐘相位 (CPHA) = 0:
表示在時鐘的 第一個邊沿(對于 Mode 0 來說是 上升沿)進(jìn)行數(shù)據(jù)采樣(讀取數(shù)據(jù))。
而在第二個邊沿(下降沿)進(jìn)行數(shù)據(jù)切換(發(fā)送下一位數(shù)據(jù))。
數(shù)據(jù)位順序 (Bit Order):
MSB First(高位先發(fā))。
六、IRQ觸發(fā)方式說明
PAN3031 的 IRQ 信號為 上升沿 觸發(fā)。
CW32 需將對應(yīng) GPIO 配置為外部中斷輸入,并設(shè)置正確的觸發(fā)方式。
七、PAN3031模塊使用說明(詳細(xì)版)
PAN3031 SDK使用流程
初始化流程

參數(shù)配置流程


1. PAN3031_set_freq (設(shè)置中心頻率)
干什么用的: 設(shè)置模塊工作在哪個頻段(比如 2.4GHz、470MHz 等)。
小白比喻:調(diào)對講機頻道。如果主機在 1 頻道喊話,從機在 2 頻道聽,兩人永遠(yuǎn)對不上話。
2. PAN3031_set_code_rate (設(shè)置編碼糾錯率)
干什么用的: 決定在發(fā)送真實數(shù)據(jù)時,夾帶多少“冗余糾錯碼”。
小白比喻:給快遞包防震膜。空氣中干擾很多,容易丟包。糾錯率設(shè)得越高(膜包得越厚),就算數(shù)據(jù)在空中損壞了一點,接收端也能自己推算修復(fù)回來;但代價是有效數(shù)據(jù)的傳輸效率變低了。
3. PAN3031_set_bw (設(shè)置帶寬 Bandwidth)
干什么用的: 決定無線信號占據(jù)的頻率寬度。
小白比喻:修多寬的馬路。帶寬越大,數(shù)據(jù)傳得越快;但馬路越寬,越容易受到旁邊車道(其他無線電信號)的干擾,接收靈敏度會下降。
4. PAN3031_set_sf (設(shè)置擴(kuò)頻因子 Spreading Factor)
干什么用的: 這是擴(kuò)頻通信(如 LoRa 調(diào)制)里非常關(guān)鍵的參數(shù),決定每個數(shù)據(jù)符號的持續(xù)時間。
小白比喻:講話的語速。SF 值越大,相當(dāng)于你講話越慢、發(fā)音越長,哪怕距離很遠(yuǎn)、環(huán)境很吵對方也能聽清(穿墻能力大增);但缺點是一句話要說很久,模塊工作時間變長,非常費電。
5. PAN3031_set_tx_power (設(shè)置發(fā)射功率)
干什么用的: 設(shè)置芯片射頻引腳輸出的能量大小(比如 10dBm、22dBm)。
小白比喻:嗓門有多大。功率調(diào)得越高,信號覆蓋范圍越廣,但也意味著你的電池會被抽干得越快。
6. PAN3031_set_crc (設(shè)置 CRC 循環(huán)冗余校驗)
干什么用的: 開啟后,硬件會自動在數(shù)據(jù)包尾部追加一段校驗碼。
小白比喻:貼封條防偽。接收端拿到包裹后,會檢查封條是否完好。如果發(fā)現(xiàn)對不上,說明數(shù)據(jù)在空中被干擾串味了,直接丟棄,防止單片機讀到錯誤的 ADC 抄表數(shù)據(jù)。

發(fā)送流程


接收流程



PAN3031 部分SDK接口函數(shù)

agc(自動增益控制)
功能: 全稱 Automatic Gain Control。它會根據(jù)收到的無線信號強弱,自動調(diào)節(jié)內(nèi)部放大器的放大倍數(shù)。
小白比喻:“自動音量調(diào)節(jié)”。如果發(fā)射端離得很近,信號太強,它就調(diào)低增益防止“震耳朵”;如果離得遠(yuǎn)信號弱,它就自動調(diào)高增益,確保無論遠(yuǎn)近,芯片都能清晰地“聽見”數(shù)據(jù)。
AGC 的核心原理是一個 “檢測 -> 反饋 -> 調(diào)整” 的閉環(huán)系統(tǒng)。
技術(shù)實現(xiàn)流程:
信號進(jìn)入: 天線接收到的原始無線信號進(jìn)入芯片。
強度檢測: 芯片內(nèi)部有一個“偵察兵”(信號強度檢測器),實時測量這個信號的功率(也就是我們常說的 RSSI)。
比較判斷: 芯片內(nèi)部設(shè)定了一個“理想音量”范圍。
如果信號太強: 會導(dǎo)致后面的電路“破音”(飽和失真),數(shù)據(jù)就全亂了。
如果信號太弱: 背景噪音就會蓋過數(shù)據(jù)。
反饋調(diào)整: 偵察兵發(fā)現(xiàn)信號太強,就立刻下令讓 LNA(低噪聲放大器) 降低放大倍數(shù)(減小增益)。
發(fā)現(xiàn)信號太弱,就下令讓 LNA 全力放大(增大增益)。
antenna_init(天線初始化)
功能: 配置射頻端口和天線開關(guān)。
小白比喻:“切換車道”。無線芯片通常有一個天線,但有“發(fā)”和“收”兩條路。這個步驟是初始化天線開關(guān)的控制邏輯,確保你想發(fā)的時候數(shù)據(jù)能傳給天線,想收的時候天線信號能傳給芯片。
Antenna_init 的原理本質(zhì)上是 “單刀雙擲開關(guān)(SPDT)” 的邏輯配置。
技術(shù)實現(xiàn)流程:
鏈路分離: 無線芯片內(nèi)部其實有兩套完全獨立的系統(tǒng):發(fā)射機(TX)產(chǎn)生強大的信號,接收機(RX)負(fù)責(zé)捕捉微弱的信號。
物理矛盾: 但是,為了節(jié)省成本和空間,整個設(shè)備通常只有一根天線。
開關(guān)切換: 在天線和芯片之間,有一個射頻開關(guān)(RF Switch)。
發(fā)送時: 開關(guān)必須撥向“發(fā)射鏈路”,把功率放大器(PA)產(chǎn)生的信號推向天線。
接收時: 開關(guān)必須撥向“接收鏈路”,把天線捕捉到的微弱波浪送給接收器。
初始化保護(hù):antenna_init 就是在初始化階段,配置好控制這個“開關(guān)”的 GPIO 引腳邏輯。

節(jié)能模式:芯片的“休息時間”
PAN3031_MODE_DEEP_SLEEP(深度睡眠)
狀態(tài): 芯片幾乎完全關(guān)閉,功耗降到最低(微安級)。
小白比喻:徹底關(guān)機。這是抄表系統(tǒng)最常用的狀態(tài)。電表每天 99% 的時間都應(yīng)該處于這個模式來省電。
PAN3031_MODE_SLEEP(睡眠)
狀態(tài): 功耗略高于深度睡眠,但保留了寄存器的配置。
小白比喻:電腦休眠。喚醒速度比深度睡眠快一點,不需要重新加載所有配置。
準(zhǔn)備模式:芯片的“熱身階段”
這三個 STB (Standby) 模式是處于休眠和工作之間的中間地帶,它們決定了芯片內(nèi)部哪些組件(如晶振、頻率合成器)是開著的。
PAN3031_MODE_STB1 / STB2
狀態(tài): 基礎(chǔ)待機。內(nèi)部晶振開始起振。
小白比喻:坐在板凳上熱身。雖然沒下場比賽,但已經(jīng)穿好運動鞋了。
STB1:深度省電的“淺睡”模式
在 STB1 模式下,芯片關(guān)閉了外部晶振,只靠內(nèi)部一個很弱的 RC 電路維持基本邏輯。
優(yōu)點: 非常省電,比 STB2 能多省下不少微安級的電流。
缺點: 當(dāng)你需要發(fā)數(shù)據(jù)時,從 STB1 切換到 TX(發(fā)射)需要一段“暖機時間”,因為外部晶振從靜止到穩(wěn)定震蕩需要幾百微秒甚至毫秒級的時間。
STB2:隨時待命的“備戰(zhàn)”模式
在 STB2 模式下,芯片已經(jīng)把昂貴且精確的外部晶振給跑起來了。
優(yōu)點: 響應(yīng)極其靈敏。如果你在做一個需要頻繁快速回應(yīng)(比如 10ms 內(nèi)必須回信)的協(xié)議,STB2 是唯一的選擇。
缺點: 功耗相對較高。如果一直停在 STB2,你的電表電池可能撐不了幾年。
PAN3031_MODE_STB3
狀態(tài): 高級待機。頻率合成器(決定你發(fā)什么頻率)已經(jīng)鎖定。
小白比喻:在起跑線上蹲好了。這是進(jìn)入“發(fā)射”或“接收”之前的最后一站。在你之前的代碼里,進(jìn)入 rf_single_tx_data 之前都會先切換到這個模式。
工作模式:芯片的“上場比賽”
PAN3031_MODE_TX(發(fā)射模式)
狀態(tài): 功率放大器開啟,全力向天線推送電磁波。
小白比喻:放聲大喊。這是最費電的時刻,所以發(fā)送完數(shù)據(jù)一定要趕緊讓它睡覺。
PAN3031_MODE_RX(接收模式)
狀態(tài): 接收鏈路全開,實時捕捉空中的微弱信號。
小白比喻:豎起耳朵細(xì)聽。在抄表項目中,電表端通常只在發(fā)送完數(shù)據(jù)后的那幾百毫秒開啟這個模式來等確認(rèn)。



RF_PARA_TYPE_FREQ(中心頻率)
技術(shù)內(nèi)幕: 指無線電波能量最集中的那個點(例如 470MHz 或 433MHz)。
實戰(zhàn)要點:
必須匹配:主機和從機的頻率誤差不能超過一定范圍(通常是晶振精度的幾倍),否則由于“偏頻”會導(dǎo)致信號極差甚至搜不到包。
避開干擾:如果小區(qū)里有大量同頻段的無線設(shè)備,可以微調(diào)頻率(跳頻)來尋找一個“安靜”的頻道。
RF_PARA_TYPE_CR(編碼糾錯率)
技術(shù)內(nèi)幕: 全稱 Code Rate。它在原始數(shù)據(jù)中加入冗余的校驗位(例如 4/5 代表 4 位數(shù)據(jù)加 1 位冗余)。
實戰(zhàn)要點:
抗干擾性:設(shè)置越高(如 4/8),抗突發(fā)干擾能力越強,就算空中丟了幾位數(shù)據(jù),芯片也能靠算法補回來。
副作用:糾錯位越多,整個數(shù)據(jù)包就越長,空中飛行時間(ToA) 增加,從而增加功耗。
RF_PARA_TYPE_BW(帶寬)
技術(shù)內(nèi)幕: 指信號占據(jù)的頻率寬度(如 125kHz, 250kHz, 500kHz)。
實戰(zhàn)要點:
速率 vs. 靈敏度:馬路越寬(BW 大),車速越快(數(shù)據(jù)率高),但路上的噪音也多(底噪高,靈敏度差)。
抄表選擇:通常選擇較小的帶寬(如 125kHz)來換取更高的接收靈敏度,確保能穿透更厚的墻。
RF_PARA_TYPE_SF(擴(kuò)頻因子)
技術(shù)內(nèi)幕:Spreading Factor,是 LoRa/擴(kuò)頻通信的靈魂。它決定了一個數(shù)據(jù)符號被拉得有多長。
實戰(zhàn)要點:
穿墻神器:SF 越大(如 SF12),信號在噪聲中被識別的能力越強,距離翻倍。
功耗陷阱:SF 每增加一級,數(shù)據(jù)在空中停留的時間幾乎翻倍。這會導(dǎo)致 PAN3031 的發(fā)射電流持續(xù)時間變長,嚴(yán)重縮短電表壽命。
RF_PARA_TYPE_TXPOWER(發(fā)射功率)
技術(shù)內(nèi)幕: 芯片輸出信號的強度,單位通常為 dBm。
實戰(zhàn)要點:
按需調(diào)整:如果電表就在網(wǎng)關(guān)旁邊,沒必要開 20dBm(最大功率),調(diào)低功率能有效節(jié)省電量。
法規(guī)限制:不同國家和地區(qū)對不同頻段的最大功率有法律限制,開發(fā)時需查閱當(dāng)?shù)貥?biāo)準(zhǔn)。
RF_PARA_TYPE_CRC(循環(huán)冗余校驗)
技術(shù)內(nèi)幕: 在數(shù)據(jù)包末尾添加計算好的校驗碼。
實戰(zhàn)要點:
數(shù)據(jù)保真:無線環(huán)境非常臟,數(shù)據(jù)包很容易被干擾成亂碼。開啟 CRC 后,如果收到的包計算結(jié)果不符,硬件會自動丟棄,防止你的單片機讀到錯誤的“水費”或“電費”數(shù)據(jù)。
核心變量:內(nèi)部狀態(tài)記錄員
程序定義了兩個 static(靜態(tài))變量,它們就像是掛在實驗室門口的記事板,用來記錄無線模塊當(dāng)前的工作狀態(tài)。
packet_received:專門記錄接收的狀態(tài)。是收到了?還是超時了?還是出錯了?
packet_transmit:專門記錄發(fā)送的狀態(tài)。是正在發(fā)?還是發(fā)完了?
RxDoneParams:這是一個結(jié)構(gòu)體,它像是一個快遞暫存柜。當(dāng)收到新包裹(數(shù)據(jù))時,包裹的內(nèi)容、重量(長度)、信號強度等信息都會暫時存放在這里。

RADIO_FLAG_IDLE0 空閑。此時模塊沒活干,可以安排新任務(wù)
RADIO_FLAG_TXDONE1發(fā)送成功。信件已成功打向空中
RADIO_FLAG_RXDONE2接收成功。抓到了一個完整的有效數(shù)據(jù)包
RADIO_FLAG_RXTIMEOUT3接收超時。等了半天沒人理我,放棄等待
RADIO_FLAG_RXERR4接收錯誤。抓到了包,但數(shù)據(jù)內(nèi)容壞了(校驗失?。?/p>
RADIO_FLAG_PLHDRXDONE5報頭接收完成。 —— 報頭接收完成


(獲取函數(shù)):這是詢問窗口。比如 rf_get_recv_flag() 就是在問:“現(xiàn)在接收到哪一步了?”
(設(shè)置函數(shù)):這是更新窗口。比如 rf_set_recv_flag(status) 就是在通知系統(tǒng):“我已經(jīng)處理完這個包了,請把狀態(tài)重置為空閑?!?/p>




1. rf_enter_single_rx (進(jìn)入單次接收模式)
簡單理解: 這個函數(shù)相當(dāng)于讓無線模塊“張開耳朵聽一次”。
它的作用: 將模塊從空閑狀態(tài)切換到接收狀態(tài)。
它的執(zhí)行邏輯:
準(zhǔn)備: 同樣先進(jìn)入待機狀態(tài)并切換到發(fā)送模式。
點火: 調(diào)整振蕩器匹配發(fā)送頻率。
投遞: 調(diào)用 PAN3031_send_packet 正式把數(shù)據(jù)包打向空中。
記錄: 記錄下這次發(fā)送耗費的時間,方便后續(xù)計算功耗或排查延遲。
buf:要發(fā)送的“信件內(nèi)容”(數(shù)據(jù)緩沖區(qū)指針)。
size:這封信有多長(數(shù)據(jù)長度)。
tx_time:發(fā)送這封信花了多少時間(由函數(shù)自動計算并返回)。
熱身: 先進(jìn)入 STB3 (待機) 模式。
換向: 將射頻口切換到接收方向。
調(diào)頻: 調(diào)整內(nèi)部振蕩器 (VCO) 匹配接收頻率。
鎖定: 設(shè)置為 SINGLE (單次) 接收模式,意味著收到一個完整的數(shù)據(jù)包后,模塊會自動停下來,不會一直傻聽。

2. rf_single_tx_data (單次數(shù)據(jù)發(fā)送)
簡單理解: 這個函數(shù)相當(dāng)于“把寫好的信投遞出去”。
它的參數(shù):
它的執(zhí)行邏輯:


PAN3031 SDK示例加移植


/* --- PAN3031 Tx-rx 模式示例程序 --- */
// 1. 初始化階段
ret = rf_init(); // 執(zhí)行射頻芯片初始化
if (ret != OK) {
DDL_Printf(" RF Init Fail"); // 如果初始化失敗,打印錯誤信息
while (1); // 程序在此死循環(huán),不再繼續(xù)運行
}
rf_set_default_para(); // 配置射頻芯片的默認(rèn)通信參數(shù)(頻率、功率等)
// 2. 初始數(shù)據(jù)發(fā)送
if (rf_single_tx_data(tx_test_buf, TX_LEN, &tx_time) != OK) {
DDL_Printf("tx fail rn"); // 嘗試發(fā)送第一包數(shù)據(jù),若失敗則報錯
}
else {
txcnt++; // 發(fā)送計數(shù)加 1
DDL_Printf("Tx cnt %drn", txcnt); // 打印當(dāng)前發(fā)送次數(shù)
while (RADIO_FLAG_IDLE == rf_get_transmit_flag()); // 等待硬件發(fā)送標(biāo)志位改變,確保發(fā)送動作完成
rf_set_transmit_flag(RADIO_FLAG_IDLE); // 手動將發(fā)送標(biāo)志位清零,準(zhǔn)備下次操作
rf_sleep(); // 令射頻模塊進(jìn)入休眠狀態(tài)以省電
rf_sleep_wakeup(); // 喚醒模塊,準(zhǔn)備切換到接收狀態(tài)
rf_enter_single_timeout_rx(15000); // 開啟單次超時接收,設(shè)置超時時間為 15000 毫秒(15秒)
}
// 3. 主循環(huán)處理階段
while (1) {
SysTick_Delay(5); // 短暫延時,降低系統(tǒng)負(fù)擔(dān)
// --- 情況 A:接收成功 ---
if (rf_get_recv_flag() == RADIO_FLAG_RXDONE) { // 判斷硬件標(biāo)志位是否為“接收完成”
BSP_LED_Toggle(); // 翻轉(zhuǎn) LED 燈狀態(tài),直觀顯示接收成功
rf_set_recv_flag(RADIO_FLAG_IDLE); // 清除接收標(biāo)志位
// 打印信號質(zhì)量信息:信噪比 (SNR) 和 信號強度 (RSSI)
DDL_Printf("Rx : SNR: %f ,RSSI: %f rn", RxDoneParams.Snr, RxDoneParams.Rssi);
// 循環(huán)打印收到的原始十六進(jìn)制數(shù)據(jù)內(nèi)容
for (i = 0; i < RxDoneParams.Size; i++) {
DDL_Printf("0x%02x ", RxDoneParams.Payload[i]);
}
DDL_Printf("rn");
rxcnt++; // 接收成功計數(shù)加 1
DDL_Printf("###Rx cnt %d##rn", rxcnt);
rf_sleep(); // 接收任務(wù)完成,先進(jìn)入休眠
rf_sleep_wakeup(); // 喚醒,準(zhǔn)備下一次循環(huán)發(fā)送
SysTick_Delay(3000); // 延時 3 秒后再進(jìn)行下一次動作
// 成功接收后,再次發(fā)起數(shù)據(jù)發(fā)送(形成收發(fā)循環(huán))
if (rf_single_tx_data(tx_test_buf, TX_LEN, &tx_time) != OK) {
DDL_Printf("tx fail rn");
}
else {
txcnt++;
DDL_Printf("Tx cnt %drn", txcnt);
while (RADIO_FLAG_IDLE == rf_get_transmit_flag()); // 等待發(fā)送結(jié)束
rf_set_transmit_flag(RADIO_FLAG_IDLE);
rf_sleep();
rf_sleep_wakeup();
rf_enter_single_timeout_rx(15000); // 再次進(jìn)入接收等待狀態(tài)
}
}
// --- 情況 B:接收超時或出錯 ---
if ((rf_get_recv_flag() == RADIO_FLAG_RXTIMEOUT) || (rf_get_recv_flag() == RADIO_FLAG_RXERR)) {
rf_set_recv_flag(RADIO_FLAG_IDLE); // 清除異常標(biāo)志位
DDL_Printf("Rxerrrn"); // 打印接收錯誤或超時提示
rf_sleep();
rf_sleep_wakeup();
HAL_Delay(10000); // 出錯后延時 10 秒(避開干擾或重試間隔)
// 即使失敗,也嘗試再次發(fā)送數(shù)據(jù)
if (rf_single_tx_data(tx_test_buf, TX_LEN, &tx_time) != OK) {
DDL_Printf("tx fail rn");
}
else {
txcnt++;
DDL_Printf("Tx cnt %drn", txcnt);
while (RADIO_FLAG_IDLE == rf_get_transmit_flag());
rf_set_transmit_flag(RADIO_FLAG_IDLE);
rf_sleep();
rf_sleep_wakeup();
rf_enter_single_timeout_rx(15000); // 重新進(jìn)入接收等待
}
}
}
值得參考點
業(yè)務(wù)閉環(huán)完整: 涵蓋了“發(fā)送 -> 等待接收 -> 成功處理 -> 失敗/超時兜底”的完整通信全生命周期。
狀態(tài)切換規(guī)范: 在每次收發(fā)狀態(tài)切換前,都老老實實地調(diào)用了 rf_sleep() 和 rf_sleep_wakeup()。這種“先歸零再啟動”的做法能有效防止射頻芯片內(nèi)部狀態(tài)機卡死。
易讀性高: 純順序執(zhí)行邏輯,沒有復(fù)雜的結(jié)構(gòu)體指針嵌套,適合初學(xué)者順著流程往下讀。
缺點
1.代碼嚴(yán)重冗余:
rf_single_tx_data 及其后續(xù)的 while 等待、rf_sleep 等邏輯,在代碼中出現(xiàn)了三次:
初始化后第一次發(fā)送(第 14-26 行)。
接收成功后再次發(fā)送(第 52-64 行)。
接收失敗后再次發(fā)送(第 81-93 行)。
在工程中,如果一段邏輯在兩處以上被用到,必須封裝成函數(shù)。這不僅是為了美觀,更是為了方便維護(hù)。如果你想修改發(fā)送后的超時時間,在冗余代碼里你要改三次,漏改一個就是 Bug;在函數(shù)里你只需要改一次。
修改方式:
// 封裝成一個通用的“發(fā)送并處理”函數(shù)
void App_RF_Transmit_Flow(void) {
if (rf_single_tx_data(tx_test_buf, TX_LEN, &tx_time) == OK) {
txcnt++;
// 等待發(fā)送完成(建議加入下文提到的超時機制)
while (RADIO_FLAG_IDLE == rf_get_transmit_flag());
rf_set_transmit_flag(RADIO_FLAG_IDLE);
rf_sleep();
rf_sleep_wakeup();
rf_enter_single_timeout_rx(15000); // 開啟下一次接收窗口
}
}
2. “死等”式阻塞:
程序中多次使用 while (RADIO_FLAG_IDLE == rf_get_transmit_flag());。 這段代碼的意思是:只要射頻芯片不回傳“我空閑了”的信號,單片機就永遠(yuǎn)停在這里。
實際應(yīng)用中的做法:絕對不允許出現(xiàn)無條件的死循環(huán)。 如果 SPI 線松了、無線模塊受靜電干擾掛了,或者由于強電磁干擾導(dǎo)致標(biāo)志位沒跳變,你的單片機就會直接“變磚”,不再響應(yīng)任何按鍵或采集任務(wù)。工業(yè)級代碼必須有超時退出或中斷驅(qū)動機制。
修改方式(增加安全計數(shù)器):
uint32_t timeout_cnt = 0x100000; // 設(shè)置一個足夠長的安全計數(shù)器
while (RADIO_FLAG_IDLE == rf_get_transmit_flag()) {
if (--timeout_cnt == 0) {
DDL_Printf("Hard Err: RF Hardware No Response!rn");
// 這里可以執(zhí)行硬件復(fù)位或跳出循環(huán)
break;
}
}
PAN3031 狀態(tài)圖






-
SPI
+關(guān)注
關(guān)注
17文章
1897瀏覽量
101982 -
無線射頻
+關(guān)注
關(guān)注
4文章
220瀏覽量
28032 -
智能水表
+關(guān)注
關(guān)注
4文章
217瀏覽量
24389 -
CW32
+關(guān)注
關(guān)注
1文章
323瀏覽量
1943
發(fā)布評論請先 登錄
CW32量產(chǎn)燒錄工具
【項目展示】基于CW32的遙控循跡小車
【CW32無線抄表項目】W25Q+CW32程序示例
【CW32無線抄表項目】CW32搭配PAN3031通信教程
評論