/* ---------------------------------------------------------------------------- * Source lndk_avr011.c * Programme pour le micro-controleur ATMEGA8535L * Mesures d'une station solaire, commandes de délestage des charges * * Copyright (c) 2007-2008, Marc Dilasser, Le Net du Kermeur * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1 Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2 Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3 Neither the name of the copyright holders nor the names of * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * History : * Original : Marc Dilasser, Le Net du Kermeur, Novembre 2007 * Octobre 2008 : * LNDK_AVR008 : date dernier déclenchement du watchdog, * réintégration du test de la led, reset software, * diverses optimisations de taille ... * Novembre 2008 : * LNDK_AVR010 : Prise des mesures sur l'interruption ADC_NOISE */ #include #include #include #include #include #include #include #include #include "version.h" #include "lndk_avr011.h" // #define LNDK_VERSION "LNDK_AVR011 b.002 22/10/2008" #define TRUE (1) #define FALSE (0) #define SPACE 0x20 #define FREQ_CPU 8000000 // Calcul du diviseur : DIVISEUR = (((FREQ_CPU / (BAUDRATE * 16))) - 1) // Valeur pour 19200 #define BAUDRATE 19200 #define DIVISEUR 25 // Valeur pour 9600 // #define BAUDRATE 9600 // #define DIVISEUR 51 // Utilisation du mode ADC_NOISE_REDUCTION pour les mesures #define ADC_NOISE_REDUCTION #define MAX_LISSAGE (8) #define NB_ADC 8 // Extension Timer #define EXTENSION_TIMER // La fonction TESTLED dépend de l'EXTENSION_TIMER, // rétablie dans cette version #define TESTLED // Débuggage de la mesure ADC #define DEBUG_ADC // Reset software de l'Atmega8535, commande RESET du programme #define EXTENSION_REINIT // L'aide en ligne seulement s'il reste de la place #define AIDE_EN_LIGNE // Watchdog de reset du micro-contrôleur #define WATCHDOG #define MIN_WATCHDOG 60 #define MAX_WATCHDOG 86400 #define SendCRLF SendChar('\n') // La mesure différentielle n'est pas utilisable sur le package PDIP // de l'ATMEGA8535 (cf. page 206 du DataSheet), dommage ... // #define MESURE_DIFFERENTIELLE uint8_t ch = ' ', // Caractère dans la ligne de commande data = ' '; // Caractère sur le port série volatile int inda = 1; // Index écriture du buffer de réception int indb = 1, // Index lecture de ce meme buffer inde = 1, running = 1, debug = 1; int echo = 0; // Echo des caractères reçus #ifdef EXTENSION_TIMER // DEBUT_SIECLE=$(date -d "2000-01-01 00:00:00" "+%s") + 3600 #define DEBUT_SIECLE 946684800L #define MODE_UPTIME 0 #define MODE_DATE 1 #define MODE_LASTWATCH 2 // A tester #define POWER_SAVING // Le code pour le CRON ne passe pas sur l'ATMEGA8535, attendre l'ATMEGA128 #ifdef __AVR_ATmega128__ #define CRON #endif // Duree maximale de temporisation = 24H #define MAX_DUREE 86400L volatile uint32_t timer = 1L; // Secondes ecoulees #ifdef WATCHDOG volatile uint32_t silence = 1L; uint32_t watchdog = 1L; uint32_t lastwatch = 1L; #endif uint8_t dizieme = 1; // Dizieme de seconde #ifdef TESTLED int testled = 1, activite = 1; // Délai de clignotement (en 1/10s) si activité série #endif uint32_t offsec = 1L; // Secondes à rajouter à l'uptime pour date Unix uint32_t portbend[8] = { 1, 1, 1, 1, 1, 1, 1, 1 }; uint8_t portbeta[8] = { 1, 1, 1, 1, 1, 1, 1, 1 }; int portsflg = 1; #endif // Buffer de reception du port série char bufrec[64] = " " " "; // Buffer pour ligne de commande char line[32] = " "; #ifdef WATCHDOG char cmdwatch[32] = " "; #endif #ifdef CRON #define NBCRON 4 #define MIN_CRON 30 int flgcron = 1; uint32_t datcron[NBCRON] = { 1L, 1L, 1L, 1L }; uint32_t intcron[NBCRON] = { 1L, 1L, 1L, 1L }; char cmdcron[NBCRON][32] = { " ", " ", " ", " " }; #endif int mesures[NB_ADC * MAX_LISSAGE] = { -1, -1, -1, -1, -1, -1, -1, -1}; int lissage = 5; volatile int aadc = 1; volatile uint16_t valadc = 1; int radc = 1; #ifdef AIDE_EN_LIGNE const char MsgHlp[] PROGMEM = "lndk_avr011, commandes :\n" " ?\n" " help\n" " adca 1..8\n" " adcas\n" " date [Unixtime]\n" " debug\n" " echo [on|off]\n" #ifdef TESTLED " led\n" #endif " lissage [n]\n" " modeb [NN]\n" " portb 1..8 [ON-OFF [DELAI]]\n" " portbs\n" " relais 1..4 [ON-OFF [DELAI]]\n" #ifdef EXTENSION_REINIT " reset\n" #endif " UPTime\n" " VERsion\n" " watch delai commande\n"; #else const char MsgHlp[] PROGMEM = "lndk_avr011, commandes :\n" " Voir http://www.lekermeur.net/lndkavr/\n"; #endif const char StrLndk[] PROGMEM = LNDK_VERSION; const char StrOn[] PROGMEM = "ON"; const char StrOff[] PROGMEM = "OFF"; #ifdef CRON const char StrCron[] PROGMEM = "CRON"; #endif const char StrModeB[] PROGMEM = "MODEB "; const char StrPortB[] PROGMEM = "PORTB x : "; const char StrRelais[] PROGMEM = "RELAIS "; const char StrWatch[] PROGMEM = "WATCH : "; const char StrAdcA[] PROGMEM = "ADCA x : "; const char StrLedOn[] PROGMEM = "LED ON"; const char StrDebugOn[] PROGMEM = "DEBUG ON"; const char StrLissage[] PROGMEM = "LISSAGE= "; const char StrPrompt[] PROGMEM = "-> "; const char StrVersion[] PROGMEM = "VERSION"; const char StrDieze[] PROGMEM = "###"; char MsgBuffer[40] = "Date 2008-01-01 24h 60m 60s "; // ------------------------------------------------ U S A R T _ R X _ v e c t // Gestion de l'interruption caractere recu ISR(USART_RX_vect) { data = UDR; if (data > 0) { bufrec[inda++] = data; inda &= 0x3F; #ifdef EXTENSION_TIMER #ifdef TESTLED activite = 6; #endif #endif if (echo) { UDR = data; // Si caractere RETOUR-CHARIOT, rajouter un LINE-FEED if (data == 13) { while ( !( UCSRA & (1<= 10) { timer ++; dizieme = 0; #ifdef WATCHDOG silence ++; #endif #ifdef ADC_NOISE_REDUCTION // Demande d'activation d'une mesure ADC sur ADC_NOISE_REDUCTION aadc = 1; #endif // #ifdef POWER_SAVING // if (! activite) activite = 1; // #endif } #ifdef TESTLED // Si activite en cours, ou changement de seconde, changer etat de la diode if (testled) { // Si indicateur d'activite UART, le decrementer if (activite > 0) activite--; if ((activite) || (dizieme == 0)) { PORTB ^= (1 << 0); } } #endif } // ---------------------------------------------------------- A D C _ v e c t // Traitement de l'interruption fin de conversion Analogique/Digital #ifdef ADC_NOISE_REDUCTION ISR(ADC_vect) { int ik, im; valadc = ADCL; valadc |= (ADCH << 8); im = radc * MAX_LISSAGE; // Décalage des mesures précédentes for (ik = im; ik < im + (lissage - 1); ik ++) { mesures[ik] = mesures[ik + 1]; } mesures[ik] = valadc; // Desactiver le convertisseur Analogique/Digital ADCSRA = (1 << ADPS2) | (1 << ADPS1)| (1 << ADPS0); // Désactiver la demande de mesure aadc = 0; // Est ce bien necessaire ? // sleep_disable(); } #endif #endif // ---------------------------------------------------------- S e n d C h a r int SendChar(char carac) { if (echo) { // Fin de ligne en RC/LF if (carac == '\n') { SendChar('\r'); } while ( !( UCSRA & (1< 2) { max = total = 0; min = 1024; for (ij = im; ij < (im + lissage); ij ++) { ik = mesures[ij]; total += ik; if (ik >= max) max = ik; if (ik <= min) min = ik; } val = (total - (min + max)) / (lissage - 2); } else { if (lissage == 2) val = (mesures[im] + mesures[im + 1]) / 2; else val = mesures[im]; } strcpy_P(MsgBuffer, StrAdcA); #ifdef MESURE_DIFFERENTIELLE MsgBuffer[5] = (Diff == 0) ? (Canal + 49) : (Diff + 64); #else MsgBuffer[5] = Canal + 49; #endif if (val >= 1024) { strcpy_P(MsgBuffer + 9, StrDieze); done = FALSE; } else { utoa(val, MsgBuffer + 9, 10); done = TRUE; } SendBuffer(); return(done); } #ifdef EXTENSION_TIMER // -------------------------------------------------------------- U p t i m e int Uptime(int mode) { uint32_t seconds, secdeb, duree; int year, month, jou, heu, min, sec, ij, done; // En mode Date ou Uptime, prendre le timer courant, en mode LastWatch // prendre la date du dernier déclenchement du Watchdog seconds = (mode != MODE_LASTWATCH) ? timer : lastwatch; year = 2000; secdeb = DEBUT_SIECLE; month = 1; if (mode) { // Calcul de date valide du 1/01/2000 au 28/02/2100, l'année 2100 ne // sera pas bissextile (divisible par 4 mais divisible par 100) if (offsec >= DEBUT_SIECLE) { if (mode == MODE_DATE) seconds += offsec; // Trouver l'année done = FALSE; do { duree = ((year % 4) == 0) ? (366 * 86400L) : (365 * 86400L); if ((secdeb + duree) < seconds) { secdeb += duree; year ++; } else done = TRUE; } while (! done); // Trouver le mois done = FALSE; while ( ! done) { // Mois de 31 jours duree = 31L; // Sauf Avril, Juin, Septembre, Novembre if ((month == 4) || (month == 6) || (month == 9) || (month == 11)) { duree -= 1L; } // Et Février à 28 ou 29 suivant si l'année est bissextile ou non if (month == 2) duree -= ((year % 4) == 0) ? 2L : 3L; // Traduire en nombre de secondes (86400 = 24 x 3600) duree *= 86400L; if ((secdeb + duree) < seconds) { secdeb += duree; month ++; } else done = TRUE; } jou = ((seconds - secdeb) / 86400L) + 1; seconds -= secdeb; seconds -= ((jou - 1) * 86400L); } else mode = MODE_UPTIME; } if (! mode) { jou = (seconds / 86400L); seconds -= (jou * 86400L); } heu = (seconds / 3600L); seconds -= (heu * 3600L); min = (seconds / 60L); seconds -= (min * 60L); sec = seconds; ij = 0; if (mode) { strcpy_P(MsgBuffer, (mode == MODE_DATE) ? PSTR("Date") : PSTR("Last")); ij = 4; MsgBuffer[ij++] = ' '; #ifdef ANCIEN_CODE MsgBuffer[ij++] = (year / 1000) + 48; MsgBuffer[ij++] = ((year % 1000) / 100) + 48; MsgBuffer[ij++] = ((year % 100) / 10) + 48; MsgBuffer[ij++] = (year % 10) + 48; #else utoa(year, MsgBuffer + 5, 10); ij = 9; #endif MsgBuffer[ij++] = '-'; MsgBuffer[ij++] = (month / 10) + 48; MsgBuffer[ij++] = (month % 10) + 48; MsgBuffer[ij++] = '-'; MsgBuffer[ij++] = (jou / 10) + 48; MsgBuffer[ij++] = (jou % 10) + 48; } else { strcpy_P(MsgBuffer, PSTR("Uptime")); ij = 6; MsgBuffer[ij++] = ' '; if (jou > 0) { if (jou >= 1000) MsgBuffer[ij++] = ((jou / 1000) + 48); if (jou >= 100) MsgBuffer[ij++] = (((jou % 1000) / 100) + 48); if (jou >= 10) MsgBuffer[ij++] = (((jou % 100) / 10) + 48); MsgBuffer[ij++] = ((jou % 10) + 48); MsgBuffer[ij++] = 'j'; } } MsgBuffer[ij++] = ' '; if (heu >= 10) MsgBuffer[ij++] = ((heu / 10) + 48); MsgBuffer[ij++] = ((heu % 10) + 48); MsgBuffer[ij++] = 'h'; MsgBuffer[ij++] = ' '; MsgBuffer[ij++] = ((min / 10) + 48); MsgBuffer[ij++] = ((min % 10) + 48); MsgBuffer[ij++] = 'm'; MsgBuffer[ij++] = ' '; MsgBuffer[ij++] = ((sec / 10) + 48); MsgBuffer[ij++] = ((sec % 10) + 48); MsgBuffer[ij++] = 's'; MsgBuffer[ij] = '\0'; SendBuffer(); return TRUE; } #endif // ------------------------------------------------------ P o r t B S t a t e int PortBState(int pinoche, int Affiche) { int state; // Lecture de la valeur en cours state = FALSE; if (~ PINB & (1 << pinoche)) { state = TRUE; } if (Affiche) { strcpy_P(MsgBuffer, StrPortB); MsgBuffer[6] = pinoche + 49; MsgBuffer[10] = state + 48; MsgBuffer[11] = '\0'; SendBuffer(); } return(state); } // ---------------------------------------------- T o u t e s _ M e s u r e s int Toutes_Mesures(void) { int ij, done; done = TRUE; for (ij = 0; ij < 8; ij ++) { done &= Mesure(ij, 0); } return(done); } // -------------------------------------------------------------- P r o m p t int Prompt(void) { SendString_P(StrPrompt); return TRUE; } // ------------------------------------------------------------ T r a i t 4 0 void Trait40(void) { int ij; SendCRLF; for (ij = 0; ij < 40; ij++) SendChar('-'); SendCRLF; } // ---------------------------------------------------------- B a n n i e r e void Banniere(void) { Trait40(); SendString_P(StrLndk); Trait40(); Prompt(); } // ------------------------------------------------------ T r a i t e m e n t int Traitement_Ligne(void) { int ij, ik, ik1, ik2, pina, done; #ifdef MESURE_DIFFERENTIELLE int pinb; #endif #ifdef EXTENSION_TIMER uint32_t u32tmp, duree; #endif // Nettoyer les blancs de fin while ((line[inde] == ' ') && (inde > 0)) { inde--; line[inde] = 0; } if (debug) { SendString(line); SendCRLF; } done = FALSE; // Ligne de moins de 3 caractères est invalide if (inde >= 3) { // Switcher sur le premier caractère pour éviter // de multiplier les comparaisons de chaines ch = line[0]; switch (ch) { case 'A' : if (inde == 5) { if (! strcmp_P(line, PSTR("ADCAS"))) { done = Toutes_Mesures(); } } if (inde == 6) { if (! strncmp_P(line, StrAdcA, 5)) { // Numero de pinoche de 1 a 8 ik = line[5] - 48; if ((ik >= 1) && (ik <= 8)) { done = Mesure(ik - 1, 0); } } } break; #ifdef CRON case 'C' : if (! strcmp_P(line, StrCron)) { if ((inde == 5) && (line[4] == 'S')) { // Rappel des commandes crons en cours for (ij = 0; ij < NBCRON; ij++) { if (datcron[ij] > 0L) { SendString(cmdcron[ij]); SendCRLF; } } done = TRUE; } else { if ((line[4] == ' ') && (line[6] == ' ')) { ik = line[5] - 49; if ((ik >= 0) && (ik < NBCRON)) { ij = 7; u32tmp = 0L; while ((line[ij] >= '0') && (line[ij] <='9')) { u32tmp = (10 * u32tmp) + (line[ij] - 48); ij ++; } if ( (u32tmp >= timer) && (line[ij] == ' ')) { ij ++; duree = 0L; while ((line[ij] >= '0') && (line[ij] <='9')) { duree = (10 * duree) + (line[ij] - 48); ij ++; } if ( (duree >= 30) && (line[ij] == ' ')) { ik1 = 0; strcpy_P(MsgBuffer, StrCron); MsgBuffer[4] = ' '; MsgBuffer[5] = ik + 49; MsgBuffer[6] = ' '; // Copier la commande while (line[ij] >= SPACE) { cmdcron[ik][ik1] = line[ij]; MsgBuffer[ik1 + 8] = line[ij]; ij++; ik1++; } cmdcron[ik][ik1] = '\0'; MsgBuffer[ik1 + 8] = '\0'; datcron[ik] = u32tmp; intcron[ik] = duree; SendBuffer(); done = TRUE; } } } } } } break; #endif case 'D' : if ( (inde <= 5) && (! strncmp_P(line, StrDebugOn, (inde < 5) ? inde : 5))) { debug = (! debug); ij = 0; strcpy_P(MsgBuffer, StrDebugOn); if (! debug) strcpy_P(MsgBuffer + 6, StrOff); SendBuffer(); done = TRUE; } #ifdef EXTENSION_TIMER else { if (inde >= 4) { if (! strncmp_P(line, PSTR("DATE "), 4)) { if (inde == 4) { Uptime(MODE_DATE); if (lastwatch != 0L) Uptime(MODE_LASTWATCH); done = TRUE; } else { // Mise à l'heure du timer // u32tmp = atol(line + 5); u32tmp = strtoul(line + 5, NULL, 10); // Pas de base inférieure a 2000-01-01 00h00m00s UTC if (u32tmp >= DEBUT_SIECLE) { offsec = u32tmp - timer; done = TRUE; } } } #ifdef MESURE_DIFFERENTIELLE else { // Mesure différentielle de tension, amplification x 10 if (! strcmp_P(line, PSTR("DIFF ")) && (line[4] == ' ') && (line[6] == ' ') && (line[8] == '\0')) { // Numero de pinoche de 1 a 8 pina = line[5] - 48; pinb = line[7] - 48; if ( ((pina == 1) && (pinb == 2)) || ((pina == 3) && (pinb == 4))) { done = Mesure(0, (pinb / 2)); } } } #endif } } #endif break; case 'E' : if (inde >= 7) { if (! strncmp_P(line, PSTR("ECHO "), 5)) { if (! strcmp_P(line + 5, StrOff)) { echo = 0; done = TRUE; } else { if (! strcmp_P(line + 5, StrOn)) { echo = 1; done = TRUE; } } } } break; case 'H' : if (! strcmp_P(line, PSTR("HELP"))) { Help(); done = TRUE; } break; case 'L' : #ifdef TESTLED if ((inde == 3) && (! strncmp_P(line, StrLedOn, 3))) { testled = (! testled); // ij = 0; strcpy_P(MsgBuffer, StrLedOn); if (! testled) { strcpy_P(MsgBuffer + 4, StrOff); PORTB |= (1 << 0); } SendBuffer(); done = TRUE; } #endif if ((inde >= 7) && (! strncmp_P(line, StrLissage, 7))) { if (inde == 7) { // Simple interrogation de la valeur strcpy_P(MsgBuffer, StrLissage); MsgBuffer[8] = 48 + lissage; SendBuffer(); done = TRUE; } else { if ((inde == 9) && (line[7] == ' ')) { ik = line[8] - 48; if ((ik >= 1) && (ik <= MAX_LISSAGE)) { lissage = ik; done = TRUE; } } } } break; case 'M' : if (! strncmp_P(line, StrModeB, 5)) { if (inde == 5) { // ik = DDRB & 0x0F; ik = DDRB; ik1 = ik >> 4; ik2 = ik & 0x0F; strcpy_P(MsgBuffer, StrModeB); ij = 6; // Valeur affichée en hexa MsgBuffer[ij++] = '0'; MsgBuffer[ij++] = 'x'; MsgBuffer[ij++] = (ik1 >= 10) ? (ik1 + 55) : (ik1 + 48); MsgBuffer[ij++] = (ik2 >= 10) ? (ik2 + 55) : (ik2 + 48); MsgBuffer[ij] = '\0'; SendBuffer(); done = TRUE; } else { if ( (inde >= 7) && (inde <= 8) && (line[5] == ' ') && ((line[6] >= '0') && (line[6] <= '9'))) { ik = line[6] - 48; if (inde == 8) ik = (10 * ik) + (line[7] - 48); if ((ik >= 0) && (ik <= 15)) { DDRB = (0x0F << 4) | ik; done = TRUE; } } } } break; case 'P' : // Commandes sur les ports I/O if (inde >= 7) { if (! strncmp_P(line, StrPortB, 6)) { // Numero de pinoche de 1 a 8 ik = line[6] - 48; if ((ik >= 1) && (ik <= 8)) { pina = ik - 1; if (inde == 7) { PortBState(pina, TRUE); done = TRUE; } else { if (inde >= 10) { if ((line[7] == ' ') && (line[8] == 'O')) { // Commandes a ON if (line[9] == 'N') { // Simple commande a ON if (line[10] == '\0') { PORTB &= (~(1 << pina)); done = TRUE; } #ifdef EXTENSION_TIMER // Commande a ON avec duree if (line[10] == ' ') { // duree = atol(line + 11); duree = strtoul(line + 11, NULL, 10); if ((duree > 0L) && (duree <= MAX_DUREE)) { portbeta[pina] = PortBState(pina, FALSE); portbend[pina] = timer + duree; portsflg |= (1 << pina); PORTB &= (~(1 << pina)); done = TRUE; } } #endif } if ((line[9] == 'F') && (line[10] == 'F')) { // Simple commande a OFF if (line[11] == '\0') { PORTB |= (1 << pina); done = TRUE; } #ifdef EXTENSION_TIMER // Commande a OFF avec duree if (line[11] == ' ') { // duree = atol(line + 11); duree = strtoul(line + 11, NULL, 10); if ((duree > 0L) && (duree <= MAX_DUREE)) { portbeta[pina] = PortBState(pina, FALSE); portbend[pina] = timer + duree; portsflg |= (1 << pina); PORTB |= (1 << pina); done = TRUE; } } #endif } } } } } // else { // Numero de pinoche incorrecte // Syntaxe(); // } } } else { if (! strcmp_P(line, PSTR("PORTBS"))) { for (pina = 0; pina < 8; pina ++) PortBState(pina, TRUE); done = TRUE; } } break; case 'R' : if (inde >= 11) { // Commande RELAIS Numero ON|OFF [DUREE] // Comme la commande PORTB mais a ON pour relais monte // et les ports 5 a 8 correspondent aux relais 1 a 4 if (! strncmp_P(line, StrRelais, 7)) { // Numero de relais de 1 a 4 pina = (line[7] - 48); if ((pina >= 1) && (pina <= 4)) { // Les relais sont cables sur PORTB 5 a 8 pina += 3; // Commandes a ON if (line[10] == 'N') { // Simple commande a ON if (line[11] == '\0') { PORTB |= (1 << pina); done = TRUE; } #ifdef EXTENSION_TIMER // Commande a ON avec duree if (line[11] == ' ') { // duree = atol(line + 11); duree = strtoul(line + 11, NULL, 10); if ((duree > 0L) && (duree <= MAX_DUREE)) { portbeta[pina] = PortBState(pina, FALSE); portbend[pina] = timer + duree; portsflg |= (1 << pina); PORTB |= (1 << pina); done = TRUE; } } } // Fin de commande ON #endif if ((line[10] == 'F') && (line[11] == 'F')) { // Simple commande a OFF if (line[12] == '\0') { PORTB &= (~(1 << pina)); done = TRUE; } #ifdef EXTENSION_TIMER // Commande a OFF avec duree if (line[12] == ' ') { // duree = atol(line + 12); duree = strtoul(line + 12, NULL, 10); if ((duree > 0L) && (duree <= MAX_DUREE)) { portbeta[pina] = PortBState(pina, FALSE); portbend[pina] = timer + duree; portsflg |= (1 << pina); PORTB &= (~(1 << pina)); done = TRUE; } } #endif } // Fin de commande OFF } // Fin numero de relais de 1 a 4 } // Fin de commande RELAIS } // Fin de longueur de commande >= 11 #ifdef EXTENSION_REINIT if (! strncmp_P(line, PSTR("RESET"), inde)) { // Software reset cli(); wdt_enable(WDTO_15MS); while (1) { }; } #endif break; #ifdef EXTENSION_TIMER case 'U' : if (! strncmp_P(line, PSTR("UPTIME"), inde)) { Uptime(MODE_UPTIME); done = TRUE; } break; #endif case 'V' : if (! strncmp_P(line, StrVersion, inde)) { SendString_P(StrLndk); SendCRLF; done = TRUE; } break; #ifdef WATCHDOG case 'W' : if (inde >= 5) { if (! strncmp_P(line, StrWatch, 5)) { if (inde == 5) { // Rappel de la commande watch en cours. if (watchdog > 0L) { SendString(cmdwatch); SendCRLF; } done = TRUE; } else { if (line[5] == ' ') { if (! strcmp_P(line + 6, StrOff)) { watchdog = 0L; cmdwatch[0] = '\0'; done = TRUE; } else { ij = 6; u32tmp = 0L; while ((line[ij] >= '0') && (line[ij] <='9')) { u32tmp = (10 * u32tmp) + (line[ij] - 48); ij ++; } if ( (u32tmp >= MIN_WATCHDOG) && (u32tmp <= MAX_WATCHDOG) && (line[ij] == ' ') && ( (! strncmp_P (line + (ij + 1), StrPortB, 6)) || (! strncmp_P(line + (ij + 1), StrRelais, 7)))) { ij ++; ik = 0; strcpy_P(MsgBuffer, StrWatch); // Copier la commande while (line[ij] >= SPACE) { cmdwatch[ik] = line[ij]; MsgBuffer[ik + 8] = line[ij]; ij++; ik++; } cmdwatch[ik] = '\0'; MsgBuffer[ik + 8] = '\0'; watchdog = u32tmp; SendBuffer(); done = TRUE; } } } } } } break; #endif } } else { if ((inde == 1) && (line[0] == '?')) { done = Help(); } } ij = 0; if (done) { MsgBuffer[ij++] = 'O'; MsgBuffer[ij++] = 'K'; #ifdef WATCHDOG silence = 0L; #endif } else { MsgBuffer[ij++] = 'E'; MsgBuffer[ij++] = 'R'; MsgBuffer[ij++] = 'R'; } MsgBuffer[ij] = '\0'; SendBuffer(); Prompt(); return(FALSE); } // ------------------------------------------------------ R e s e t _ L i n e void Reset_Line(void) { for (inde = 0; inde < 32; inde ++) line[inde] = '\0'; inde = 0; } // ------------------------------------------------------ I n i t _ P o r t B void Init_PortB(void) { // Sur le port B , activer les pins 5 à 8 en output (relais), // 2 à 4 en input et 1 en output si on se sert de la LED DDRB = (testled) ? 0xF1 : 0xF0; PORTB = 0xF0; } #ifdef EXTENSION_TIMER // ------------------------------------------------------ I n i t _ T i m e r void Init_Timer(void) { // Configurer le Timer en CTC mode TCCR1B |= (1 << WGM12); // Activation de l'interrupt CTC TIMSK |= (1 << OCIE1A); // Pour une interruption toutes les 1/10e seconde OCR1A = 12500; // Timer a Frequence CPU / 64 TCCR1B |= ((1 << CS10) | (1 << CS11)); sei(); } #endif // -------------------------------------------------------- I n i t _ C o m m void Init_Comm(int diviseur) { // Set Baud rate - Cast High byte UBRRH = (uint8_t)(diviseur >> 8); // Set Baud rate - Cast Low byte UBRRL = (uint8_t) diviseur; // Enable Receiver & Transmitter UCSRB = (1<= 97) && (ch <= 122)) ch -= 32; if (debug) { if (ch < 0x20) { if ((ch != 13) && (ch != 8)) { line[inde++] = '^'; ch +=64; } } } } if ((ch > 0x20) && (ch < 127)) { line[inde++] = ch; inde %= 0x1f; } else { // Les blancs de debut de ligne sont ignores if (ch == 0x20) { if (inde) { line[inde++] = ch; inde &= 0x3f; } } else { if (ch == 13) { if (inde == 0) { Banniere(); } else { // Traiter la ligne dans le buffer Traitement_Ligne(); Reset_Line(); } } else { if (((ch == 8) || (ch == 127)) && (inde > 0)) { inde --; } } } } if (inde >= 60) { Reset_Line(); } line[inde] = 0; } #ifdef EXTENSION_TIMER // Traiter les delais en attente if (seconds != timer) { seconds = timer; if (portsflg) { for (ij = 0; ij < 8; ij ++) { if (portsflg & (1 << ij)) { if (portbend[ij] <= seconds) { if (portbeta[ij]) PORTB &= (~(1 << ij)); else PORTB |= (1 << ij); // Resetter le flag portsflg &= (~(1 << ij)); } } } } #ifdef WATCHDOG if (watchdog > 0L) { if (silence >= watchdog) { inde = strlen(cmdwatch); strcpy(line, cmdwatch); Traitement_Ligne(); Reset_Line(); // Conserver la date du dernier declenchement if (offsec >= DEBUT_SIECLE) lastwatch = offsec + timer; } } #endif #ifdef CRON if (flgcron) { for (ij = 0; ij < NBCRON; ij ++) { if (datcron[ij] > DEBUT_SIECLE) { if (seconds > datcron[ij]) { inde = strlen(cmdcron[ij]); strcpy(line, cmdcron[ij]); Traitement_Ligne(); Reset_Line(); if (intcron[ij] >= MIN_CRON) datcron[ij] += intcron[ij]; else { datcron[ij] = 0L; flgcron &= (1 << ij); } } } } } #endif } if (aadc == 1) { // Rang du port ADC a mesurer radc++; radc %= NB_ADC; #ifdef ADC_NOISE_REDUCTION ADCSRA = (1 << ADEN) | (1 << ADPS2) | (1 << ADPS1)| (1 << ADPS0); // Choix du Canal et de la reference de tension // ADMUX = 0xE0 | Canal; ADMUX = (1 << REFS1) | (1 << REFS0) | radc; ADCSRA |= (1 << ADIE); // Activation de la conversion par ADC Noise reduction MCUCR = (MCUCR & 0x0F) | (1 << SM0); // set_sleep_mode(SM0); MCUCR |= (1 << SE); // sleep_enable(); sleep_cpu(); // Séquence exécutée au réveil de la CPU après la fin de // l'interruption ADC_NOISE_REDUCTION, en mode DEBUG sortie // de la dernière mesure, soit une mesure par seconde. sleep_disable(); #ifdef DEBUG_ADC if (debug) { // Tester si l'interruption a été traitée if (! aadc) { strcpy_P(MsgBuffer, StrAdcA); MsgBuffer[5] = radc + 49; utoa(valadc, MsgBuffer + 9, 10); SendBuffer(); } } #endif #else ADCSRA = (1 << ADEN) | (1 << ADPS2) | (1 << ADPS1)| (1 << ADPS0); // Choix du Canal et de la reference de tension // ADMUX = 0xE0 | Canal; ADMUX = (1 << REFS1) | (1 << REFS0) | radc; // Activer la conversion ADCSRA = ADCSRA | ( 1 << ADSC); // Attendre le bit ADIF while (! (ADCSRA & (1 << ADIF))); val = ADCL; val |= (ADCH << 8); mesures[radc] = (val + mesures[radc]) / 2; // Desactiver le convertisseur Analogique/Digital ADCSRA = (1 << ADPS2) | (1 << ADPS1)| (1 << ADPS0); // Plus de port a mesurer aadc = 0; #endif } #ifdef POWER_SAVING #ifdef ANCIEN_CODE if (! activite) { // Mode Idle (SM0 = SM1 = SM2 = 0) MCUCR &= 0x0F; // set_sleep_enable MCUCR |= (1 << SE); // sleep_enable(); sleep_cpu(); } #else cli(); if (! activite) { set_sleep_mode(SLEEP_MODE_IDLE); sleep_enable(); sei(); sleep_cpu(); sleep_disable(); } sei(); #endif #endif #endif } return(0); } /* -------- End of lndk_avr011.c -------- That's All, Folks -------- */