Je suis aussi sur un projet de monitoring d'une dizaine de ruches :
Chaque ruche est équipée d’un micro contrôleur Promini 5V avec une carte HX711et sa sonde de poids, une sonde DS18B20 en I2C et un module RS485 pour la communication avec le maître. Dans un premier temps, c'est un nano qui fait office de Promini pour être plus simple à programmer.
Câblage RS485 : 3 entrées digitales comme D10 D11 et D12
Câblage HX711 : DT en A2 et SCK en A3
Câblage DS18B20 : une seule entrée digitale comme D2
La communication entre chaque ruche passe donc par un réseau RS485 qui a la bonne idée de pouvoir faire jusqu'à 1.2km ...ce qui permet de se rapprocher d'une source d'alimentation pour le master et le réseau : l'akéru qui fait la tournée des popotes régulièrement et envoie son faible message de 22 octets. 22 octets c'est pas grand chose donc on laisse juste un octet pour le poids et un octet pour la température par ruche :
Pour une température de -15°C à 45°C (70) en tablant sur des quarts de degrés, ça fonctionne et ça devrait suffire en précision :
Température Conversion en octet
-15 0
-10 20
0 60
10 100
20 140
30 180
40 220
45 240
temp1 = (temp+15)*4;
tempbyte = (byte) temp1; //Ça c'est du code puissant !
Pour le poids, même principe :
Capteur de poids de 20kg monté en face d’un axe. Le 0 à 20kg équivaut à un 0 à 40 kg avec une plage utile de 20 à 40 kg soit 20 kg pour 255 points soit 0.1 kg par unité : ça devrait pouvoir permettre de détecter l'envol d'un essaim.
Mesure avec offset à 20kg Poids réel Conversion en octet
0 20 0
0.05 20.1 kg 1
1 22 kg 20
5 30 kg 100
10 40 kg 200
C'est l'Amérique car il reste encore 2 octets pour faire remonter des codes d'erreur sur l'alim ou la défaillance d'un esclave...
weight1 = weight*10;
weightbyte = (byte) weight1; //deuxième démonstration de puissance du code !
Voila donc le code en mode brouillon pour l'esclave...mais uniquement pour renvoyer les 2 octets sur le PC via la liaison série, il n'y a pas de RS485 pour l'instant...par contre, la partie capteur fonctionne :
- Code: Tout sélectionner
#include "HX711.h"
#include <OneWire.h> // Inclusion de la librairie OneWire pour la sonde de température
#define DS18B20 0x28 // Adresse 1-Wire du DS18B20, détectée en chargeant un utilitaire qui la renvoie sur le PC
#define BROCHE_ONEWIRE 2 // Broche utilisée pour le bus 1-Wire
HX711 scale(A2, A3); // parameter "gain" is ommited; the default value 128 is used by the library
OneWire ds(BROCHE_ONEWIRE); // Création de l'objet OneWire ds en intégrant le fait que ça se passe sur la patte 2 définie ci dessus dans les variables
float tempmax = 0 ; // variable d'enregistrement de la tempérarure max, initialisée à 0 pour être sur de la changer à la première boucle
float tempmin = 40 ; // variable d'enregistrement de la tempérarure min, initialisée à 40 pour être sur de la changer à la première boucle
float temp; //température en degré
float temp1; //température en quart de degré pour conversion en octet + 15°
byte tempbyte; //température convertie en octet
float weight; // poids
float weight1; //poids en hectogramme pour conversion en octet
byte weightbyte; //poids converti en octet
// FONCTION récupérant la température depuis le DS18B20 - pompée toute faite sur internet. Casse pied à décortiquer car relève de la lecture de messages série.
// Retourne true si tout va bien, ou false en cas d'erreur sur la variable booléan
boolean getTemperature(float *temp){
byte data[9], addr[8];
// data : Données lues depuis le scratchpad
// addr : adresse du module 1-Wire détecté
if (!ds.search(addr)) { // Recherche un module 1-Wire
ds.reset_search(); // Réinitialise la recherche de module
return false; // Retourne une erreur
}
if (OneWire::crc8(addr, 7) != addr[7]) // Vérifie que l'adresse a été correctement reçue
return false; // Si le message est corrompu on retourne une erreur
if (addr[0] != DS18B20) // Vérifie qu'il s'agit bien d'un DS18B20
return false; // Si ce n'est pas le cas on retourne une erreur
ds.reset(); // On reset le bus 1-Wire
ds.select(addr); // On sélectionne le DS18B20
ds.write(0x44, 1); // On lance une prise de mesure de température
delay(800); // Et on attend la fin de la mesure
ds.reset(); // On reset le bus 1-Wire
ds.select(addr); // On sélectionne le DS18B20
ds.write(0xBE); // On envoie une demande de lecture du scratchpad
for (byte i = 0; i < 9; i++) // On lit le scratchpad
data[i] = ds.read(); // Et on stock les octets reçus
// Calcul de la température en degré Celsius
*temp = ((data[1] << 8) | data[0]) * 0.0625;
// Pas d'erreur
return true;
}
//fin de la fonction de lecture de la température depuis le DS18B20 - pompée toute faite sur internet.
void setup() {
Serial.begin(9600); // lance le port série pour le retour vers le PC
// la balance :
scale.set_scale(); // initialise la balance pour détermination du facteur de conversion
scale.tare(); // reset la balance à zéro
delay(1000); // pause pour avoir le temps de lire
scale.set_scale(100000.f); // calibre la balance par division entre le poids de test connu et la valeur affichée lors du test
}
void loop() {
// début de la routine d'affichage du poids
weight = scale.get_units();
Serial.print(" Poids : ");
Serial.println(weight);
//Serial.println(scale.get_units(), 3);
//scale.power_down(); // put the ADC in sleep mode
//scale.power_up();
// fin de la routine d'affichage du poids
// début de la routine d'affichage de la température
getTemperature(&temp); // Lit la température ambiante à ~1Hz dans la fonction déja vue en début de programme et pompée intégrale
Serial.print(" Temp : ");
Serial.println(temp);
// if(getTemperature(&temp)) { // Lit la température ambiante à ~1Hz dans la fonction déja vue en début de programme et pompée intégrale
// fin de la routine d'affichage de la température
// enregistrement des températures min et max
if (temp > tempmax) { // enregistrement de la température max, si la température lue est sup à la température max archivée alors
tempmax = temp ; //la nouvelle température max devient la température lue
} // fin de cette collecte de la température max
if (temp < tempmin) {// enregistrement de la température min, si la température lue est inf à la température min archivée alors
tempmin = temp ;
} // fin de la collecte de la température min
// fin d'enregistrement des températures min et max
//routine de conversion de weight et temp en octet pour communication avec le maitre
Serial.print(" Temp convertie en quart de degres : ");
temp1 = (temp+15)*4;
tempbyte = (byte) temp1;
Serial.println(tempbyte);
Serial.print(" Poids converti en hectogramme : ");
weight1 = weight*10;
weightbyte = (byte) weight1;
Serial.println(weightbyte);
//fin de routine de conversion de weight et temp en octet pour communication avec le maitre
}
Voila pour le début, les photos et la suite (le master) arrivent. Par contre, pas de faux espoirs : je n'ai pas abordé du tout l'aspect mise en œuvre de la communication via le RS485 entre l'akéru et ses dix esclaves. J'ai idée qu'il faut appeler chaque esclave à tour de rôle et lui demander ses 2 octets poids et température avec un code d'identification simple qui permet d'être sur que c'est le bon esclave qui a répondu et dans les temps. Ensuite, après avoir stocké les 20 octets et regardé la tension d'alim, la présence de 220V etc...on envoie le super message de 22 octets dans les airs...