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

參數(shù)配置流程


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

發(fā)送流程


接收流程



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

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

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



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

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


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




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

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


PAN3031 SDK示例加移植


/* --- PAN3031 Tx-rx 模式示例程序 --- */
// 1. 初始化階段
ret = rf_init(); // 執(zhí)行射頻芯片初始化
if (ret != OK) {
DDL_Printf(" RF Init Fail"); // 如果初始化失敗,打印錯(cuò)誤信息
while (1); // 程序在此死循環(huán),不再繼續(xù)運(yùn)行
}
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ù),若失敗則報(bào)錯(cuò)
}
else {
txcnt++; // 發(fā)送計(jì)數(shù)加 1
DDL_Printf("Tx cnt %drn", txcnt); // 打印當(dāng)前發(fā)送次數(shù)
while (RADIO_FLAG_IDLE == rf_get_transmit_flag()); // 等待硬件發(fā)送標(biāo)志位改變,確保發(fā)送動(dòng)作完成
rf_set_transmit_flag(RADIO_FLAG_IDLE); // 手動(dòng)將發(fā)送標(biāo)志位清零,準(zhǔn)備下次操作
rf_sleep(); // 令射頻模塊進(jìn)入休眠狀態(tài)以省電
rf_sleep_wakeup(); // 喚醒模塊,準(zhǔn)備切換到接收狀態(tài)
rf_enter_single_timeout_rx(15000); // 開(kāi)啟單次超時(shí)接收,設(shè)置超時(shí)時(shí)間為 15000 毫秒(15秒)
}
// 3. 主循環(huán)處理階段
while (1) {
SysTick_Delay(5); // 短暫延時(shí),降低系統(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)志位
// 打印信號(hào)質(zhì)量信息:信噪比 (SNR) 和 信號(hào)強(qiáng)度 (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++; // 接收成功計(jì)數(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); // 延時(shí) 3 秒后再進(jìn)行下一次動(dòng)作
// 成功接收后,再次發(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:接收超時(shí)或出錯(cuò) ---
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"); // 打印接收錯(cuò)誤或超時(shí)提示
rf_sleep();
rf_sleep_wakeup();
HAL_Delay(10000); // 出錯(cuò)后延時(shí) 10 秒(避開(kāi)干擾或重試間隔)
// 即使失敗,也嘗試再次發(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)入接收等待
}
}
}
值得參考點(diǎn)
業(yè)務(wù)閉環(huán)完整: 涵蓋了“發(fā)送 -> 等待接收 -> 成功處理 -> 失敗/超時(shí)兜底”的完整通信全生命周期。
狀態(tài)切換規(guī)范: 在每次收發(fā)狀態(tài)切換前,都老老實(shí)實(shí)地調(diào)用了 rf_sleep() 和 rf_sleep_wakeup()。這種“先歸零再啟動(dòng)”的做法能有效防止射頻芯片內(nèi)部狀態(tài)機(jī)卡死。
易讀性高: 純順序執(zhí)行邏輯,沒(méi)有復(fù)雜的結(jié)構(gòu)體指針嵌套,適合初學(xué)者順著流程往下讀。
缺點(diǎn)
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ā)送后的超時(shí)時(shí)間,在冗余代碼里你要改三次,漏改一個(gè)就是 Bug;在函數(shù)里你只需要改一次。
修改方式:
// 封裝成一個(gè)通用的“發(fā)送并處理”函數(shù)
void App_RF_Transmit_Flow(void) {
if (rf_single_tx_data(tx_test_buf, TX_LEN, &tx_time) == OK) {
txcnt++;
// 等待發(fā)送完成(建議加入下文提到的超時(shí)機(jī)制)
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); // 開(kāi)啟下一次接收窗口
}
}
2. “死等”式阻塞:
程序中多次使用 while (RADIO_FLAG_IDLE == rf_get_transmit_flag());。 這段代碼的意思是:只要射頻芯片不回傳“我空閑了”的信號(hào),單片機(jī)就永遠(yuǎn)停在這里。
實(shí)際應(yīng)用中的做法:絕對(duì)不允許出現(xiàn)無(wú)條件的死循環(huán)。 如果 SPI 線松了、無(wú)線模塊受靜電干擾掛了,或者由于強(qiáng)電磁干擾導(dǎo)致標(biāo)志位沒(méi)跳變,你的單片機(jī)就會(huì)直接“變磚”,不再響應(yīng)任何按鍵或采集任務(wù)。工業(yè)級(jí)代碼必須有超時(shí)退出或中斷驅(qū)動(dòng)機(jī)制。
修改方式(增加安全計(jì)數(shù)器):
uint32_t timeout_cnt = 0x100000; // 設(shè)置一個(gè)足夠長(zhǎng)的安全計(jì)數(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文章
1892瀏覽量
101637 -
無(wú)線射頻
+關(guān)注
關(guān)注
4文章
222瀏覽量
28017 -
智能水表
+關(guān)注
關(guān)注
4文章
221瀏覽量
24383 -
CW32
+關(guān)注
關(guān)注
1文章
322瀏覽量
1923
發(fā)布評(píng)論請(qǐng)先 登錄
CW32量產(chǎn)燒錄工具
【項(xiàng)目展示】基于CW32的遙控循跡小車
【CW32無(wú)線抄表項(xiàng)目】CW32搭配PAN3031通信教程
評(píng)論