找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 22637|回复: 20
打印 上一主题 下一主题
收起左侧

Arduino学习16-连接nRF24L01无线收发模块

  [复制链接]
跳转到指定楼层
楼主
nRF24L01是一款工作在 2.4~2.5GHz 世界通用ISM频段的单片无线收发器芯片,输出功率、频道选择和协议的设置可以通过SPI接口进行设置。有极低的电流消耗,当工作在发射模式下发射功率为-6dBm时电流消耗为9.0mA,接收模式时为12.3mA。掉电模式和待机模式下电流消耗更低。
nRF24L01参考数据:供电电压:1.9 V~3.6V;最大发射功率:0 dBm;最大数据传输率:2000 kbps;发射模式下电流消耗(0dBm时):11.3 mA;接收模式下电流消耗(2000kbps):12.3 mA;接收模式数据传输率为1000kbps下的灵敏度:-85 dBm;掉电模式下电流消耗:900 nA。

淘宝上面有两种nRF24L01模块,一种是单纯的nRF24L01模块,号称传输距离250m的,几块钱就有交易;另外一种是NRF24L01+PA+LNA模块,包含放大,号称可以传输1000m,价格几十块。实际距离视地形和障碍物而定,是否够远只能通过试用确定。

下面用廉价的第一种单纯nRF24L01模块做示例:




一、nRF24L01硬件连接:
此模块是使用SPI方式连接,在标准SPI口基础增加CE和CSN引脚:
nRF24L01 Arduino UNO
VCC <-> 3.3V
GND <-> GND
CE <-> D9
CSN <-> D10
MOSI<-> D11
MISO<-> D12
SCK <-> D13
IRQ <-> 不接

还有就是nRF24L01属于对传模块。每块芯片既是发射器,也是接收器。所以一般来说,要使用两块nRF24L01+两块Arduino才能进行测试。

二、应用例子
实验1:

将Sender机A0的AD转换值无线发送到Receiver机

原理图:

Sender机(A0端与电源两端接一个电位器,阻值随意,一般1k~100k均可):


Receiver机:


代码:

首先需要安装Mirf库,可以在http://playground.arduino.cc/InterfacingWithHardware/Nrf24L01下载或者本文附件下载。

Sender机:
  1.     /*
  2.     nRF24L01 Arduino发送端
  3.      
  4.     Ansifa
  5.     2015/3/7
  6.      
  7.     引脚接法:
  8.     nRF24L01   Arduino UNO
  9.     VCC        <->        3.3V
  10.     GND        <->        GND
  11.     CE        <->        D9
  12.     CSN        <->        D10
  13.     MOSI<->        D11
  14.     MISO<->        D12
  15.     SCK        <->        D13
  16.     IRQ        <->        不接
  17.     */
  18.      
  19.     #include
  20.     #include
  21.     #include
  22.     #include
  23.     void setup()
  24.     {
  25.         Serial.begin(9600);
  26.      
  27.         Mirf.cePin = 9;                //设置CE引脚为D9
  28.         Mirf.csnPin = 10;        //设置CE引脚为D10
  29.         Mirf.spi = &MirfHardwareSpi;
  30.         Mirf.init();  //初始化nRF24L01               
  31.      
  32.             //设置接收标识符"Sen01"
  33.         Mirf.setRADDR((byte *)"Sen01");
  34.         //设置一次收发的字节数,这里发一个整数,写sizeof(unsigned int),实际等于2字节
  35.         Mirf.payload = sizeof(unsigned int);
  36.         //发送通道,可以填0~128,收发必须一致。
  37.         Mirf.channel = 3;
  38.         Mirf.config();
  39.      
  40.             //注意一个Arduino写Sender.ino,另一个写Receiver.ino。
  41.             //这里标识写入了Sender.ino
  42.         Serial.println("I'm Sender...");
  43.     }
  44.     unsigned int adata = 0;
  45.     void loop()
  46.     {
  47.             //读取A0值到adata
  48.         adata = analogRead(A0);
  49.      
  50.         //由于nRF24L01只能以byte单字节数组形式发送Mirf.payload个数据,
  51.         //所以必须将所有需要传输的数据拆成byte。
  52.         //下面定义byte数组,存放待发数据,因为Mirf.payload = sizeof(unsigned int);
  53.         //实际下面等于byte data[2];
  54.         byte data[Mirf.payload];
  55.      
  56.         //adata是unsigned int双字节数据,必须拆开。
  57.         //将adata高低八位拆分:
  58.         data[0] = adata & 0xFF;                //低八位给data[0],
  59.         data[1] = adata >> 8;                //高八位给data[1]。
  60.      
  61.         //设置向"serv1"发送数据
  62.         Mirf.setTADDR((byte *)"Rec01");
  63.         Mirf.send(data);
  64.         //while死循环等待发送完毕,才能进行下一步操作。
  65.         while(Mirf.isSending()) {}
  66.         delay(20);
  67.     }
复制代码

Receiver机:
  1.     /*
  2.     nRF24L01 Arduino Receiver接收端
  3.      
  4.     Ansifa
  5.     2015/3/7
  6.      
  7.     引脚接法:
  8.     nRF24L01   Arduino UNO
  9.     VCC <-> 3.3V
  10.     GND <-> GND
  11.     CE  <-> D9
  12.     CSN <-> D10
  13.     MOSI<-> D11
  14.     MISO<-> D12
  15.     SCK <-> D13
  16.     IRQ <-> 不接
  17.     */
  18.      
  19.     #include
  20.     #include
  21.     #include
  22.     #include
  23.      
  24.         //定义一个变量adata存储最终结果,oldadata存储旧结果,防止相同结果刷屏。
  25.         unsigned int adata = 0, oldadata = 0;
  26.      
  27.     void setup()
  28.     {
  29.         Serial.begin(9600);
  30.      
  31.         //---------初始化部分,不可随时修改---------
  32.         Mirf.cePin = 9;     //设置CE引脚为D9
  33.         Mirf.csnPin = 10;   //设置CE引脚为D10
  34.         Mirf.spi = &MirfHardwareSpi;
  35.         Mirf.init();  //初始化nRF24L01
  36.      
  37.         //---------配置部分,可以随时修改---------
  38.         //设置接收标识符"Rev01"
  39.         Mirf.setRADDR((byte *)"Rec01");
  40.         //设置一次收发的字节数,这里发一个整数,
  41.         //写sizeof(unsigned int),实际等于2字节
  42.         Mirf.payload = sizeof(unsigned int);
  43.         //发送通道,可以填0~128,收发必须一致。
  44.         Mirf.channel = 3;
  45.         Mirf.config();
  46.      
  47.         //注意一个Arduino写Sender.ino,另一个写Receiver.ino。
  48.         //这里用来辨别写入了Receiver.ino程序
  49.         Serial.println("I'm Receiver...");
  50.     }
  51.      
  52.     void loop()
  53.     {
  54.         //定义一个暂存数组,大小为Mirf.payload。
  55.         byte data[Mirf.payload];
  56.         if(Mirf.dataReady())    //等待接收数据准备好
  57.         {
  58.             Mirf.getData(data);    //接收数据到data数组
  59.             //data[1]<左移8位与data[0]并,重组数据。
  60.             adata = (unsigned int)((data[1] << 8) | data[0]);
  61.      
  62.             //与上一次结果比较,避免相同结果刷屏,降低串口流量
  63.             if(adata != oldadata)
  64.             {
  65.                 oldadata = adata; //本次结果作为历史结果。
  66.                 //Serial.print输出数据
  67.                 Serial.print("A0=");
  68.                 Serial.println(adata);
  69.                 //也可以输出双字节数据
  70.                 //Serial.write(data[1]);
  71.                 //Serial.write(data[0]);
  72.             }
  73.      
  74.         }
  75.     }
复制代码

实验2:

将上述的数据绘图表。

修改一下输出格式,然后用现成的串口图表软件显示出来。

原理图:
与实验1一样。
代码:
发射端代码与原来一样。
接收端新代码:
  1.     /*
  2.     nRF24L01 Arduino Receiver接收端
  3.     图表输出版本
  4.      
  5.     Ansifa
  6.     2015/3/7
  7.      
  8.     引脚接法:
  9.     nRF24L01   Arduino UNO
  10.     VCC <-> 3.3V
  11.     GND <-> GND
  12.     CE  <-> D9
  13.     CSN <-> D10
  14.     MOSI<-> D11
  15.     MISO<-> D12
  16.     SCK <-> D13
  17.     IRQ <-> 不接
  18.     */
  19.      
  20.     #include
  21.     #include
  22.     #include
  23.     #include
  24.      
  25.     //定义一个变量adata存储最终结果。
  26.     unsigned int adata = 0;
  27.      
  28.     void setup()
  29.     {
  30.         Serial.begin(9600);
  31.      
  32.         //---------初始化部分,不可随时修改---------
  33.         Mirf.cePin = 9;     //设置CE引脚为D9
  34.         Mirf.csnPin = 10;   //设置CE引脚为D10
  35.         Mirf.spi = &MirfHardwareSpi;
  36.         Mirf.init();  //初始化nRF24L01
  37.      
  38.         //---------配置部分,可以随时修改---------
  39.         //设置接收标识符"Rev01"
  40.         Mirf.setRADDR((byte *)"Rec01");
  41.         //设置一次收发的字节数,这里发一个整数,
  42.         //写sizeof(unsigned int),实际等于2字节
  43.         Mirf.payload = sizeof(unsigned int);
  44.         //发送通道,可以填0~128,收发必须一致。
  45.         Mirf.channel = 3;
  46.         Mirf.config();
  47.      
  48.         //注意一个Arduino写Sender.ino,另一个写Receiver.ino。
  49.         //这里用来辨别写入了Receiver.ino程序
  50.         Serial.println("I'm Receiver...");
  51.     }
  52.      
  53.     void loop()
  54.     {
  55.         //定义一个暂存数组,大小为Mirf.payload。
  56.         byte data[Mirf.payload];
  57.         if(Mirf.dataReady())    //等待接收数据准备好
  58.         {
  59.             Mirf.getData(data);    //接收数据到data数组
  60.             //data[1]<左移8位与data[0]并,重组数据。
  61.             adata = (unsigned int)((data[1] << 8) | data[0]);
  62.      
  63.             //输出双字节数据
  64.             Serial.write(data[0]);
  65.             Serial.write(data[1]);
  66.         }
  67.     }
复制代码

上位机:
直接用现成软件比如这个串口猎人。
配置如图。依照图片顺序配置成截图一样即可。





特意测试了一下可以,这个说是+7dB的,比wifi的+5dB高一点,感觉会比wifi好一些。

下面是PDF版本文章与源代码:

Arduino连接NRF24L01无线收发模块.zip (3.25 MB, 下载次数: 177)

评分

参与人数 4黑币 +12 收起 理由
midrich + 5 绝世好帖!
lionel + 5 回帖助人的奖励!
savantor + 1 先赞一个!我弄nrf弄了好久
spps + 1 很给力!

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏2 分享淘帖 顶1 踩
回复

使用道具 举报

沙发
ID:114115 发表于 2016-4-18 03:41 | 只看该作者
问题解答:
楼主你好,我想请教下,如果一次发送多个传感器的数据该怎么改呢?我试着改了一下你的程序,但是只能接收到第一个传感器的数据,第二个传感器的数据一直不对,能帮我看下吗?谢谢了
发送端程序
#include <SPI.h>
#include <Mirf.h>
#include <nRF24L01.h>
#include <MirfHardwareSpiDriver.h>
void setup()
{
    Serial.begin(9600);

    Mirf.cePin = 8;                //设置CE引脚为D9
    Mirf.csnPin = 7;        //设置CE引脚为D10
    Mirf.spi = &MirfHardwareSpi;
    Mirf.init();  //初始化nRF24L01               

        //设置接收标识符"Sen01"
    Mirf.setRADDR((byte *)"Sen01");
    Mirf.payload = sizeof(unsigned int);
    Mirf.channel = 3;
    Mirf.config();

        //注意一个Arduino写Sender.ino,另一个写Receiver.ino。
        //这里标识写入了Sender.ino
    Serial.println("I'm Sender...");
}
unsigned int adata = 0;
unsigned int bdata = 0;
void loop()
{
        //读取A0值到adata
    adata = analogRead(A0);
    bdata = analogRead(A1);

    //由于nRF24L01只能以byte单字节数组形式发送Mirf.payload个数据,
    //所以必须将所有需要传输的数据拆成byte。
    //下面定义byte数组,存放待发数据,因为Mirf.payload = sizeof(unsigned int);
    //实际下面等于byte data[2];
    byte data[Mirf.payload];

    //adata是unsigned int双字节数据,必须拆开。
    //将adata高低八位拆分:
    data[0] = adata & 0xFF;                //低八位给data[0],
    data[1] = adata >> 8;    //高八位给data[1]。
  data[2] = bdata & 0xFF;                //低八位给data[0],
    data[3] = bdata >> 8;
    //设置向"serv1"发送数据
    Mirf.setTADDR((byte *)"Rec01");
    Mirf.send(data);
    //while死循环等待发送完毕,才能进行下一步操作。
    while(Mirf.isSending()) {}
    Serial.println(adata);
    Serial.print("*****");
    Serial.println(bdata,DEC);
    delay(3000);
}

接收端程序:

#include <SPI.h>
#include <Mirf.h>
#include <nRF24L01.h>
#include <MirfHardwareSpiDriver.h>

    //定义一个变量adata存储最终结果,oldadata存储旧结果,防止相同结果刷屏。
    unsigned int adata = 0, bdata = 0;

void setup()
{
    Serial.begin(9600);

    //---------初始化部分,不可随时修改---------
    Mirf.cePin = 8;     //设置CE引脚为D9
    Mirf.csnPin = 7;   //设置CE引脚为D10
    Mirf.spi = &MirfHardwareSpi;
    Mirf.init();  //初始化nRF24L01

    //---------配置部分,可以随时修改---------
    //设置接收标识符"Rev01"
    Mirf.setRADDR((byte *)"Rec01");
    //设置一次收发的字节数,这里发一个整数,
    //写sizeof(unsigned int),实际等于2字节
    Mirf.payload = sizeof(unsigned int);
    //发送通道,可以填0~128,收发必须一致。
    Mirf.channel = 3;
    Mirf.config();

    //注意一个Arduino写Sender.ino,另一个写Receiver.ino。
    //这里用来辨别写入了Receiver.ino程序
    Serial.println("I'm Receiver...");
}

void loop()
{
    //定义一个暂存数组,大小为Mirf.payload。
    byte data[Mirf.payload];
    if(Mirf.dataReady())    //等待接收数据准备好
    {
        Mirf.getData(data);    //接收数据到data数组
        //data[1]<左移8位与data[0]并,重组数据。
        adata = (unsigned int)((data[1] << 8) | data[0]);
  bdata = (unsigned int)((data[3] << 8) | data[2]);



          Serial.println(adata);
    Serial.print("*****");
    Serial.println(bdata,DEC);
    }
}

求指教,十分感谢!

-----------------------------------------------

答:
你在可以这样修改:

发送端程序
#include <SPI.h>
#include <Mirf.h>
#include <nRF24L01.h>
#include <MirfHardwareSpiDriver.h>
void setup()
{
    Serial.begin(9600);

    Mirf.cePin = 8;                //设置CE引脚为D9
    Mirf.csnPin = 7;        //设置CE引脚为D10
    Mirf.spi = &MirfHardwareSpi;
    Mirf.init();  //初始化nRF24L01               

        //设置接收标识符"Sen01"
    Mirf.setRADDR((byte *)"Sen01");
    Mirf.payload = sizeof(unsigned int);//在这把2 修改成4
    Mirf.channel = 3;
    Mirf.config();

        //注意一个Arduino写Sender.ino,另一个写Receiver.ino。
        //这里标识写入了Sender.ino
    Serial.println("I'm Sender...");
}
unsigned int adata = 0,bdata = 0;

void loop()
{
        //读取A0值到adata
    adata = analogRead(A0);
    bdata = analogRead(A1);

    //由于nRF24L01只能以byte单字节数组形式发送Mirf.payload个数据,
    //所以必须将所有需要传输的数据拆成byte。
    //下面定义byte数组,存放待发数据,因为Mirf.payload = sizeof(unsigned int);
    //实际下面等于byte data[2];
    byte data[Mirf.payload];

    //adata是unsigned int双字节数据,必须拆开。
    //将adata高低八位拆分:
    data[0] = adata & 0xFF;                //低八位给data[0],
    data[1] = adata >> 8;    //高八位给data[1]。
    data[2] = bdata & 0xFF;                //低八位给data[0],
    data[3] = bdata >> 8;
    //设置向"serv1"发送数据
    Mirf.setTADDR((byte *)"Rec01");
    Mirf.send(data);
    //while死循环等待发送完毕,才能进行下一步操作。
    while(Mirf.isSending()) {}
    Serial.println(adata);
    Serial.print("*****");
    Serial.println(bdata,DEC);
    delay(3000);
}

接收端程序:

#include <SPI.h>
#include <Mirf.h>
#include <nRF24L01.h>
#include <MirfHardwareSpiDriver.h>

    //定义一个变量adata存储最终结果,oldadata存储旧结果,防止相同结果刷屏。
    unsigned int adata = 0, bdata = 0;

void setup()
{
    Serial.begin(9600);

    //---------初始化部分,不可随时修改---------
    Mirf.cePin = 8;     //设置CE引脚为D9
    Mirf.csnPin = 7;   //设置CE引脚为D10
    Mirf.spi = &MirfHardwareSpi;
    Mirf.init();  //初始化nRF24L01

    //---------配置部分,可以随时修改---------
    //设置接收标识符"Rev01"
    Mirf.setRADDR((byte *)"Rec01");
    //设置一次收发的字节数,这里发一个整数,
    //写sizeof(unsigned int),实际等于2字节
    Mirf.payload = sizeof(unsigned int);//在这把2 修改成4
    //发送通道,可以填0~128,收发必须一致。
    Mirf.channel = 3;
    Mirf.config();

    //注意一个Arduino写Sender.ino,另一个写Receiver.ino。
    //这里用来辨别写入了Receiver.ino程序
    Serial.println("I'm Receiver...");
}

void loop()
{
    //定义一个暂存数组,大小为Mirf.payload。
    byte data[Mirf.payload];
    if(Mirf.dataReady())    //等待接收数据准备好
    {
        Mirf.getData(data);    //接收数据到data数组
        //data[1]<左移8位与data[0]并,重组数据。
        adata = (unsigned int)((data[1] << 8) | data[0]);
        bdata = (unsigned int)((data[3] << 8) | data[2]);
   
      
            
          Serial.println(adata);
    Serial.print("*****");
    Serial.println(bdata,DEC);
    }
}

回复

使用道具 举报

板凳
ID:156727 发表于 2016-12-22 01:11 来自手机 | 只看该作者
教程真的不错。
回复

使用道具 举报

地板
ID:156727 发表于 2016-12-22 01:13 来自手机 | 只看该作者
相当不错的教程
回复

使用道具 举报

5#
ID:165849 发表于 2017-2-22 01:05 | 只看该作者
1) 终于成功测试成功。  不过网上的MIRF 库有多个版本的,我用上老的版本·
https://github.com/aaronds/arduino-nrf24l01

2)  设置CE CSN引脚也很方便可以用以下指令
Mirf.cePin = 9;   
Mirf.csnPin = 10

3) 范例开始的这段漏了  
#include
#include
#include
#include ,  
后来查了一下应该是
#include <SPI.h>
#include <Mirf.h>
#include <nRF24L01.h>
#include <MirfHardwareSpiDriver.h>
回复

使用道具 举报

6#
ID:189188 发表于 2017-4-13 14:42 | 只看该作者
参照了您的写法,一对一成功了,请问一对多如何改写
回复

使用道具 举报

7#
ID:190306 发表于 2017-4-17 09:06 | 只看该作者
很不错的教程,学习了
回复

使用道具 举报

8#
ID:190397 发表于 2017-4-17 13:00 | 只看该作者
有一对多的代码吗?
回复

使用道具 举报

9#
ID:189188 发表于 2017-4-18 09:40 | 只看该作者
这个是别人写的多通道发送端程序,更改地址,但是只有03号地址才能用为啥?
  1. /*
  2.     nRF24L01 Arduino Receiver接收端
  3.     图表输出版本
  4.      
  5.     Ansifa
  6.     2015/3/7
  7.      
  8.     引脚接法:
  9.     nRF24L01   Arduino UNO
  10.     VCC <-> 3.3V
  11.     GND <-> GND
  12.     CE  <-> D9
  13.     CSN <-> D10
  14.     MOSI<-> D11
  15.     MISO<-> D12
  16.     SCK <-> D13
  17.     IRQ <-> 不接
  18.     */
  19. #include"Multiple.h"

  20. Multiple nrf(9,10,13,11,12);//构建函数,参数分别为CE,CSN,CLK,MOSI,MISO

  21. uint8_t tx_addr[] = { 0x03, 0xFF, 0xFF, 0xFF, 0xFF};//发送地址
  22. uint8_t tx_data[32]={3,0,2,5,8};//发送的数据,32位
  23. //uint8_t channel;//接收通道
  24. //uint8_t tmp;

  25. void setup() {
  26.   nrf.send_mode(tx_addr);//设置为发送模式,参数为发送地址
  27. }

  28. void loop() {
  29.    
  30.   tx_data[2]++;
  31.   nrf.send(tx_addr,tx_data);//发送数据,参数:发送地址,数据
  32.   delay(1000);

  33. }
复制代码
回复

使用道具 举报

10#
ID:191906 发表于 2017-5-17 00:53 | 只看该作者
支持一个,我用RF24丢包好严重,不懂是什么问题
回复

使用道具 举报

11#
ID:198286 发表于 2017-5-28 19:33 | 只看该作者
丢包多数是信号强度不够,你看设置有问题没,简单办法可以试试降低速率,如果可以就是这样的问题
回复

使用道具 举报

12#
ID:55085 发表于 2017-8-1 22:52 | 只看该作者
不小心重复了下载,怎么又扣分哪!!!!!!!

评分

参与人数 1黑币 +80 收起 理由
admin + 80 补偿

查看全部评分

回复

使用道具 举报

13#
ID:55085 发表于 2017-8-1 22:53 | 只看该作者
我下载了再次,扣了我再次5分!!!!!!冤枉啊!!!!!!!!!
回复

使用道具 举报

14#
ID:238632 发表于 2017-10-11 16:52 | 只看该作者
请问下怎样实现两个边发送 边接收
回复

使用道具 举报

15#
ID:221153 发表于 2017-12-15 23:18 | 只看该作者
用的库里带的事例,一直这样
Beginning ...
Finished sending
Timeout on response from server!
Finished sending
Timeout on response from server!
Finished sending
Timeout on response from server!
Finished sending
Timeout on response from server!
Finished sending
Timeout on response from server!
Finished sending
回复

使用道具 举报

16#
ID:221153 发表于 2017-12-15 23:28 | 只看该作者
I'm Receiver...
没有然后了
回复

使用道具 举报

17#
ID:380141 发表于 2018-8-27 10:10 | 只看该作者
我也点“后退”结果造成重复下载被重复扣了5分!!!
回复

使用道具 举报

18#
ID:442524 发表于 2018-12-9 10:35 | 只看该作者
学习一下           
回复

使用道具 举报

19#
ID:442524 发表于 2018-12-27 09:03 | 只看该作者
下载一个看看
回复

使用道具 举报

20#
ID:329997 发表于 2019-1-19 20:05 | 只看该作者
楼主您好!我今天也碰巧搞这个模块,不过好像存在些问题,接线没有问题。C:\Users\Administrator\DesktopC:\Users\Administrator\Desktop
回复

使用道具 举报

21#
ID:594522 发表于 2019-8-3 11:11 | 只看该作者
gdgzwqz 发表于 2017-8-1 22:53
我下载了再次,扣了我再次5分!!!!!!冤枉啊!!!!!!!!!

下载好的能不能分享一下
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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