找回密码
 立即注册
查看: 2963|回复: 14

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

[复制链接]
  • 打卡等级:常住居民III
  • 打卡总天数:135
  • 最近打卡:2024-12-25 10:15:05

47

主题

1350

回帖

8060

积分

荣誉版主

冲哥视频教程和各种开源资料QQ交流群884047237,可群

积分
8060
QQ
发表于 2023-11-2 11:36:32 | 显示全部楼层 |阅读模式
本帖最后由 电子DIY小家 于 2023-11-2 23:14 编辑

截图202311021026024211.jpg




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

截图202311021028231224.jpg



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

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

截图202311021041139971.jpg

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



这里附上接线说明:

模块                屠龙刀

CE      <-->      P4^5;                                                                                                  
CSN    <-->      P4^6;                                                                                                          
SCK    <-->      P4^3;                                                                                                  
MOSI  <-->      P4^0;                                                                                                          
MISO  <-->      P4^1;                                                                                                  
IRQ    <-->       P4^7;                                                                                                  


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

截图202311021044298703.jpg


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

默认为接收模式,需要发送的时候配置为发送,发完继续进入接收模式!

参考手册,这个模块有如下的几种模式:

截图202311021048354256.jpg


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

截图202311021050106335.jpg

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

截图202311021050408843.jpg


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

截图202311021052362178.jpg


当然这里就直接看我们的代码了,先附上接收端的代码:

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


截图202311021054462459.jpg


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

截图202311021059426898.jpg

可以看到这个地址最大为五个字节,所以这里直接写入五个字节的数据,注意这里发送和接收的地址必须一致才能接收!!!不一致的话死都配对不上的哈!我用的地址如下:

  1. #define TX_ADR_WIDTH           5         
  2. u8 xdata TX_ADDRESS[TX_ADR_WIDTH] = {0x0A,0x0A,0x0A,0x0A,0x0A};  
复制代码



第三步,开启自动确认

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

截图202311021104081449.jpg


第四步,设置射频通道

截图202311021105199136.jpg

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


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

截图202311021107295303.jpg

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


第六步,设置传输速率

截图202311021110094707.jpg

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


最后一步,校验

截图202311021112138902.jpg

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



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

  1. void SI24_TX_DATA(u8 *buf )
  2. {
  3.         u8 da=0;
  4.         u8 state =0;
  5.         CE = 0;
  6.         //spi_rw_reg(FLUSH_TX,0x00);
  7.           spi_write_buf(W_REGISTER + TX_ADDR, TX_ADDRESS, TX_ADR_WIDTH);                     // 写入发送地址
  8.           spi_write_buf(W_REGISTER + RX_ADDR_P0, TX_ADDRESS, TX_ADR_WIDTH);                  // 为了应答接收设备,接收通道0地址和发送地址相同
  9.           spi_write_buf(W_TX_PAYLOAD, buf, TX_PLOAD_WIDTH);                            // 写数据包到TX FIFO ACK
  10.         spi_rw_reg(W_REGISTER + SETUP_AW, 0x03);                                                                   // 5 byte Address width
  11.           spi_rw_reg(W_REGISTER + EN_RXADDR, 0x01);                                                            // 使能接收通道0
  12.           spi_rw_reg(W_REGISTER + SETUP_RETR, 0x0F);                                                           // 使能自动重发 1ms 15次重发
  13.           spi_rw_reg(W_REGISTER + RF_CH, 0x40);                                                              // 选择射频通道0x40
  14.           spi_rw_reg(W_REGISTER + RF_SETUP, 0x07);                                                                // 数据传输率1Mbps(**与24L01不同**),7dbm TX power
  15.         spi_rw_reg(W_REGISTER + CONFIG, 0x4e);                                                           // TX_DS IRQ enable CRC使能,16位CRC校验,上电, PTX mode        
  16.         CE = 1;        
  17.         while(IRQ == 1)                                                                                                                           //等待发送完成        
  18.         {
  19.                 da++;                                                                                                                                //增加超时退出功能
  20.                 if( da>10 )
  21.                         break;
  22.                 delay_ms(1);
  23.         }
  24.         status_reg = spi_rw_reg(STATUS,0x00);                                                                // 返回状态寄存器
  25.         if(TX_DS)                                                                                                                                //接收到ack信号,读取成功
  26.         {
  27.                 spi_rw_reg(W_REGISTER + STATUS,status_reg);                                                  // 清除TX_D中断标志        
  28.                 state = 0;        
  29.         }
  30.         else
  31.         {
  32.                 if(MAX_RT)                                                                                                                        //读取ack超时
  33.                 {
  34.                         spi_rw_reg(W_REGISTER + STATUS,status_reg);                                                //手动清除状态
  35.                         spi_rw_reg(FLUSH_TX);
  36.                         state=0;
  37.                 }
  38.         }        
  39. }
复制代码
这里第一步,写入发送地址

截图202311021119098440.jpg

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



第二步,写入接受地址

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



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

截图202311021123252503.jpg

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


第四步,写入地址宽度

截图202311021125219588.jpg

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


第五步,使能接收通道0

截图202311021126335252.jpg

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


第六步,自动重发

截图202311021127112925.jpg

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


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


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

截图202311021130212696.jpg

因为手册这个位置讲了,打开了这个位,每次发送完成救护自爱IRQ引脚产生一个中断,这里简单实现就用一个WHILE来搞定了,当然还加了个10ms的超时自动退出。

然后最后就是两个标志位的判断了,一个发送成功和一个发送失败的标志位,这俩比较简单,照抄即可。当然有什么发送成功执行的任务或者错误执行的任务也可以放在这里面。


最后在看下主函数

  1.   /*****************************************数据发送处理************************************/               
  2.                 if(P32==0 )                                                                                //如果P32按键按下了,发送特定的数据
  3.                 {
  4.                         delay_ms(10);
  5.                         if(P32==0 )
  6.                         {
  7.                                 while(P32==0 );
  8.                                 TX_DAT[0] = 0x04;
  9.                                 SI24_TX_DATA(TX_DAT);                                
  10.                         }
  11.                 }
  12.                 if(P33==0 )                                                                                //如果P33按键按下了,发送特定的数据
  13.                 {
  14.                         delay_ms(10);
  15.                         if(P33==0 )
  16.                         {
  17.                                 while(P33==0 );
  18.                                 TX_DAT[0] = 0x08;        
  19.                                 SI24_TX_DATA(TX_DAT);                                       
  20.                         }
  21.                 }               
  22.                 if(P34==0 )                                                                                //如果P34按键按下了,发送特定的数据
  23.                 {
  24.                         delay_ms(10);
  25.                         if(P34==0 )
  26.                         {
  27.                                 while(P34==0 );
  28.                                 TX_DAT[0] = 0x10;
  29.                                 SI24_TX_DATA(TX_DAT);        
  30.                         }
  31.                 }                                
  32.                 if(P35==0 )                                                                                //如果P35按键按下了,发送特定的数据
  33.                 {
  34.                         delay_ms(10);
  35.                         if(P35==0 )
  36.                         {
  37.                                 while(P35==0 );
  38.                                 TX_DAT[0] = 0x20;        
  39.                                 SI24_TX_DATA(TX_DAT);        
  40.                         }
  41.                 }        
  42.                 delay_ms(1);        
  43.                
  44.                 /*****************************************数据发送处理************************************/        
  45.                 SI24_RX_MODE();                                                                        //设置为接收模式
  46.                 delay_ms(1);               
  47.                 rx_data = SI24_RX_DATA();                                                //读取接受到的数据        
  48.                
  49.                 if( rx_data==0x04 )                                                                //根据读取到的数据操作LED
  50.                         P22=!P22;
  51.                 else if( rx_data==0x08 )
  52.                         P23=!P23;               
  53.                 else if( rx_data==0x10 )
  54.                         P24=!P24;
  55.                 else if( rx_data==0x20 )
  56.                         P25=!P25;        
复制代码



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

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


VID_20231102_230836.mp4

89.47 MB, 下载次数: 150

2 喜欢他/她就送朵鲜花吧,赠人玫瑰,手有余香!
回复

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:7
  • 最近打卡:2025-04-24 13:36:20

8

主题

39

回帖

342

积分

中级会员

积分
342
发表于 2023-11-2 12:05:45 | 显示全部楼层
冲哥 辛苦!这个好。学习了
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:419
  • 最近打卡:2025-05-09 08:02:37

4

主题

80

回帖

1913

积分

金牌会员

积分
1913
发表于 2023-11-2 13:19:56 | 显示全部楼层
好资料,从群里下了。谢谢冲哥! 顺便请问一下,这个控制距离大概有多远?一楼到四楼可以吗?

点评

要看模块的外置天线增益,楼层间的遮挡等等,反正无障碍,无电磁干扰,无天线的环境下,空旷距离大概有几百米左右  详情 回复 发表于 2023-11-2 13:53
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:135
  • 最近打卡:2024-12-25 10:15:05

47

主题

1350

回帖

8060

积分

荣誉版主

冲哥视频教程和各种开源资料QQ交流群884047237,可群

积分
8060
QQ
发表于 2023-11-2 13:53:44 | 显示全部楼层
well*** 发表于 2023-11-2 13:19
好资料,从群里下了。谢谢冲哥! 顺便请问一下,这个控制距离大概有多远?一楼到四楼可以吗? ...

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

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:419
  • 最近打卡:2025-05-09 08:02:37

4

主题

80

回帖

1913

积分

金牌会员

积分
1913
发表于 2023-11-2 14:38:23 | 显示全部楼层
电子DI*** 发表于 2023-11-2 13:53
要看模块的外置天线增益,楼层间的遮挡等等,反正无障碍,无电磁干扰,无天线的环境下,空旷距离大概有几 ...

那距离应当够了,想做一个水塔控制。谢谢冲哥!
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:495
  • 最近打卡:2025-05-08 22:07:54

1

主题

114

回帖

1705

积分

金牌会员

积分
1705
发表于 2023-11-9 13:00:16 | 显示全部楼层
学习了,有2块NRF2401L

点评

正好试试是不是兼容的  详情 回复 发表于 2023-11-9 14:12
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:135
  • 最近打卡:2024-12-25 10:15:05

47

主题

1350

回帖

8060

积分

荣誉版主

冲哥视频教程和各种开源资料QQ交流群884047237,可群

积分
8060
QQ
发表于 2023-11-9 14:12:21 | 显示全部楼层
jker*** 发表于 2023-11-9 13:00
学习了,有2块NRF2401L

正好试试是不是兼容的
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:偶尔看看I
  • 打卡总天数:14
  • 最近打卡:2024-11-16 11:36:36

8

主题

9

回帖

214

积分

中级会员

积分
214
发表于 2023-11-17 19:29:02 | 显示全部楼层
请问是使用的STC32G自带是硬件SPI实现的吗?可以看看你的spi初始化的配置吗,是怎么配置的呢?

点评

是硬件的SPI的,代码自取  详情 回复 发表于 2023-11-18 21:30
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:135
  • 最近打卡:2024-12-25 10:15:05

47

主题

1350

回帖

8060

积分

荣誉版主

冲哥视频教程和各种开源资料QQ交流群884047237,可群

积分
8060
QQ
发表于 2023-11-18 21:30:32 | 显示全部楼层
ilys*** 发表于 2023-11-17 19:29
请问是使用的STC32G自带是硬件SPI实现的吗?可以看看你的spi初始化的配置吗,是怎么配置的呢? ...

是硬件的SPI的,代码自取
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:527
  • 最近打卡:2025-05-09 00:12:18
已绑定手机
已实名认证

46

主题

161

回帖

516

积分

高级会员

积分
516
发表于 2023-11-18 23:09:54 | 显示全部楼层
学习了
MCU开发者和爱好者
回复

使用道具 举报 送花

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|小黑屋|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2025-5-9 19:06 , Processed in 0.158870 second(s), 123 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表