Version MSP430G2452 avec DS3231
Retour partie 3Avant de commencer cet article, juste un petit mot pour vous dire que c'est la configuration que j'ai choisie et qui tourne depuis des mois. Avant d'aller plus loin voici une photo du montage dans sa boite.
DS3231
Nous allons améliorer notre montage précédent en changeant de RTC, le composant DS3231 dispose de 2 alarmes et d'une sortie (pin3) INT/SQW. L'adressage du bus i2C est le même que pour le DS1307 (0x68). Avec l'arduino on peut utiliser la même librairie pour jouer avec. Utile pour mettre à l'heure l'horloge par exemple.
Remarques: Attention à la manipulation du processeur, les pattes sont fragiles au moment de la mise en place et du retrait. Aidez vous d'une pince à épiler à passer dessous le boitier pour le lever uniformément.
Du côté de la programmation, il existe le logiciel Energia qui est le clône d'arduino avec ces sketchs. Mais là il y a un soucis quand on s’intéresse comme moi à la consommation, on se rend compte qu'avec Energia on ne peut pas utiliser le mode veille comme on le voudrait, peut-être que cela a été changé depuis.... Alors j'ai décidé de télécharger le logiciel proposé par TI sous licence mais gratuit à condition d'avoir des projets de petites tailles ce qui est mon cas. Après avoir rempli un formulaire assez précis de l'utilisation que l'on veut en faire, on arrive enfin à télécharger "Code-composer studio 5-5'.
Le schéma :
Le montage du prototype :
Partie code :Pourquoi utiliser le MSP430G2452 ?
La nouvelle génération d'arduino devient intéressante avec la version 3.3 volts et la possibilité de mettre en veille le port série. Mais j'ai consulté des articles, des forums au sujet de la consommation d'énergie et dans ce domaine les MSP430 s'en sortent plutôt pas mal annonçant des modes veilles de quelques nano-ampères et en plus un réveil rapide. Sur le marché Texas instrument propose des LaunchPad pour débuter, par défaut dans la boite vous trouverez 2 micros-contrôleurs :- MSP430G2553
- MSP430G2452
Remarques: Attention à la manipulation du processeur, les pattes sont fragiles au moment de la mise en place et du retrait. Aidez vous d'une pince à épiler à passer dessous le boitier pour le lever uniformément.
Les changements induits ?
L'alimentation du MSP430G2452 est de 3.3v, par conséquent le bus I2C doit fonctionner en 3.3v, heureusement pour nous, le DS3231 s'en sort bien il fonctionne correctement à cette tension nous ne serons pas obligé de mettre des pull-up. Idem pour la commande moteur si vous utilisez le 'DRV8885 de chez pololu' aucun changement à faire. Plutôt des bonnes nouvelles de ce côté là.Du côté de la programmation, il existe le logiciel Energia qui est le clône d'arduino avec ces sketchs. Mais là il y a un soucis quand on s’intéresse comme moi à la consommation, on se rend compte qu'avec Energia on ne peut pas utiliser le mode veille comme on le voudrait, peut-être que cela a été changé depuis.... Alors j'ai décidé de télécharger le logiciel proposé par TI sous licence mais gratuit à condition d'avoir des projets de petites tailles ce qui est mon cas. Après avoir rempli un formulaire assez précis de l'utilisation que l'on veut en faire, on arrive enfin à télécharger "Code-composer studio 5-5'.
Les premiers pas !
Il existe des tutos divers et très bien fait sur le sujet donc je ne m'attarderai pas sur la configuration du logiciel et de la compilation du code du MSP430.Le schéma :
Remarques : l'alimentation du DS3231 est permanente, le micro-contrôleur pourrait commander l'alim, via un 4N55 et il faudrait brancher une résistance de tirage (pull-up) sur l'alarme pour fonctionner sans alimentation extérieure ce qui permettrait de gagner encore...
Le montage du prototype :
J'ai transposé le code arduino, on retrouve
les temps de descente et de montée
static const unsigned long Timeropen=15;
static const unsigned long Timerclose=12;
le tableau de réglage mois par mois.
////////////////////////////////////// JANV FEV Mars Avr Mai Jun
unsigned char LeveSoleilHeure[12]= { 7, 6, 6, 6, 5, 5, 4, 4, 4, 4, 4, 4 };
unsigned char LeveSoleilMinute[12]= { 0,50, 40,20, 40, 0, 30, 5, 5, 0, 0, 0 };
unsigned char CoucheSoleilHeure[12]= {18,18, 18,19, 19,20, 20,20, 20,20, 21,21 };
unsigned char CoucheSoleilMinute[12]={10,15, 30,00, 45,35, 0,25, 45,55, 15,35 };
Le principe est presque identique à la version Arduino.
Au démarrage la porte du poulailler doit être fermée. Lors de la mise sous tension, la porte s'ouvre (cela permet de vérifier que tout est correctement branché), puis une fois que l'alarme est programmée je mets en veille le MSP430G2452 il est réveillé par interruption sur la pin 1.4 lorsque l'alarme se déclenche. Le micro-contrôleur procède alors à l'ouverture ou fermeture selon l'heure et programme la prochaine alarme sur le DS3231 et se rendort gentiment...
La fonction arduino "delay()" est remplacée par l'utilisation du TimerA avec interruption.
J'ai utilisé et adapté la librairie I2C développé par
* Kerr D. Wong
* http://www.kerrywong.com
extrait du fichier principal "main.c"
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Commande d'un moteur pour l'ouverture et la fermeture d'un poulailler
// ELECTRONIC77
// 26/03/2014
// Matériel :
// - MSP430G2452
// - RTC DS3232 I2C
// - Carte de commande bidirectionnelle d'un moteur CC
// - 4N35 optocoupleur
// - Transistor de puissance BD233
// - Résistance 220 Ohms
// - 1 Moteur CC
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/* Branchement
* 2 alimentation VCC 3.3 et VCC2 5V
*
* Clock MSP430G2452
* SQW P1.4
* SQL P1.6
* SDA P1.7
* VCC 3.3V
* GND GND
*
* 4N35 MSP430G2452
* 1 220 Ohms P1.0
* 2 GND
* 3
* 4 BD233 patte 3
* 5 VCC2
* 6
*
* BD233
* 1 Carte de commande VCC
* 2 VCC2
* 3 4N35 4
*
* Carte de commande
* VCC BD233 1
* GND GND2
* IB1 MSP430G2452 P1.1
* IA1 MSP430G2452 P1.2
*
* MSP430G2452
* RST résistance de 47kOmhs Vcc + condo de 100nano vers GND
*
*/
#include <msp430.h>
#include "DS3231.h"
///////////////////////////////////////////////////
//Header
unsigned char getIndex(Date t);
void initCommandeMoteur();
void ouvre();
void fermeture();
void SetAlarm();
void stop();
//////////////////////////////////////////////////
static const unsigned long Timeropen=15;
static const unsigned long Timerclose=12;
//////////////////////////////////////////////////
//Heure Hiver
//http://ecole.onsevoitdemainalors.org/IMG/pdf/41_Tableau_02.pdf
//matin retire 1h45
// soir ajoute 1h30
////////////////////////////////////// JANV FEV Mars Avr Mai Jun
unsigned char LeveSoleilHeure[12]= { 7, 6, 6, 6, 5, 5, 4, 4, 4, 4, 4, 4 };
unsigned char LeveSoleilMinute[12]= { 0,50, 40,20, 40, 0, 30, 5, 5, 0, 0, 0 };
unsigned char CoucheSoleilHeure[12]= {18,18, 18,19, 19,20, 20,20, 20,20, 21,21 };
unsigned char CoucheSoleilMinute[12]={10,15, 30,00, 45,35, 0,25, 45,55, 15,35 };
/**
* Kerr D. Wong
* http://www.kerrywong.com
*
* D3231 RTC Example Using MSP430G2452
* sans pull up p1.6=SCL p1.7=sda
*/
volatile unsigned long iCompteur=0;
unsigned char isAlarmSet;
Date dt;
Date dtAlarm;
Date dtSetAlarm;
/**
* Stop the Watch Dog Timer
*/
void inline stopWatchDogTimer() {
WDTCTL = WDTPW + WDTHOLD;
}
void init()
{
stopWatchDogTimer();
/*
P1DIR = 0xFF; // All P1.x outputs
P1OUT = 0; // All P1.x reset
P2DIR = 0xFF; // All P2.x outputs
P2OUT = 0;
*/
}
void StartInterruptClock(){
P1DIR = 0x01; // P1.0 output, else input
P1OUT = 0x10; // P1.4 set, else reset
P1REN |= 0x10; // P1.4 pullup
P1IE |= 0x10; // P1.4 interrupt enabled
P1IES |= 0x10; // P1.4 High to Low Edge
P1IFG &= ~0x10; // P1.4 IFG cleared
_BIS_SR(LPM4_bits+GIE); // Enter low power mode 4 le plus bas)
}
// Port 1 interrupt service routine
#pragma vector=PORT1_VECTOR
__interrupt void Port_1(void){
turnOffAlarm(0x01);
//P1OUT ^=0x01; // P1.0 =toggle ^ XOR // POUR DEBUG
P1IFG &=~0x10; //P1.4 IFG Cleared (flag)
//Ouvre ou ferme la porte du poulailler
initCommandeMoteur();
//Tempo
unsigned char i=0;
for (i=0;i<255;i++);
if (dtAlarm.hour<12)
{
//lever
ouvre();
}
else
{
//Coucher
fermeture();
}
stop();
//Programmer la prochaine alarme
SetAlarm();
}
void SetAlarm(){
setupRTC3232();
///////////////////////////////////
turnOffAlarm(0x01);
checkIfAlarm(0x01);
//////////////////////////////////
//setDate3232(); // ToDO A virer c'est pour le reglage de l'heure
//Lecture de l'heure
dt=getDateDS3232();
/*unsigned char c=dt.second;
c=dt.minute;
c=dt.hour ;
c=dt.dayOfWeek;
c=dt.dayOfMonth;
c=dt.month ;
c=dt.year ;*/
//recherche l'index de la date d'alarme dans la matrice
unsigned char index=getIndex(dt);
signed char Lever=CompareTimeHM(dt,LeveSoleilHeure[index],LeveSoleilMinute[index]);
signed char Coucher=CompareTimeHM(dt,CoucheSoleilHeure[index],CoucheSoleilMinute[index]);
if (Lever==0){
// Si l'heure correspond à l'alarme du lever alors on programme l'alarme du couche
dtAlarm.dayOfWeek=dt.dayOfWeek;
dtAlarm.minute=CoucheSoleilMinute[index];
dtAlarm.hour=CoucheSoleilHeure[index];
dtAlarm.second=0;
}
else if(Coucher==0 || Coucher>0){
// Si l'heure correspond à l'alarme du coucher alors on programme l'alarme du lever le lendemain
// Si L'heure est superieur alarme du coucher on programme l'alarme du lever
dtAlarm.dayOfWeek=dt.dayOfWeek+1;
if (dtAlarm.dayOfWeek>6) dtAlarm.dayOfWeek=0;
dtAlarm.minute=LeveSoleilMinute[index];
dtAlarm.hour=LeveSoleilHeure[index];
dtAlarm.second=0;
}
else if (Lever>0 && Coucher<0)
{
//On entre le lever et le coucher (par exemple 7h00 vers 19h00) On programme le coucher
dtAlarm.dayOfWeek=dt.dayOfWeek;
dtAlarm.minute=CoucheSoleilMinute[index];
dtAlarm.hour=CoucheSoleilHeure[index];
dtAlarm.second=0;
}
else if (Lever<0){
//L'heure est plus petite que le lever on programme le lever
dtAlarm.dayOfWeek=dt.dayOfWeek;
dtAlarm.minute=LeveSoleilMinute[index];
dtAlarm.hour=LeveSoleilHeure[index];
dtAlarm.second=0;
}
//RAPPEL ERRROR ATTENTION DIFFERENT unsigned char A1MH=0x52;//t.minute;
turnOnAlarm(1);
isAlarmSet=checkAlarmEnabled(1);
setA1Time(dtAlarm.dayOfWeek,dtAlarm.hour,dtAlarm.minute,dtAlarm.second,0x08,0x01,0x00,0x00); //une fois par seconde
dtSetAlarm=getA1Time();
//repete la transmission de l'alarme en cas de pbl
unsigned char i=0;
for (i=0;i<5;i++)
{
if (CompareTimeHM(dtSetAlarm,dtAlarm.hour,dtAlarm.minute)!=0)
{
setA1Time(dtAlarm.dayOfWeek,dtAlarm.hour,dtAlarm.minute,dtAlarm.second,0x08,0x01,0x00,0x00); //une fois par seconde
dtSetAlarm=getA1Time();
}
}
}
void main(void) {
init();
// La premiere fois ouvre
// refermer à la main si nécessaire
initCommandeMoteur();
ouvre();
stop();
SetAlarm();
StartInterruptClock(); // Enter low power mode 4 le plus bas)
}
////////////////////////////////////////////////////:
///////////////DELAY /////////////////////////////:
////////////////////////////////////////////////////:
void StartInterruptTimerA(){
CCTL0 = CCIE; // CCR0 interrupt enabled
CCR0 = 50000; // 50000 SMCLK cycles
TACTL = TASSEL_2 + MC_2; // SMCLK, contmode
//_BIS_SR(LPM0_bits + GIE); // Enter LPM0 w/ interrupt
_BIS_SR( GIE); // Enter LPM0 w/ interrupt
}
// Timer A0 interrupt service routine
#pragma vector=TIMER0_A0_VECTOR
__interrupt void Timer_A (void)
{
//P1OUT ^= 0x01; // Toggle P1.0
//CCR0 += 50000; // Add Offset to CCR0
//Arrete le timer et on averti que c'est bon
TACTL = TASSEL_2 + MC_0; // Stop Le timer
CCTL0 &= ~ CCIE; // disable interrupt
}
void delay(unsigned long aDelay){
iCompteur=0;
for (iCompteur=0;iCompteur<aDelay;iCompteur++){
StartInterruptTimerA();
while(CCTL0 & CCIE)//FlagTimerA==0)
{
//P1OUT ^=0x01; // P1.0 =toggle ^ XOR // POUR DEBUG
}
}
}
///////////////////////////////////////////////////////////////////////
//////: GESTION POULAILLER
///////////////////////////////////////////////////////////////////////
unsigned char getIndex(Date t){
unsigned char Index=t.month;
if (t.month>6)
{
// on redescend dans le tableau Juillet -> decembre
Index=13-t.month;
Index=(Index-1)*2;
if( t.dayOfMonth<15)
Index++;
}
else
{
// Janvier vers Juin
Index=(Index-1)*2;
if( t.dayOfMonth>15)
Index++;
}
return Index;
}
void initCommandeMoteur()
{
// ALIMENTATION
P1DIR |= 0x01; //P1.0 output (alimentation Carte moteur)
// Commande Moteur 1
P1DIR |= 0x02; //P1.1 output
// Commande Moteur 2
P1DIR |= 0x04; //P1.2 Output
// Active l'alimentation
P1OUT |= 0x01; //set High Alimentation du moteur
}
void ouvre(){
P1OUT |= 0x02;
P1OUT &=~0x04;
delay(Timeropen);
}
void fermeture(){
P1OUT |= 0x04;
P1OUT &=~0x02;
delay(Timerclose);
}
void stop(){
//Arrete tout
P1OUT &=~0x04;
P1OUT &=~0x02;
P1OUT &=~0x01; // coupe l'alimentation du DS3231
}
Lien vers le code source complet : Commande de portillon avec MSP430 G 2452
Cette version est plus économe en énergie, environ 3mA. Si on regarde en détail on perd 1mA par le régulateur, si on dispose d'un accu 3v alors on peut le supprimer. Autre piste la carte DS3231 qui consomme 1mA avec une petite led sur la carte qui reste allumée que l'on pourrait supprimer. Pour ma part je me contente de cette version suffisamment optimisée.
Il ne reste plus qu'à l'alimenter avec un petit kit solaire (l'autonomie est alors largement suffisante > 1 mois ).
Je vais écrire un nouvel article sur la détection crépusculaire, j'ai trouvé une led crépusculaire intéressante proche de la sensibilité de l'oeil humain et des poules.
Il ne reste plus qu'à l'alimenter avec un petit kit solaire (l'autonomie est alors largement suffisante > 1 mois ).
Je vais écrire un nouvel article sur la détection crépusculaire, j'ai trouvé une led crépusculaire intéressante proche de la sensibilité de l'oeil humain et des poules.
Part 5
Bonjour,
RépondreSupprimerC'est sympa de partager votre expérience.
On a eu la même idée.
Votre système mécanique est astucieux. J'avais opté pour le même principe, mais avec des contacts fin de course.
Ayant eu pas mal de problème et pour éviter qu'un intrus réussisse à forcer la porte, j'ai opté pour une deuxième poulie et ficelle toujours tendue.
Ça fonctionne bien aussi. http://moncastel.free.fr/forum/trappePoule/
L'arduino Uno consomme 7 mA en veille, mais le pro mini peut descendre beaucoup plus bas http://forum.arduino.cc/index.php?topic=290236.0
Je vais quand même faire l'essai d'alimenter le UNo en basse tension sans passer par le régulateur pour voir demain ?
Le DS3231 me plait bien, j'en ai commandé un. On devrais pouvoir commuter directement l'alimentation de l'arduino, comme ça il ne consommerait plus rien en période de veille ;)
RépondreSupprimerDésolé pour la réponse tardive,
RépondreSupprimervotre remarque est judicieuse, un intrus avec son museau pourra facilement soulever un peu la porte pour peu que cette dernière ne soit pas descendue complétement en buté.
Concernant l'alimentation, il me semble que la broche Vin accepte jusqu' a 12 V.
Bon bricolage !
bravo, j'avais suivi votre projet arduino et comme je me questionne sur le TI msp340, fortuitement je vous ai retrouvé. Je m'amuse avec un timer de ce genre, prenant en compte aussi les calculs de lever et coucher du soleil et de la lune. J'en suis encore à Arduino, mais tout a basculé il y a quelques semainesavec la découverte de l'horloge RV1805-C3
RépondreSupprimerhttps://cdn.sparkfun.com/assets/1/8/9/e/2/RV-1805-C3.pdf
qui peut déconnecter le msp430 ou Arduino( éteint au lieu d'en veille), fonctionne avec un supercondensateur, et qui ne consomme que 22 NANOAMPERES. Bonus, 512 k de RAM . Par conséquent je revois tout mon programme. Bravo et je vais me mettre au msp340.