找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 22688|回复: 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);
    }
}

回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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