1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364
|
Démontre l'opération TX avec un ATtiny85 en utilisant 2 pins pour la radio.
* L'ATtiny s'allume, prend les mesures du capteur, envoie les données, puis s'éteint.
* La consommation de courant est d'environ 5 microampères lorsqu'il est éteint.
* Le timer watchdog est utilisé pour réveiller l'ATtiny à un intervalle configurable.
* Le récepteur peut modifier certains paramètres en fournissant un accusé de réception du paquet NewSettingsPacket.
l'exemple 'Sensor_RX' pour plus de détails. Les nouveaux paramètres sont enregistrés dans l'eeprom.
* Des messages d'information sont envoyés au récepteur pour certains événements, comme le chargement de l'eeprom.
Cette logique peut être utilisée pour le débogage à distance, ce qui est très cool.
* La broche physique 5 (Arduino 0) agit comme un interrupteur d'alimentation. La radio et les capteurs ont tous un VCC connecté,
et la broche physique 5 fournit leur connexion à GND. Ainsi, lorsque l'ATtiny sort de son sommeil, il fait de la broche physique 5 une OUTPUT et la connecte à GND.
la broche physique 5 une SORTIE et la met à l'état BAS afin de mettre sous tension la radio et les capteurs.
* Suivez le 2-Pin Hookup Guide sur https://github.com/dparson55/NRFLite pour créer les connexions MOMI et SCK
pour la radio.
* Il y a une image du circuit dans le même dossier que ce fichier .ino.
Connexions ATtiny
* Broche physique 1 / RESET > Bouton de réinitialisation > GND
* Broche physique 2 / PB3 > Connexion DHT 22
* Broche physique 3 / PB4 > MOMI du circuit radio à 2 broches
* Broche physique 4 / GND
* Broche physique 5 / PB0 > Connexion au GND de la radio et au GND des circuits DHT22 et de la LED
* Broche physique 6 / PB1 > SCK du circuit radio à 2 broches
* Broche physique 7 / PB2 > NC
* Broche physique 8 / VCC > pas plus de 3,6 volts puisque c'est le maximum pour la radio
*/
#include "NRFLite.h"
#include <avr/eeprom.h>
#include <avr/sleep.h>
#include <avr/wdt.h>
#include <DHT.h>
//#define brocheDeBranchementDHT 2
//#define typeDeDHT DHT22
DHT dht(3, DHT22);
//float dhtt,dhth;
float tt ;
float hh ;
const static uint8_t PIN_RADIO_MOMI = 4;
const static uint8_t PIN_RADIO_SCK = 1;
const static uint8_t PIN_POWER_BUS = 0;
const static uint8_t DESTINATION_RADIO_ID = 0;
const uint8_t EEPROM_SETTINGS_VERSION = 1;
/*****************************/
struct EepromSettings
{
uint8_t RadioId;
uint32_t SleepIntervalSeconds;
float TemperatureCorrection;
float VoltageCorrection;
uint8_t Version;
};
/*****************************/
struct RadioPacket
{
uint8_t FromRadioId;
uint32_t FailedTxCount;
float Temperature;
float Humidite;
float Voltage;
};
/****************************/
struct MessagePacket
{
uint8_t FromRadioId;
uint8_t message[31]; // Can hold a 30 character string + the null terminator.
};
/****************************/
enum ChangeType
{
ChangeRadioId,
ChangeSleepInterval,
ChangeTemperatureCorrection,
ChangeVoltageCorrection
};
/*****************************/
struct NewSettingsPacket
{
ChangeType ChangeType;
uint8_t ForRadioId;
uint8_t NewRadioId;
uint32_t NewSleepIntervalSeconds;
float NewTemperatureCorrection;
float NewVoltageCorrection;
};
/*****************************/
NRFLite _radio;
EepromSettings _settings;
uint32_t _failedTxCount;
#define eepromBegin() eeprom_busy_wait(); noInterrupts() // Details on https://youtu.be/_yOcKwu7mQA
#define eepromEnd() interrupts()
/*****************************/
void processSettingsChange(NewSettingsPacket newSettings); // Nécessité de prédéclarer cette fonction puisqu'elle utilise une structure personnalisée comme paramètre (ou d'utiliser un fichier .h à la place).
/*****************************/
/* SETUP */
/*****************************/
void setup()
{
// Activez le bus d'alimentation. Il alimente tous les capteurs et la radio, et nous l'éteindrons lorsque nous dormirons pour économiser de l'énergie.
pinMode(PIN_POWER_BUS, OUTPUT);
digitalWrite(PIN_POWER_BUS, LOW);
//DHT22 sur
dht.begin(); // Connect DHT sensor PB3
// Load settings from eeprom.
eepromBegin();
eeprom_read_block(&_settings, 0, sizeof(_settings));
eepromEnd();
if (_settings.Version == EEPROM_SETTINGS_VERSION)
{
setupRadio();
sendMessage(F("Paramètres chargés")); // Save memory using F() for strings. Details on https://learn.adafruit.com/memories-of-an-arduino/optimizing-sram
}
else
{
// The settings version in eeprom is not what we expect, so assign default values.
_settings.RadioId = 1;
_settings.SleepIntervalSeconds = 2;
_settings.TemperatureCorrection = 0;
_settings.VoltageCorrection = 0;
_settings.Version = EEPROM_SETTINGS_VERSION;
setupRadio();
sendMessage(F("Eeprom ancienne, utilisant les valeurs par défaut"));
saveSettings();
}
}
/*****************************/
void setupRadio()
{
if (!_radio.initTwoPin(_settings.RadioId, PIN_RADIO_MOMI, PIN_RADIO_SCK, NRFLite::BITRATE250KBPS))
{
while (1); // Impossible de communiquer avec la radio et arrêt de tout traitement.
}
}
/*****************************/
/* LOOP */
/*****************************/
void loop()
{
// Mettre le microcontrôleur, les capteurs et la radio dans un état de faible consommation. Le traitement s'arrête ici jusqu'à ce que le timer du chien de garde nous réveille.
sleep(_settings.SleepIntervalSeconds);
// Maintenant que nous sommes réveillés, rassemblez tous les relevés des capteurs.
RadioPacket radioData;
radioData.FromRadioId = _settings.RadioId;
//radioData.FailedTxCount = _failedTxCount;
radioData.Temperature = getTemperature();
radioData.Humidite = getHumidite();
radioData.Voltage = getVcc();
// Essayer d'envoyer les données du capteur.
if (_radio.send(DESTINATION_RADIO_ID, &radioData, sizeof(radioData)))
{
// Si nous sommes ici, cela signifie que les données ont été envoyées avec succès.
// Vérifier si le récepteur a fourni un paquet de données d'accusé de réception.
// Il le fera s'il souhaite que nous modifiions l'un de nos paramètres.
if (_radio.hasAckData())
{
NewSettingsPacket newSettingsData;
_radio.readData(&newSettingsData);
// Confirmez que les paramètres que nous avons reçus nous sont destinés (peut-être essayait-il de modifier les paramètres pour un autre émetteur).
if (newSettingsData.ForRadioId == _settings.RadioId)
{
processSettingsChange(newSettingsData);
}
else
{
sendMessage(F("Ignorer les changements de paramètres"));
String msg = F(" Demande de radio ");
msg += String(newSettingsData.ForRadioId);
sendMessage(msg);
sendMessage(F(" Veuillez réessayer"));
}
}
}
else
{
_failedTxCount++;
}
}
ISR(WDT_vect) // Gestionnaire d'interruption du chien de garde.
{
wdt_disable();
}
/*****************************/
float getHumidite()
{
float hum = dht.readHumidity(); // Lecture du taux d'humidité (en %)
if (isnan(hum)) {
sendMessage(F("Probleme Humidite DHT22"));
return;
}
hh=round(hum);
return hh;
}
/*****************************/
float getTemperature()
{
float temp = dht.readTemperature(); // Lecture de la température, exprimée en degrés Celsius
// Vérification si données bien reçues
if (isnan(temp)) {
sendMessage(F("Probleme Temperature DHT22"));
return;
}
tt=(round(temp)+_settings.TemperatureCorrection);
return tt;
}
/*****************************/
float getVcc()
{
// Details on http://provideyourown.com/2012/secret-arduino-voltmeter-measure-battery-voltage/
ADMUX = _BV(MUX3) | _BV(MUX2); // Sélection d'une référence interne de 1,1 V pour la mesure.
delay(2); // Laisser la tension se stabiliser.
ADCSRA |= _BV(ADSC); // Commencez à mesurer.
while (ADCSRA & _BV(ADSC)); // Wait for measurement to complete.
uint16_t adcReading = ADC;
float vcc = 1.1 * 1024.0 / adcReading; // Notez que la référence de 1,1 V peut être décalée de +/- 10 %, et qu'un étalonnage est donc nécessaire.
return vcc + _settings.VoltageCorrection;
}
/*****************************/
void processSettingsChange(NewSettingsPacket newSettings)
{
String msg;
if (newSettings.ChangeType == ChangeRadioId)
{
msg = F("Changer l'Id en ");
msg += newSettings.NewRadioId;
sendMessage(msg);
_settings.RadioId = newSettings.NewRadioId;
setupRadio();
}
else if (newSettings.ChangeType == ChangeSleepInterval)
{
sendMessage(F("Changing sleep interval"));
_settings.SleepIntervalSeconds = newSettings.NewSleepIntervalSeconds;
}
else if (newSettings.ChangeType == ChangeTemperatureCorrection)
{
sendMessage(F("Correction de température"));
_settings.TemperatureCorrection = newSettings.NewTemperatureCorrection;
}
else if (newSettings.ChangeType == ChangeVoltageCorrection)
{
sendMessage(F("Modification de la correction de la tension"));
_settings.VoltageCorrection = newSettings.NewVoltageCorrection;
}
saveSettings();
}
/*****************************/
void saveSettings()
{
EepromSettings settingsCurrentlyInEeprom;
eepromBegin();
eeprom_read_block(&settingsCurrentlyInEeprom, 0, sizeof(settingsCurrentlyInEeprom));
eepromEnd();
// Ne gaspillez pas 1 des 100 000 écritures garanties de l'eeprom si les réglages n'ont pas changé.
if (memcmp(&settingsCurrentlyInEeprom, &_settings, sizeof(_settings)) == 0)
{
sendMessage(F("Pas de sauvegarde de l'eeprom, pas de changement"));
}
else
{
sendMessage(F("Sauvegarde des paramètres"));
eepromBegin();
eeprom_write_block(&_settings, 0, sizeof(_settings));
eepromEnd();
}
}
/*****************************/
void sendMessage(String msg)
{
MessagePacket messageData;
messageData.FromRadioId = _settings.RadioId;
// S'assurer que le message n'est pas trop volumineux pour le MessagePacket.
if (msg.length() > sizeof(messageData.message) - 1)
{
msg = msg.substring(0, sizeof(messageData.message) - 1);
}
// Convertit la chaîne de messages en un tableau d'octets.
msg.getBytes((unsigned char*)messageData.message, msg.length() + 1);
_radio.send(DESTINATION_RADIO_ID, &messageData, sizeof(messageData));
}
/*****************************/
void sleep(uint32_t seconds)
{
uint32_t totalPowerDownSeconds = 0;
uint8_t canSleep8Seconds;
_radio.powerDown(); // Mettre la radio dans un état de faible consommation.
pinMode(PIN_POWER_BUS, INPUT); // Déconnecter le bus d'alimentation.
ADCSRA &= ~_BV(ADEN); // Désactive l'ADC pour économiser de l'énergie.
while (totalPowerDownSeconds < seconds)
{
canSleep8Seconds = seconds - totalPowerDownSeconds >= 8;
if (canSleep8Seconds)
{
WDTCR = _BV(WDIE) | _BV(WDP3) | _BV(WDP0); // Active le chien de garde et définit un temps d'interruption de 8 secondes.
totalPowerDownSeconds += 8;
}
else
{
WDTCR = _BV(WDIE) | _BV(WDP2) | _BV(WDP1); // Durée d'interruption de 1 seconde.
totalPowerDownSeconds++;
}
wdt_reset();
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
sleep_enable();
//MCUCR |= _BV(BODS) | _BV(BODSE); // Désactiver la détection du brown-out (uniquement supporté par l'ATtiny85 RevC et les versions ultérieures).
//MCUCR = _BV(BODS);
sleep_cpu();
sleep_disable();
}
ADCSRA |= _BV(ADEN); // Réactiver l'ADC.
pinMode(PIN_POWER_BUS, OUTPUT); // Réactiver le bus d'alimentation. Il est déjà à l'état BAS puisqu'il a été configuré dans 'setup()'.
setupRadio(); // Réinitialiser la radio.
} |
Partager