Рассмотрим использование двух Arduino, соединенных через беспроводную связь, для сбора и отображения данных.
О проекте
Иногда непрактично использовать один Arduino для чтения с датчика и показания результата здесь же. Например, устройство планируется разместить в недоступном или опасном месте, или там, где прокладка кабеля нецелесообразна. В таких случаях, мы должны передавать полученные данные на второй удаленный Arduino, например, в соседней комнате управления или диспетчерской.
В данном руководстве мы будем использовать барометрический датчик давления и температуры BMP280, подключенный к одному Arduino, а затем использовать 24 ГГц радиосвязь, предоставляемую двумя цифровыми приемопередатчиками NRF24L01 (трансивер), для передачи этих данных на второй Arduino, который расположен на некотором расстоянии.
Это расстояние должно быть менее 50 м в зависимости от наличия стен между ними. Трансивер означает комбинированный передатчик и приемник в одном устройстве.
В проекте один Arduino будет оснащен BMP280, подключенный как I2C, а также NRF24L01 соединенный через SPI. Он будет передавать радиосигнал на второй Arduino, который также оснащен другим NRF24L01 работает в качестве приемника, который будет отображать входящие данные на последовательном мониторе.
Вы можете использовать ЖК-дисплей. NRF может работать в обоих направлениях, то есть приемник может ответить с подтверждением, но это добавит больше сложности в реализации устройства, чем нам нужно.
Следует иметь в виду, что это настоящая радиосвязь SHF (Super High Frequency - Супер высокая частота), и чем она выше, тем лучше, как и во всех подобных радиосвязях. К тому же, она имеет тенденцию "вести себя" как разряженный световой луч, поэтому чем меньше препятствий, т.е. стен, тем лучше.
Работа BMP280
BMP280 поставляется в различных типах в зависимости от того, где вы его покупаете. Имейте в виду, так как некоторые из них являются устройствами с 5 В, а некоторые - с 3.3 В. Кроме того, некоторые - SPI или I2C, а некоторые - нет. В этой статье будет использована версия I2C 3.3 В. Эта, хотя и 3 В, соответствует 5 В на выводах данных. Мы используем I2C версию, так как NRF24L01 использует шину SPI.

Диапазон давления составляет от 300 до 1100 гПа, что примерно на 500 м ниже уровня моря до 9 км в высоту и между 950 и 1050 гПа, а точность высоты +/-1 м, что довольно неплохо. Диапазон температур составляет от 40 до 85 °C с точностью +/-1 °C и 0,5 при 25.
На некоторых устройствах адрес I2C установлен на 0x77, а на других - на 0x76. На официальном сайте Arduino есть полезный сканер адресов по этой ссылке. Если он не найдет адрес, проверьте проводку.
Соединяем BMP280 и Ардуино
Соединяем наш датчик с платой согласно следующей таблице:
BMP280 | Uno |
VCC | 3.3V |
GND | GND |
SCL | A5 |
SDA | A4 |
CSB | Не используется |
SDD | Не используется |
Работа NRF24L01
NRF24L01 - это цифровой приемопередатчик с SPI-подключением, способный передавать и принимать данные в диапазоне 24 ГГц ISM (ISM - промышленный, научный и медицинский; Industrial, Scientific, Medical).

Это тот же самый диапазон, который используется Bluetooth и WiFi, и не требует лицензирования, так как он маломощный. Это устройство с питанием от 3 В, но линии данных соответствуют 5 В, поэтому преобразование не требуется. Вы можете управлять его VCC выводом прямо с вывода 3,3 В Arduino Uno.
Интерфейс SPI работает со скоростью до 10 Мбит/с. Каждый модуль работает на одной и той же частоте или канале в диапазоне от 2,400 до 2,525 ГГц. Внутри каждого канала имеется 6 "линий", позволяющих установить до 6 связей в каждом канале. Это означает, что один мастер может прослушивать 6 ведомых устройств, все на одном канале, но на разных "линиях".
Соединяем NRF24L01 и Ардуино
Распиновка модуля NRF24L01:

Соединяем модуль с Ардуино согласно таблице:
NRF24L01 | Uno |
VCC | 3.3V |
GND | GND |
MOSI | 11 |
MISO | 12 |
SCK | 13 |
CE | 9 |
CSN | 8 |
IRQ | Не используется |
Я обнаружил, что двухрядный разъем не очень подходит для использования с типичной макетной платой, поэтому я сделал свою собственную несущую плату, чтобы иметь один ряд контактов, чтобы легче подключить к макетной плате:

Схема соединения
Соединяем все Ардуино согласно схеме ниже:
Установка библиотек
Требуется несколько библиотек для этого проекта:
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <Adafruit_BMP280.h>
Замечания по программе
Функция sizeof()
определяет длину переменной в байтах, т.е. int имеет длину 2 байта, float - 4 байта и т.д.
На принимающей стороне у вас должны быть совпадающие типы данных, потому что на самом деле NRF24 посылает серию байт длиной sizeof()
.
Если попытаться вставить 2 байта в 1 байт в приемной стороне, то получится мусор.
При использовании массива можно отправить несколько фрагментов данных в одном сообщении при условии, что 32-байтовый предел не превышен. Вы можете отправлять данные любого типа, т.е. строки типа char
, целые числа (integer) или с плавающей точкой (float). Просто убедитесь, что приемник ожидает перехват одного и того же типа данных. В нашем примере, так как мы хотим использовать 3 десятичных значения, мы используем массив из 3 элементов с плавающей точкой. Максимальная длина одного сообщения - 32 байта. Таким образом, 3 элементам с плавающей запятой нужны 12 байт, что оставляет много свободного пространства.
Все контакты, кроме CE и CSN, должны быть подключены в соответствии с инструкциями. Однако, эти два контакта могут быть любыми удобными и объявлены как:
RF24 nrf(9, 8); // CE, CSN
Ардуино код для Мастера
Код для нашего ведущего Ардуино (т.е. мастера):
//nrf2401 transmitter:
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <Adafruit_BMP280.h>
RF24 nrf(9, 8); // CE, CSN
Adafruit_BMP280 bmp;
const byte linkAddress[6] = "link1";
float QNH = 1022.67; // Change the "1022.67" to your current sea level barrometric pressure (https://www.wunderground.com)
const int BMP_address = 0x76;
float pressure;
float temperature;
float altimeter;
float data[3];
char charVal[17];
////////////////////////////////////////////////////
void setup()
{
Serial.begin(9600);
Serial.println("BMP280/NRF24L01 link");
nrf.begin();
bmp.begin(BMP_address);
nrf.openWritingPipe(linkAddress); //set the address
//nrf.setPALevel(RF24_PA_LOW); //keep tx level low to stop psu noise, can remove this but then put in decoupling caps
// Options are: RF24_PA_MIN=-18dBm, RF24_PA_LOW=-12dBm, RF24_PA_HIGH=0dBm.
nrf.setPALevel(RF24_PA_HIGH);
nrf.stopListening(); //act as a transmitter
}
///////////////////////////////////////////////////
void loop()
{
pressure = bmp.readPressure()/100; //and conv Pa to hPa
temperature = bmp.readTemperature();
altimeter = bmp.readAltitude (QNH); //QNH is local sea lev pressure
data[0] = pressure;
data[1] = temperature;
data[2] = altimeter;
//----- display on local monitor: ------------
Serial.print(data[0]); Serial.print("hPa ");
Serial.print(data[1]);
Serial.write(0xC2); //send degree symbol
Serial.write(0xB0); //send degree symbol
Serial.print("C ");
Serial.print(data[2]); Serial.println("m");
//---------------------------------------------
nrf.write(data, sizeof(data)); //spit out the data array
delay(300);
}
/////////////////////////////////////////////////
Разбираем код Мастера
float QNH = 1022.67;
QNH - авиационный термин. Это один из факторов коррекции, который при применении к альтиметру позволит ему точно считывать высоту над уровнем моря в текущем местоположении.
Варьируется ото дня ко дню и даже от часа к часу. Пилоты должны устанавливать этот коэффициент каждый раз при полете для калибровки своих альтиметров. Если пилоты не могут этого добиться, например, во время полета над океаном, они все используют 1013, то все их высотомеры считывают используя один и тот же эталон. Это позволяет им летать на разных высотах, чтобы избежать столкновения. Его можно получить на погодных сайтах.
Например, вот для Кейптауна - см. ссылку.
Вам не обязательно это делать. Но без скорректированного значения высоты в вашем местоположении, оно будет неверным (так как вы должны учитывать местные изменения атмосферного давления) и может даже отображаться отрицательным. Фактическое давление и температура все равно будут верны.
nrf.openWritingPipe(linkAddress);
Запускает один из 125 каналов. Передатчик и приемник должны иметь один и тот же адрес.
nrf.setPALevel(RF24_PA_HIGH);
Устанавливает уровень мощности передатчика. Высокий уровень может вызвать проблемы с нестабильностью, если питание 3,3 В осуществляется по длинным проводам. Лучше всего вставить через него конденсатор 100 мкФ, но для более долгого срока службы батареи лучше использовать низкочастотный конденсатор.
nrf.stopListening();
Говорит модулю вести себя как передатчик и наоборот:
nrf.startListening();
говорит ему вести себя как приемник.
Передаваемые данные выводятся локально на последовательный монитор (если он подключен), а также передаются на приемник.
Строки:
Serial.write(0xC2);
Serial.write(0xB0);
посылают символ степени на последовательный монитор (для некоторых ПК это может отличаться).
Если вы используете ЖК-дисплей, вы можете сделать это с помощью:
lcd.print((char) 223); // добавить знак степени
Наконец, nrf.write(data, sizeof(data));
передает содержимое массива данных. Обратите внимание, что ему необходимо знать, сколько байт отправить и sizeof()
получит это.
Код Ардуино для ведомого
Код для нашего ведомого Ардуино (slave):
//nrf2401 receiver
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
RF24 nrf(9, 8); // CE, CSN
const byte linkAddress[6] = "link1"; //address through which two modules communicate.
const byte greenLED = 10;
float data[3];
/////////////////////////////////////////////////////////////////////
void setup()
{
Serial.begin(9600);
Serial.println("Starting");
pinMode(greenLED, OUTPUT);
nrf.begin();
nrf.openReadingPipe(0, linkAddress); //set the address
nrf.startListening(); //Set nrf as receiver
}
///////////////////////////////////////////////////
void loop()
{
digitalWrite(greenLED, HIGH);
delay(50);
digitalWrite(greenLED, LOW);
delay(50);
if (nrf.available()) //Read the data if available in buffer
{
nrf.read(&data, sizeof(data));
Serial.print(data[0]); Serial.print("hPa ");
Serial.print(data[1]);
Serial.write(0xC2); //send degree symbol
Serial.write(0xB0); //send degree symbol
Serial.print("C ");
Serial.print(data[2]); Serial.println("m");
}
}
//////////////////////////////////////////////
Разбираем код ведомого Ардуино
Большая часть кода довольно похожа на мастер, но:
nrf.openReadingPipe(0, linkAddress);
запускает одну из 6 линий.
Передатчик и приемник должны иметь один и тот же адрес. Обратите внимание, что здесь есть дополнительный параметр, который устанавливает, какая из линий считывания используется (в данном случае 0).
Последовательный монитор NRF24L01
Если все правильно подключено, в последовательном мониторе на приемном Arduino должно появиться следующее:
