[应用方案] nRF24L01一对六通信

[复制链接]
1428|3
 楼主| cowboy2014 发表于 2016-4-26 11:21 | 显示全部楼层 |阅读模式

nRF24L01是NORDIC公司生产的一款无线通信芯片,采用FSK调制,内部集成NORDIC自己的Enhanced ShortBurst协议。可以实现点对点或者是1对6的无线通信。无线通信速度可以达到2Mbps。

但是具体如何实现一对六通信,芯片手册中也只是简单的介绍只要6路数据通道的发送地址和接收地址匹配即可。但是如何匹配并没有给出明确的说明。这就产生了一个问题。对于0和1通道,接收端和发送端的地址是可以都写成5个字节的地址,当然可以两端是同样的地址,很容易就实现了通信;但是对于2、3、4、5通道,接收端的地址只有低字节可以设置,发送端的发送地址却是5个字节的。如何相同是个问题。

查找网络上有很多人分享的程序,虽然他们说着是1对6的程序,但是下载下来试了2~5通道都不能用,其中包括广为流传的Bluebird的程序也是不能用的。FLY2000开发板的技术部人员说不能实现一对六,他们只做过点对点;迅通科技的工程师说需要组网和跳频才能实现。我只能说我很无语。

通过求教他人和仔细阅读数据手册,最后把一对六调通了,其中也遇到了一个小问题,就是如何判断接收数据通道号的问题。芯片的状态寄存器STATUS,其中RX_P_NO这三位就是代表了接收数据通道号,在我们读这个寄存器的值得时候却一直出现0x0E这个值,数据明明是接收到了,这个值却是错了,下面也会给出原因和解决方法。

下面想把已经调试通过的NRF24L01一对六的程序写出来,但是eeeeeee额,不知道为么,最重要的地址部分一提交博文就看不到了,难道内容**??那我只能把需要注意的点提出来:

接收部分的地址设置:

  1. uchar code TX_ADDRESS[TX_ADR_WIDTH] = {0x78,0x78,0x78,0x78,0x78}; // 本地地址  

  2. uchar code RX_ADDRESS0[TX_ADR_WIDTH] = {0x78,0x78,0x78,0x78,0x78};//写地址寄存器是先写低字节,因此后面几个字节相同

  3. uchar code RX_ADDRESS1[TX_ADR_WIDTH] = {0xF1,0xB6,0xB5,0xB4,0xB3};//写地址寄存器是先写低字节,因此后面几个字节相同
  4. uchar code RX_ADDRESS2[1] = {0xCD};
  5. uchar code RX_ADDRESS3[1] = {0xA3};
  6. uchar code RX_ADDRESS4[1] = {0x0F};
  7. uchar code RX_ADDRESS5[1] = {0x05};



  8. void init_NRF24L01(void)
  9. {
  10.     inerDelay_us(600);
  11.   CE=0;    // chip enable
  12.   CSN=1;   // Spi  disable
  13.   SCK=0;   //
  14. SPI_Write_Buf(WRITE_REG + TX_ADDR, TX_ADDRESS, TX_ADR_WIDTH);    // 写本地地址
  15.   _nop_();
  16.   _nop_();
  17.   _nop_();
  18. SPI_Write_Buf(WRITE_REG + RX_ADDR_P0, RX_ADDRESS0, TX_ADR_WIDTH); // 写接收端0地址
  19. SPI_Write_Buf(WRITE_REG + RX_ADDR_P1, RX_ADDRESS1, TX_ADR_WIDTH); // 写接收端1地址
  20. SPI_Write_Buf(WRITE_REG + RX_ADDR_P2, RX_ADDRESS2, 1); // 写接收端2地址
  21. SPI_Write_Buf(WRITE_REG + RX_ADDR_P3, RX_ADDRESS3, 1); // 写接收端3地址
  22. SPI_Write_Buf(WRITE_REG + RX_ADDR_P4, RX_ADDRESS4, 1); // 写接收端4地址
  23. SPI_Write_Buf(WRITE_REG + RX_ADDR_P5, RX_ADDRESS5, 1); // 写接收端5地址

  24. SPI_RW_Reg(WRITE_REG + RX_PW_P0, TX_PLOAD_WIDTH);  // 接收通道0选择和发送通道相同有效数据宽度,32字节长度
  25.    SPI_RW_Reg(WRITE_REG + RX_PW_P1, TX_PLOAD_WIDTH);//32字节长度
  26.    SPI_RW_Reg(WRITE_REG + RX_PW_P2, TX_PLOAD_WIDTH);//32字节长度
  27.    SPI_RW_Reg(WRITE_REG + RX_PW_P3, TX_PLOAD_WIDTH);//32字节长度
  28.    SPI_RW_Reg(WRITE_REG + RX_PW_P4, TX_PLOAD_WIDTH);//32字节长度
  29.    SPI_RW_Reg(WRITE_REG + RX_PW_P5, TX_PLOAD_WIDTH);//32字节长度
  30.   _nop_();
  31.   _nop_();
  32.   _nop_();
  33. SPI_RW_Reg(WRITE_REG + EN_AA, 0x3f);      //  所有通道自动 ACK应答允许
  34.   _nop_();
  35.   _nop_();
  36.   _nop_();
  37. //SPI_RW_Reg(WRITE_REG + EN_RXADDR, 0x01);  //  允许接收地址只有频道0,如果需要多频道可以参考Page21
  38. SPI_RW_Reg(WRITE_REG + EN_RXADDR, 0x3f);  //使能所有接受通道
  39.      _nop_();
  40.   _nop_();
  41.   _nop_();
  42. SPI_RW_Reg(WRITE_REG + RF_CH, 0);        //   设置信道工作为2.4GHZ,收发必须一致
  43.   _nop_();
  44.   _nop_();
  45.   _nop_();
  46.   
  47. SPI_RW_Reg(WRITE_REG + RF_SETUP, 0x0F);    //设置发射速率为1MHZ,发射功率为最大值0dB
  48. CE=1;
  49. }
送端的库函数:因为0和1通道的发送端的发送地址(本地地址)和接收端的P0、P1一样即可,现只给出2通道的例子,剩下的3、4、5通道的设置就和2的类似。
  1. uint const TX_ADDRESS[TX_ADR_WIDTH] = {0xCD,0xB6,0xB5,0xB4,0xB3}; //本地地址
  2. uint const RX_ADDRESS[TX_ADR_WIDTH] = {0xCD,0xB6,0xB5,0xB4,0xB3}; //接收地址

  3. void init_NRF24L01(void)
  4. {
  5.     inerDelay_us(600);
  6.   CE=0;    // chip enable
  7.   CSN=1;   // Spi  disable
  8.   SCK=0;   //
  9. SPI_Write_Buf(WRITE_REG + TX_ADDR, TX_ADDRESS, TX_ADR_WIDTH);    // 写本地地址
  10.   _nop_();
  11.   _nop_();
  12.   _nop_();
  13. SPI_Write_Buf(WRITE_REG + RX_ADDR_P0, RX_ADDRESS, RX_ADR_WIDTH);
  14.   _nop_();
  15.   _nop_();
  16.   _nop_();
  17. SPI_RW_Reg(WRITE_REG + EN_AA, 0x01);      //  频道0自动 ACK应答允许
  18.   _nop_();
  19.   _nop_();
  20.   _nop_();
  21. SPI_RW_Reg(WRITE_REG + EN_RXADDR, 0x01);  //  允许接收地址只有频道0,如果需要多频道可以参考Page21
  22.      _nop_();
  23.   _nop_();
  24.   _nop_();
  25. SPI_RW_Reg(WRITE_REG + RF_CH, 0);        //   设置信道工作为2.4GHZ,收发必须一致
  26.   _nop_();
  27.   _nop_();
  28.   _nop_();
  29. SPI_RW_Reg(WRITE_REG + RX_PW_P0, RX_PLOAD_WIDTH); //设置接收数据长度,本次设置为32字节
  30.   _nop_();
  31.   _nop_();
  32.   _nop_();
  33. SPI_RW_Reg(WRITE_REG + RF_SETUP, 0x0F);    //设置发射速率为1MHZ,发射功率为最大值0dB
  34. CE=1;
  35. }



 楼主| cowboy2014 发表于 2016-4-26 11:21 | 显示全部楼层
接收主函数:
  1. void main(void)
  2. {
  3.     uchar tf=0;
  4.     init_NRF24L01() ;
  5.     P0=0x00;
  6.     Delay(6000);

  7. while(1)
  8.   {
  9.      SetRX_Mode(); //设定为接收模式
  10.      Delay(1000);
  11.      nRF24L01_RxPacket(RxBuf); //接收数据
  12.      Delay(2000);   
  13.     tf=SPI_RW_Reg(READ_REG + STATUS);
  14.     Sendchar(tf);   //读数据通道号     
  15.   }

发送主函数:
  1. void main(void)
  2. {
  3.     init_NRF24L01();
  4.     P0=0x00;
  5.     Delay(6000);

  6. nRF24L01_TxPacket(TxBuf); // Transmit Tx buffer data
  7.    Delay(2000);
  8.    SPI_RW_Reg(FLUSH_TX,0x00);
  9.    SPI_RW_Reg(WRITE_REG+STATUS,0x7F);//关系着是否能顺利通信和接收端的数据通道号能否正确读出。数据手册中有这么一句话:如果MAX_RX中断产生则必须清除后才能进行通讯。
  10. }
wahahaheihei 发表于 2016-4-26 20:08 | 显示全部楼层
以前我只用过点到点的通信,这个芯片在好多无线鼠标里用的很多
bitofnoone 发表于 2016-4-26 20:41 | 显示全部楼层
那么收发的时候是如何处理的呢?
您需要登录后才可以回帖 登录 | 注册

本版积分规则

78

主题

821

帖子

5

粉丝
快速回复 在线客服 返回列表 返回顶部