Istnieje kilka opcji dla wdrożenia któregokolwiek z dwóch wyżej wymienionych trybów komunikacji, a wybór konkretnej opcji zależy zwykle od specyfikacji projektu, zwłaszcza odległości między urządzeniami i kosztów. W przypadku komunikacji o niewielkim zasięgu i niskim budżecie pomiędzy dwoma mikrokontrolerami, jednym z najbardziej preferowanych mediów jest komunikacja za pomocą fal radiowych (RF) z wykorzystaniem modułów nadajnika i odbiornika 433MHz RF. W tym projekcie przyjrzymy się, jak wykorzystać te moduły do nawiązania komunikacji pomiędzy dwoma płytkami Arduino.
Moduły nadajnika i odbiornika 433 MHz
Moduły te są bardzo popularne wśród konstruktorów ze względu na ich niski koszt i łatwość użycia. Są one wykorzystywane we wszystkich formach komunikacji simplexowej krótkiego zasięgu między dwoma mikrokontrolerami, gdy jeden z mikrokontrolerów służy jako nadajnik, a drugi służy jako odbiornik.Są to moduły ASK (Amplitude Shift Keying) lub OOK (Of Hook Keying) , co oznacza, że zazwyczaj nie czerpią żadnej mocy podczas transmisji logicznego "zero" i jako takie zużywają mało energii. Ten niski pobór mocy czyni je bardzo użytecznymi w implementacjach opartych na bateriach.
Niektóre specyfikacje modułów nadajnika i odbiornika są wymienione poniżej.
Specyfikacja nadajnika
- Napięcie robocze: 3…12 V
- Prąd roboczy: maks. mniej niż 40 mA, min. 9 mA
- Tryb rezonansu: (SAW)
- Tryb modulacji: ASK
- Częstotliwość robocza: 433,92 MHz
- Moc nadawania: 25 mW
- Błąd częstotliwości: +150 kHz (max)
- Szybkość: mniej niż 10 Kbps
- Zasięg transmisji: 90 m (w otwartej przestrzeni)
Specyfikacja odbiornika
- Napięcie robocze: 5 VDC +0,5 V
- Prąd roboczy: ≤5,5 mA max
- Tryb modulacji: OOK/ASK
- Częstotliwość robocza: 433,92 MHz
- Szerokość pasma: 2 MHz
- Czułość: przekracza -100 dBm (50 Ω)
Aby zademonstrować łatwość, z jaką można dodać funkcje bezprzewodowe do projektów wykorzystujących te moduły, zbudujemy stację pogodową z możliwością zdalnego wyświetlania danych. Stacja pogodowa będzie składała się głównie z czujnika temperatury i wilgotności oraz modułu nadajnika 433 RF. Będzie mierzyć temperaturę i wilgotność otoczenia i wysyłać je przez nadajnik RF do jednostki wyświetlającej (odbierane przez moduł odbiornika RF) na kolorowym wyświetlaczu ST7735 1.8″ TFT LCD.
Schematy
Istnieją dwa schematy dla tego projektu. Pierwszy z nich jest dla nadajnika, który pobiera temperaturę i wilgotność z otoczenia i wysyła je do drugiej części projektu, odbiornika, który wyświetla dane na wyświetlaczu.
Schemat nadajnika
Układ nadajnika składa się z Arduino, czujnika temperatury i wilgotności DHT22 oraz modułu nadajnika RF 433 MHz. Można dodać akumulator, aby zapewnić zasilanie Arduino, gdy jest odłączone od komputera. Podłącz elementy tak, jak pokazano poniżej.
Dla przejrzystości, połączenia pinów pomiędzy Arduino i innymi komponentami są pokazane poniżej.
Schemat układu odbiornika
Odbiornik składa się z modułu odbiornika RF 433 MHz, kolorowego wyświetlacza TFT ST7735 1,8″ oraz Arduino Uno. Podłącz elementy jak pokazano poniżej.
Ze względu na różnice w układzie pinów wyświetlacza w zależności od producenta i dla przejrzystości, połączenia pinów pomiędzy Arduino i innymi komponentami tworzącymi odbiornik są podane poniżej:
Po wykonaniu wszystkich połączeń, możemy przystąpić do pisania kodu dla tego projektu.
Kod
Tak jak musieliśmy zbudować dwa urządzenia, tak samo napiszemy dwa różne kody do tego projektu. Jeden z nich będzie służył do sterowania nadajnikiem, a drugi do sterowania odbiornikiem.
Aby łatwo napisać kod do tego projektu, użyjemy bibliotek, które ułatwiają sterowanie każdą częścią projektu. Dla modułów RF użyjemy biblioteki virtual wire do wysyłania i odbierania danych, natomiast do wyświetlania odebranych danych użyjemy bibliotek Adafruit GFX i Adafruit ST7735, aby łatwo aktualizować wyświetlacz LCD ST7735. Aby łatwo uzyskać dane o temperaturze i wilgotności z czujnika DHT22. Użyjemy biblioteki Adafruit DHT sensor.
Algorytm działania kodu jest prosty. Dla nadajnika, uzyskujemy wartości temperatury i wilgotności z DHT22 i wysyłamy przez nadajnik RF do odbiornika. Dla odbiornika, uzyskanie wartości temperatury i wilgotności wysłanej przez nadajnik za pomocą modułu RF Receiver i wyświetlenie jej na wyświetlaczu LCD.
Pokrótce wyjaśnię kod dla dwóch połówek projektu, zaczynając od kodu nadajnika.
Kod nadajnika
Zaczynamy od dołączenia bibliotek, które będą używane w kodzie.
//Written by Nick Koumaris
//info@educ8s.tv
#include <VirtualWire.h>
#include "DHT.h"
Po tym deklarujemy pin Arduino, do którego podłączony jest nasz DHT, a także określamy typ używanego DHT.
#define DHTPIN 4
#define DHTTYPE DHT22
Następnie wskazujemy pin Arduino, który będzie użyty jako pin do transmisji danych (który jest połączony z pinem danych modułu nadajnika RF) oraz tworzymy pakiet struct, który będzie użyty do wysyłania danych.
const int led_pin = 13;
const int transmit_pin = 12;
struct package
{
float temperature ;
float humidity ;
};
Następnie definiujemy typ dla pakietu i tworzymy instancję klasy DHT, aby zaadresować czujnik DHT.
typedef struct package Package;
Package data;
DHT dht(DHTPIN, DHTTYPE);
Po wykonaniu tych czynności przechodzimy do funkcji void setup(), w której ustawiamy pin TX oraz inne parametry inicjalizujące moduł RF.
void setup()
{
// Initialise the IO and ISR
vw_set_tx_pin(transmit_pin);
vw_set_ptt_inverted(true); // Required for DR3100
vw_setup(500); // Bits per sec
pinMode(led_pin, OUTPUT);
}
Następna jest funkcja void loop(), w której za pomocą funkcji read sensor otrzymujemy temperaturę i wilgotność. Po uzyskaniu danych, są one wysyłane za pomocą funkcji vw_send(). Czas opóźnienia 2000ms jest zaimplementowany, aby stworzyć odstęp pomiędzy danymi i zapewnić, że jedna z nich zostanie wysłana przed drugą.
void loop()
{
digitalWrite(led_pin, HIGH); // Flash a light to show transmitting
readSensor();
vw_send((uint8_t *)&data, sizeof(data));
vw_wait_tx(); // Wait until the whole message is gone
digitalWrite(led_pin, LOW);
delay(2000);
}
Kompletny kod jest napisany poniżej i dołączony do pliku zip w sekcji download.
#include <VirtualWire.h>
#include "DHT.h"
#define DHTPIN 4
#define DHTTYPE DHT22
const int led_pin = 13;
const int transmit_pin = 12;
struct package
{
float temperature ;
float humidity ;
};
typedef struct package Package;
Package data;
DHT dht(DHTPIN, DHTTYPE);
void setup()
{
// Initialise the IO and ISR
vw_set_tx_pin(transmit_pin);
vw_set_ptt_inverted(true); // Required for DR3100
vw_setup(500); // Bits per sec
pinMode(led_pin, OUTPUT);
}
void loop()
{
digitalWrite(led_pin, HIGH); // Flash a light to show transmitting
readSensor();
vw_send((uint8_t *)&data, sizeof(data));
vw_wait_tx(); // Wait until the whole message is gone
digitalWrite(led_pin, LOW);
delay(2000);
}
void readSensor()
{
dht.begin();
delay(1000);
data.humidity = dht.readHumidity();
data.temperature = dht.readTemperature();
}
Kod odbiornika
Jak zwykle zaczynamy od dołączenia bibliotek, które będą używane.
//Written by Nick Koumaris
//info@educ8s.tv
#include <VirtualWire.h>
#include <Adafruit_ST7735.h>
#include <Adafruit_GFX.h>
Następnie deklarujemy piny Arduino, do których podłączone są piny wyświetlacza LCD.
#define TFT_CS 10
#define TFT_RST 8
#define TFT_DC 9
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);
// Option 2: use any pins but a little slower
#define TFT_SCLK 13 // set these to be whatever pins you like!
#define TFT_MOSI 11 // set these to be whatever pins you like!
Następnie deklarujemy pin(receive_pin) Arduino, do którego podłączony jest pin danych modułu odbiornika RF i tworzymy zmienne char, które będą przechowywały wartości temperatury i wilgotności.
const int receive_pin = 12;
char temperatureChar[10];
char humidityChar[10];
Następnie tworzymy pakiet struct podobny do tego, który znajduje się w kodzie nadajnika.
struct package
{
float temperature = 0.0;
float humidity = 0.0;
};
Po wykonaniu tych czynności przechodzimy do funkcji void setup(), w której inicjalizujemy wyświetlacz oraz moduł odbiornika RF ustawiając prędkość bitową oraz uruchamiając PLL odbiornika.
void setup()
{
tft.initR(INITR_BLACKTAB);
tft.fillScreen(ST7735_BLACK);
printUI();
delay(1000);
// Initialise the IO and ISR
vw_set_rx_pin(receive_pin);
vw_setup(500); // Bits per sec
vw_rx_start(); // Start the receiver PLL running
}
Następnie funkcja void loop(). Rozpoczynamy ją od sprawdzenia czy została odebrana wiadomość za pomocą funkcji vw_have_message(). Jeśli wiadomość została odebrana, wyciągamy z niej dane o temperaturze i wilgotności i wyświetlamy je na wyświetlaczu LCD.
void loop()
{
uint8_t buf[sizeof(data)];
uint8_t buflen = sizeof(data);
if (vw_have_message()) // Is there a packet for us?
{
vw_get_message(buf, &buflen);
memcpy(&data,&buf,buflen);
Serial.print("\nPackage:");
Serial.print(data.temperature);
String temperatureString = String(data.temperature,1);
temperatureString.toCharArray(temperatureChar,10);
tft.fillRect(10,20,80,30,ST7735_BLACK);
printText(temperatureChar, ST7735_WHITE,10,20,3);
String humidityString = String(data.humidity,1);
humidityString.toCharArray(humidityChar,10);
tft.fillRect(10,95,80,100,ST7735_BLACK);
printText(humidityChar, ST7735_WHITE,10,95,3);
Serial.print("\n");
Serial.println(data.humidity);
}
}
W kodzie znajdują się również funkcje, które posłużyły do wyświetlenia wyników w sposób bardziej przyjazny dla użytkownika.
void printText(char *text, uint16_t color, int x, int y,int textSize)
{
tft.setCursor(x, y);
tft.setTextColor(color);
tft.setTextSize(textSize);
tft.setTextWrap(true);
tft.print(text);
}
void printUI()
{
printText("TEMPERATURE", ST7735_GREEN,30,5,1); // Temperature Static Text
printText("o", ST7735_WHITE,90,13,2);
printText("C", ST7735_WHITE,105,20,3);
printText("HUMIDITY", ST7735_BLUE,30,80,1); // Temperature Static Text
printText("%", ST7735_WHITE,90,95,3);
}
Kompletny kod odbiornika jest dostępny poniżej. Jest on również załączony w pliku zip w sekcji download tego projektu.
#include <VirtualWire.h>
#include <Adafruit_ST7735.h>
#include <Adafruit_GFX.h>
#define TFT_CS 10
#define TFT_RST 8
#define TFT_DC 9
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);
// Option 2: use any pins but a little slower!
#define TFT_SCLK 13 // set these to be whatever pins you like!
#define TFT_MOSI 11 // set these to be whatever pins you like!
const int receive_pin = 12;
char temperatureChar[10];
char humidityChar[10];
struct package
{
float temperature = 0.0;
float humidity = 0.0;
};
typedef struct package Package;
Package data;
void setup()
{
tft.initR(INITR_BLACKTAB);
tft.fillScreen(ST7735_BLACK);
printUI();
delay(1000);
// Initialise the IO and ISR
vw_set_rx_pin(receive_pin);
vw_setup(500); // Bits per sec
vw_rx_start(); // Start the receiver PLL running
}
void loop()
{
uint8_t buf[sizeof(data)];
uint8_t buflen = sizeof(data);
if (vw_have_message()) // Is there a packet for us?
{
vw_get_message(buf, &buflen);
memcpy(&data,&buf,buflen);
Serial.print("\nPackage:");
Serial.print(data.temperature);
String temperatureString = String(data.temperature,1);
temperatureString.toCharArray(temperatureChar,10);
tft.fillRect(10,20,80,30,ST7735_BLACK);
printText(temperatureChar, ST7735_WHITE,10,20,3);
String humidityString = String(data.humidity,1);
humidityString.toCharArray(humidityChar,10);
tft.fillRect(10,95,80,100,ST7735_BLACK);
printText(humidityChar, ST7735_WHITE,10,95,3);
Serial.print("\n");
Serial.println(data.humidity);
}
}
void printText(char *text, uint16_t color, int x, int y,int textSize)
{
tft.setCursor(x, y);
tft.setTextColor(color);
tft.setTextSize(textSize);
tft.setTextWrap(true);
tft.print(text);
}
void printUI()
{
printText("TEMPERATURE", ST7735_GREEN,30,5,1); // Temperature Static Text
printText("o", ST7735_WHITE,90,13,2);
printText("C", ST7735_WHITE,105,20,3);
printText("HUMIDITY", ST7735_BLUE,30,80,1); // Temperature Static Text
printText("%", ST7735_WHITE,90,95,3);
}
Demo
Wgraj odpowiedni kod do każdego z Arduino. Obie płytki Arduino mogą być zasilane za pomocą baterii. Po kilku minutach od włączenia urządzeń, na wyświetlaczu LCD powinny pojawić się dane o temperaturze i wilgotności.
Zasięg pary modułów nadajnika i odbiornika 433 MHz jest generalnie niewielki, ale poprzez przylutowanie zewnętrznych anten można zwiększyć ich zasięg.