电子DIY小家 发表于 2023-11-2 11:36:32

STC32G驱动SI24R1(兼容NRF24L01)实现主从通信(带ACK)

本帖最后由 电子DIY小家 于 2023-11-2 23:14 编辑






最近买了个这个模块,据说完美兼容NRF24L01,正好买了几个回来测试下(PS:我买的这个店家实在太坑,强烈不建议大家踩坑这家,这里就不放这个连接了,大家只要买模块上带SI24R1芯片的模块均可)





先来看下他的芯片参数,总的来说就是稳定、省电、速度快。而且他的外围电路特别简单,非常适合集成到自己的板子上,


当然这里一定要特别注意,这个芯片的供电电压是1.9-3.6V,当然IO口电压可以支持1.9-5.25V,所以切记用核心板供电的时候一定要配置好电源,我用的屠龙刀做的测试,可以直接改两个电阻的位置就可以配置为3.3V的电源了!具体参考如下图所示!


切记一定不能用5V供电!切记一定不能用5V供电!切记一定不能用5V供电!


这里附上接线说明:

模块                屠龙刀
CE      <-->      P4^5;                                                                                                
CSN    <-->      P4^6;                                                                                                      
SCK    <-->      P4^3;                                                                                                
MOSI<-->      P4^0;                                                                                                      
MISO<-->      P4^1;                                                                                                
IRQ    <-->       P4^7;                                                                                                


最后完整的接线图如下所示:



下面直接进入正文,这里我们需要的需求就是实现两个板子之间的相互通信,用到板子上P32-P35四个按钮和P22-P25四个灯。这边板子的P32按钮按下,那边板子的P22灯取反,反过来那边的P32按钮按下,这边板子的P22灯取反。所以这个时候就需要给他们配置发送和接收的模式了,思路就是这样:
默认为接收模式,需要发送的时候配置为发送,发完继续进入接收模式!
参考手册,这个模块有如下的几种模式:




可以看到他模式切换的时候都有几百us的延迟,所以这里需要注意切换模式的时候要给他点延时,其次这个发送和接收还可以配置为带校验的通信模式:


当然强大的地方在于他还能自动重发:



当然说了这么多其实还很空洞,不知道代码从何入手?这里看到手册最后附录有参考案例,这里可以看看:



当然这里就直接看我们的代码了,先附上接收端的代码:
//========================================================================
// 函数名称: rx_mode
// 函数功能: 这个函数设置Si24R1为接收模式,等待接收发送设备的数据包
// 入口参数:无
// 函数返回:无
// 其他说明:
//========================================================================
void SI24_RX_MODE(void)
{
      u8 state=0;
      u8 da=0;
      
      CE = 0;
      spi_write_buf(W_REGISTER + RX_ADDR_P0, TX_ADDRESS, TX_ADR_WIDTH);                // 接收设备接收通道0使用和发送设备相同的发送地址
          //spi_rw_reg(W_REGISTER + EN_AA, 0x01);                                                       // 使能接收通道0自动应答
          spi_rw_reg(W_REGISTER + EN_RXADDR, 0x01);                                                   // 使能接收通道0
          spi_rw_reg(W_REGISTER + RF_CH, 0x40);                                                         // 选择射频通道0x40
          spi_rw_reg(W_REGISTER + RX_PW_P0, TX_PLOAD_WIDTH);                                          // 接收通道0选择和发送通道相同有效数据宽度
          spi_rw_reg(W_REGISTER + RF_SETUP, 0x07);                                                    // 数据传输率1Mbps,7dbm TX power
          spi_rw_reg(W_REGISTER + CONFIG, 0x0f);                                                      // CRC使能,16位CRC校验,上电,RX mode      
         CE = 1;
}
首先第一步,清除CE,CE为1就会激活RX或者TX,这里需要配置他的参数所以可以直接断开他。因为这芯片用的都是标准的SPI协议,所以后面直接都用SPI的函数驱动即可




第二步,设置发送和接收的地址


可以看到这个地址最大为五个字节,所以这里直接写入五个字节的数据,注意这里发送和接收的地址必须一致才能接收!!!不一致的话死都配对不上的哈!我用的地址如下:
#define TX_ADR_WIDTH         5         
u8 xdata TX_ADDRESS = {0x0A,0x0A,0x0A,0x0A,0x0A};


第三步,开启自动确认
上面我们说过我们要发送一个数据到对面,对面确认接受到了在发一个确认的ACK过来,那这个自动确认的过程我们就可以给他开启这个配置,这类用的通道0,所以这一行就是这个寄存器的最低位写1就可以了



第四步,设置射频通道


芯片一共有0-125个信道,这里可以自由选择,但是注意发送和接收的信道一定要保持一致,否则,你发你的,我发我的,两个人八竿子打不着。

第五步,发送和接收保持一样的数据长度


一个通道一次最大32个数据,这里其实只写入了一个数据,当然如果一定要他们的数据长度不一样的话,也可看手册的“4.2.3 动态 PAYLOAD 长度与静态 PAYLOAD 长度”章节,有介绍,但是如果没有特殊要求,建议发送接收数据长度保持一致!

第六步,设置传输速率


一般速度越低越稳定,功率越大越稳定(也会越费电)

最后一步,校验


"当接收到数据包的地址与芯片的地址相同,并且 CRC 检查正确时,数据会自动存入 RX FIFO,并产生数据接收中断。"手册的原话是这么说的,也就是自动校验数据准确性!


接收模式配置完了,再来看发送模式

void SI24_TX_DATA(u8 *buf )
{
      u8 da=0;
      u8 state =0;
      CE = 0;
      //spi_rw_reg(FLUSH_TX,0x00);
          spi_write_buf(W_REGISTER + TX_ADDR, TX_ADDRESS, TX_ADR_WIDTH);                     // 写入发送地址
          spi_write_buf(W_REGISTER + RX_ADDR_P0, TX_ADDRESS, TX_ADR_WIDTH);                  // 为了应答接收设备,接收通道0地址和发送地址相同
          spi_write_buf(W_TX_PAYLOAD, buf, TX_PLOAD_WIDTH);                            // 写数据包到TX FIFO ACK
      spi_rw_reg(W_REGISTER + SETUP_AW, 0x03);                                                                   // 5 byte Address width
          spi_rw_reg(W_REGISTER + EN_RXADDR, 0x01);                                                            // 使能接收通道0
          spi_rw_reg(W_REGISTER + SETUP_RETR, 0x0F);                                                         // 使能自动重发 1ms 15次重发
          spi_rw_reg(W_REGISTER + RF_CH, 0x40);                                                            // 选择射频通道0x40
          spi_rw_reg(W_REGISTER + RF_SETUP, 0x07);                                                                // 数据传输率1Mbps(**与24L01不同**),7dbm TX power
      spi_rw_reg(W_REGISTER + CONFIG, 0x4e);                                                         // TX_DS IRQ enable CRC使能,16位CRC校验,上电, PTX mode      
      CE = 1;      

      while(IRQ == 1)                                                                                                                           //等待发送完成      
      {
                da++;                                                                                                                              //增加超时退出功能
                if( da>10 )
                        break;
                delay_ms(1);
      }
      status_reg = spi_rw_reg(STATUS,0x00);                                                                // 返回状态寄存器

      if(TX_DS)                                                                                                                              //接收到ack信号,读取成功
      {
                spi_rw_reg(W_REGISTER + STATUS,status_reg);                                                // 清除TX_D中断标志      
                state = 0;      
      }
      else
      {
                if(MAX_RT)                                                                                                                        //读取ack超时
                {
                        spi_rw_reg(W_REGISTER + STATUS,status_reg);                                                //手动清除状态
                        spi_rw_reg(FLUSH_TX);
                        state=0;
                }
      }      
}这里第一步,写入发送地址


上面配置为接受模式的时候设置了地址,同理这里发送就要指定到这个地址才能发送!


第二步,写入接受地址

因为接受模块接收到数据之后会发ack回来,所以接收地址记得也要配置为一样的哈,不然就不知道发哪里去了,具体的寄存器配置见上面接收端配置


第三步,写数据包到TX FIFO ACK


可以看到发送数据的缓冲地址在0XA0,所以在发送之前只要往这个地址写入需要发送的数据即可。

第四步,写入地址宽度


因为用的五个字节的地址,这里对照手册这个寄存器直接写入3即可

第五步,使能接收通道0


用的通道0的,这里直接开启通道0的即可

第六步,自动重发


可以配置自动重发次数和间隔,因为一帧数据传输怕被干扰,这里如果一报数据错误了可以多次自动重发,可以大大减少我们程序防错机制的工作量

第七步,选择频率,传输速度和校验等,这些和接收板部分配置一致,这里就不展开了。

在发送这里会有一行while(IRQ == 1) //等待发送完成


因为手册这个位置讲了,打开了这个位,每次发送完成救护自爱IRQ引脚产生一个中断,这里简单实现就用一个WHILE来搞定了,当然还加了个10ms的超时自动退出。
然后最后就是两个标志位的判断了,一个发送成功和一个发送失败的标志位,这俩比较简单,照抄即可。当然有什么发送成功执行的任务或者错误执行的任务也可以放在这里面。

最后在看下主函数
/*****************************************数据发送处理************************************/               
                if(P32==0 )                                                                              //如果P32按键按下了,发送特定的数据
                {
                        delay_ms(10);
                        if(P32==0 )
                        {
                              while(P32==0 );
                              TX_DAT = 0x04;
                              SI24_TX_DATA(TX_DAT);                              
                        }
                }
                if(P33==0 )                                                                              //如果P33按键按下了,发送特定的数据
                {
                        delay_ms(10);
                        if(P33==0 )
                        {
                              while(P33==0 );
                              TX_DAT = 0x08;      
                              SI24_TX_DATA(TX_DAT);                                       
                        }
                }               
                if(P34==0 )                                                                              //如果P34按键按下了,发送特定的数据
                {
                        delay_ms(10);
                        if(P34==0 )
                        {
                              while(P34==0 );
                              TX_DAT = 0x10;
                              SI24_TX_DATA(TX_DAT);      
                        }
                }                              
                if(P35==0 )                                                                              //如果P35按键按下了,发送特定的数据
                {
                        delay_ms(10);
                        if(P35==0 )
                        {
                              while(P35==0 );
                              TX_DAT = 0x20;      
                              SI24_TX_DATA(TX_DAT);      
                        }
                }      
                delay_ms(1);      
               
                /*****************************************数据发送处理************************************/      
                SI24_RX_MODE();                                                                        //设置为接收模式
                delay_ms(1);               
                rx_data = SI24_RX_DATA();                                                //读取接受到的数据      
               
                if( rx_data==0x04 )                                                                //根据读取到的数据操作LED
                        P22=!P22;
                else if( rx_data==0x08 )
                        P23=!P23;               
                else if( rx_data==0x10 )
                        P24=!P24;
                else if( rx_data==0x20 )
                        P25=!P25;      



最简单的四个按键,按下按键并释放之后就会发出一个数据,发送就会自动切换到接收模式。接收端接收到数据,数据匹配的话就会切换对应的引脚的电平!是不是感觉特别的简单~

需要程序的群文件下载,随时更新。

飞龙在天 发表于 2023-11-2 12:05:45

冲哥 辛苦!这个好。学习了

wellhope 发表于 2023-11-2 13:19:56

好资料,从群里下了。谢谢冲哥! 顺便请问一下,这个控制距离大概有多远?一楼到四楼可以吗?

电子DIY小家 发表于 2023-11-2 13:53:44

wellhope 发表于 2023-11-2 13:19
好资料,从群里下了。谢谢冲哥! 顺便请问一下,这个控制距离大概有多远?一楼到四楼可以吗? ...

要看模块的外置天线增益,楼层间的遮挡等等,反正无障碍,无电磁干扰,无天线的环境下,空旷距离大概有几百米左右

wellhope 发表于 2023-11-2 14:38:23

电子DIY小家 发表于 2023-11-2 13:53
要看模块的外置天线增益,楼层间的遮挡等等,反正无障碍,无电磁干扰,无天线的环境下,空旷距离大概有几 ...

那距离应当够了,想做一个水塔控制。谢谢冲哥!

jkernet 发表于 2023-11-9 13:00:16

学习了,有2块NRF2401L

电子DIY小家 发表于 2023-11-9 14:12:21

jkernet 发表于 2023-11-9 13:00
学习了,有2块NRF2401L

正好试试是不是兼容的

ilysmile 发表于 2023-11-17 19:29:02

请问是使用的STC32G自带是硬件SPI实现的吗?可以看看你的spi初始化的配置吗,是怎么配置的呢?

电子DIY小家 发表于 2023-11-18 21:30:32

ilysmile 发表于 2023-11-17 19:29
请问是使用的STC32G自带是硬件SPI实现的吗?可以看看你的spi初始化的配置吗,是怎么配置的呢? ...

是硬件的SPI的,代码自取

lijinlei 发表于 2023-11-18 23:09:54

学习了
页: [1] 2
查看完整版本: STC32G驱动SI24R1(兼容NRF24L01)实现主从通信(带ACK)