/***************************************************************************************** * FILENAME : attiny85_BAL.ino * * DESCRIPTION : ATTiny85 - 2 switchs + DS18B20 + émetteur 433MHz (format Oregon) pour BàL * * * NOTES : * * * Source : https://github.com/winkste/attiny85_rfWeather * *****************************************************************************************/ /************************************************************ Emplacement des PIN de la puce ATtiny85 + connexions sur carte type D1 mini +-------+ | D1 mini board D1 | Ain0 D5 PB5 1|* |8 VCC | D0 D2 | Ain3 D3 PB3 2| |7 PB2 D2 Ain1 | D5 D3 | Ain2 D4 PB4 3| |6 PB1 D1 pwm1 | D6 D4 | GND 4| |5 PB0 D0 pwm0 | D7 Câblage +-------+ 1|* |8 (+) DS18B20 2| |7 TX433 alim DS18B20 + TX433 3| |6 Switch B (porte) (-) 4| |5 Switch A (fente) +-------+ */ /****************************************************************************************/ /* Include Interfaces */ #include #include #include #include #include "OneWire.h" // version modifiée pour ne pas avoir besoin de résistance de pull-up : https://forum.arduino.cc/index.php?topic=229612.0 #include "DallasTemperature.h" #include "os_v2_1_temp_hum_sensor.h" /****************************************************************************************/ /* Local constant defines */ #define CHANNEL 0x20 #define ID_DS18B20 0xCC // 2 chiffres après 2D pour l'ID #define ID_SWITCH_A 0xAA // Identifiant switch A #define ID_SWITCH_B 0xBB // Identifiant switch B // Canal d'émission: 3 canaux possibles: // canal 1: 0x10 canal 2: 0x20 canal 3: 0x30 const byte canal = 0x10; #define TX_PIN PB2 // pin 7 TX433 #define ONE_WIRE_BUS PB3 // pin 2 DS18B20 #define SWITCH_A_PIN PB0 // pin 5 SWITCH A input #define SWITCH_B_PIN PB1 // pin 6 SWITCH B input #define ENABLE_PIN PB4 // pin 3 alimentation TX43, condensateur 20 uF // time until the watchdog wakes the mc in seconds #define WATCHDOG_TIME 8u // 1, 2, 4 or 8 seconds // after how many watchdog wakeups we should collect and send the data #define WATCHDOG_WAKEUPS_TARGET 7u // 8 * 7 = 56 seconds between each data collection #define NB_CYCLE_DS18B20 5u // Période ds18b20 : secondes = NB_CYCLE_DS18B20 x WATCHDOG_WAKEUPS_TARGET x WATCHDOG_TIME #define NB_CYCLE_AB 10u // Période switchs A et B (fente et porte) // min max values for the ADC to calculate the battery percent /*#define BAT_ADC_MIN 0u // ~0V #define BAT_ADC_MAX 1023u // ~10V #define BAT_ADC_REF_VOLTAGE 5.0f #define BAT_ADC_VOLT_DIVID 2u */ #define BAT_VCC_MIN 3200 // ~3.2 V => 0% #define BAT_VCC_MAX 4200 // ~4.2 V => 100% /****************************************************************************************/ /* Local function like makros */ /****************************************************************************************/ /* Local type definitions (enum, struct, union) */ /****************************************************************************************/ /* Static Data instantiation */ OneWire oneWire(ONE_WIRE_BUS); // pour DS18B20 DallasTemperature sensors(&oneWire); // pour DS18B20 static OS_v2_1_temp_hum_sensor ds18b20_message(TX_PIN); // émission 433MHz pour température static OS_v2_1_temp_hum_sensor switch_A_message(TX_PIN); // émission 433MHz pour switch A static OS_v2_1_temp_hum_sensor switch_B_message(TX_PIN); // émission 433MHz pour switch B static float humidity_f32s = 0.0f; static float temperature_f32s = 0.0f; static int16_t txTemperature_s16s = 0; static int16_t txHumidity_s16s = 0; bool status_A = 0; // statut switch A volatile bool oldStatus_A = 0; volatile uint16_t Total_A = 0; bool send_switch_A = 0; bool status_B = 0; // statut switch B volatile bool oldStatus_B = 0; volatile uint16_t Total_B = 0; bool send_switch_B = 0; static uint16_t isrCounter_u16s = 0u; static uint16_t counter_ds18b20_u16s = NB_CYCLE_DS18B20; static uint16_t counter_ab_u16s = NB_CYCLE_AB; /****************************************************************************************/ /* Local functions (reduced visibility) */ static void EnableWatchdog(void); static void EnterSleep(void); //static void SetupAdc(void); static uint16_t BatCheck(void); /****************************************************************************************/ /* Public functions (unlimited visibility) */ /**--------------------------------------------------------------------------------------- * @brief ARDUINO Setup function * @author winkste * @date 06. Mar. 2018 * @return true, if message is compliant to checks *//*-----------------------------------------------------------------------------------*/ void setup() { CLKPR = (1<= NB_CYCLE_DS18B20) { counter_ds18b20_u16s = 0; pinMode(ONE_WIRE_BUS, OUTPUT); //digitalWrite(ONE_WIRE_BUS, LOW); //sensors.begin(); delay(10); sensors.requestTemperatures(); // lit ds18b20 delay(10); temperature_f32s = sensors.getTempCByIndex(0); uint16_t batPercent = BatCheck(); // mesure niveau batterie et renvoie pourcentage humidity_f32s = batPercent; // on utilise l'humidité pour envoyer le pourcentage de batterie EnableTX433(); // active émetteur 433 MHz et charge condensateur ds18b20_message.setBatteryStatus((batPercent > 10)?true:false); // 0 : low, 1 : high ds18b20_message.setTemperature(temperature_f32s); ds18b20_message.setHumidity((byte) humidity_f32s); ds18b20_message.buildAndSendPacket();digitalWrite(TX_PIN, LOW); } if (counter_ab_u16s >= NB_CYCLE_AB) { send_switch_A = 1; send_switch_B = 1; counter_ab_u16s = 0; } // Envoi message pour switch A if (send_switch_A) { send_switch_A = 0; EnableTX433(); // active pin émetteur 433 MHz et charge condensateur switch_A_message.setTemperature(Total_A); // envoie le total en tant que température switch_A_message.setHumidity((byte) status_A); // envoie le statut à travers humidité switch_A_message.buildAndSendPacket();digitalWrite(TX_PIN, LOW); } // Envoi message pour switch B if (send_switch_B) { send_switch_B = 0; EnableTX433(); // active pin émetteur 433 MHz et charge condensateur switch_B_message.setTemperature(Total_B); // envoie le total en tant que température switch_B_message.setHumidity((byte) status_B); // envoie le statut à travers humidité switch_B_message.buildAndSendPacket();digitalWrite(TX_PIN, LOW); } counter_ds18b20_u16s++; counter_ab_u16s++; // actions avant deepsleep digitalWrite(ONE_WIRE_BUS, LOW); // met la pin DATA de la DS18B20 à zéro (économie énergie) digitalWrite(ENABLE_PIN, LOW); // coupe alimentation émetteur 433 MHz (économie énergie) delay(5); pinMode(ONE_WIRE_BUS, INPUT); // passe en input (économie énergie) pinMode(ENABLE_PIN, INPUT); // passe en input (économie énergie) // deep sleep for(uint8_t idx_u8 = 0u; idx_u8 < WATCHDOG_WAKEUPS_TARGET; idx_u8++) { EnterSleep(); // En sortie de deepsleep (notamment si réveillé par interrupt), on regarde l'état de switchs // Switch A CheckStatusA(); // Switch B CheckStatusB(); if (send_switch_A || send_switch_B) break; // sortie de la boucle for pour envoyer les messages immédiatement } // actions après deepsleep // => à partir d'ici, on repart au début de loop (pas de reset en sortie deepsleep) } /****************************************************************************************/ /* Private functions: */ /**--------------------------------------------------------------------------------------- * @brief Configures and enables the Wotchdog * @author winkste * @date 06. Mar. 2018 * @return n/a *//*-----------------------------------------------------------------------------------*/ void EnableWatchdog(void) { cli(); // clear the reset flag MCUSR &= ~(1 << WDRF); // set WDCE to be able to change/set WDE WDTCR |= (1 << WDCE) | (1 << WDE); // set new watchdog timeout prescaler value #if WATCHDOG_TIME == 1 WDTCR = 1 << WDP1 | 1 << WDP2; #elif WATCHDOG_TIME == 2 WDTCR = 1 << WDP0 | 1 << WDP1 | 1 << WDP2; #elif WATCHDOG_TIME == 4 WDTCR = 1 << WDP3; #elif WATCHDOG_TIME == 8 WDTCR = 1 << WDP0 | 1 << WDP3; #else #error WATCHDOG_TIME must be 1, 2, 4 or 8! #endif // enable the WD interrupt to get an interrupt instead of a reset WDTCR |= (1 << WDIE); sei(); } /**--------------------------------------------------------------------------------------- * @brief function to go to sleep * @author winkste * @date 06. Mar. 2018 * @return n/a *//*-----------------------------------------------------------------------------------*/ void EnterSleep(void) { /* EDIT: could also use SLEEP_MODE_PWR_DOWN for lowest power consumption. */ set_sleep_mode(SLEEP_MODE_PWR_DOWN); sleep_enable(); /* Now enter sleep mode. */ sleep_mode(); /* The program will continue from here after the WDT timeout*/ sleep_disable(); /* First thing to do is disable sleep. */ } /**--------------------------------------------------------------------------------------- * @brief Setup of the A to D measurement for battery voltage at pin PB4 * @author winkste * @date 06. Mar. 2018 * @return true, if message is compliant to checks *//*-----------------------------------------------------------------------------------*/ /* void SetupAdc(void) { // setup the ADC ADMUX = (1 << ADLAR) | // left shift result (0 << REFS1) | // Sets ref. voltage to VCC, bit 0 (0 << REFS0) | // Sets ref. voltage to VCC, bit 0 (0 << MUX3) | // use ADC2 for input (PB4), MUX bit 3 (0 << MUX2) | // use ADC2 for input (PB4), MUX bit 2 (1 << MUX1) | // use ADC2 for input (PB4), MUX bit 1 (0 << MUX0); // use ADC2 for input (PB4), MUX bit 0 ADCSRA = (1 << ADEN) | // enable ADC (1 << ADPS2) | // set prescaler to 64, bit 2 (1 << ADPS1) | // set prescaler to 64, bit 1 (0 << ADPS0); // set prescaler to 64, bit 0 // disable ADC for powersaving ADCSRA &= ~(1<> 6; // clear the ADIF bit by writing 1 to it ADCSRA |= (1 << ADIF); // disable the ADC ADCSRA &= ~(1 << ADEN); // calc the battery voltage based on the reference voltage measuredVoltage_f32 = (float)rawAdcVal_u16; measuredVoltage_f32 = measuredVoltage_f32 / 1024.0f; measuredVoltage_f32 = measuredVoltage_f32 * BAT_ADC_REF_VOLTAGE; measuredVoltage_f32 = measuredVoltage_f32 / BAT_ADC_VOLT_DIVID; measuredVoltage_f32 = measuredVoltage_f32 * 100.0f; return ((uint16_t) measuredVoltage_f32); //return(rawAdcVal_u16); }*/ /**--------------------------------------------------------------------------------------- * @brief function to read and send the battery status * @author winkste * @date 06. Mar. 2018 * @return returns the measured voltage at Pon pb4 *//*-----------------------------------------------------------------------------------*/ uint16_t BatCheck(void) { // Read 1.1V reference against AVcc // set the reference to Vcc and the measurement to the internal 1.1V reference // enable the ADC ADCSRA |= (1 << ADEN); // short delay _delay_ms(10); #if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); #elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__) ADMUX = _BV(MUX5) | _BV(MUX0); #elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) ADMUX = _BV(MUX3) | _BV(MUX2); #else ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); #endif delay(2); // Wait for Vref to settle ADCSRA |= _BV(ADSC); // Start conversion while (bit_is_set(ADCSRA,ADSC)); // measuring // disable the ADC ADCSRA &= ~(1 << ADEN); uint8_t low = ADCL; // must read ADCL first - it then locks ADCH uint8_t high = ADCH; // unlocks both long vcc = (high<<8) | low; vcc = 1125300L / vcc; // Calculate Vcc (in mV); 1125300 = 1.1*1023*1000 vcc = vcc - 180; // Offset de calibration vcc = min(vcc, BAT_VCC_MAX); vcc = 100 * (vcc - BAT_VCC_MIN) / (BAT_VCC_MAX - BAT_VCC_MIN); // batterie en pourcent de 3.2-4.2 V vcc = min(vcc, 99); return (int) vcc; } /**--------------------------------------------------------------------------------------- * @brief Interrupt Service Routine for watchdog interrupt vector * @author winkste * @date 06. Mar. 2018 * @WDT_vect watchdog interrupt vector *//*-----------------------------------------------------------------------------------*/ // watchdog ISR ISR(WDT_vect) { // nothing to do here, just wake up isrCounter_u16s++; } // PIN Interrupt Service ISR(PCINT0_vect) { //wake up delay(10); // debounce } /**--------------------------------------------------------------------------------------- * @brief active la pin avec Ds18B20 / émetteur / condensateur, attend la charge tout en surveillant les switchs * @author Seb * @date 22. Apr. 2020 * @return rien *//*-----------------------------------------------------------------------------------*/ void EnableTX433() { pinMode(ENABLE_PIN, OUTPUT); digitalWrite(ENABLE_PIN, HIGH); // alimente émetteur 433 MHz unsigned long startedAt = millis(); while ( (millis() - startedAt) < 1000 ) { // délai pour laisser charger le condensateur CheckStatusA(); // surveille switch A pendant ce temps CheckStatusB(); // surveille switch B pendant ce temps delay(10); } } /**--------------------------------------------------------------------------------------- * @brief vérifie si le switch A a changé * @author Seb * @date 22. Apr. 2020 * @return rien *//*-----------------------------------------------------------------------------------*/ void CheckStatusA() { status_A = (digitalRead(SWITCH_A_PIN)==1 ? 1 : 0); if (status_A != oldStatus_A) { send_switch_A = 1; oldStatus_A = status_A; if (status_A) { Total_A++; if (Total_A >= 100) Total_A = 0; // température max = 140°C, on retourne à zéro avant } counter_ds18b20_u16s = 0; // reporte l'envoi régulier de la température counter_ab_u16s = 0; // reporte l'envoi régulier des switchs } } /**--------------------------------------------------------------------------------------- * @brief vérifie si le switch B a changé * @author Seb * @date 22. Apr. 2020 * @return rien *//*-----------------------------------------------------------------------------------*/ void CheckStatusB() { status_B = (digitalRead(SWITCH_B_PIN)==1 ? 1 : 0); if (status_B != oldStatus_B) { send_switch_B = 1; oldStatus_B = status_B; if (status_B) { Total_B++; if (Total_B >= 100) Total_B = 0; // température max = 140°C, on retourne à zéro avant } counter_ds18b20_u16s = 0; // reporte l'envoi régulier de la température counter_ab_u16s = 0; // reporte l'envoi régulier des switchs } }