找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 27869|回复: 49
收起左侧

NRF24L01无线模块多机通信单片机程序 上位机+下位机

  [复制链接]
ID:82008 发表于 2015-6-4 13:55 | 显示全部楼层 |阅读模式
最近在接了一个项目,要求各个设备能够联网(不是互联网)控制。nrf24l01刚好有这个功能。但是之前只做过一对一的通信,还是用例程的那一种。我在想,用两个地址,共用同一个通道应该也可以完成。后来他又要求发过去的数据还要能回传,这下我只好来研究多通道通信了。

多机通信和一对一通信基本上相同,就是要配置其他通道的地址和使能其他通道的有效数据宽度,还有自动应答。

这是接收机的:

​void NRF24L01_Init_RX(void)
{   
CE=0;   
CSN=1;   
SCK=0;   
SPI_Write_Buf(WRITE_REG + TX_ADDR, RX_ADDRESS, TX_ADR_WIDTH);
SPI_Write_Buf(WRITE_REG + RX_ADDR_P0, RX_ADDRESS, RX_ADR_WIDTH);
SPI_Write_Buf(WRITE_REG + RX_ADDR_P1, RX_ADDRESS1, RX_ADR_WIDTH);
SPI_Write_Reg(WRITE_REG + EN_AA, 0x3f);
SPI_Write_Reg(WRITE_REG + EN_RXADDR, 0x3f);
SPI_Write_Reg(WRITE_REG + RF_CH, 40);
SPI_Write_Reg(WRITE_REG + RX_PW_P0, RX_PLOAD_WIDTH);
SPI_Write_Reg(WRITE_REG + RX_PW_P1, RX_PLOAD_WIDTH);
SPI_Write_Reg(WRITE_REG + RF_SETUP, 0x0F);
SPI_Write_Reg(WRITE_REG + CONFIG, 0x0f);
}

​由于我用的是KeilC51和MDK5共存的,所以注释复制过来之后就成了乱码,在此贴图一张:

NRF24L01_Init_Rx(void)
​下面就到了发送机了的配置了:

void NRF24L01_Init_TX(uint8_t *ADDRn)
{   
CE=0;
CSN=1;
SCK=0;
SPI_Write_Buf(WRITE_REG + TX_ADDR, (uint8_t*)ADDRn, TX_ADR_WIDTH);
SPI_Write_Buf(WRITE_REG + RX_ADDR_P0, (uint8_t*)ADDRn, RX_ADR_WIDTH);
SPI_Write_Reg(WRITE_REG + EN_AA, 0x3f);
SPI_Write_Reg(WRITE_REG + EN_RXADDR, 0x3f);
SPI_Write_Reg(WRITE_REG + RF_CH, 40);
SPI_Write_Reg(WRITE_REG + RX_PW_P0, RX_PLOAD_WIDTH);
SPI_Write_Reg(WRITE_REG + RX_PW_P1, RX_PLOAD_WIDTH);
SPI_Write_Reg(WRITE_REG + SETUP_RETR, 0xff);
SPI_Write_Reg(WRITE_REG + RF_SETUP, 0x0f);
SPI_Write_Reg(WRITE_REG + CONFIG, 0x0E);
}

同样:


NRF24L01_Init_TX(uint8_t *ADDRn)
​发送给其他通道,只要改成其他通道的地址就可以了,不用改通道号,现在还不知道为什么。

接下来就是发送函数:

uint8_t nRF24L01_TxPacket(unsigned char * tx_buf)
{
uint8_t Return_Flag=0;
CE=0;
SPI_Write_Buf(WR_TX_PLOAD, tx_buf, TX_PLOAD_WIDTH);
Delayms(2);
Return_Flag = Check_ACK(1);
return Return_Flag;
}

​由于我是通过电脑串口控制上位机,发给某一个下位机,然后再发回到我的上位机中,最后回传到电脑,所以没有数据抢答的问题。

最后再说一句,要配置第N个​的通道,前N个通道也必须被配置,要不然配置不成功。

最后贴上上位机程序:
  1. #include <stc12c5a.H>
  2. #include <intrins.h>
  3. #include "nrf24l01.h"
  4. #include "delay.h"
  5. #define uint32_t unsigned int
  6. #define uint8_t unsigned char

  7. uint8_t const RX_ADDRESS[TX_ADR_WIDTH]= {0x01,0x13,0x5C,0x0C,0x03};        //本地地址
  8. uint8_t const RX_ADDRESS1[TX_ADR_WIDTH]={0x02,0x13,0x5C,0x0C,0x03}; //本地地址1


  9. extern uint8_t Rx_Buf[32];
  10. extern uint8_t Tx_Buf[32];

  11. /**********************************RNF24L01状态标志位************************************************/
  12. uint8_t         bdata sta;   
  13. sbit        RX_DR        =sta^6;
  14. sbit        TX_DS        =sta^5;
  15. sbit        MAX_RT        =sta^4;

  16. /**********************************NRF24L01管脚与单片机接口定义**************************************/


  17. sbit  MISO =P3^4;
  18. sbit  MOSI =P3^6;
  19. sbit SCK =P3^3;
  20. sbit  CE =P3^2;
  21. sbit CSN =P3^5;
  22. sbit IRQ =P3^7;



  23. /***************************************************************************
  24. 函数名称:uchar SPI_RW(uint8_t dat)
  25. 函数功能:NRF24L01的SPI写时序
  26. 函数备注:
  27. ***************************************************************************/
  28. uint8_t SPI_RW(uint8_t dat)
  29. {
  30.         uint8_t i;
  31.            for(i=0;i<8;i++)
  32.            {
  33.                 MOSI = (dat & 0x80);         
  34.                 dat = (dat << 1);           
  35.                 SCK = 1;                     
  36.                 dat |= MISO;                         
  37.                 SCK = 0;                              
  38.            }
  39.     return(dat);                             
  40. }

  41. /***************************************************************************
  42. 函数名称:uint8_t SPI_Read(uint8_t cmd_reg)
  43. 函数功能:NRF24L01的SPI读时序
  44. 函数备注:
  45. ***************************************************************************/
  46. uint8_t SPI_Read(uint8_t cmd_reg)
  47. {
  48.         uint8_t value;
  49.        
  50.         CSN = 0;               
  51.         SPI_RW(cmd_reg);            
  52.         value = SPI_RW(0);   
  53.         CSN = 1;               
  54.        
  55.         return(value);        
  56. }

  57. /***************************************************************************
  58. 函数名称:void SPI_Write_Reg(uint8_t cmd_reg, uint8_t value)
  59. 函数功能:写入NRF24L01寄寄存器和从NRF24L01寄存器中读出
  60. 函数备注:
  61. ***************************************************************************/
  62. void SPI_Write_Reg(uint8_t cmd_reg, uint8_t value)
  63. {       
  64.         CSN = 0;                  
  65.         SPI_RW(cmd_reg);     
  66.         SPI_RW(value);            
  67.         CSN = 1;                  
  68. }

  69. /***************************************************************************
  70. 函数名称:uint8_t SPI_Read_Buf(uint8_t cmd_reg, uint8_t *pBuf, uint8_t num)
  71. 函数功能:从NRF24L01寄存器中读出数据
  72. 函数备注:reg:为寄存器地址,pBuf:为待读出数据地址,uint8_t:读出数据的个数
  73. ***************************************************************************/
  74. uint8_t SPI_Read_Buf(uint8_t cmd_reg, uint8_t *pBuf, uint8_t num)
  75. {
  76.         uint8_t status,i;
  77.        
  78.         CSN = 0;                                   
  79.         status = SPI_RW(cmd_reg);                      
  80.         for(i=0;i<num;i++)   pBuf[i] = SPI_RW(0);           
  81.         CSN = 1;                           
  82.        
  83.         return(status);                    
  84. }

  85. /***************************************************************************
  86. 函数名称:void SPI_Write_Buf(uint8_t cmd_reg, uint8_t *pBuf, uint8_t num)
  87. 函数功能:在NRF24L01寄存器中写入数据
  88. 函数备注:reg:为寄存器地址,pBuf:为待写入数据地址,uint8_t:写入数据的个数
  89. ***************************************************************************/
  90. void SPI_Write_Buf(uint8_t cmd_reg, uint8_t *pBuf, uint8_t num)
  91. {
  92.         uint8_t i;       
  93.         CSN = 0;            //SPI使能      
  94.         SPI_RW(cmd_reg);   
  95.         for(i=0; i<num; i++)   SPI_RW(*pBuf++);
  96.         CSN = 1;           //关闭SPI
  97. }

  98. /***************************************************************************
  99. 函数名称:uint8_t nRF24L01_RxPacket(uint8_t* rx_buf)
  100. 函数功能:数据读取后放入rx_buf接收缓冲区中
  101. 函数备注:
  102. ***************************************************************************/
  103. uint8_t nRF24L01_RxPacket(uint8_t* rx_buf)
  104. {
  105.    uint8_t flag;
  106.         CE = 1;                          //很重要!启动接收!
  107.         Delayms(1);
  108.         sta=SPI_Read(READ_REG+STATUS);        // 读取状态寄存其来判断数据接收状况           //寄存器前面要加是读还是写
  109.         if(RX_DR)                                // 判断是否接收到数据  如果置1则说明接到数据并且放置在接收缓存器
  110.         {
  111.            CE = 0;                
  112.                 SPI_Read_Buf(RD_RX_PLOAD,rx_buf,RX_PLOAD_WIDTH); //这本来就是指令,不用加,意思说去缓存器里读
  113.                 flag =1;                        //读取数据完成标志
  114.         }
  115.         SPI_Write_Reg(WRITE_REG+STATUS,sta);   //接收到数据后RX_DR,TX_DS,MAX_PT都置高为1,通过写1来清楚中断标志
  116.         return flag;
  117. }




  118. /**************************************************
  119. 函数:Check_ACK(bit clear)
  120. 描述:检查接收设备有无接收到数据包,设定没有收到应答信
  121.             号是否重发
  122. /**************************************************/
  123. uint8_t Check_ACK(bit clear)
  124. {
  125.         while(IRQ);
  126.         sta = SPI_RW(NOP);                    // 返回状态寄存器
  127.         if(MAX_RT)
  128.                 if(clear)                         // 是否清除TX FIFO,没有清除在复位MAX_RT中断标志后重发
  129.                         SPI_RW(FLUSH_TX);   //清空寄存器,很重要!!!
  130.         SPI_Write_Reg(WRITE_REG + STATUS, sta);  // 清除TX_DS或MAX_RT中断标志
  131.         IRQ = 1;
  132.         if(TX_DS)
  133.                 return(0x01);
  134.         else
  135.                 return(0x00);
  136. }


  137. /***************************************************************************
  138. 函数名称:void nRF24L01_TxPacket(unsigned char * tx_buf)
  139. 函数功能:发送 tx_buf中数据
  140. 函数备注:
  141. ***************************************************************************/
  142. uint8_t nRF24L01_TxPacket(unsigned char * tx_buf)
  143. {
  144.         uint8_t Return_Flag=0;
  145.         CE=0;                        //StandBy I模式       
  146.         SPI_Write_Buf(WR_TX_PLOAD, tx_buf, TX_PLOAD_WIDTH);                          // 装载数据  WR_TX_PLOAD本来就是指令  不用加   将数据放入发送缓存器       
  147.         CE=1;                 //置高CE,激发数据发送
  148.         Delayms(2);
  149.         Return_Flag = Check_ACK(1);
  150.         return Return_Flag;
  151. }


  152. /***************************************************************************
  153. 函数名称:void NRF24L01_Init_TX(void)
  154. 函数功能:初始化NRF24L01
  155. 函数备注:在调用NRF24L01作为发射时,都要先调用该函数对NRF24L01进行初始化
  156. ***************************************************************************/
  157. void NRF24L01_Init_TX(uint8_t *ADDRn)
  158. {   
  159.         /*待机模式*/
  160.         CE=0;
  161.         CSN=1;
  162.         SCK=0;
  163.         /*装载数据*/
  164.         SPI_Write_Buf(WRITE_REG + TX_ADDR, (uint8_t*)ADDRn, TX_ADR_WIDTH);//写TX节点地址
  165.         SPI_Write_Buf(WRITE_REG + RX_ADDR_P0, (uint8_t*)ADDRn, RX_ADR_WIDTH); //设置TX节点地址,主要为了使能ACK          
  166.         /*配置寄存器*/
  167.         SPI_Write_Reg(WRITE_REG + EN_AA, 0x3f); //使能通道所有的自动应答   
  168.         SPI_Write_Reg(WRITE_REG + EN_RXADDR, 0x3f);//使能通道所有的接收地址  
  169.         SPI_Write_Reg(WRITE_REG + RF_CH, 40);//设置RF通道为40   收发必须一致!
  170.         SPI_Write_Reg(WRITE_REG + RX_PW_P0, RX_PLOAD_WIDTH); //选择通道0的有效数据宽度           
  171.         SPI_Write_Reg(WRITE_REG + RX_PW_P1, RX_PLOAD_WIDTH); //选择通道1的有效数据宽度           
  172.         SPI_Write_Reg(WRITE_REG + SETUP_RETR, 0xff);//自动重发  4000+86us    重发15次
  173.         SPI_Write_Reg(WRITE_REG + RF_SETUP, 0x0f); //设置TX发射参数,0db增益,2Mbps,低噪声增益开启  收发必须一致!                 
  174.         SPI_Write_Reg(WRITE_REG + CONFIG, 0x0E);  //配置基本工作模式的参数;PWR_UP,EN_CRC,16BIT_CRC,接收模式,开启所有中断                         
  175. }


  176. /***************************************************************************
  177. 函数名称:void NRF24L01_Init_RX(void)
  178. 函数功能:初始化NRF24L01
  179. 函数备注:在调用NRF24L01作为接收时,都要先调用该函数对NRF24L01进行初始化
  180. ***************************************************************************/
  181. void NRF24L01_Init_RX(void)
  182. {   
  183.         /*待机模式*/
  184.         CE=0;   
  185.         CSN=1;   
  186.         SCK=0;   
  187.         /*装载数据*/
  188.         SPI_Write_Buf(WRITE_REG + TX_ADDR, RX_ADDRESS, TX_ADR_WIDTH);//写TX节点地址            
  189.         SPI_Write_Buf(WRITE_REG + RX_ADDR_P0, RX_ADDRESS, RX_ADR_WIDTH);  //设置TX节点地址,主要为了使能ACK
  190.         SPI_Write_Buf(WRITE_REG + RX_ADDR_P1, RX_ADDRESS1, RX_ADR_WIDTH);  //设置TX节点地址,主要为了使能ACK
  191.         /*配置寄存器*/
  192.         SPI_Write_Reg(WRITE_REG + EN_AA, 0x3f);//使能通道0的自动应答
  193.         SPI_Write_Reg(WRITE_REG + EN_RXADDR, 0x3f); //使能通道0的接收地址   
  194.         SPI_Write_Reg(WRITE_REG + RF_CH, 40); //设置RF通道为40   收发必须一致!
  195.         SPI_Write_Reg(WRITE_REG + RX_PW_P0, RX_PLOAD_WIDTH); //选择通道0的有效数据宽度
  196.         SPI_Write_Reg(WRITE_REG + RX_PW_P1, RX_PLOAD_WIDTH); //选择通道1的有效数据宽度
  197.         SPI_Write_Reg(WRITE_REG + RF_SETUP, 0x0F); //设置TX发射参数,0db增益,2Mbps,低噪声增益开启  收发必须一致!
  198.         SPI_Write_Reg(WRITE_REG + CONFIG, 0x0f); //配置基本工作模式的参数;PWR_UP,EN_CRC,16BIT_CRC,接收模式,开启所有中断
  199. }
复制代码




1发2发1.zip

309.64 KB, 下载次数: 553, 下载积分: 黑币 -5

评分

参与人数 5黑币 +17 收起 理由
zkkfly + 5 赞一个!
tyx_ly + 3
fqsqsdq123456 + 3 很给力!
second1111 + 3 很给力!
sywangjunqing + 3 很有价值!

查看全部评分

回复

使用道具 举报

ID:54731 发表于 2015-6-4 18:38 | 显示全部楼层
谢谢!资料下载,我不知道与别人的有什么不一样?
回复

使用道具 举报

ID:83347 发表于 2015-6-18 11:28 | 显示全部楼层
感谢楼主,我最近也在这个无线模块,我的数据刷新有问题,参考下楼主的
回复

使用道具 举报

ID:83347 发表于 2015-6-18 11:28 | 显示全部楼层
不知道楼主这个数据刷新是如何处理的
回复

使用道具 举报

ID:84511 发表于 2015-7-3 16:07 | 显示全部楼层
很好的东西
回复

使用道具 举报

ID:89490 发表于 2015-9-6 13:59 | 显示全部楼层
非常感谢楼主无私奉献
回复

使用道具 举报

ID:44267 发表于 2015-10-19 13:16 | 显示全部楼层
太强了,顶起
回复

使用道具 举报

ID:77282 发表于 2015-10-19 16:58 | 显示全部楼层
本帖最后由 jiakuo25 于 2015-10-19 17:00 编辑

顶一下
QQ截图20151019165917.jpg
回复

使用道具 举报

ID:79544 发表于 2015-10-19 23:21 | 显示全部楼层
上位机的源码不全啊、
回复

使用道具 举报

ID:101398 发表于 2016-1-1 00:10 | 显示全部楼层
非常感谢
回复

使用道具 举报

ID:8625 发表于 2016-1-15 18:28 来自手机 | 显示全部楼层
还是不太懂啊,比如一对十,各个接收单元如何知道主机是对它发数据?
回复

使用道具 举报

ID:112498 发表于 2016-4-6 14:23 | 显示全部楼层
如何可以获得黑币呀,新手不懂

评分

参与人数 1黑币 +10 收起 理由
admin + 10 传几个教程到论坛 就不愁黑币了

查看全部评分

回复

使用道具 举报

ID:112498 发表于 2016-4-6 17:35 | 显示全部楼层
xuanyifeng 发表于 2016-4-6 14:23
如何可以获得黑币呀,新手不懂

谢谢你,太给力了,能先奖励点么,嘿嘿嘿

评分

参与人数 1黑币 +30 收起 理由
admin + 30 淡定,上传资料到论坛可以大量奖励黑币

查看全部评分

回复

使用道具 举报

ID:112498 发表于 2016-4-6 20:42 | 显示全部楼层
好的,十分感谢
回复

使用道具 举报

ID:112498 发表于 2016-4-6 20:49 | 显示全部楼层
xuanyifeng 发表于 2016-4-6 17:35
谢谢你,太给力了,能先奖励点么,嘿嘿嘿

别人下载资源,自己可以奖励黑币么?如何设置呢
回复

使用道具 举报

ID:1 发表于 2016-4-6 21:17 | 显示全部楼层
xuanyifeng 发表于 2016-4-6 20:49
别人下载资源,自己可以奖励黑币么?如何设置呢

设置出售附件即可,不过要工程师级别才可以。
回复

使用道具 举报

ID:113838 发表于 2016-4-12 22:30 | 显示全部楼层
hao  zi liao
回复

使用道具 举报

ID:142150 发表于 2016-10-10 10:29 | 显示全部楼层
不错的学习资料,谢谢楼主
回复

使用道具 举报

ID:143367 发表于 2016-10-19 14:25 | 显示全部楼层
感谢楼主的无私分享
回复

使用道具 举报

ID:104154 发表于 2017-3-21 11:58 | 显示全部楼层
正想研究一下 谢谢!
回复

使用道具 举报

ID:185362 发表于 2017-4-8 22:15 | 显示全部楼层
感谢楼主分享
回复

使用道具 举报

ID:193216 发表于 2017-4-24 21:34 | 显示全部楼层
感谢楼主
回复

使用道具 举报

ID:193904 发表于 2017-4-26 17:49 | 显示全部楼层
谢谢分享,正在学习
回复

使用道具 举报

ID:193947 发表于 2017-4-26 19:25 | 显示全部楼层
主要协议得写对,还得稳定,不卡死
回复

使用道具 举报

ID:110875 发表于 2017-4-27 09:52 | 显示全部楼层
1-1,1-2都简单,有没有1-3到1-6的我参考一下
回复

使用道具 举报

ID:236932 发表于 2017-10-1 21:36 | 显示全部楼层

不错的学习资料,谢谢楼主
回复

使用道具 举报

ID:237997 发表于 2017-10-9 14:22 | 显示全部楼层
不错谢谢分享
回复

使用道具 举报

ID:227832 发表于 2017-11-28 21:08 | 显示全部楼层
感谢楼主的无私分享
回复

使用道具 举报

ID:263693 发表于 2017-12-19 14:59 | 显示全部楼层

感谢楼主的无私分享
回复

使用道具 举报

ID:284472 发表于 2018-3-8 00:25 | 显示全部楼层
还是有用的
回复

使用道具 举报

ID:66287 发表于 2018-3-11 16:58 | 显示全部楼层
感谢楼主的无私奉献
回复

使用道具 举报

ID:345346 发表于 2018-6-5 13:18 | 显示全部楼层
谢谢楼主
回复

使用道具 举报

ID:344529 发表于 2018-6-5 15:33 | 显示全部楼层

谢谢分享! 51黑有你更精彩!!!
回复

使用道具 举报

ID:206350 发表于 2018-7-20 16:04 | 显示全部楼层
支持!!!!!!!!!!!!!
回复

使用道具 举报

ID:32574 发表于 2018-8-15 07:04 | 显示全部楼层
谢谢楼主分享,正在学习该项目。
回复

使用道具 举报

ID:32574 发表于 2018-8-27 16:56 | 显示全部楼层
谢谢老师分享,我也在做电脑发送地址的方式与多个nrf24l01终端通信,但是一直没有成功。
回复

使用道具 举报

ID:286070 发表于 2019-1-19 20:42 | 显示全部楼层
谢谢分享
回复

使用道具 举报

ID:492708 发表于 2019-3-17 19:25 | 显示全部楼层
楼主,想知道NRF24L01多对一的的发送,对于接受端是如何判断是由哪个发送端发送的数据,又要如何处理?
回复

使用道具 举报

ID:544565 发表于 2019-9-7 13:43 来自手机 | 显示全部楼层
我也下载来膜拜一下
回复

使用道具 举报

ID:185482 发表于 2019-9-8 02:27 | 显示全部楼层
也来看看
回复

使用道具 举报

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

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

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