Retour Part-2
Version arduino avec horloge RTC
Dans cette article nous allons voir comment utiliser une horloge RTC. L'idée est de fermer et d'ouvrir la porte du poulailler selon un horaire défini par le microcontrôleur. On a besoin d'une horloge (Real Time Clock) DS1307 sur batterie interne, d'une carte de commande de moteur CC avec un bridge type DRV8835 par exemple et de 2 alimentations : une pour le microcontrôleur et l'autre pour le moteur.
La mise en oeuvre d'une horloge RTC sur bus I2C se fait en connectant la sortie 'sda' sur le pin 4 et 'sdl' sur le pin 5 de l'arduino. Pour le branchement des autres éléments je vous invite à consulter la partie 2.
Schéma de câblage :
Réglage de l'heure :
Lors de l'achat de votre RTC, vous voudrez certainement régler l'heure, inutile de faire un article de plus vous trouverez toutes les infos ici ! Voici le lien vers la librairie RTCLib nécessaire pour utiliser l'horloge.
Dans mon cas j'ai opté pour conserver l'heure d'hiver.
L'étape suivante est de paramétrer les tableaux d'ouverture et de fermeture dans le code du microcontrôleur (ces tableaux seront utilisés dans le sketch de l'arduino un peu plus loin) :
Après une petite recherche sur internet, vous trouverez certainement les horaires de lever et de coucher du soleil de votre région.
http://ecole.onsevoitdemainalors.org/IMG/pdf/41_Tableau_02.pdf
Voici les tableaux que nous allons utiliser :
////////////////////////// JANV FEV Mars Avr Mai Jun
int LeveSoleilHeure[12]= {07,06, 06,06, 05,05, 04,04, 03,03, 03,03 };
int LeveSoleilMinute[12]= {00,50, 40,20, 40,00, 30,00, 45,15, 05,05 };
int CoucheSoleilHeure[12]= {18,18, 19,19, 19,20, 21,21, 21,22, 22,22 };
int CoucheSoleilMinute[12]={15,45, 00,30, 45,35, 00,25, 45,05, 20,25 };
Observons les 2 tableaux suivants: LeveSoleilHeure[12] ,LeveSoleilMinute[12].
Ils représentent une demi année, pour faire l'année complète on reprends le tableau à l'envers, ainsi juillet=juin, aout=mai etc... il y a un tableau pour les heures et un autre pour les minutes. Il y a 2 heures de défini par mois par exemple pour le mois de janvier, du [1-14] l'ouverture est programmé à 07h00 et du [15-31] janvier l'ouverture se fait à 06h50 heure d'hiver.
Remarques : Pour économiser de l’énergie, je coupe l'alimentation de la carte de commande du moteur (pin D3), idem pour l'horloge (pin D2, elle passera automatiquement sur pile de sauvegarde).
Les conditions initiales :
l'arduino doit-être branché de jour et la porte du poulailler est fermée.
Voici le code complet:
/*
Electronic 77
Version 3.0 du 09/01/2014
L9110 or DRV8835 motor driver controlling
- 1 small DC motors
- RTC DS1307
*/
#include <Wire.h>
#include "RTClib.h"
#include <avr/sleep.h>
// This library contains functions to set various low-power
// states for the ATmega328
// This variable is made volatile because it is changed inside
// an interrupt function
volatile int sleep_count = 0; // Keep track of how many sleep
// cycles have been completed.
const int interval = 5; // Interval in minutes between waking
// and doing tasks.
const int sleep_total = (interval*60)/8; // Approximate number
// of sleep cycles needed before the interval defined above
// elapses. Not that this does integer math.
/*
SCHEMA Utilisation d'un moteur CC
pin IA1 || LOW || High
pin IB1 || HIGH || Low
Motor || backward || forward
PWM: 3, 5, 6, 9, 10, and 11. Provide 8-bit PWM output with the analogWrite() function.
*/
const int IA1 = 9; // DIGITAL PIN 8 Bits
const int IB1 = 10; // DIGITAL PIN 8 Bits
const int TpsMontee=1200; // réglage du temps de montée
const int TpsDescente=880; // réglage du temps de descente
/*MODULE RTC SPARK FUN BOB 099
DS 1307 Communication I2C
Récupération de l'heure via I2C sur les ports 4 et 5 analogique de l'arduino NANO
*/
// RTC
RTC_DS1307 RTC;
int AlimentationRTC=3;
//Carte Brighe Commande
int ALimentationCMD=2;
//POULAILLER
boolean FlagOpen=false; //porte
//Heure Hiver
//http://ecole.onsevoitdemainalors.org/IMG/pdf/41_Tableau_02.pdf
//matin retire 1h45
// soir ajoute 1h30
////////////////////////// JANV FEV Mars Avr Mai Jun
int LeveSoleilHeure[12]= {07,06, 06,06, 05,05, 04,04, 03,03, 03,03 };
int LeveSoleilMinute[12]= {00,50, 40,20, 40,00, 30,00, 45,15, 05,05 };
int CoucheSoleilHeure[12]= {18,18, 19,19, 19,20, 21,21, 21,22, 22,22 };
int CoucheSoleilMinute[12]={15,45, 00,30, 45,35, 00,25, 45,05, 20,25 };
void setup(void) {
//Commande du moteur cc via le L9110H
pinMode(IA1, OUTPUT); // set pin to output
pinMode(IB1, OUTPUT); // set pin to output
// au branchement lance l'ouverture
// COndition initiales :
// - faire jour
//- Porte poulailler fermée
stop();
// Carte de commande des moteurs switch alim pour economie d'nrj
pinMode(ALimentationCMD, OUTPUT);
digitalWrite(ALimentationCMD, LOW);
pinMode(AlimentationRTC, OUTPUT);
digitalWrite(AlimentationRTC, LOW);
Wire.begin();
RTC.begin();;
//Serial.begin(57600);
watchdogOn(); // Turn on the watch dog timer.
// The following saves some extra power by disabling some
// peripherals I am not using.
// Disable the ADC by setting the ADEN bit (bit 7) to zero.
ADCSRA = ADCSRA & B01111111;
// Disable the analog comparator by setting the ACD bit
// (bit 7) to one.
ACSR = B10000000;
// Disable digital input buffers on all analog input pins
// by setting bits 0-5 to one.
DIDR0 = DIDR0 | B00111111;
//Serial.print("FIN init");
//Serial.println();
}
void loop(void) {
goToSleep(); // ATmega328 goes to sleep for about 8 seconds
// and continues to execute code when it wakes up
if (sleep_count == sleep_total) {
// CODE TO BE EXECUTED PERIODICALLY
digitalWrite(AlimentationRTC, HIGH);
delay(500);
DateTime now = RTC.now();
digitalWrite(AlimentationRTC, LOW);
//Les poules sont -elles levées
int index= getIndex(now);
if (FlagOpen==false && canOpen(now,index))
{
//Ouvre
OpenPorte();
FlagOpen=true;
}
if (FlagOpen && canClose(now,index))
{
//Ferme
ClosePorte();
FlagOpen=false;
}
//Serial.print(now.year(), DEC);
//Serial.print('/');
//Serial.print(now.month(), DEC);
//Serial.print('/');
//Serial.print(now.day(), DEC);
//Serial.print(' ');
//Serial.print(now.hour(), DEC);
//Serial.print(':');
//Serial.print(now.minute(), DEC);
//Serial.print(':');
//Serial.print(now.second(), DEC);
//Serial.println();
delay(5000);
sleep_count = 0;
}
}
void goToSleep()
{
// The ATmega328 has five different sleep states.
// See the ATmega 328 datasheet for more information.
// SLEEP_MODE_IDLE -the least power savings
// SLEEP_MODE_ADC
// SLEEP_MODE_PWR_SAVE
// SLEEP_MODE_STANDBY
// SLEEP_MODE_PWR_DOWN -the most power savings
// I am using the deepest sleep mode from which a
// watchdog timer interrupt can wake the ATMega328
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // Set sleep mode.
sleep_enable(); // Enable sleep mode.
sleep_mode(); // Enter sleep mode.
// After waking from watchdog interrupt the code continues
// to execute from this point.
sleep_disable(); // Disable sleep mode after waking.
}
void watchdogOn() {
// Clear the reset flag, the WDRF bit (bit 3) of MCUSR.
MCUSR = MCUSR & B11110111;
// Set the WDCE bit (bit 4) and the WDE bit (bit 3)
// of WDTCSR. The WDCE bit must be set in order to
// change WDE or the watchdog prescalers. Setting the
// WDCE bit will allow updtaes to the prescalers and
// WDE for 4 clock cycles then it will be reset by
// hardware.
WDTCSR = WDTCSR | B00011000;
// Set the watchdog timeout prescaler value to 1024 K
// which will yeild a time-out interval of about 8.0 s.
WDTCSR = B00100001;
// Enable the watchdog timer interupt.
WDTCSR = WDTCSR | B01000000;
MCUSR = MCUSR & B11110111;
}
ISR(WDT_vect)
{
sleep_count ++; // keep track of how many sleep cycles
// have been completed.
}
///////////////////////////////////////////////////////////////////////
//////: GESTION POULIAILER
///////////////////////////////////////////////////////////////////////
int getIndex(DateTime t){
int Index=t.month();
if (t.month()>6)
{
Index=13-t.month();
Index=(Index-1)*2;
if( t.day()<15)
Index++;
}
else
{
Index=(Index-1)*2;
if( t.day()>15)
Index++;
}
//Serial.print("Index ");
//Serial.print(Index, DEC);
//Serial.println();
return Index;
}
boolean canOpen(DateTime t,int index)
{
if (t.hour()<=13 && (t.hour()== LeveSoleilHeure[index] && t.minute()>= LeveSoleilMinute[index] || t.hour()> LeveSoleilHeure[index]))
return true;
else
return false;
}
boolean canClose(DateTime t,int index){
if (t.hour()<=23 && (t.hour()== CoucheSoleilHeure[index] && t.minute()>= CoucheSoleilMinute[index] || t.hour()> CoucheSoleilHeure[index]))
return true;
else
return false;
}
void SetALimentationCMD(boolean isAlimente)
{
if (isAlimente)
{
digitalWrite(ALimentationCMD, HIGH);
delay(1000);
}
else
digitalWrite(ALimentationCMD, LOW);
}
void ClosePorte()
{
SetALimentationCMD(true);
//Serial.print("Fermeture de la porte\n");
backward();
delay(TpsDescente);
stop();
SetALimentationCMD(false);
}
void OpenPorte()
{
SetALimentationCMD(true);
//Serial.print("Ouverture de la porte\n");
forward();
delay(TpsMontee);
stop();
SetALimentationCMD(false);
}
void stop(){
digitalWrite(IA1, LOW);
digitalWrite(IB1, LOW);
delay(1000);
}
void backward()
{
digitalWrite(IA1, LOW);
digitalWrite(IB1, HIGH);
}
void forward()
{
digitalWrite(IA1, HIGH);
digitalWrite(IB1, LOW);
}
////////////////////////////////////////////////////////////////////////
Quel est l'avantage d'utiliser une horloge par rapport à un capteur crépusculaire ?
L'horloge est un système plus robuste, il ne souffre pas d'une mauvaise détection du capteur (feuille sur le capteur, etc... ), pas de rebond de détection.
Cependant la consommation comme le montage précédent ne permet pas de tenir la semaine. Malgré une mise en veille de l'arduino toute les 8 secondes.
C'est pourquoi dans la 4ème partie nous allons utiliser une horloge RTC DS3231 qui à l'avantage d'avoir un mode alarme pour mettre en veille prolongée le microcontrôleur et en plus, on va
changer de microcontrôleur par un moins gourmand en énergie. J'ai choisi d'acheter un kit 'launchpad' de
la famille MSP430 de chez Texas Instrument.
Lien vers la partie 4