极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 213171|回复: 80

Arduino学习笔记A16 - Arduino连接nRF24L01无线收发模块

  [复制链接]
发表于 2015-3-8 01:02:33 | 显示全部楼层 |阅读模式
本帖最后由 Ansifa 于 2015-6-29 15:21 编辑

Arduino连接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机:
[pre lang="arduino" line="1" file="Sender.ino"]/*
nRF24L01 Arduino发送端

Ansifa
2015/3/7

引脚接法:
nRF24L01   Arduino UNO
VCC        <->        3.3V
GND        <->        GND
CE        <->        D9
CSN        <->        D10
MOSI<->        D11
MISO<->        D12
SCK        <->        D13
IRQ        <->        不接
*/

#include <SPI.h>
#include <Mirf.h>
#include <nRF24L01.h>
#include <MirfHardwareSpiDriver.h>
void setup()
{
    Serial.begin(9600);

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

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

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

    //由于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]。

    //设置向"serv1"发送数据
    Mirf.setTADDR((byte *)"Rec01");
    Mirf.send(data);
    //while死循环等待发送完毕,才能进行下一步操作。
    while(Mirf.isSending()) {}
    delay(20);
}
[/code]
Receiver机:
[pre lang="arduino" line="1" file="Receiver.ino"]/*
nRF24L01 Arduino Receiver接收端

Ansifa
2015/3/7

引脚接法:
nRF24L01   Arduino UNO
VCC <-> 3.3V
GND <-> GND
CE  <-> D9
CSN <-> D10
MOSI<-> D11
MISO<-> D12
SCK <-> D13
IRQ <-> 不接
*/

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

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

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

    //---------初始化部分,不可随时修改---------
    Mirf.cePin = 9;     //设置CE引脚为D9
    Mirf.csnPin = 10;   //设置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]);

        //与上一次结果比较,避免相同结果刷屏,降低串口流量
        if(adata != oldadata)
        {
            oldadata = adata; //本次结果作为历史结果。
            //Serial.print输出数据
            Serial.print("A0=");
            Serial.println(adata);
            //也可以输出双字节数据
            //Serial.write(data[1]);
            //Serial.write(data[0]);
        }

    }
}
[/code]

实验2:

将上述的数据绘图表。

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

原理图:
与实验1一样。
代码:
发射端代码与原来一样。
接收端新代码:
[pre lang="arduino" line="1" file="Sender.ino"]
/*
nRF24L01 Arduino Receiver接收端
图表输出版本

Ansifa
2015/3/7

引脚接法:
nRF24L01   Arduino UNO
VCC <-> 3.3V
GND <-> GND
CE  <-> D9
CSN <-> D10
MOSI<-> D11
MISO<-> D12
SCK <-> D13
IRQ <-> 不接
*/

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

//定义一个变量adata存储最终结果。
unsigned int adata = 0;

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

    //---------初始化部分,不可随时修改---------
    Mirf.cePin = 9;     //设置CE引脚为D9
    Mirf.csnPin = 10;   //设置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]);

        //输出双字节数据
        Serial.write(data[0]);
        Serial.write(data[1]);
    }
}
[/code]

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







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



本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
回复

使用道具 举报

 楼主| 发表于 2015-3-23 22:59:58 | 显示全部楼层
zhangdeyue1 发表于 2015-3-19 15:00
写的很好~!请问在设置好主从模式后两个模块还能双向通讯么?

可以的,其实没有NRF24L01主从模式并不是严格意义上的,只要接收方的Mirf.setRADDR和发送的Mirf.setTADDR一样就能发,每片nrf都可以分别设置自己的Mirf.setRADDR和Mirf.setTADDR。可以说是半双工
回复 支持 1 反对 1

使用道具 举报

发表于 2016-4-3 14:41:46 | 显示全部楼层
首先感谢大神的教程,有一个问题像请教一下,就是我根据教程,把两端的代码改成对舵机的控制了,so问题来了,控制一个舵机可以,但是我如果像让他控制两个或者更多的舵机,收发代码该如何改呢,或者说思路是什么。我试了让发送端发送Sen01、Sen02这样,没有效果。求指教!
回复 支持 1 反对 0

使用道具 举报

发表于 2015-3-8 15:46:39 | 显示全部楼层
几块钱的那种能穿一堵墙么
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-3-8 18:15:57 | 显示全部楼层
マイナス37度 发表于 2015-3-8 15:46
几块钱的那种能穿一堵墙么

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

使用道具 举报

发表于 2015-3-11 14:51:39 | 显示全部楼层
本帖最后由 マイナス37度 于 2015-3-11 14:56 编辑
Ansifa 发表于 2015-3-8 18:15
特意测试了一下可以,这个说是+7dB的,比wifi的+5dB高一点,感觉会比wifi好一些。


恩,谢谢,抽空试试
问个和主题无关的问题哈,io口用内上拉做输入,然后我接了根1米多的电线接开关上,这根线会不会拉低信号
我现在的情况是老是误触发开关
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-3-13 21:36:46 | 显示全部楼层
マイナス37度 发表于 2015-3-11 14:51
恩,谢谢,抽空试试
问个和主题无关的问题哈,io口用内上拉做输入,然后我接了根1米多的电线接开关 ...

内上拉电阻太大了!干扰信号稍微大一点都会有影响。再外接一个10k甚至1k的上拉电阻就行了
回复 支持 反对

使用道具 举报

发表于 2015-3-14 19:25:31 | 显示全部楼层
Ansifa 发表于 2015-3-13 21:36
内上拉电阻太大了!干扰信号稍微大一点都会有影响。再外接一个10k甚至1k的上拉电阻就行了

恩谢谢,我试试
回复 支持 反对

使用道具 举报

发表于 2015-3-16 12:19:16 | 显示全部楼层
好人那,写的那么清晰完整。该模块用处很大
回复 支持 反对

使用道具 举报

发表于 2015-3-19 15:00:00 | 显示全部楼层
写的很好~!请问在设置好主从模式后两个模块还能双向通讯么?
回复 支持 反对

使用道具 举报

发表于 2015-3-26 11:32:56 | 显示全部楼层
Ansifa 发表于 2015-3-23 22:59
可以的,其实没有NRF24L01主从模式并不是严格意义上的,只要接收方的Mirf.setRADDR和发送的Mirf.setTADDR ...

谢谢!
最近在做双向通讯的时候出现一个问题
就是开始是打算主机发送指令,从机接到后返回一个固定指令表示相应,正常通讯的时候都挺好,可以如果我复位从机或从机断电在通电,就会出现程序卡死,主机好像被卡在了等待从机返回指令的那段,就是if(Mirf.dataReady()),而因为从机没有接受到新的主机指令,也不会进行动作,解决办法只有重启主机。请问有解决办法吗?
回复 支持 反对

使用道具 举报

发表于 2015-5-19 14:37:57 | 显示全部楼层
这个讲解的还算比较清楚, 待有时间试验一下。多谢楼主!
回复 支持 反对

使用道具 举报

发表于 2015-5-22 13:59:44 | 显示全部楼层
很重要哦~~~
学习了。~
回复 支持 反对

使用道具 举报

发表于 2015-5-30 21:26:44 | 显示全部楼层
原理图是用什么软件画的?我用的frtzing,找到的nrf24l01跟你画的不一样。
回复 支持 反对

使用道具 举报

发表于 2015-5-31 21:47:18 | 显示全部楼层
讲得很详细,谢谢分享,收藏了~
回复 支持 反对

使用道具 举报

发表于 2015-6-23 21:21:17 | 显示全部楼层
楼主V5 实验成功。
就是有个问题等待解释。
发送的代码是发送一个数字后延迟0.5s再自增,发送下一个。

当我重启接收机时,会收到一些很大的数字,然后就正常了。下面是结果。


I'm receiving 1
I'm receiving 2
I'm receiving 3
I'm receiving 4
I'm receiving 5
I'm receiving 6
I'm receiving 7
I'm receiving 8
I'm receiving 9
I'm receiving 10
I'm receiver...
I'm receiving 2827
I'm receiving 14
I'm receiving 15
I'm receiving 16
I'm receiving 17
I'm receiver...
I'm receiving 4883
I'm receiving 21
I'm receiving 22
I'm receiving 23
I'm receiving 24
I'm receiver...
I'm receiving 6425
I'm receiving 29
I'm receiving 30
I'm receiving 31
I'm receiving 32
I'm receiver...
I'm receiving 8481
I'm receiving 36
I'm receiving 37
I'm receiving 38
I'm receiving 39
I'm receiving 40
I'm receiving&#65533;I'm receiver...
I'm receiving 10794
I'm receiving 45
I'm receiving 46
I'm receiver...
I'm receiving 12079
I'm receiving 51
I'm receiving 52
I'm receiver...
I'm receiving 13621
I'm receiving 56
I'm receiving 57
I'm receivin&#65533;I'm receiver...
I'm receiving 15163
I'm receiving 62
I'm receiving 63
I'm receiving 64
I'm receiver...
I'm receiving 16705
I'm receiving 68
I'm receiving 69
I'm receiving 70
I'm receiver...
I'm receiving 18247
I'm receiving 74
I'm receiving 75
I'm receiving 76
I'm receiver...
I'm receiving 19789
I'm receiving 81
I'm receiving 82
I'm receiving 83
回复 支持 反对

使用道具 举报

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

本版积分规则 需要先绑定手机号

Archiver|联系我们|极客工坊

GMT+8, 2024-4-23 14:58 , Processed in 0.048675 second(s), 29 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2021, Tencent Cloud.

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