Bonsoir
dans une file de discussion un membre du forum avait besoin d'un code d'exemple de communication sans fil bi-directionnelle entre 2 arduino
J'ai donc créé ce petit code d'exemple.
Voici à quoi le montage ressemble
2 x Arduino UNO
2 x Membrane 4 boutons
2 x (2 Leds + 2 résistances de limitation de courant adéquates)
2 x (NRF24L01+ avec leur support adaptateur de tension 5V)
L'idée est toute simple, on met le même code sur les 2 arduinos mais le code va se configurer dynamiquement en fonction de la valeur de la Pin A0. si elle est à GND vous aurez le rôle 0, si elle est à une autre valeur alors vous avez le rôle 1.
Connexions depuis les composants vers l'arduino
Membrane 4 boutons. elle a 5 connecteurs:
1 --> GND
(le fil blanc qui part de la gauche du connecteur de la membrane sur la photo)
2 --> D3
(le fil gris)
3 --> D4
(le fil violet)
4 --> D5
(le fil bleu)
5 --> D6
(le fil vert)
NRF24L01+ avec leur support adaptateur de tension:
VCC --> 5V
GND --> GND
CE --> D7
CSN --> D8
SCK --> D13
MOSI (MO) --> D11
MISO (MI) --> D12
IRQ --> Non connecté
les Leds et résistances
GND --> Résistance 220Ω --> Cathode --> LED 1 --> Anode --> Pin D9
GND --> Résistance 220Ω --> Cathode --> LED 2 --> Anode --> Pin D10
Configuration du logiciel
Arduino Pin A0 --> GND sur le premier Arduino (rôle = 0)
Arduino Pin A0 --> 3.3V sur le second Arduino (rôle = 1) (j'ai pris 3.3V car la pin 5V était prise )
L'idée du code de démonstration est la suivante
Vous pressez un bouton de 1 à 4 d'un côté, la valeur 1 à 4 est envoyée à l'autre Arduino qui fait une action.
1 = leds OFF OFF
2 = leds ON OFF
3 = leds OFF ON
4 = leds ON ON
Une fois l'action exécutée, l'arduino renvoie une confirmation sous forme d'un octet 100+valeur ce qui nous permet de confirmer que l'action demandée a été effectuée.
Pour simplifier au maximum le code, j'utilise la librairie OneButton qui va gérer pour vous l'appui sur les boutons, le bouncing etc. (cf mon tuto de programmation par machine à états où j'en parle un peu)
Le setup() configure tout ce qu'il faut
la loop() est toute simple:
- elle regarde si un bouton est appuyé en si oui envoie le message
- elle écoute si un message est arrivé et si oui fait l'action associée
Voici le code
// ************* La Radio *************
#include <SPI.h>
#include <RF24.h> // voir http://tmrh20.github.io/RF24/
// Configurer vos radio nRF24L01+ sur le bus SPI et mettre CE sur D7 et CSN sur D8
RF24 radio(7, 8);
// Le nom des "pipes" de communication, un en lecture, un en écriture
const byte adresses[][6] = {"0pipe", "1pipe"}; // Pipes 1-5 should share the same address, except the first byte. Only the first byte in the array should be unique
// A CONFIGURER sur la pin A0
// si A0 est à GND alors rôle = 0 --> le premier Arduino
// si A0 est à 3.3V ou 5V alors rôle = 1 --> pour le second
const byte configurationPin = A0;
uint8_t role;
// ****************** Les Boutons ******************
// library = https://github.com/mathertel/OneButton
// documentation = http://www.mathertel.de/Arduino/OneButtonLibrary.aspx
#include <OneButton.h>
OneButton bouton1(4, true); // true pour le mettre en INPUT_PULLUP
OneButton bouton2(3, true);
OneButton bouton3(6, true);
OneButton bouton4(5, true);
// ************* Deux Leds avec résitances de limiation de courant *************
const byte pinLed0 = 9;
const byte pinLed1 = 10;
// ----------------------------------------------------------------------------------------
void bouton1Click()
{
Serial.println(F("Bouton 1 local, envoi du message 1"));
envoyerMessage((uint8_t) 1);
}
void bouton2Click()
{
Serial.println(F("Bouton 2 local, envoi du message 2"));
envoyerMessage((uint8_t) 2);
}
void bouton3Click()
{
Serial.println(F("Bouton 3 local, envoi du message 3"));
envoyerMessage((uint8_t) 3);
}
void bouton4Click()
{
Serial.println(F("Bouton 4 local, envoi du message 4"));
envoyerMessage((uint8_t) 4);
}
// ----------------------------------------------------------------------------------------
void verifierBoutons()
{
bouton1.tick();
bouton2.tick();
bouton3.tick();
bouton4.tick();
}
// ----------------------------------------------------------------------------------------
// envoi d'un octet vers l'autre radio
// ----------------------------------------------------------------------------------------
void envoyerMessage(uint8_t nombre)
{
radio.stopListening(); // On arrête d'écouter pour qu'on puisse émettre
if (!radio.write( &nombre, sizeof(nombre) )) {
Serial.println(F("erreur d'envoi"));
}
radio.startListening(); // On se remet en mode écoute
}
// ----------------------------------------------------------------------------------------
// vérifie si on a reçu une commande de la part de l'autre radio (1 octet)
// ----------------------------------------------------------------------------------------
uint8_t ecouterRadio()
{
uint8_t message = 0; // 0 = pas de commande
if ( radio.available()) {
while (radio.available()) {
radio.read( &message, sizeof(message) ); // on lit l'octet reçu (si plusieurs messages on ne conserve que le dernier)
}
Serial.print(F("J'ai recu ")); Serial.println(message);
}
return message;
}
// ----------------------------------------------------------------------------------------
void executerAction(uint8_t messageRecu)
{
if (messageRecu >= 1 && messageRecu <= 4) {
switch (messageRecu) {
case 1:
Serial.println(F("Action Bouton 1 distant"));
digitalWrite(pinLed0, LOW);
digitalWrite(pinLed1, LOW);
break;
case 2:
Serial.println(F("Action Bouton 2 distant"));
digitalWrite(pinLed0, HIGH);
digitalWrite(pinLed1, LOW);
break;
case 3:
Serial.println(F("Action Bouton 3 distant"));
digitalWrite(pinLed0, LOW);
digitalWrite(pinLed1, HIGH);
break;
case 4:
Serial.println(F("Action Bouton 4 distant"));
digitalWrite(pinLed0, HIGH);
digitalWrite(pinLed1, HIGH);
break;
}
// on envoie un accusé de réception qui vaut 100 + la valeur du message
envoyerMessage((uint8_t) 100 + messageRecu);
} else if (messageRecu >= 100) { // c'est un ACK d'une action distante
Serial.print(F("Confiramtion Execution action distante Bouton "));
Serial.println(messageRecu - 100);
}
}
// ------------------------------------------------------------------
// ------------------------------------------------------------------
// ------------------------------------------------------------------
void setup() {
pinMode(pinLed0, OUTPUT);
pinMode(pinLed1, OUTPUT);
pinMode(A0, INPUT);
Serial.begin(115200);
role = (digitalRead(configurationPin) == LOW) ? 0 : 1 ;
Serial.print(F("\nMon Role = ")); Serial.println(role);
// On configure la radio
radio.begin();
// pour le test on règle le niveau d'énergie à RF24_PA_LOW pour éviter les interférences
// mettre à RF24_PA_MAX si on veut la puissance d'émission max
radio.setPALevel(RF24_PA_LOW);
// On ouvre un pipe de lecture et un d'écriture avec des noms opposés en fonction du rôle
// comme ça un parle sur "pipe0" et l'autre écoute sur "pipe0"
// et l'autre parle sur "pipe1" tandisque Le premier écoute sur "pipe1"
radio.openWritingPipe(adresses[role]); // role doit être 0 ou 1
radio.openReadingPipe(1, adresses[1 - role]); // 1 - role = l'autre adresse
// Start the radio listening for data
radio.startListening();
// On attache la fonction boutonXClick() comme callBack en cas de simple click rapide
// ou si le bouton est tenu longtemps appuyé (au relachement)
// il existe 3 callback attachLongPressStart, attachLongPressStop, attachDuringLongPress
bouton1.attachClick(bouton1Click); bouton1.attachLongPressStop(bouton1Click);
bouton2.attachClick(bouton2Click); bouton2.attachLongPressStop(bouton2Click);
bouton3.attachClick(bouton3Click); bouton3.attachLongPressStop(bouton3Click);
bouton4.attachClick(bouton4Click); bouton4.attachLongPressStop(bouton4Click);
}
// ------------------------------------------------------------------
void loop() {
uint8_t messageRecu;
verifierBoutons(); // regarde si les boutons sont enfoncés et déclenche une action dans ce cas
if (messageRecu = ecouterRadio()) // si on a reçu un message
executerAction(messageRecu); // on execute l'action associée
}