In questa pagina è descritto come collegare nRF24L01+ ad Arduino e verificare il suo funzionamento. Nel limite di quanto è possibile fare con semplici strumenti di laboratorio, verranno anche mostrati alcuni dei segnali scambiati sul bus SPI e in radiofrequenza tra due apparati radio.
Preliminarmente è necessario installare le librerie RF24, direttamente dall'IDE di Arduino. La versione utilizzata è la 1.4.2, la più recente al momento della prima stesura di questa pagine:
La documentazione è disponibile alla pagina nrf24.github.io/RF24.
nRF24L01+ richiede sei fili (nota 1) per il collegamento al processore, oltre a massa ed alimentazione. Lo schema elettrico è il seguente:
Il collegamento fisico tra Arduino e nRF24L01+ può essere fatto in vari modi a secondo dei materiali a disposizione.
Il metodo più semplice è utilizzare un apposito circuito stampato. Purtroppo non mi risulta ce ne siano in commercio... e quindi me lo sono costruito.
In alternativa è possibile usare sette cavetti maschio-femmina DuPont, ampiamente disponibili online. La fotografia di apertura mostra una possibile realizzazione pratica e qui sotto una rappresentazione fotorealistica.
È importante, oltre l'evitare errori che potrebbero facilmente essere distruttivi, garantire una buona robustezza meccanica ed una buona continuità elettrica. Alcuni consigli:
Prima di procedere è bene verificare il corretto collegamento e la funzionalità generale del modulo. Può essere utile il seguente codice, di comprensione immediata:
#include <RF24.h>
RF24 radio(7, 8); // Imposta CE e nCSN conformemente all'hardware
void setup() {
Serial.begin(9600);
radio.begin();
}
void loop() {
if (radio.isChipConnected())
Serial.println ("nRF24L01p presente");
else
Serial.println ("nRF24L01p non rilevato");
delay(1000);
}
Il grafico seguente mostra i segnali SPI scambiati tra Arduino a nRF24L01+ all'interno di loop():
Analizziamo il significato dei dati scambiati tra Arduino e nRF24L01. SI tratta di 2 + 2 byte trasmessi in modalità full-duplex:
La frequenza del clock SPI è 8 MHz e quindi la trasmissione di un byte richiede circa 1 µs.
Un altro metodo utile per avere informazioni preliminari su nRF24L01+ è radio.printPrettyDetails() (nota 2) che stampa molte informazioni relative alla configurazione di nRF24L01.
Riprodurre quando sopra illustrato:
Per quanto riguarda l'ultimo punto, individuare in particolare:
Per il significato dei termini appena utilizzati potete fare riferimento alla pagina nRF24L01+ oppure direttamente al foglio tecnico.
Per utilizzare nRF24L01+ servono due Arduino: uno configurato come Primary Transmitter (PTX) e l'altro come Primary Receiver (PRX). Il compito è certamente facilitato dalla presenza di uno dei dispositivi sicuramente funzionante e già configurato (nota 5).
Il seguente codice trasmette un array di caratteri di lunghezza fissa (32 byte). La configurazione usata è in larga parte quella predefinita e analizzata nell'attività 1, con le uniche modifiche evidenziate nel codice (nota 6).
#include <RF24.h>
#include <printf.h>
#define bufferSize 32
const byte address[6] = {0x30, 0x30, 0x30, 0x30, 0x32}; // Indirizzo del
pipe
int counter=0;
char Hello[bufferSize];
RF24 radio(7, 8); // Imposta CE e nCSN conformemente all'hardware
void setup() {
Serial.begin(9600);
printf_begin();
radio.begin();
radio.setAutoAck(false); // Disattiva la richiesta di ACK
radio.openWritingPipe(address); // Imposta l'indirizzo del pipe
di trasmissione
radio.stopListening();
radio.printPrettyDetails();
}
void loop() {
sprintf(Hello, "Ciao mondo %i", counter++); // Personalizzare il testo
trasmesso
radio.write(Hello, bufferSize);
delay(1000);
}
Alcuni fake nRF24L01+ potrebbero avere problemi nel funzionare con il codice mostrato. Potrebbe essere utile aggiungere la seguente riga di configurazione:
radio.setPALevel(RF24_PA_MIN); // Imposta la potenza RF al minimo
Inoltre, solo se è possibile modificare anche il ricevitore:
radio.setDataRate(RF24_2MBPS); // Imposta la velocità a 2 Mbps
Infine, soprattutto se si usa Arduino Nano, potrebbe essere utile inserire tra massa e VDD (3.3 V) un condensatore, possibilmente al tantalio, da qualche decina di microfarard.
Durante il debug è utile stampare il contenuto del frame trasmesso in esadecimale con una funzione simile alla seguente:
void printBuffer(uint8_t buffer[], int len) {
for (int i = 0; i < len; i++) {
Serial.print(buffer[i] < 16 ? "0" : "");
Serial.print(buffer[i], HEX);
Serial.print(" ");
}
Serial.println(" ");
}
IMPORTANTE Questa attività può essere portata a termine solo se è disponibile un Primary Receiver già configurato; altrimenti occorre completarla in parallelo alla Attività 2bis (nota 5).
Il seguente codice riceve un array di caratteri di lunghezza fissa (32 byte). La configurazione usata è in larga parte quella predefinita e analizzata nell'attività 1, con le uniche modifiche evidenziate nel codice (nota 6).
#include <RF24.h>
#include <printf.h>
#define bufferSize 32
const byte address[6] = {0x30, 0x30, 0x30, 0x30, 0x32}; // Indirizzo del
pipe
char Received[bufferSize];
RF24 radio(7, 8); // Imposta CE e nCSN conformemente all'hardware
void setup() {
Serial.begin(9600);
printf_begin();
radio.begin();
radio.openReadingPipe(0, address); // Imposta l'indirizzo del pipe 0 di
ricezione
radio.setAutoAck(false); // Disattiva la richiesta di ACK
radio.printPrettyDetails();
radio.startListening();
Serial.println("Pronto...");
}
void loop() {
if (radio.available()) {
radio.read(Received, bufferSize);
Serial.println(Received);
}
}
IMPORTANTE Questa attività può essere portata a termine solo se è disponibile un trasmettitore già configurato; altrimenti occorre completarla in parallelo alla Attività 2 (nota 5).
Dopo aver configurato un Arduino come Primary Receiver ed un altro come Primary Transmitter (attività 2bis), modificare alcuni dei parametri di comunicazione. IMPORTANTE: procedere modificando un solo parametro alla volta, agendo in parallelo sia sul PTX che sul PRX.
Ricapitolando le caratteristiche del segnale radio generato da nRF24L01+:
Le due immagini seguenti mostrano cosa è visibile con un analizzatore di spettro (Aaronia HF-6065-X V3):
Il codice di partenza per una comunicazione bidirezionale è il seguente, identico per trasmettitore e ricevitore:
#include <RF24.h>
#define bufferSize 32
const byte address[6] = {0x30, 0x30, 0x30, 0x30, 0x32}; // Indirizzo del
pipe
RF24 radio(7, 8); // Imposta CE e nCSN conformemente all'hardware
void setup() {
Serial.begin(9600);
radio.begin();
radio.setAutoAck(true); // Attiva la richiesta di ACK
radio.openWritingPipe(address); // Imposta l'indirizzo del pipe di
trasmissione
radio.openReadingPipe(0, address); // Imposta l'indirizzo del pipe 0 di
ricezione
radio.startListening();
}
void loop() {
char Hello[bufferSize];
String string;
if (Serial.available()) {
string = Serial.readString();
string.toCharArray(Hello, bufferSize);
radio.stopListening();
radio.write(Hello, bufferSize);
radio.startListening();
}
if (radio.available()) {
radio.read(Hello, bufferSize);
Serial.print(Hello);
}
}
Analizzare il comportamento del codice di comunicazione bidirezionale proposto e provarlo utilizzando due Arduino. Se si è in una ambiente con molti trasmettitore attivi, per esempio un laboratorio scolastico, impostare un canale RF libero (nota 8).
Modificare il codice per usare due pipe con indirizzi diversi, uno per la ricezione ed uno per la trasmissione. Ovviamente in questo caso il codice del ricevitore e quello del trasmettitore non saranno identici.
Il dispositivo PIC-WL-Sen trasmette ogni 8 secondi alcune misure ambientali. Scrivere il codice che riceve il pacchetto e stampa i vari campi.
La configurazione:
Nella versione base il pacchetto contenuto nel payload è una struct di 30 byte:
#define ID_LEN 6 // Lunghezza in byte dell'identificatore
univoco del dispositivo
struct frame_t {
uint8_t vID;
// Identificativo della versione del pacchetto (0x4A)
uint8_t flags; // 8 bits:
ciascun bit identifica la presenza o meno di una campo "misura"
// Esempio: 1100 0000 -> VDD + Temperatura + 6 campi non implementati
uint16_t mID; //
Numerazione progressiva dei pacchetti
uint8_t devID[ID_LEN]; // Identificatore univoco del dispositivo
uint16_t vdd; //
Tensione della batteria [mV]
int16_t temperature; // Temperatura, in centesimi di °C
(Esempio: 36,5°C -> 3650)
uint16_t measure[6]; // Altre misure ambientali, non
implementato
uint32_t S;
// Secure hash, non implementato
};
Il contenuto può essere stampato come sequenza di 30 byte:
... oppure decodificando i vari campi che costituiscono la struct:
Pagina creata nel dicembre 2021
Ultima modifica: 7 gennaio 2022
Appunti scolastici - Versione 0.1029 - Gennaio 2025
Copyright 2012-2025, Vincenzo Villa (https://www.vincenzov.net)
Creative Commons | Attribution-ShareAlike 4.0 International (CC BY-SA 4.0)