2.4G模块的教程使用干货
引言
在单片机无线通信方案选型中,2.4GHz技术、蓝牙和WiFi是三种主流选择。SI24R1作为一款完全兼容NRF24L01的国产芯片,以其优异的性价比和简单易用的特性成为许多项目的首选。虽然ESP系列芯片在物联网领域表现突出,但对于需要简单可靠无线通信的应用场景,SI24R1提供了更加经济高效的解决方案。下面我将使用大夏龙雀科技有限公司的两个纯硬件模块NR-02和DX-PJ26开发板进行简单的无线通信。
开发板概述
DX-PJ26是一款开发套件,具备以下突出特性:
- 主控芯片:STM32F103C8T6
- PC系统:推荐Windows10
- MCU集成开发环境:keil5,STM32F1xxMDm
- 烧录方式:typc数据线(串口烧录)
- 调试工具:串口助手(log调试信息)
芯片特性概述
SI24R1工作在2.4GHz全球开放ISM频段,具备以下突出特性:
- 传输速率最高可达2Mbps,采用GFSK调制技术,抗干扰能力出色
- 支持126个通信频道,满足多点通信和跳频需求
- 内置硬件CRC校验和多点通信地址控制机制
- 工作电压范围1.9-3.6V,待机电流仅22μA,掉电模式低至900nA
- 集成稳压电路,在各种电源环境下都能保持稳定通信
- 标准2.54mm间距DIP封装,便于集成和使用
工作状态管理
SI24R1基于状态机设计,主要工作状态包括:
- 掉电模式(Power Down Mode)
- 发射模式(Tx Mode
- 接收模式(Rx Mode)
- 两种待机模式(Standby-1/2 Mode)
上面五种模式之间的相互切换方法以及切换所需要的时间参照下图:

按照惯例,我们先查看模块的引脚,然后将它们一一对应到开发板的引脚上,进行引脚初始化操作

图3-2 NR02模块

图3-3 PJ26开发板
由于我们带插针的NR02模块和PJ26开发板属于配套的开发套件,我们只需要将NR02插入PJ26对应的脚位即可
我们在.h文件里面进行一下管脚定义

确定了管脚的对应关系,就可以给每个管脚进行初始化操作了
void SW_SPI_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_7;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStruct);
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IPU;
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_6;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_15;
GPIO_Init(GPIOC,&GPIO_InitStruct);
SPI_CE_PIN=0;
SPI_SCK_PIN=0;
SPI_IRQ_PIN=1;
SPI_CSN_PIN=1;
}
使用stm32内部硬件操作SPI需要我们设置SPI相关的时钟配置,就要去看手册里面的时序图,时序图规定了通信双方之间的时序规则

通过官方手册查看时序图可以知道,读操作时,CSN信号线要处于低电平,SCL时钟线处于上升沿,数据位从高位开始,一次读写8位。所以在配置SPI时,我们设置SPI发送接收8位帧结构,初始时钟悬空低,数据捕获于第一个时钟沿,数据传输从MSB位开始。
SPI通信接口实现
SI24R1通过SPI接口与主控制器通信,最高支持10MHz时钟频率。配置时需注意:
- 读操作期间CSN保持低电平
- 数据在SCL上升沿采样
- 采用MSB优先的传输格式
- 对知识管理工具感兴趣的自学者
SPI读写操作实现如下:
// SPI字节读写函数
uint8_t SPI_ReadWriteByte(uint8_t tx_data)
{
uint8_t rx_data = 0;
for(uint8_t i = 0; i < 8; i++) {
MOSI_PIN = (tx_data & 0x80) ? 1 : 0;
tx_data <<= 1;
SCLK_PIN = 1;
rx_data = (rx_data << 1) | MISO_PIN;
SCLK_PIN = 0;
}
return rx_data;
}
// 寄存器写操作
uint8_t Write_Register(uint8_t reg, uint8_t value)
{
CSN_PIN = 0;
uint8_t status = SPI_ReadWriteByte(reg);
SPI_ReadWriteByte(value);
CSN_PIN = 1;
return status;
}
// 寄存器读操作
uint8_t Read_Register(uint8_t reg)
{
CSN_PIN = 0;
SPI_ReadWriteByte(reg);
uint8_t value = SPI_ReadWriteByte(0xFF);
CSN_PIN = 1;
return value;
}
接着,我们需要测试主机与SI24R1的读写是否正常,以便后面进行无线通信做准备。可以编写一个检查函数如下:
u8 Si24R1_Check(void)
{
u8 check_in_data[5] = {0X55, 0XAA, 0X55, 0XAA, 0X55};
u8 check_out_data[5] = {0x00};
SPI_CE_PIN = 0;
Si24R1_Write_Buf(NRF_WRITE_REG+TX_ADDR, check_in_data, 5);
Si24R1_Read_Buf(NRF_READ_REG+TX_ADDR, check_out_data, 5);
if((check_out_data[0] == 0x55) &&
(check_out_data[1] == 0xAA) &&
(check_out_data[2] == 0x55) &&
(check_out_data[3] == 0xAA) &&
(check_out_data[4] == 0x55))
return 0;
else
return 1;
}
void Si24R1_Init(void)
{
while(Si24R1_Check())
{
printf("No Si24R1 Error\r\n");
delay_ms(500);
}
// 其他射频初始化
}
如果串口没打印"No Si24R1 Error",证明我们的通信是正常的。接下来就可以安心进行设置SI24R1状态机和发送数据以及接收数据函数的编写了。
设置SI24R1状态
众所周知,SI24R1常用的有5种状态,这里我们只讨论能够实现通信功能的发送模式和接收模式。实际上要设置这两种模式也很简单,无非就是下面的固定几步:
Tx模式初始化过程:
- 写Tx节点的地址TX_ADDR
- 写Rx节点的地址(主要是为了使能Auto Ack)RX_ADDR_P0
- 使能AUTO ACK EN_AA
- 使能PIPE 0 EN_RXADDR
- 配置自动重发次数SETUP_RETR
- 选择通信频率RF_CH
- 配置发射参数(低噪放大器增益、发射功率、无线速率)RF_SETUP
- 选择通道0有效数据宽度Rx_Pw_P0
- 配置SI24R1的基本参数以及切换工作模式CONFIG
Rx模式初始化过程:
- 初始化步骤SI24R1相关寄存器
- 写Rx节点的地址RX_ADDR_P0
- 使能AUTO ACK EN_AA
- 使能PIPE 0 EN_RXADDR
- 选择通信频率RF_CH
- 选择通道0有效数据宽度Rx_Pw_P0
- 配置发射参数(低噪放大器增益、发射功率、无线速率)RF_SETUP
- 配置SI24R1的基本参数以及切换工作模式CONFIG
Tx模式初始化:
代码如下:
void Si24R1_TX_Mode(void)
{
SPI_CE_PIN = 0;
Si24R1_Write_Reg(NRF_WRITE_REG+RX_PW_P0, R_RX_PAYLOAD_WIDTH);
Si24R1_Write_Buf(NRF_WRITE_REG+TX_ADDR, (u8*)TX_ADDRESS, TX_ADDR_WIDTH);
Si24R1_Write_Buf(NRF_WRITE_REG+RX_ADDR_P0, (u8*)RX_ADDRESS, RX_ADDR_WIDTH);
Si24R1_Write_Reg(NRF_WRITE_REG+EN_AA, 0x01);
Si24R1_Write_Reg(NRF_WRITE_REG+EN_RXADDR, 0x01);
Si24R1_Write_Reg(NRF_WRITE_REG+SETUP_RETR, 0x03);
Si24R1_Write_Reg(NRF_WRITE_REG+RF_CH, 2);
Si24R1_Write_Reg(NRF_WRITE_REG+RF_SETUP, 0x0f);
Si24R1_Write_Reg(NRF_WRITE_REG+CONFIG, 0x0e);
SPI_CE_PIN = 1;
}
Rx模式初始化过程:
有了配置Tx模式初始化的经验,Rx模式初始化和它高度一致,直接上配置完成的代码:
void Si24R1_RX_Mode(void)
{
SPI_CE_PIN = 0;
Si24R1_Write_Reg(NRF_WRITE_REG+RX_PW_P0, R_RX_PAYLOAD_WIDTH);
Si24R1_Write_Buf(NRF_WRITE_REG+TX_ADDR, (u8*)TX_ADDRESS, TX_ADDR_WIDTH);
Si24R1_Write_Buf(NRF_WRITE_REG+RX_ADDR_P0, (u8*)RX_ADDRESS, RX_ADDR_WIDTH);
Si24R1_Write_Reg(NRF_WRITE_REG+EN_AA, 0x01);
Si24R1_Write_Reg(NRF_WRITE_REG+EN_RXADDR, 0x01);
Si24R1_Write_Reg(NRF_WRITE_REG+SETUP_RETR, 0x03);
Si24R1_Write_Reg(NRF_WRITE_REG+RF_CH, 2);
Si24R1_Write_Reg(NRF_WRITE_REG+RF_SETUP, 0x0f);
Si24R1_Write_Reg(NRF_WRITE_REG+CONFIG, 0x0f);
delay_ms(5);
SPI_CE_PIN = 1;
}
发送和接收数据包
发送流程:
- 配置接收地址和要接收的数据包大小
- SI24R1通过把STATUS寄存器置位(STATUS一般引起微控制器中断)通知微控制器
- 读取中断标志位
- 清除中断标志位以便下一次中断的正常进行
- 判断发生了哪种中断,若发生超时中断则清除发送超时的发送缓冲区
// 启动SI24R1发送一次数据// txbuf:待发送数据首地址// 返回值:发送完成状况
u8 Si24R1_TxPacket(u8 *txbuf)
{
u8 sta;
SPI_CE_PIN = 0;
Si24R1_TX_Mode();
Si24R1_Write_Buf(WR_TX_PLOAD, txbuf, W_RX_PAYLOAD_WIDTH); // 写数据到TX BUF 32个字节
SPI_CE_PIN = 1;
while(SPI_IRQ_PIN != 0); // 等待数据发送完成中断
sta = Si24R1_Read_Reg(STATUS); // 读取状态寄存器的值
Si24R1_Write_Reg(NRF_WRITE_REG+STATUS, sta); // 清除TX_DS或MAX_RT中断标志
Si24R1_RX_Mode();
if(sta & MAX_TX) // 达到最大重发次数
{
Si24R1_Write_Reg(FLUSH_TX, 0xff); // 清除TX FIFO寄存器
return 2;
}
if(sta & TX_OK) // 发送完成
{
return 1;
}
return 0; // 其他原因发送失败
}
接收流程:
- 当接收到正确的数据包(正确的地址和CRC校验码),SI24R1自动把字头、地址和CRC校验位移去
- SI24R1通过把STATUS寄存器的RX_DR置位(STATUS一般引起微控制器中断)通知微控制器
- 微控制器把数据从FIFO读出(0X61指令)
- 所有数据读取完毕后,可以清除STATUS寄存器。SI24R1可以进入四种主要的模式之一
// SI24R1接收一次数据// rxbuf:SI24R1接收数据缓冲区// 返回值:0,接收完成;其他,错误代码
u8 Si24R1_RxPacket(u8 *rxbuf)
{
u8 sta;
sta = Si24R1_Read_Reg(STATUS); // 读取状态寄存器的值
Si24R1_Write_Reg(NRF_WRITE_REG+STATUS, sta); // 清除TX_DS或MAX_RT中断标志
if(sta & RX_OK) // 接收到数据
{
Si24R1_Read_Buf(RD_RX_PLOAD, rxbuf, R_RX_PAYLOAD_WIDTH); // 读取数据
Si24R1_Write_Reg(FLUSH_RX, 0xff); // 清除RX FIFO寄存器
return 0;
}
return 1; // 没收到任何数据
}
最后提供一个主函数实例供大家参考:
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
delay_init();
uart_init(115200); // 串口1初始化
LED_Init();
RF_RX_Init();
APP_Process();
}
// 收发一体void APP_Process(void)
{
for(;;)
{
APP_RecieveHandler();
APP_TransmitHandler();
}
}
// 发送处理void APP_TransmitHandler(void)
{
u8 rx_buf[32] = "hello\r\n";
Si24R1_TxPacket(rx_buf);
delay_ms(50);
}
// 接收处理void APP_RecieveHandler(void)
{
u8 u[32];
if(Si24R1_RxPacket(u) == 0)
{
LED1_ON();
printf("%s", u);
GPIO_SetBits(GPIOC, GPIO_Pin_13);
}
}
通过上述代码,我们可以实现基于SI24R1芯片的无线通信功能。
总结
SI24R1作为国产无线通信芯片的优秀代表,完全兼容NRF24L01且具有更好的性价比。通过本文介绍的SPI通信接口、工作模式配置和数据收发方法,开发者可以快速上手使用这款芯片。其低功耗、高可靠性的特点使其特别适合工业控制、智能家居和物联网等应用领域。
在实际项目中,建议注意以下几点:
- 电源稳定性对通信性能有重要影响
- 合理选择通信频道避免干扰
- 根据实际需求调整发射功率和数据速率
- 实现适当的错误处理和重传机制
通过合理利用SI24R1的特性,可以构建出高效可靠的无线通信系统,为各类嵌入式应用提供强有力的通信支持。
更多推荐


所有评论(0)