找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 4812|回复: 1
收起左侧

51单片机驱动NRF24L01双向通信调试通过

[复制链接]
ID:79544 发表于 2016-5-1 07:44 | 显示全部楼层 |阅读模式
经过几个星期的折腾,NRF24L01无线模块终于调试通过。现在附上程序,我用的是2片不一样的单片机。程序里有详细解释。希望对大家有帮助。程序是来自网络的感谢作者的无私分享!
  1. /***************************************************
  2. //NRF24L01调试程序,全双工双向通信,即两个模块兼具收发功能,
  3. 自动高速切换收发模式。
  4. //使用本程序的前提条件是:硬件没问题。如果能正确运行本程序,
  5. 也能说明你的硬件电路没问题。
  6. //大家根据实际情况,更改 NRF24L01 各引脚、LED 和 KEY 的宏定义。
  7. //LED灯的状态由RxBuf[0]来决定,RxBuf[0] == 0,
  8. LED输出0;RxBuf[0] == 1,LED输出1;你也可以自行更改规则。
  9. //KEY可以改变TxBuf[0]的值,从而改变另一起模块RxBuf[0]的值,
  10. 进而改变LED的状态。
  11. //此程序未用到外部中断,即不响应IRQ 因此IRQ引脚可以接任意I/O口,
  12. 不必接到外部中断引脚,不过建议接到外部中断引脚。
  13. ***************************************************/

  14. /********************************************************
  15.         功   能:甲单片机通过NRF24L01发送数据乙单片机接收
  16.                         通过LED指示。同理乙单片机发送数据甲单片机接收
  17.                         通过LED指示,实现双机相互通信。
  18.                                 调试通过
  19.         甲单片机:STC12C5608AD
  20.         乙单片机:STC12C5A60S2
  21.         晶    振:11.0592M
  22.         作    者:苏义江改编自网络《感谢作者》
  23.         时    间:2016.5.1
  24.         注    释:如果甲乙单片机是一种型号NRF24L01的端口可以
  25.                         都用一组IO口(例甲单片机用PO口乙单片机也用P0口
  26.                         程序里的IO就不用换啦)
  27. *********************************************************/
  28. #include<reg52.h>
  29. #include<intrins.h>

  30. #define uchar unsigned char
  31. #define uint unsigned int

  32. void delayus(uint us)
  33. {
  34.         for(;us >0;us--)
  35.         {       
  36.                 _nop_();
  37.         }
  38. }

  39. //*****stc12c5608ad** NRF24L01端口定义************//
  40. /*sbit KEY =P2^4;
  41. sbit LED =P2^0;
  42. sbit LED1=P2^1;

  43. sbit CE  =P1^3;
  44. sbit SCK =P1^5;
  45. sbit CSN =P1^2;
  46. sbit MISO=P1^7;
  47. sbit MOSI=P1^4;
  48. sbit IRQ =P1^6;*/

  49. //***stc12c5a60s2**NRF24L01端口定义******************//
  50. sbit KEY =P3^7;
  51. sbit LED =P1^3;
  52. sbit LED1=P1^4;

  53. sbit CE  =P1^6;
  54. sbit SCK =P2^3;
  55. sbit CSN =P2^4;
  56. sbit MISO=P2^1;
  57. sbit MOSI=P2^2;
  58. sbit IRQ =P2^0;
  59. //**********NRF24L01的接收和发送地址***************/
  60. #define TX_ADR_WIDTH    5   // 5个字节的TX地址长度
  61. #define RX_ADR_WIDTH    5   // 5个字节的RX地址长度
  62. #define TX_PLOAD_WIDTH  16  // 16个字节的TX数据长度
  63. #define RX_PLOAD_WIDTH  16  // 16个字节的RX数据长度
  64. uchar const TX_ADDRESS[TX_ADR_WIDTH]= {0x34,0x43,0x10,0x10,0x01};        //本地地址
  65. uchar const RX_ADDRESS[RX_ADR_WIDTH]= {0x34,0x43,0x10,0x10,0x01};        //接收地址
  66. //***************************************NRF24L01寄存器指令**********************************//
  67. #define READ_REG        0x00          // 读寄存器
  68. #define WRITE_REG       0x20         // 写寄存器
  69. #define RD_RX_PLOAD     0x61          // 读取接收数据
  70. #define WR_TX_PLOAD     0xA0          // 写待发数据
  71. #define FLUSH_TX        0xE1         // 冲洗发送 FIFO
  72. #define FLUSH_RX        0xE2          // 冲洗接收 FIFO
  73. #define REUSE_TX_PL     0xE3          // 定义重复装载数据
  74. #define NOP             0xFF          // 保留
  75. //*************************************SPI(nRF24L01)寄存器地址*****************************//
  76. #define CONFIG          0x00  // 配置收发状态,CRC校验模式以及收发状态响应方式
  77. #define EN_AA           0x01  // 自动应答功能设置
  78. #define EN_RXADDR       0x02  // 可用信道设置
  79. #define SETUP_AW        0x03  // 收发地址宽度设置
  80. #define SETUP_RETR      0x04  // 自动重发功能设置
  81. #define RF_CH           0x05  // 工作频率设置
  82. #define RF_SETUP        0x06  // 发射速率、功耗功能设置
  83. #define STATUS          0x07  // 状态寄存器
  84. #define OBSERVE_TX      0x08  // 发送监测功能
  85. #define CD              0x09  // 地址检测   
  86. #define RX_ADDR_P0      0x0A  // 频道0接收数据地址
  87. #define RX_ADDR_P1      0x0B  // 频道1接收数据地址
  88. #define RX_ADDR_P2      0x0C  // 频道2接收数据地址
  89. #define RX_ADDR_P3      0x0D  // 频道3接收数据地址
  90. #define RX_ADDR_P4      0x0E  // 频道4接收数据地址
  91. #define RX_ADDR_P5      0x0F  // 频道5接收数据地址
  92. #define TX_ADDR         0x10  // 发送地址寄存器
  93. #define RX_PW_P0        0x11  // 接收频道0接收数据长度
  94. #define RX_PW_P1        0x12  // 接收频道0接收数据长度
  95. #define RX_PW_P2        0x13  // 接收频道0接收数据长度
  96. #define RX_PW_P3        0x14  // 接收频道0接收数据长度
  97. #define RX_PW_P4        0x15  // 接收频道0接收数据长度
  98. #define RX_PW_P5        0x16  // 接收频道0接收数据长度
  99. #define FIFO_STATUS     0x17  // FIFO栈入栈出状态寄存器设置
  100. void init_NRF24L01();
  101. uchar SPI_RW(uchar num);
  102. uchar SPI_Read(uchar reg);
  103. void SetRX_Mode();
  104. void SetTx_Mode();
  105. uchar SPI_RW_Reg(uchar reg, uchar value);
  106. uchar SPI_Read_Buf(uchar reg, uchar *pBuf, uchar uchars);
  107. uchar SPI_Write_Buf(uchar reg, uchar *pBuf, uchar uchars);
  108. void nRF24L01_RxPacket(uchar *rx_buf);
  109. void nRF24L01_TxPacket(uchar *tx_buf);
  110. //**********状态标志*****************************//
  111. uchar         bdata sta;
  112. sbit        RX_DR        =sta^6;
  113. sbit        TX_DS        =sta^5;
  114. sbit        MAX_RT        =sta^4;
  115. //***********NRF24L01初始化***************************//
  116. void init_NRF24L01()
  117. {
  118.     delayus(100);
  119.         CE=0;    // 片选使能
  120.         CSN=1;   // SPI使能
  121.         SCK=0;   // SPI时钟拉低
  122.         SPI_Write_Buf(WRITE_REG + TX_ADDR, TX_ADDRESS, TX_ADR_WIDTH);   
  123. //写本地地址       
  124.         SPI_Write_Buf(WRITE_REG + RX_ADDR_P0, RX_ADDRESS, RX_ADR_WIDTH);
  125. //写接收端地址
  126.         SPI_RW_Reg(WRITE_REG + EN_AA, 0x01);                             
  127. //通道0自动应答        
  128.         SPI_RW_Reg(WRITE_REG + EN_RXADDR, 0x01);                        
  129. //允许接收地址频道0
  130.         SPI_RW_Reg(WRITE_REG + RF_CH, 0x32);                             
  131. //设置信道工作频率,收发必须一致
  132.         SPI_RW_Reg(WRITE_REG + RX_PW_P0, RX_PLOAD_WIDTH);               
  133. //设置接收数据长度
  134.         SPI_RW_Reg(WRITE_REG + RF_SETUP, 0x0f);                                    
  135. //设置发射速率为2MHZ,发射功率为最大值0dB       
  136.         SPI_RW_Reg(WRITE_REG + CONFIG, 0x7c);                                                          
  137. //IRQ引脚不显示中断 掉电模式  1~16CRC校验
  138. }
  139. /*******************************************************
  140. /*函数:uint SPI_RW(uint uchar)
  141. /*功能:NRF24L01的SPI写时序
  142. /*********************************************************/
  143. uchar SPI_RW(uchar num)
  144. {
  145.         uchar bit_ctr;
  146.            for(bit_ctr=0;bit_ctr<8;bit_ctr++)  // output 8-bit
  147.            {
  148.                 MOSI = (num & 0x80);            // output 'uchar', MSB to MOSI
  149.                 num = (num << 1);               // shift next bit into MSB..
  150.                 SCK = 1;                        // Set SCK high..
  151.                 num |= MISO;                               // capture current MISO bit
  152.                 SCK = 0;                                // ..then set SCK low again
  153.            }
  154.     return(num);                                   // return read uchar
  155. }
  156. /**************************************************************
  157. 函数:uchar SPI_Read(uchar reg)
  158. 功能:NRF24L01的SPI时序
  159. *************************************************************/
  160. uchar SPI_Read(uchar reg)
  161. {
  162.         uchar reg_val;
  163.        
  164.         CSN = 0;                // CSN low, initialize SPI communication...
  165.         SPI_RW(reg);            // Select register to read from..
  166.         reg_val = SPI_RW(0);    // ..then read registervalue
  167.         CSN = 1;                // CSN high, terminate SPI communication
  168.        
  169.         return(reg_val);        // return register value
  170. }
  171. /******************************************************************/
  172. /*功能:NRF24L01读写寄存器函数
  173. /**************************************************************/
  174. uchar SPI_RW_Reg(uchar reg, uchar value)
  175. {
  176.         uchar status;
  177. CSN = 0;                   // CSN low, init SPI transaction
  178.         status = SPI_RW(reg);      // select register
  179.         SPI_RW(value);             // ..and write value to it..
  180.         CSN = 1;                   // CSN high again
  181.         return(status);            // return nRF24L01 status uchar
  182. }
  183. /****************************************************************/
  184. uchar SPI_Read_Buf(uchar reg, uchar *pBuf, uchar bytes)
  185. {
  186.         uchar status,byte_ctr;
  187.         CSN = 0; // Set CSN low, init SPI tranaction
  188.         status = SPI_RW(reg); // Select register to write to and read status byte
  189.         for(byte_ctr=0;byte_ctr<bytes;byte_ctr++)
  190.         pBuf[byte_ctr] = SPI_RW(0); // Perform SPI_RW to read byte from nRF24L01
  191.         CSN = 1; // Set CSN high again
  192.         return(status); // return nRF24L01 status byte
  193. }
  194. /************************************************************
  195. /*函数:uint SPI_Write_Buf(uchar reg, uchar *pBuf, uchar uchars)
  196. /*功能: 用于写数据:为寄存器地址,pBuf:为待写入数据地址,
  197. uchars:写入数据的个数
  198. /*****************************************************************/
  199. uchar SPI_Write_Buf(uchar reg, uchar *pBuf, uchar uchars)
  200. {
  201.         uchar status,uchar_ctr;
  202.        
  203.         CSN = 0;            //SPI使能      
  204.         status = SPI_RW(reg);   
  205.         for(uchar_ctr=0; uchar_ctr<uchars; uchar_ctr++) //
  206.                 SPI_RW(*pBuf++);
  207.         CSN = 1;           //关闭SPI
  208.         return(status);    //
  209. }
  210. //********** nrf收发程序 **********
  211. void nrf_RxTx(uchar mod_nrf,uchar *buff) //NRF24L01收发程序       
  212. {                       
  213.         static uchar mod_nrf_b;//static 地址不释放

  214. //******进入发射模式******
  215.         if(mod_nrf == 't')
  216.         {
  217.                 if(mod_nrf_b != 't')
  218.                 {       
  219.                         mod_nrf_b = 't';
  220.                         CE = 0;
  221.                         SPI_RW_Reg(WRITE_REG+STATUS,0xff);        
  222. //清除中断标志
  223.                         SPI_RW_Reg(FLUSH_TX,0x00);                       
  224. //清除TX_FIFO寄存器
  225.                         SPI_RW_Reg(WRITE_REG + CONFIG,0x7e);
  226. //IRQ引脚不显示中断 上电 发射模式  1~16CRC校验
  227.                         CE = 1;
  228.                         delayus(330);
  229. //从CE = 0 到 CE = 1;即待机模式到收发模式,需要最大130us                  
  230.                 }
  231. //******发送数据******
  232.                 CE = 0;                        //StandBy I模式       
  233.                 SPI_Write_Buf(WRITE_REG + RX_ADDR_P0, TX_ADDRESS, TX_ADR_WIDTH);
  234. // 装载接收端地址
  235.                 SPI_Write_Buf(WR_TX_PLOAD,buff,TX_PLOAD_WIDTH);                          
  236. // 装载数据
  237.                 CE = 1;                 //置高CE激发数据发送
  238.                 delayus(230);
  239. //从CE = 0 到 CE = 1;即待机模式到收发模式,需要最大130us
  240.                
  241.                 delayus(100);
  242. //给发送数据一点时间         比发送速度较快 延时可以比接收少
  243.                 sta = SPI_Read(STATUS);//读取状态寄存器的值
  244.                 SPI_RW_Reg(WRITE_REG+STATUS,sta);//清除对应的中断
  245.                                                
  246.                 if(TX_DS == 1)//发送成功再清除tx fifo寄存器
  247.                 {       
  248.                         CE = 0;                       
  249.                         SPI_RW_Reg(FLUSH_TX,0x00);
  250. //清除tx fifo寄存器        //********重要*********
  251.                         CE = 1;
  252.                 }                                                               
  253.                                
  254.         }
  255. //******进入接收模式******
  256.         else if(mod_nrf == 'r')//接收模式
  257.         {
  258.                 if(mod_nrf_b != 'r')
  259.                 {
  260.                         mod_nrf_b = 'r';
  261.                         CE = 0;
  262.                         SPI_RW_Reg(WRITE_REG+STATUS,0xff);       
  263. //清除中断标志
  264.                         SPI_RW_Reg(FLUSH_RX,0x00);                        
  265. //清除RX_FIFO寄存器
  266.                         SPI_RW_Reg(WRITE_REG + CONFIG, 0x7f);
  267. //IRQ引脚不显示中断 上电 接收模式   1~16CRC校验   
  268.                         CE = 1;
  269.                         delayus(230);
  270. //从CE = 0 到 CE = 1;即待机模式到收发模式,需要最大130us
  271.                 }               
  272.                 delayus(1500); //不能少 值可调  给接收数据一点时间
  273.                 sta = SPI_Read(STATUS);
  274.                 SPI_RW_Reg(WRITE_REG+STATUS,sta);   
  275.                 if(RX_DR == 1)   
  276.                 {
  277.                         CE = 0;  
  278.                         SPI_Read_Buf(RD_RX_PLOAD,buff,RX_PLOAD_WIDTH);
  279. //读取数据 存入数组
  280.                         SPI_RW_Reg(FLUSH_RX,0x00);
  281. //清除rx fifo寄存器        数据不抖动
  282.                         CE = 1;
  283.                 }                 
  284.          }
  285. }
  286. void main()
  287. {
  288.         uchar idata RxBuf[16];        //接收缓存 存入idata区
  289.         uchar idata TxBuf[16];        //发送缓存
  290.         uint t_while = 0;
  291.         uint t_tx = 100;
  292.         uint t_rx = 100;       
  293.         init_NRF24L01();                //nrf24l01初始化       
  294.         RxBuf[0] = 1;
  295.         TxBuf[0] = 0;       
  296.         LED = 1;
  297.         LED1 = 1;
  298.         while(1)
  299.         {
  300.                 t_while = t_tx;
  301.                 while(t_while--)
  302. //一旦发送成功就跳出循环 最多发送t_while次
  303.                 {
  304.                         nrf_RxTx('t',TxBuf);//发送模式
  305.                         if(TX_DS == 1)                //发送成功
  306.                         LED = 0;
  307.                         delayus(2300);
  308.                         LED = 1;
  309.                                 break;                       
  310. //跳出循环进入接收模式
  311.                 }                       
  312.                
  313.                
  314.                 t_while = t_rx ;
  315.                 while(t_while--)                       
  316. //一旦接收成功就跳出循环 最多接收t_while次       
  317.                 {       
  318.                         nrf_RxTx('r',RxBuf);//接收模式
  319.                        
  320.                         if(RX_DR == 1)        //接收成功
  321.                                 LED = 0;
  322.                                 break;        //跳出循环进入发送模式
  323.                 }
  324.                
  325.                 if(RxBuf[0] == 0)
  326.                         LED1= 0;
  327.                 else
  328.                         LED1 = 1;

  329.                 if(KEY == 0)
  330.                 {
  331.                
  332.                         TxBuf[0] = 1;
  333.                 }
  334.                 else
  335.                         TxBuf[0] = 0;                       
  336.                
  337.         }
  338. }
复制代码


评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

回复

使用道具 举报

ID:284472 发表于 2018-3-8 00:54 | 显示全部楼层
很棒很有用nice
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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