0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

【CW32无线抄表项目】CW32搭配PAN3031通信教程

CW32生态社区 来源:CW32生态社区 2026-04-01 17:17 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

一、SPI通信基础知识

SPI(Serial Peripheral Interface)是一种同步串行通信协议,常用于 MCU 与外设之间的高速通信。
SPI 通信通常包含以下信号线:
在本方案中:

CW32 作为 SPI 主机

PAN3031 作为 SPI 从机

SPI 通信由 CW32 主动发起

SCK(Serial Clock):由主机产生的时钟信号

MOSI(Master Out Slave In):主机发送数据给从机

MISO(Master In Slave Out):从机发送数据给主机

CS/SS(Chip Select):片选信号,用于选择通信的从机

二、IQR外部中断知识

IRQ(Interrupt Request)是外设向 MCU 发出的中断请求信号。

PAN3031 通过 IRQ 引脚向 CW32 通知以下事件(示例):

有数据可读取

状态发生变化

需要 MCU 处理的事件发生

MCU 在检测到 IRQ 触发后,会进入中断服务函数(ISR),通常只做:

事件标志位设置

简单状态记录

不建议在中断中直接进行 SPI 通信,而应在主循环或任务中处理。

三、CW32与PAN3031的通信整体流程

CW32 与 PAN3031 的通信方式为:

以两块 CW32 搭配两块 PAN3031 为例:

主机端(Master):

A1: 第一块 CW32(大脑/指挥官)

A2: 第一块 PAN3031(嘴巴和耳朵/无线网卡)

从机端(Slave):

B1: 第二块 CW32(大脑/指挥官)

B2: 第二块 PAN3031(嘴巴和耳朵/无线网卡)

通信全过程分为两部分:

第一段路:大脑指挥网卡 (板级有线通信 - SPI)

A1 与 A2 之间(以及 B1 与 B2 之间)是通过 SPI 接口 连接的。 这就像是老板(CW32)通过内线电话指挥秘书(PAN3031)。

物理连接:它们之间用杜邦线线连接(CSN、SCK、MOSI、MISO)。

通信方式:

A1 (CW32) 发送指令:通过 MOSI 线告诉 A2 “把数据发出去”或者“把配置改一下”。

A2 (PAN3031) 反馈数据:通过 MISO 线把收到的无线数据传回给 A1。

通知机制 (IRQ):当 A2 收到无线数据或者发完数据时,它会拉动 IRQ 引脚(按门铃),告诉 A1 “有情况,快来处理”。

第二段路:网卡隔空对话 (板间无线通信 - 2.4G RF)

A2 与 B2 之间是通过 2.4GHz 无线射频信号 连接的。 这就像是两个拿着对讲机的人在隔空喊话。

物理连接:没有导线,靠天线发射电磁波。

通信方式:

调制 (Tx):A2 把 A1 给它的数字信号(0101...)转换成高频无线电波发射出去。

解调 (Rx):B2 的天线捕捉到这些电波,把它还原成数字信号(0101...)。

特点:这是半双工的,也就是说 A2 在说的时候,B2 必须在听;不能两个人同时说话,否则信号会打架(同频干扰)。

完整的数据传输接力跑 (以主机发送 "kunkun" 为例)

整个通信过程就像一次接力赛,数据是从 A1 的内存 跑到 B1 的内存:

打包 (A1):主机 CW32 (A1) 把字符串 "kunkun" 准备好。

下达指令 (A1 -> A2):A1 通过 SPI 接口,把数据写入 A2 的发送缓冲区,并命令 A2:“发射!”

发射 (A2 -> 空中):A2 启动射频电路,把数据变成无线电波发向空中。

接收 (空中 -> B2):从机 PAN3031 (B2) 的天线捕捉到信号,解析出 "kunkun",存入自己的接收缓冲区。

按门铃 (B2 -> B1):B2 拉高 IRQ 引脚,触发 B1 的外部中断。

读取 (B1 -> B2):从机 CW32 (B1) 收到中断后,通过 SPI 接口 读取 B2 缓冲区里的数据。

处理 (B1):B1 拿到了 "kunkun"。

四、SPI硬件连接说明

SPI 硬件连接如下(示例):

CW32 引脚 PAN3031 引脚 说明
SCK SCK SPI 时钟
MOSI MOSI 主发从收
MISO MISO 从发主收
GPIOx CS SPI 片选
GPIOy IRQ 外部中断

CS 信号通常为 低电平有效,需由软件控制。

五、SPI工作模式说明

SPI 通信就像两个人跳绳,必须在同一个节奏点上起跳才不会绊倒。为了让 CW32(主机)能正确读写 PAN3031(从机),双方的配置必须完全一致。

PAN3031 使用的是标准的 SPI Mode 0,CW32 初始化 SPI 时必须严格按照以下参数配置:

SPI 模式:Mode 0

时钟极性 (CPOL) = 0:

表示 SCLK 时钟线在空闲状态(没有传输数据时)保持 低电平 (Low Level)。

时钟相位 (CPHA) = 0:

表示在时钟的 第一个边沿(对于 Mode 0 来说是 上升沿)进行数据采样(读取数据)。

而在第二个边沿(下降沿)进行数据切换(发送下一位数据)。

数据位顺序 (Bit Order):

MSB First(高位先发)。

六、IRQ触发方式说明

PAN3031 的 IRQ 信号为 上升沿 触发。

CW32 需将对应 GPIO 配置为外部中断输入,并设置正确的触发方式。

七、PAN3031模块使用说明(详细版)

PAN3031 SDK使用流程

初始化流程

wKgZO2nLyIGATcdrAABWJO81OQg291.jpg

参数配置流程

wKgZO2nM4J2AdkCgAAAzGVw1H_s625.jpg

wKgZPGnLyIKAEXUtAABDELgCPsc214.jpg

1. PAN3031_set_freq (设置中心频率)

干什么用的: 设置模块工作在哪个频段(比如 2.4GHz、470MHz 等)。

小白比喻:调对讲机频道。如果主机在 1 频道喊话,从机在 2 频道听,两人永远对不上话。

2. PAN3031_set_code_rate (设置编码纠错率)

干什么用的: 决定在发送真实数据时,夹带多少“冗余纠错码”。

小白比喻:给快递包防震膜。空气中干扰很多,容易丢包。纠错率设得越高(膜包得越厚),就算数据在空中损坏了一点,接收端也能自己推算修复回来;但代价是有效数据的传输效率变低了。

3. PAN3031_set_bw (设置带宽 Bandwidth)

干什么用的: 决定无线信号占据的频率宽度。

小白比喻:修多宽的马路。带宽越大,数据传得越快;但马路越宽,越容易受到旁边车道(其他无线电信号)的干扰,接收灵敏度会下降。

4. PAN3031_set_sf (设置扩频因子 Spreading Factor)

干什么用的: 这是扩频通信(如 LoRa 调制)里非常关键的参数,决定每个数据符号的持续时间。

小白比喻:讲话的语速。SF 值越大,相当于你讲话越慢、发音越长,哪怕距离很远、环境很吵对方也能听清(穿墙能力大增);但缺点是一句话要说很久,模块工作时间变长,非常费电。

5. PAN3031_set_tx_power (设置发射功率)

干什么用的: 设置芯片射频引脚输出的能量大小(比如 10dBm、22dBm)。

小白比喻:嗓门有多大。功率调得越高,信号覆盖范围越广,但也意味着你的电池会被抽干得越快。

6. PAN3031_set_crc (设置 CRC 循环冗余校验)

干什么用的: 开启后,硬件会自动在数据包尾部追加一段校验码。

小白比喻:贴封条防伪。接收端拿到包裹后,会检查封条是否完好。如果发现对不上,说明数据在空中被干扰串味了,直接丢弃,防止单片机读到错误的 ADC 抄表数据。

图片

发送流程

图片

wKgZO2nLyIOAbQ0cAAA9WFzYDog316.jpg

接收流程

wKgZPGnLyIWAdlSZAABIBuBMt60678.jpg

wKgZO2nLyIWAY1sdAAAsqoqkbKw557.jpg

wKgZO2nLyIaAbgoJAAAackWkuLE697.jpg

PAN3031 部分SDK接口函数

图片

agc(自动增益控制)

功能: 全称 Automatic Gain Control。它会根据收到的无线信号强弱,自动调节内部放大器的放大倍数。

小白比喻:“自动音量调节”。如果发射端离得很近,信号太强,它就调低增益防止“震耳朵”;如果离得远信号弱,它就自动调高增益,确保无论远近,芯片都能清晰地“听见”数据。

AGC 的核心原理是一个 “检测 -> 反馈 -> 调整” 的闭环系统。

技术实现流程:

信号进入: 天线接收到的原始无线信号进入芯片。

强度检测: 芯片内部有一个“侦察兵”(信号强度检测器),实时测量这个信号的功率(也就是我们常说的 RSSI)。

比较判断: 芯片内部设定了一个“理想音量”范围。

如果信号太强: 会导致后面的电路“破音”(饱和失真),数据就全乱了。

如果信号太弱: 背景噪音就会盖过数据。

反馈调整: 侦察兵发现信号太强,就立刻下令让 LNA(低噪声放大器) 降低放大倍数(减小增益)。

发现信号太弱,就下令让 LNA 全力放大(增大增益)。

antenna_init(天线初始化)

功能: 配置射频端口和天线开关。

小白比喻:“切换车道”。无线芯片通常有一个天线,但有“发”和“收”两条路。这个步骤是初始化天线开关的控制逻辑,确保你想发的时候数据能传给天线,想收的时候天线信号能传给芯片。

Antenna_init 的原理本质上是 “单刀双掷开关(SPDT)” 的逻辑配置。

技术实现流程:

链路分离: 无线芯片内部其实有两套完全独立的系统:发射机(TX)产生强大的信号,接收机(RX)负责捕捉微弱的信号。

物理矛盾: 但是,为了节省成本和空间,整个设备通常只有一根天线。

开关切换: 在天线和芯片之间,有一个射频开关(RF Switch)。

发送时: 开关必须拨向“发射链路”,把功率放大器(PA)产生的信号推向天线。

接收时: 开关必须拨向“接收链路”,把天线捕捉到的微弱波浪送给接收器

初始化保护:antenna_init 就是在初始化阶段,配置好控制这个“开关”的 GPIO 引脚逻辑。

wKgZPGnLyIaARBoQAABuCludVzw333.jpg

节能模式:芯片的“休息时间”

PAN3031_MODE_DEEP_SLEEP(深度睡眠)

状态: 芯片几乎完全关闭,功耗降到最低(微安级)。

小白比喻:彻底关机。这是抄表系统最常用的状态。电表每天 99% 的时间都应该处于这个模式来省电。

PAN3031_MODE_SLEEP(睡眠)

状态: 功耗略高于深度睡眠,但保留了寄存器的配置。

小白比喻:电脑休眠。唤醒速度比深度睡眠快一点,不需要重新加载所有配置。

准备模式:芯片的“热身阶段”

这三个 STB (Standby) 模式是处于休眠和工作之间的中间地带,它们决定了芯片内部哪些组件(如晶振、频率合成器)是开着的。

PAN3031_MODE_STB1 / STB2

状态: 基础待机。内部晶振开始起振。

小白比喻:坐在板凳上热身。虽然没下场比赛,但已经穿好运动鞋了。

STB1:深度省电的“浅睡”模式

在 STB1 模式下,芯片关闭了外部晶振,只靠内部一个很弱的 RC 电路维持基本逻辑。

优点: 非常省电,比 STB2 能多省下不少微安级的电流

缺点: 当你需要发数据时,从 STB1 切换到 TX(发射)需要一段“暖机时间”,因为外部晶振从静止到稳定震荡需要几百微秒甚至毫秒级的时间。

STB2:随时待命的“备战”模式

在 STB2 模式下,芯片已经把昂贵且精确的外部晶振给跑起来了。

优点: 响应极其灵敏。如果你在做一个需要频繁快速回应(比如 10ms 内必须回信)的协议,STB2 是唯一的选择。

缺点: 功耗相对较高。如果一直停在 STB2,你的电表电池可能撑不了几年。

PAN3031_MODE_STB3

状态: 高级待机。频率合成器(决定你发什么频率)已经锁定。

小白比喻:在起跑线上蹲好了。这是进入“发射”或“接收”之前的最后一站。在你之前的代码里,进入 rf_single_tx_data 之前都会先切换到这个模式。

工作模式:芯片的“上场比赛”

PAN3031_MODE_TX(发射模式)

状态: 功率放大器开启,全力向天线推送电磁波。

小白比喻:放声大喊。这是最费电的时刻,所以发送完数据一定要赶紧让它睡觉。

PAN3031_MODE_RX(接收模式)

状态: 接收链路全开,实时捕捉空中的微弱信号。

小白比喻:竖起耳朵细听。在抄表项目中,电表端通常只在发送完数据后的那几百毫秒开启这个模式来等确认。

wKgZO2nLyIeAJAUFAAAWguGB0zk961.jpg

wKgZO2nM4J2AXHHIAAEWPTa_IvM214.jpg

wKgZPGnLyIiAf4dKAAAPChdL-IQ698.jpg

RF_PARA_TYPE_FREQ(中心频率)

技术内幕: 指无线电波能量最集中的那个点(例如 470MHz 或 433MHz)。

实战要点:

必须匹配:主机和从机的频率误差不能超过一定范围(通常是晶振精度的几倍),否则由于“偏频”会导致信号极差甚至搜不到包。

避开干扰:如果小区里有大量同频段的无线设备,可以微调频率(跳频)来寻找一个“安静”的频道。

RF_PARA_TYPE_CR(编码纠错率)

技术内幕: 全称 Code Rate。它在原始数据中加入冗余的校验位(例如 4/5 代表 4 位数据加 1 位冗余)。

实战要点:

抗干扰性:设置越高(如 4/8),抗突发干扰能力越强,就算空中丢了几位数据,芯片也能靠算法补回来。

副作用:纠错位越多,整个数据包就越长,空中飞行时间(ToA) 增加,从而增加功耗。

RF_PARA_TYPE_BW(带宽)

技术内幕: 指信号占据的频率宽度(如 125kHz, 250kHz, 500kHz)。

实战要点:

速率 vs. 灵敏度:马路越宽(BW 大),车速越快(数据率高),但路上的噪音也多(底噪高,灵敏度差)。

抄表选择:通常选择较小的带宽(如 125kHz)来换取更高的接收灵敏度,确保能穿透更厚的墙。

RF_PARA_TYPE_SF(扩频因子)

技术内幕:Spreading Factor,是 LoRa/扩频通信的灵魂。它决定了一个数据符号被拉得有多长。

实战要点:

穿墙神器:SF 越大(如 SF12),信号在噪声中被识别的能力越强,距离翻倍。

功耗陷阱:SF 每增加一级,数据在空中停留的时间几乎翻倍。这会导致 PAN3031 的发射电流持续时间变长,严重缩短电表寿命。

RF_PARA_TYPE_TXPOWER(发射功率)

技术内幕: 芯片输出信号的强度,单位通常为 dBm。

实战要点:

按需调整:如果电表就在网关旁边,没必要开 20dBm(最大功率),调低功率能有效节省电量。

法规限制:不同国家和地区对不同频段的最大功率有法律限制,开发时需查阅当地标准。

RF_PARA_TYPE_CRC(循环冗余校验)

技术内幕: 在数据包末尾添加计算好的校验码。

实战要点:

数据保真:无线环境非常脏,数据包很容易被干扰成乱码。开启 CRC 后,如果收到的包计算结果不符,硬件会自动丢弃,防止你的单片机读到错误的“水费”或“电费”数据。

核心变量:内部状态记录员

程序定义了两个 static(静态)变量,它们就像是挂在实验室门口的记事板,用来记录无线模块当前的工作状态。

packet_received:专门记录接收的状态。是收到了?还是超时了?还是出错了?

packet_transmit:专门记录发送的状态。是正在发?还是发完了?

RxDoneParams:这是一个结构体,它像是一个快递暂存柜。当收到新包裹(数据)时,包裹的内容、重量(长度)、信号强度等信息都会暂时存放在这里。

wKgZO2nM4J6ANxD4AAAuGjr91sE624.jpg

RADIO_FLAG_IDLE0 空闲。此时模块没活干,可以安排新任务

RADIO_FLAG_TXDONE1发送成功。信件已成功打向空中

RADIO_FLAG_RXDONE2接收成功。抓到了一个完整的有效数据包

RADIO_FLAG_RXTIMEOUT3接收超时。等了半天没人理我,放弃等待

RADIO_FLAG_RXERR4接收错误。抓到了包,但数据内容坏了(校验失败)

RADIO_FLAG_PLHDRXDONE5报头接收完成。 —— 报头接收完成

wKgZO2nLyImAFMVHAAAR2iB0b7k386.jpg

wKgZPGnLyImAY3akAAATGCJdnqY939.jpg

(获取函数):这是询问窗口。比如 rf_get_recv_flag() 就是在问:“现在接收到哪一步了?”

(设置函数):这是更新窗口。比如 rf_set_recv_flag(status) 就是在通知系统:“我已经处理完这个包了,请把状态重置为空闲。”

wKgZO2nLyImAVkvfAAALxPyneqE951.jpg

wKgZPGnLyIqAAdggAAAbknyI1Bo104.jpg

wKgZO2nLyIqAQCHJAAANhLSM8lg094.jpg

wKgZPGnLyIqAUPwaAAAL7g-aieA844.jpg

1. rf_enter_single_rx (进入单次接收模式)

简单理解: 这个函数相当于让无线模块“张开耳朵听一次”。

它的作用: 将模块从空闲状态切换到接收状态。

它的执行逻辑:

准备: 同样先进入待机状态并切换到发送模式。

点火: 调整振荡器匹配发送频率。

投递: 调用 PAN3031_send_packet 正式把数据包打向空中。

记录: 记录下这次发送耗费的时间,方便后续计算功耗或排查延迟。

buf:要发送的“信件内容”(数据缓冲区指针)。

size:这封信有多长(数据长度)。

tx_time:发送这封信花了多少时间(由函数自动计算并返回)。

热身: 先进入 STB3 (待机) 模式。

换向: 将射频口切换到接收方向。

调频: 调整内部振荡器 (VCO) 匹配接收频率。

锁定: 设置为 SINGLE (单次) 接收模式,意味着收到一个完整的数据包后,模块会自动停下来,不会一直傻听。

wKgZPGnM4J6AEJzdAADIcHlEbyk693.jpg


2. rf_single_tx_data (单次数据发送)
简单理解: 这个函数相当于“把写好的信投递出去”。

它的参数:

它的执行逻辑:

wKgZO2nLyIuAGHANAABFwN9LrgE608.jpg

wKgZPGnLyIuAB4FEAACZ9uRnLaI517.jpg

PAN3031 SDK示例加移植

wKgZO2nLyIyAd63yAACL-JYpGzs668.jpg

图片

/* --- PAN3031 Tx-rx 模式示例程序 --- */
// 1. 初始化阶段
ret = rf_init();                                        // 执行射频芯片初始化
if (ret != OK) {
    DDL_Printf(" RF Init Fail");                        // 如果初始化失败,打印错误信息
    while (1);                                          // 程序在此死循环,不再继续运行
}
rf_set_default_para();                                  // 配置射频芯片的默认通信参数(频率、功率等)
// 2. 初始数据发送
if (rf_single_tx_data(tx_test_buf, TX_LEN, &tx_time) != OK) { 
    DDL_Printf("tx fail rn");                         // 尝试发送第一包数据,若失败则报错
} 
else {
    txcnt++;                                            // 发送计数加 1
    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);                  // 开启单次超时接收,设置超时时间为 15000 毫秒(15秒)
}
// 3. 主循环处理阶段
while (1) {
    SysTick_Delay(5);                                   // 短暂延时,降低系统负担

    // --- 情况 A:接收成功 ---
    if (rf_get_recv_flag() == RADIO_FLAG_RXDONE) {      // 判断硬件标志位是否为“接收完成”
        BSP_LED_Toggle();                               // 翻转 LED 灯状态,直观显示接收成功
        rf_set_recv_flag(RADIO_FLAG_IDLE);              // 清除接收标志位

        // 打印信号质量信息:信噪比 (SNR) 和 信号强度 (RSSI)
        DDL_Printf("Rx : SNR: %f ,RSSI: %f rn", RxDoneParams.Snr, RxDoneParams.Rssi);

        // 循环打印收到的原始十六进制数据内容
        for (i = 0; i < RxDoneParams.Size; i++) {
            DDL_Printf("0x%02x ", RxDoneParams.Payload[i]);
        }
        DDL_Printf("rn");

        rxcnt++;                                        // 接收成功计数加 1
        DDL_Printf("###Rx cnt %d##rn", rxcnt);

        rf_sleep();                                     // 接收任务完成,先进入休眠
        rf_sleep_wakeup();                              // 唤醒,准备下一次循环发送
        SysTick_Delay(3000);                            // 延时 3 秒后再进行下一次动作

        // 成功接收后,再次发起数据发送(形成收发循环)
        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);          // 再次进入接收等待状态
        }
    }
    // --- 情况 B:接收超时或出错 ---
    if ((rf_get_recv_flag() == RADIO_FLAG_RXTIMEOUT) || (rf_get_recv_flag() == RADIO_FLAG_RXERR)) {
        rf_set_recv_flag(RADIO_FLAG_IDLE);              // 清除异常标志位
        DDL_Printf("Rxerrrn");                        // 打印接收错误或超时提示

        rf_sleep();
        rf_sleep_wakeup();
        HAL_Delay(10000);                               // 出错后延时 10 秒(避开干扰或重试间隔)

        // 即使失败,也尝试再次发送数据
        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);          // 重新进入接收等待
        }
    }
}

值得参考点

业务闭环完整: 涵盖了“发送 -> 等待接收 -> 成功处理 -> 失败/超时兜底”的完整通信全生命周期。
状态切换规范: 在每次收发状态切换前,都老老实实地调用了 rf_sleep() 和 rf_sleep_wakeup()。这种“先归零再启动”的做法能有效防止射频芯片内部状态机卡死。
易读性高: 纯顺序执行逻辑,没有复杂的结构体指针嵌套,适合初学者顺着流程往下读。

缺点

1.代码严重冗余:

rf_single_tx_data 及其后续的 while 等待、rf_sleep 等逻辑,在代码中出现了三次:

初始化后第一次发送(第 14-26 行)。

接收成功后再次发送(第 52-64 行)。

接收失败后再次发送(第 81-93 行)。

在工程中,如果一段逻辑在两处以上被用到,必须封装成函数。这不仅是为了美观,更是为了方便维护。如果你想修改发送后的超时时间,在冗余代码里你要改三次,漏改一个就是 Bug;在函数里你只需要改一次。
修改方式:

// 封装成一个通用的“发送并处理”函数
void App_RF_Transmit_Flow(void) {
    if (rf_single_tx_data(tx_test_buf, TX_LEN, &tx_time) == OK) {
        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); // 开启下一次接收窗口
    }
}

2. “死等”式阻塞:
程序中多次使用 while (RADIO_FLAG_IDLE == rf_get_transmit_flag());。 这段代码的意思是:只要射频芯片不回传“我空闲了”的信号,单片机就永远停在这里。
实际应用中的做法:绝对不允许出现无条件的死循环。 如果 SPI 线松了、无线模块受静电干扰挂了,或者由于强电磁干扰导致标志位没跳变,你的单片机就会直接“变砖”,不再响应任何按键或采集任务。工业级代码必须有超时退出或中断驱动机制。
修改方式(增加安全计数器):

uint32_t timeout_cnt = 0x100000; // 设置一个足够长的安全计数器
while (RADIO_FLAG_IDLE == rf_get_transmit_flag()) {
    if (--timeout_cnt == 0) {
        DDL_Printf("Hard Err: RF Hardware No Response!rn");
        // 这里可以执行硬件复位或跳出循环
        break; 
    }
}
PAN3031 状态图

wKgZPGnLyIyAct1ZAABSwuu6peM554.jpg

wKgZO2nLyI2AIHpiAABSCGVY9Mw302.jpg

wKgZPGnLyI2AB_47AABKbEYo-Eg564.jpg

wKgZO2nLyI2Acg6sAAAU0Hh2ItE972.jpg

wKgZPGnLyI2AKmVkAADlfIbHgRA047.jpg

388937f71cc6fac3105b8b6d20a1aa99.png

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • SPI
    SPI
    +关注

    关注

    17

    文章

    1897

    浏览量

    102081
  • 无线射频
    +关注

    关注

    4

    文章

    220

    浏览量

    28033
  • 智能水表
    +关注

    关注

    4

    文章

    218

    浏览量

    24392
  • CW32
    +关注

    关注

    1

    文章

    323

    浏览量

    1953
收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    CW32移植Free-RTOS】CW32开发者扶持计划

    CW32配置Free-RTOS全过程,CW32开发者扶持计划
    的头像 发表于 04-18 09:38 7539次阅读
    【<b class='flag-5'>CW32</b>移植Free-RTOS】<b class='flag-5'>CW32</b>开发者扶持计划

    CW32快速开发入门

    CW32快速开发入门
    的头像 发表于 04-24 18:56 3800次阅读
    <b class='flag-5'>CW32</b>快速开发入门

    CW32量产烧录工具

    本节主要介绍CW32微控制器的烧录器CW-Writer,以及与之配合的软件CW-Programmer的使用方法。烧录器CW-Writer通过ISP协议,可实现对
    的头像 发表于 04-25 15:22 3033次阅读
    <b class='flag-5'>CW32</b>量产烧录工具

    项目展示】基于CW32的遥控循迹小车

    CW32循迹小车.zip_免费高速下载|百度网盘-分享无限制  一、概述 CW32循迹、遥控小车具有循迹和遥控两种功能,小车的硬件模块由CW32F030C8T6小蓝板、智能小车控制底板、BT04-E
    的头像 发表于 05-31 17:33 2638次阅读
    【<b class='flag-5'>项目</b>展示】基于<b class='flag-5'>CW32</b>的遥控循迹小车

    CW32无线表项目】W25Q+CW32程序示例

    /Armink/SFUD 一、程序分析 硬件总线映射(引脚与时钟的“避坑点”)   #define FLASH_SPIx CW_SPI2// 注意:CW32 中 SPI1 在 APB2 总线,而 SPI2 通常
    的头像 发表于 03-31 21:29 4911次阅读
    【<b class='flag-5'>CW32</b><b class='flag-5'>无线</b><b class='flag-5'>抄</b><b class='flag-5'>表项目</b>】W25Q+<b class='flag-5'>CW</b>32程序示例

    CW32开发者扶持计划#CW32 #芯片

    CW32
    CW32生态社区
    发布于 :2023年05月24日 16:56:14

    cw32和stm32的区别

    cw32和stm32的区别 CW32和STM32是两种常见的单片机,被广泛应用于各种电子设备中。在本文中,我们将深入探讨CW32和STM32之间的区别和优劣势。 1. 硬件性能 硬件性能是衡量单片机
    的头像 发表于 08-16 11:15 6541次阅读

    cw32和gd32的区别

    cw32和gd32的区别 CW32和GD32是两种不同的芯片系列,分别由WCH和GigaDevice公司推出,两者有很多不同之处,下面我们来详细介绍。 首先从CW32系列开始,CW32
    的头像 发表于 08-16 11:15 3383次阅读

    基于CW32的无刷水泵方案

    基于CW32的无刷水泵方案
    的头像 发表于 11-03 17:28 2051次阅读
    基于<b class='flag-5'>CW32</b>的无刷水泵方案

    基于CW32热敏电阻采集温度应用

    基于CW32热敏电阻采集温度应用
    的头像 发表于 10-25 16:45 1420次阅读
    基于<b class='flag-5'>CW32</b>热敏电阻采集温度应用

    CW32的SPI单工模式主从通信介绍

    CW32的SPI单工模式主从通信介绍
    的头像 发表于 10-24 15:50 2102次阅读
    <b class='flag-5'>CW32</b>的SPI单工模式主从<b class='flag-5'>通信</b>介绍

    CW32 PWM输出功能介绍

    CW32 PWM输出功能介绍
    的头像 发表于 09-27 16:12 2352次阅读
    <b class='flag-5'>CW32</b> PWM输出功能介绍

    CW32实时时钟(RTC)介绍

    CW32实时时钟(RTC)介绍
    的头像 发表于 10-24 15:36 2375次阅读
    <b class='flag-5'>CW32</b>实时时钟(RTC)介绍

    基于CW32的RC522刷卡模块的应用

    基于CW32的RC522刷卡模块的应用
    的头像 发表于 11-02 14:53 2731次阅读
    基于<b class='flag-5'>CW32</b>的RC522刷卡模块的应用

    基于CW32的物联网应用

    CW32】基于CW32的物联网应用
    的头像 发表于 11-02 15:55 2096次阅读
    基于<b class='flag-5'>CW32</b>的物联网应用