引言

在单片机无线通信方案选型中,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的特性,可以构建出高效可靠的无线通信系统,为各类嵌入式应用提供强有力的通信支持。
Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐