说明一下沁恒 2.4G RF_Basic 示例 ...... 矜辰所致
前言
在我们使用蓝牙芯片的时候,2.4G 与 蓝牙使用的是同一套射频硬件,有时候遇到一些不同的应用场合:比如要求延迟极低(8K回报率键鼠),MCU 资源占用要尽可能小(节约内存空间),或是需要高度自定义通信逻辑。 这时我们可以不运行完整蓝牙协议栈,直接操控底层射频硬件,使用私有 2.4G 来实现无线通信功能。
沁恒提供了 2.4GRF 的库,在 EVT 中提供了几个 2.4G 的例程。
本文我们来看看其中 RF 基础例程 RF_basic 。
我是矜辰所致,全网同名,尽量用心写好每一系列文章,不浮夸,不将就,认真对待学知识的我们,矜辰所致,金石为开!
目录
- 前言
- [一、 基础介绍](#一、 基础介绍)
-
- [1.1 私有2.4G 与蓝牙比较](#1.1 私有2.4G 与蓝牙比较)
- [1.2 推荐使用场景](#1.2 推荐使用场景)
- [二、 例程说明](#二、 例程说明)
-
- [2.1 测试效果](#2.1 测试效果)
-
- [2.1.1 无应答收发](#2.1.1 无应答收发)
- [2.1.2 应答收发](#2.1.2 应答收发)
- [2.2 例程分析(BLE 分析仪)](#2.2 例程分析(BLE 分析仪))
-
- [2.2.1 代码解析](#2.2.1 代码解析)
- [2.2.2 分析仪抓包解析](#2.2.2 分析仪抓包解析)
- [2.2.3 数据格式说明](#2.2.3 数据格式说明)
- 三、一些使用说明
- 四、典型应用
-
- [4.1 模拟蓝牙广播](#4.1 模拟蓝牙广播)
- [4.2 接收蓝牙广播](#4.2 接收蓝牙广播)
- 结语
一、 基础介绍
1.1 私有2.4G 与蓝牙比较
2.4G 与 蓝牙基本区别,我们用一个表格简单介绍,不太熟悉的小伙伴依旧可以去问 AI,这些基础的概念介绍 AI 还是靠谱的 。
| 对比项 | 私有 2.4G(裸 RF) | BLE 蓝牙 |
|---|---|---|
| 通信延迟 | 可达几百 μs,时序完全可控 | 连接间隔最小 7.5ms,广播间隔最小 20ms,受协议栈约束 |
| MCU 资源 | Flash/RAM 占用极小,几百字节 RAM 即可工作 | 协议栈开销大,需几 KB~十几 KB RAM、数十上百 KB Flash |
| 协议自由度 | 极高:信道、包长、同步字、ACK、重传全部自定义 | 严格遵循 Core Spec,PDU、GATT、广播参数被规范限制 |
| 跳频策略 | 可自己实现,也可固定单信道 | 广播态 :固定 37/38/39 信道; 连接态:强制自适应跳频 |
| 数据包开销 | 头部开销少,有效载荷占比高(可达 90%+) | 存在 PDU、MIC(加密时)、ATT 等固定协议开销 |
| 设备兼容性 | 仅自家收发设备互通,无法直连手机/平板 | 原生支持手机/电脑/平板,标准设备互相兼容 |
| 系统兼容性 | 无 OS 兼容问题,行为完全由代码决定 | iOS/安卓扫描限制、GATT 缓存、连接参数被主机拒绝等 |
| 设备发现与配对 | 全部需要自己手写实现 | 协议栈自带广播扫描、配对、绑定、加密(AES-CCM) |
| 休眠低功耗 | 休眠唤醒逻辑全部自行开发 | 协议栈内置成熟的广播/连接休眠机制 |
| 抗干扰能力 | 固定信道易受 Wi-Fi/微波炉干扰,需自行处理 | AFH 跳频自动避开干扰信道,抗干扰能力更强 |
| 开发周期 | 长:射频、时序、协议、加密全部自己搭 | 短:调用协议栈 API 即可,生态成熟 |
| 认证成本 | 无需BQB认证,成本低 | 需 BQB 认证(费用较高),否则不能打蓝牙商标 |
| 传输速率 | 自定义,可做到很高(如 2Mbps+)或很低 | 标准速率:1M / 2M / 500K / 125K(LE Coded) |
1.2 推荐使用场景
选私有 2.4G:
- 追求极低延迟(8K 鼠标、游戏手柄、模型遥控)
- MCU 资源极其紧张(几 KB Flash 都嫌多)
- 需要高度自定义包格式、收发时序、重传、ACK 策略
- 设备间点对点/多点组网,不需要对接手机/电脑
- 需要固定信道做射频测试或特定场景通信
- 不想交 BQB 认证费,快速出货
选 BLE:
- 需要设备直连手机、平板、电脑,不想配 Dongle
- 需要现成配对、安全加密、设备发现,不想手写上层逻辑
- 使用标准 HID、电池、心率等 GATT Profile,追求跨厂商互通
- 需要快速开发上市,利用成熟协议栈
- 对抗 Wi-Fi 干扰有要求,需要 AFH 跳频
二、 例程说明
本文以 CH585 为例说明,例程位置如下:

RF_Basic 为 2.4G 库中的基础模式,提供 RF 收发接口函数,相关参数配置接口,便于扩展各种应用,可依据此模式进行自主开发。
2.1 测试效果
在示例 RF_basic.c 文件最上面,有一些宏定义, 通过宏定义可以配置为基础收发,带 ACK 的收发等不同模式 。
2.1.1 无应答收发
我们做基本测试是需要烧录 2 个设备,一个作为发送端,一个作为接收端 ,默认是无应答收发,我们只需要例程里面注意下面两个宏定义,分别烧录2个设备即可测试,如下图:

两个设备通过串口都可以看到 Debug 信息,分别会打印接收到的包数,与发送的包数,这个示例的串口波特率为 921600 ,如下图:

2.1.2 应答收发
只需要把宏定义 WAIT_ACK 改为 1 ,测试效果如下,打印的数据依然和上面一样:每秒发送的包数,每秒接收的包数,收到报文的 RSSI 值 ,因为发送端需要接收 ACK ,接收端需要发送 ACK ,所以两端都有收发:
c
#define WAIT_ACK 1 // 是否使能ACK

别看感觉好多错误,这是每秒的数据,每秒发将近 4000 条报文,丢几条也算是正常的。
上面是示例展示的使用效果,对于示例其实也是很简单的,因为官方提供给了我们库,我们只需要学会配置和函数的使用,就可以进行 2.4G 收发的应用了,我们下面来说明一下。
2.2 例程分析(BLE 分析仪)
2.2.1 代码解析
对于 2.4G 通信,有 5 项核心配置:
- accessAddress :接入地址
- crcInit :CRC 校验种子
- frequency :载波频点
- PHY 速率
- Whitening :数据白化开关
上面的 5 项参数一致是 PHY 层通信的必要条件。
这里推荐一篇大佬的文章,文章对 RF_basic 主要代码做了详细的注释:
代码解析参考上面文章,使用流程大家直接去看示例,因为逻辑很简单,一些注意事项与不同应用示例的应用在下文也会有说明,示例中有一个 wchrf.h 头文件,里面就是官方提供的 2.4G 库的头文件。我们主要来说明 3 个结构体:rfRoleParam_t ,rfipTx_t, rfipRx_t 实际上官方注释已经很清晰了 ,这里用表格解释一下 。
首先是 rfRoleParam_t 代表着链路层的基础配置,定义了通信双方共享的物理层参数 :
| 字段 | 类型 | 说明 |
|---|---|---|
accessAddress |
uint32_t |
接入地址,32 位 PHY 层地址。用于区分不同链路,收发双方必须一致,比如蓝牙广播的固定接入地址为 0x8E89BED6 |
crcInit |
uint32_t |
CRC 初始值,收发双方需一致,用于数据完整性校验。 |
frequency |
uint32_t |
射频频率 ,范围 2400000~2483500 kHz(即 2.4~2.4835 GHz)。 示例中直接使用通道也可以定义 0~39 (如果使用0~39赋值就是按照蓝牙通道分布对应的频段进行收发的,通道0就是 2404MHz,示例赋值为16:2438MHz) |
properties |
uint32_t |
属性位域: • bit0 : 数据白化开关(0=开启,1=关闭) • bit1 : 等待 ACK 模式(0=不等待,1=等待 ACK) • bit4-5: 速率选择(00=1Mbps,01=2Mbps) |
rxMaxLen |
uint16_t |
接收数据最大长度,防止缓冲区溢出。 |
sendInterval |
uint16_t |
重发间隔,单位 N×0.5μs。用于自动重传机制。 |
sendTime |
uint16_t |
Rx→Tx 切换时间,计算公式:(N×0.5μs) + 24μs。控制从接收状态切换到发送状态的延迟。 |
mapCheckCount |
uint8_t |
信道质量检测阈值,默认 2。连续丢包达到该次数时判定信道质量差,可触发跳频。 |
rfipTx_t 配置发送端的行为,负责确定这次发送怎么发 :
| 字段 | 类型 | 说明 |
|---|---|---|
accessAddress |
uint32_t |
同上,接入地址。 |
crcInit |
uint32_t |
同上,CRC 初始值。 |
frequency |
uint32_t |
同上,射频频率。 |
properties |
uint32_t |
属性位域(比 rfRoleParam_t 多了 bit2): • bit0 : 白化开关 • bit1 : 等待 ACK(发送后是否等待接收方回 ACK) • bit2 : 白化信道来源选择(0=自动/默认,1=使用 whiteChannel 字段) • bit4-5: 速率(00=1M,01=2M) |
txDMA |
uint32_t |
发送 DMA 地址,指向待发送数据的内存地址,硬件直接 DMA 取数发送。 |
whiteChannel |
uint8_t |
白化信道索引 ,当 properties bit2=1 时生效,用于指定数据白化算法的信道参数。 |
sendTime |
uint8_t |
Rx→Tx 切换时间,公式同上:(N×0.5μs) + 24μs。注意这里类型是 uint8_t,范围比 rfRoleParam_t 中的小。 |
sendCount |
uint16_t |
重发次数 。如果开启 ACK 模式,发送未收到 ACK 时会自动重传,最多重发 sendCount 次。 |
rfipRx_t 配置接收端的行为,负责确定这次接收怎么收 :
| 字段 | 类型 | 说明 |
|---|---|---|
accessAddress |
uint32_t |
同上。 |
crcInit |
uint32_t |
同上。 |
frequency |
uint32_t |
同上。 |
properties |
uint32_t |
属性位域: • bit0 : 白化开关 • bit1 : 发送 ACK(收到数据后是否自动回复 ACK) • bit4-5 : 速率(00=1M,01=2M) |
rxDMA |
uint32_t |
接收 DMA 地址,指向接收缓冲区,硬件收到数据后通过 DMA 直接写入。 |
whiteChannel |
uint8_t |
白化信道索引,配合数据白化使用。 |
rxMaxLen |
uint16_t |
接收数据最大长度。 |
timeOut |
uint16_t |
接收超时时间,0=无超时;非 0 时单位为 N×0.5μs。用于等待数据时的超时退出。 |
2.2.2 分析仪抓包解析
为了更加直观的展示 2.4G 的效果,我们可以通过蓝牙协议分析仪抓包看一下结果,分析仪的设置如下图 :

这里再说明一下虽然结构体 成员frequency 注释为 rf frequency (2400000kHz-2483500kHz) ,但是我们可以使用蓝牙频段(0~ 39)作为参数测试,使用(0~39)频段以蓝牙频段为准(37 为 2402 MHz) ,使用沁恒的分析仪目前直接选择通道即可,目前沁恒的分析仪也只能抓处于这些频段的 2.4G 包,如果使用其他的 2.4G 分析仪,需要注意一下使用此方式设置的通道对应的频段。
分析仪抓取的数据如下:

通过分析仪基本上数据怎配置,发出来的效果是怎样的都很直观,也没必要过多赘述 。
2.2.3 数据格式说明
上面的抓包结果我们已经可以看出来一些格式,对于完整的报文格式应该是如下图所示:

我们只需要设置好接入地址,然后应用中设定好自己需要的 PDU,第一个字节包头实际上可以自定义,0~ 0xFF 随意定义,第二个字节长度就比较关键,因为写了多少(长度不包括前面 包头+长度本身 两个字节),那么后面发出的数据就会多少个字节。
三、一些使用说明
-
要达到 8K 的速率(125us 一次数据),每包的数据是有限制的。计算这个的理论基础就是:
2M PHY:单 bit 时间 0.5μs,每个字节就是 4μs 。
所以除了用户数据,还有前导码 2B(8μs),接入地址 4B(16μs),CRC 3B(12μs),这些就固定消耗 36μs,还需要减去硬件准备需要的时间(这里按照 5μs 算,具体以实际芯片为准),对于8K来说,还剩余 125 - 36 - 5 = 84 μs ,所以我们的 Payload 最大字节数:84 ÷ 4 = 21 字节(估算,具体以实际芯片为准)。
-
2.4G 基础模式一次报文用户数据最大有效长度为 251, PDU 为 253 ,除去前面的包头和长度2个字节。
-
示例中使用的是定时器 125us 一次发送,每秒 8000 条数据,实际极限数据比这个还要快一点(注意要是同等长度的数据报文),个人测试可以达到 1W条每秒(约 100 us 一条数据,数据内容长度和示例一致的情况,实际上这个测试是为了说明下面一条,告知大家怎么连续发送数据):

-
如何连续发送数据
就是上一条极限测试数据是怎么测试出来的,就是关闭定时器周期发送,在 RF 回调函数
RF_ProcessCallBack中的发送完成状态里面调用发送(连续发送模式下面沁恒蓝牙分析仪抓取数据个人感觉有点异常,不影响本文说明,这里也不讨论),如下:
c
__HIGH_CODE
void RF_ProcessCallBack( rfRole_States_t sta,uint8_t id )
//省略......
if( sta&RF_STATE_TX_FINISH )
{
#if( WAIT_ACK )
rf_rx_start( );
#endif
gTxCount ++;
TxBuf[0] = 0x55;
TxBuf[1] = TEST_DATA_LEN;
TxBuf[2]++;
TxBuf[3] = gRssi;
rf_tx_start( TxBuf );
}
- 2.4G 发送调制波数据,根据示例方式,用户可以任意设定数据(只有第二个字节长度位置有要求,它的数据决定了后面的数据长度,其他位置都数据都可以自定义)。
发送单载波,直接调用RFIP_SingleChannel( uint8_t ch ); - 在
rf_tx_start函数中,先调用了RFIP_SetTxStart( );函数,然后才是RFIP_SetTxParm( &gTxParam );,并不是写错了,是因为这里的RFIP_SetTxStart并不是立即发送的意思,它只是状态先切换到发送,最后配置都好了以后底层会自动发送。具体在上面代码解析章节推荐博文里面有提到:

- 新的型号 CH587 有 4M 的PHY ,为了满足更快的需求,587 的 RF_Basic 在 4M 模式下面第一个字节就是长度数据(节约一个字节),这个后续有应用再来详细补充。
四、典型应用
推荐记录一些 2.4 G 的典型应用。
4.1 模拟蓝牙广播
在很多简单只需要广播,不需要连接的 Ble 简单应用中,我们可以使用 2.4G 方式实现,从而节约芯片资源(Ble 协议栈是比较大的),比如典型的 Beacon 设备。
首先我们之前讲过 BLE 广播包格式如下:

更多详细说明可参考博主之前的文章:
我们在 RF_Basic 示例基础上进行简单的修改,修改的地方如下,意思看注释:
c
//把频点改成蓝牙广播频点 37 38 39 都可以
#define TEST_FREQUENCY 37 // 通信频点
//把接入地址改成和蓝牙广播一致
gParm.accessAddress = 0x8E89BED6;
//使用 1M PHY,对应1个字节前导码
gParm.properties = LLE_MODE_PHY_1M;
//把发送频率放低一点,1S钟4次,这个根据实际需求来
TMR0_TimerInit( GetSysClock() / 4 );
最后就是修改广播数据了,我们通过上面推荐文章可以知道 Header 是如何解析的:

所以我们可以得知 TxBuf[0] 决定广播类型和 MAC 地址类型,TxBuf[1] 决定数据长度:

长度后面需要跟着 6 个字节的 MAC 地址,是需要计算进长度的,然后后面就按照 Ble 广播的「AD Structure」格式填写我们需要的数据,所以最终我们可以在 RF_Basic 示例中断中把数据定义为如下:
c
__INTERRUPT
__HIGH_CODE
void TMR0_IRQHandler(void) // TMR0 定时中断
{
if(TMR0_GetITFlag(TMR0_3_IT_CYC_END))
{
TMR0_ClearITFlag(TMR0_3_IT_CYC_END); // 清除中断标志
// 初始化发送的数据
//广播类型
TxBuf[0] = 0x02;
//数据长度(MAC地址长度+数据长度)
TxBuf[1] =0x0B;
//mac地址
TxBuf[2] = 0x11;
TxBuf[3] = 0x22;
TxBuf[4] = 0x33;
TxBuf[5] = 0x44;
TxBuf[6] = 0x55;
TxBuf[7] = 0x66;
//广播数据
TxBuf[8] = 0x05;
TxBuf[9] = 0x09;
TxBuf[10] = 'Q';
TxBuf[11] = 'Z';
TxBuf[12] = 'H';
rf_tx_start( TxBuf );
}
}
就可以得到一个名称为 "QZH" ,MAC地址为66:55:44:33:22:11 的蓝牙广播设备,通过 BLE 调试助手扫描结果如图:

4.2 接收蓝牙广播
接收蓝牙广播博主没有实测过,因为暂时并没有遇到此类需求,这里只推荐一个前辈的文章给大家参考:
结语
本文主要介绍说明了一下沁恒蓝牙芯片的 2.4G 基础示例 RF_Basic ,总的来说,RF_Basic 示例展示了RF 收发接口函数,相关参数配置接口的使用,用户可以根据自己的实际需求扩展各种应用。
好了,本文就到这里。谢谢大家!