首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

如何利用多个NRF24L01模块搭建一个Arduino无线网络

今天,我们将介绍如何搭建由多个NR24L01收发器模块组成的Arduino无线网络。在这次项目中,我们搭建了一个由5个节点组成的网络,每个节点都可以与网络中的任何节点通信,同时它们既可以作为发送器,也可以作为接收器。实际上,本项目采用这种方式设置是解释如何搭建更大网络,或者准确地说,我们可以在单个RF信道上共有3125个模块相互通信。现在就让我们来看看它是如何工作的。

我们将使用NRF24L01模块和RF24库在两个Arduino开发板之间进行无线通信。除了这个库之外,我们还使用了RF24Network库,它可以轻松地构建一个无线网络,其中许多Arduino开发板相互通信。以下是网络拓扑的工作原理。

单个NRF24L01模块可以同时主动监听多达6个其他模块。

RF24网络库利用此能力生成以树形拓扑排列的网络,其中一个节点是基础,所有其他节点是该节点或另一个节点的子节点。每个节点最多可以有5个子节点,这可以达到5级深度,这意味着我们可以创建总共3125个节点的网络。每个节点必须使用15位地址来定义,该地址精确地描述树中节点的位置。

我们实际上可以用八进制格式定义节点的地址。因此,master或base的地址为00,base子地址为01~05,01节点子地址为011~051,依此类推。

注意,如果节点011想要与节点02通信,则通信将必须通过节点01和基节点00,因此这两个节点必须始终是活动的,以便通信成功。

使用RF24Network库的Arduino无线伺服电机控制

在我们开始之前,为了更好地理解库的工作方式,让我们举两个Arduinos相互通信的简单例子。这是此例的电路图。

我们要用到的相关组件为:

NRF24L01

伺服电机

电位器

Arduino Nano

我们在使用第一个Arduino开发板上的电位计来控制第二个Arduino上的的伺服电机。现在来看看源代码。

以下是电位器端的代码:

/*

Arduino Wireless Network - Multiple NRF24L01 Tutorial

== Example 01 - Servo Control / Node 00 - Potentiometer ==

by Dejan, www.HowToMechatronics.com

Libraries:

nRF24/RF24, https://github.com/nRF24/RF24

nRF24/RF24Network, https://github.com/nRF24/RF24Network

*/

#include

#include

#include

RF24 radio(10, 9); // nRF24L01 (CE,CSN)

RF24Network network(radio); // Include the radio in the network

const uint16_t this_node = 00; // Address of this node in Octal format ( 04,031, etc)

const uint16_t node01 = 01;

void setup() {

SPI.begin();

radio.begin();

network.begin(90, this_node); //(channel, node address)

}

void loop() {

network.update();

unsigned long potValue = analogRead(A0); // Read the potentiometer value

unsigned long angleValue = map(potValue, 0, 1023, 0, 180); // Convert the value to 0-180

RF24NetworkHeader header(node01); // (Address where the data is going)

bool ok = network.write(header, &angleValue, sizeof(angleValue)); // Send the data

}

首先,我们需要包括RF24和RF24Network库以及SPI库。然后我们需要创建RF24对象,并将其包含在RF24Network对象中。这里我们需要以八进制格式定义节点的地址,也就是,为此节点定义00,为伺服侧的另一个节点定义01。

在setup()函数中,我们需要通过设置此节点的通道和地址来初始化网络。

在loop()函数中,我们需要经常调用update()函数,通过该函数发生网络中的所有操作。然后我们读取电位计的值并将其转换为0到180的值,这适用于伺服控制。然后我们创建一个网络数据头,我们在其中分配数据所在节点的地址。最后,使用write()函数将数据发送到另一个节点。这里第一个参数包含地址信息,第二个参数包含将被发送的数据,第三个参数是数据的大小。

以下是伺服电机端的代码:

/*

Arduino Wireless Network - Multiple NRF24L01 Tutorial

== Example 01 - Servo Control / Node 01 - Servo motor ==

*/

#include

#include

#include

#include

RF24 radio(10, 9); // nRF24L01 (CE,CSN)

RF24Network network(radio); // Include the radio in the network

const uint16_t this_node = 01; // Address of our node in Octal format ( 04,031, etc)

Servo myservo; // create servo object to control a servo

void setup() {

SPI.begin();

radio.begin();

network.begin(90, this_node); //(channel, node address)

myservo.attach(3); // (servo pin)

}

void loop() {

network.update();

while ( network.available() ) { // Is there any incoming data?

RF24NetworkHeader header;

unsigned long incomingData;

network.read(header, &incomingData, sizeof(incomingData)); // Read the incoming data

myservo.write(incomingData); // tell servo to go to a particular angle

}

}

在另一侧伺服电机上,我们需要以与前面所述相同的方式定义库和对象。这里八进制格式的节点地址为01。定义伺服电机地址后,在loop()函数中,使用while()循环和available()函数,我们不断检查是否有数据输入。如果为true,我们将创建一个网络数据头,通过该数据头接收数据,以及创建一个存储数据的变量。然后使用read()函数读取数据,并将其存储到incomingData变量中。最后,我们使用这些数据根据另一个节点的电位器移动伺服电机。

使用多个NRF24L01模块的Arduino无线网络

在理解了以上操作之后,我们可以继续我们的工作了,搭建一个由5个Arduino开发板相互通信的无线网络。以下是大致框图。

因此,从基本节点开始,我们将使用电位器控制节点01处的伺服电机,使用第二个电位器,我们将控制节点022处的LED,使用按钮我们将控制节点012处的LED,基本节点的LED将使用节点02处的电位器进行控制。同样使用节点012处的红外传感器,我们将控制节点01处的LED。因此我们可以注意到这例子解释了如何同时发送和接收数据, 以及如何与来自不同分支的节点通信。我们现在来看看Arduino代码。

基本节点00的代码

/*

Arduino Wireless Network - Multiple NRF24L01 Tutorial

== Base/ Master Node 00==

by Dejan, www.HowToMechatronics.com

Libraries:

nRF24/RF24, https://github.com/nRF24/RF24

nRF24/RF24Network, https://github.com/nRF24/RF24Network

*/

#include

#include

#include

#define button 2

#define led 3

RF24 radio(10, 9); // nRF24L01 (CE,CSN)

RF24Network network(radio); // Include the radio in the network

const uint16_t this_node = 00; // Address of this node in Octal format ( 04,031, etc)

const uint16_t node01 = 01; // Address of the other node in Octal format

const uint16_t node012 = 012;

const uint16_t node022 = 022;

void setup() {

SPI.begin();

radio.begin();

network.begin(90, this_node); //(channel, node address)

radio.setDataRate(RF24_2MBPS);

pinMode(button, INPUT_PULLUP);

pinMode(led, OUTPUT);

}

void loop() {

network.update();

//===== Receiving =====//

while ( network.available() ) { // Is there any incoming data?

RF24NetworkHeader header;

unsigned long incomingData;

network.read(header, &incomingData, sizeof(incomingData)); // Read the incoming data

analogWrite(led, incomingData); // PWM output to LED 01 (dimming)

}

//===== Sending =====//

// Servo control at Node 01

unsigned long potValue = analogRead(A0);

unsigned long angleValue = map(potValue, 0, 1023, 0, 180); // Suitable for servo control

RF24NetworkHeader header2(node01); // (Address where the data is going)

bool ok = network.write(header2, &angleValue, sizeof(angleValue)); // Send the data

// LED Control at Node 012

unsigned long buttonState = digitalRead(button);

RF24NetworkHeader header4(node012); // (Address where the data is going)

bool ok3 = network.write(header4, &buttonState, sizeof(buttonState)); // Send the data

// LEDs control at Node 022

unsigned long pot2Value = analogRead(A1);

RF24NetworkHeader header3(node022); // (Address where the data is going)

bool ok2 = network.write(header3, &pot2Value, sizeof(pot2Value)); // Send the data

}

因此,在基本节点或主节点,我们需要如前所述定义库和对象,并定义主节点将向其发送数据的所有其他节点。在loop()函数部分,我们首先不断检查是否有数据传入。如果有,我们读取数据,将其存储到incomingData变量中,然后使用它来控制LED亮度。这些数据实际上来自节点02的电位器。如果我们看看它的代码,我们可以注意到设置几乎是一样的。重要的是将正确的地址分配给我们想要发送数据的位置。本例中是主地址00。所以在读取电位器值并将其转换为0到255的合适PWM值后,我们将这些数据发送给主机。我们在这里可以注意到我使用millis()函数以10毫秒的间隔发送数据。

节点02的代码

/*

Arduino Wireless Network - Multiple NRF24L01 Tutorial

== Node 02 (Child of Master node 00) ==

*/

#include

#include

#include

RF24 radio(10, 9); // nRF24L01 (CE,CSN)

RF24Network network(radio); // Include the radio in the network

const uint16_t this_node = 02; // Address of our node in Octal format ( 04,031, etc)

const uint16_t master00 = 00; // Address of the other node in Octal format

const unsigned long interval = 10; //ms // How often to send data to the other unit

unsigned long last_sent; // When did we last send?

void setup() {

SPI.begin();

radio.begin();

network.begin(90, this_node); //(channel, node address)

radio.setDataRate(RF24_2MBPS);

}

void loop() {

network.update();

//===== Sending =====//

unsigned long now = millis();

if (now - last_sent >= interval) { // If it's time to send a data, send it!

last_sent = now;

unsigned long potValue = analogRead(A0);

unsigned long ledBrightness = map(potValue, 0, 1023, 0, 255);

RF24NetworkHeader header(master00); // (Address where the data is going)

bool ok = network.write(header, &ledBrightness, sizeof(ledBrightness)); // Send the data

}

}

接下来,我们从主机发送电位器数据到节点01,以控制伺服电机。

节点01的代码

/*

Arduino Wireless Network - Multiple NRF24L01 Tutorial

== Node 02 (Child of Master node 00) ==

*/

#include

#include

#include

#include

#define led 2

RF24 radio(10, 9); // nRF24L01 (CE,CSN)

RF24Network network(radio); // Include the radio in the network

const uint16_t this_node = 01; // Address of our node in Octal format ( 04,031, etc)

const uint16_t master00 = 00; // Address of the other node in Octal format

Servo myservo; // create servo object to control a servo

void setup() {

SPI.begin();

radio.begin();

network.begin(90, this_node); //(channel, node address)

radio.setDataRate(RF24_2MBPS);

myservo.attach(3); // (servo pin)

pinMode(led, OUTPUT);

}

void loop() {

network.update();

//===== Receiving =====//

while ( network.available() ) { // Is there any incoming data?

RF24NetworkHeader header;

unsigned long incomingData;

network.read(header, &incomingData, sizeof(incomingData)); // Read the incoming data

if (header.from_node == 0) { // If data comes from Node 02

myservo.write(incomingData); // tell servo to go to a particular angle

}

if (header.from_node == 10) { // If data comes from Node 012

digitalWrite(led, !incomingData); // Turn on or off the LED 02

}

}

}

节点01实际上是从两个不同的节点接收数据,一个用于伺服控制,另一个用于来自节点012的红外传感器的LED控制。

节点012的代码

/*

Arduino Wireless Network - Multiple NRF24L01 Tutorial

== Node 012 (child of Node 02)==

*/

#include

#include

#include

#define led 2

#define IR 3

RF24 radio(10, 9); // nRF24L01 (CE,CSN)

RF24Network network(radio); // Include the radio in the network

const uint16_t this_node = 012; // Address of our node in Octal format ( 04,031, etc)

const uint16_t node01 = 01; // Address of the other node in Octal format

void setup() {

SPI.begin();

radio.begin();

network.begin(90, this_node); //(channel, node address)

radio.setDataRate(RF24_2MBPS);

pinMode(led, OUTPUT);

pinMode(IR, INPUT);

}

void loop() {

network.update();

//===== Receiving =====//

while ( network.available() ) { // Is there any incoming data?

RF24NetworkHeader header;

unsigned long buttonState;

network.read(header, &buttonState, sizeof(buttonState)); // Read the incoming data

digitalWrite(led, !buttonState); // Turn on or off the LED

}

//===== Sending =====//

unsigned long irV = digitalRead(IR); // Read IR sensor

RF24NetworkHeader header8(node01);

bool ok = network.write(header8, &irV, sizeof(irV)); // Send the data

}

在本段代码中,我们使用header.from_node属性来获取数据来自哪个节点的信息。如果输入数据来自主设备,我们用它来控制伺服,如果输入数据来自节点012,我们用它来控制LED。

在节点012,我们有发送和接收。红外传感器控制节点01处的前面提到的LED,这里的LED是来自主机上的按钮的控制。

节点022的代码

/*

Arduino Wireless Network - Multiple NRF24L01 Tutorial

== Node 022 (child of Node 02)==

*/

#include

#include

#include

#define led1 2

#define led2 3

#define led3 4

#define led4 5

RF24 radio(10, 9); // nRF24L01 (CE,CSN)

RF24Network network(radio); // Include the radio in the network

const uint16_t this_node = 022; // Address of our node in Octal format ( 04,031, etc)

const uint16_t master00 = 00; // Address of the other node in Octal format

void setup() {

SPI.begin();

radio.begin();

network.begin(90, this_node); //(channel, node address)

radio.setDataRate(RF24_2MBPS);

pinMode(led1, OUTPUT);

pinMode(led2, OUTPUT);

pinMode(led3, OUTPUT);

pinMode(led4, OUTPUT);

}

void loop() {

network.update();

//===== Receiving =====//

while ( network.available() ) { // Is there any incoming data?

RF24NetworkHeader header;

unsigned long potValue;

network.read(header, &potValue, sizeof(potValue)); // Read the incoming data

// Turn on the LEDs as depending on the incoming value from the potentiometer

if (potValue > 240) {

digitalWrite(led1, HIGH);

} else {

digitalWrite(led1, LOW);

}

if (potValue > 480) {

digitalWrite(led2, HIGH);

} else {

digitalWrite(led2, LOW);

}

if (potValue > 720) {

digitalWrite(led3, HIGH);

} else {

digitalWrite(led3, LOW);

}

if (potValue > 960) {

digitalWrite(led4, HIGH);

} else {

digitalWrite(led4, LOW);

}

}

}

最后,使用来自主机上的另一个电位器的数据来控制节点022处的LED。

因此,如果一切正常连接,并且所有节点始终处于活动状态,通过精确寻址节点就可以完成我们的工作,所有繁重的工作都由强大的RF24Network库去执行。

关注风火轮,技术之路常相伴,我们下期见!

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20200228A04CUC00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券