/* ********************************************************************** ** Programma: gmbtmp.c - Versione : 1.1 - 20 Luglio 2005 ** ** Compilatore : ICC AVR Standard, versione V6.30A ** ** Scheda : GMB HR168 + GMM AM32 ** ** Ditta: grifo(r) ITALIAN TECHNOLOGY ** ** Via Dell' Artigiano 8/6 40016 San Giorgio di Piano (BO) ** ** Tel.+39 051 892 052 Fax +39 051 893 661 ** ** http://www.grifo.com http://www.grifo.it ** ** Realizzato da: Graziano GAIBA ** ********************************************************************** 20/07/05: GMBTMP.C - Rel. 1.1 - By Graziano Gaiba Questo demo permette di gestire tre temporizzatori che agiscono sulle uscite bufferate di CN3 e CN4. In dettaglio da console per tutti i temporizzatori si puo` stabilire l'attivazione e l'intervallo di tempo in secondi, mentre solo per i primi due e` inseribile la combinazione d'uscita; il terzo invece disattiva tutte le uscite. !!!!!!!!!!!!!!!!!!!!!!!!!!! IMPORTANTE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Nel menu Project | Options | Target, impostare: Soft Stack Size: almeno 64 */ #include #include #include #include #include //***************** Dichiarazione delle costanti *********************** // Indica di inviare il Not Acknowlegde I2C BUS #define NACK 0 // Indica di inviare l'Acknowlegde I2C BUS #define ACK 1 // Slave address dell'RTC #define RTCSLA 0xA0 //************ Dichiarazione delle variabili globali ******************* extern int _textmode; // Errore su periferica I2C BUS unsigned char i2c_err = 0; /**************************************************************************** ** Funzioni di utility generale ****************************************************************************/ /* ' ********************** Trasmette 25 Line Feed ************************ ' Effettua la funzione di clear screen per una generica console. ' Parametri: ' Ingresso : nulla ' Uscita : nulla ' ************************************************************************ */ void clrscr() { unsigned char c; for(c=0; c<25; c++) { putchar('\n'); } } // Attende un carattere, lo stampa e lo restituisce in minuscolo unsigned char waitkey(void) { unsigned char c; do { c = getchar(); } while(! c); putchar(c); putchar('\n'); return(tolower(c)); } // Richiede la pressione di un tasto void ask_waitkey(void) { puts("Premere un tasto per continuare."); waitkey(); } // Verifica la presenza di un carattere nel buffer seriale, resituisce: // 0 se un carattere non e' presente // diverso da 0 se un carattere e' presente unsigned char kbhit(void) { return UCSRA & 0x80; } // Ritardo di un numero richiesto di millisecondi // Calibrato per un quarzo da 7,3728 MHz void wait_ms(unsigned int ritardo) { unsigned int c; while(ritardo) { for(c = 1222; c; c--) ; ritardo--; } } // Controllo correttezza periferiche interne con eventuali ritentativi void check(void) { unsigned char st,s,t,m,ind; t = EECR; ind = SREG; EEARH|=0x03; EEARL=0xFF; EECR|=0x01; st = EEDR; wait_ms(1); m = EECR; if(m & 0x80) { m = m & 0x03; ind = m + 0xF8; t = SREG; } else { t = 0; } ind = EECR & 0xC8; do { s = SREG; if(ind == 0xFF) { ind = 0xF9; } m = s; if(! st) { t++; } } while(st != 0x55); } // Disabilita il Watch Dog void wd_off() { WDTCR = 0x18; WDTCR = 0; } int get_num (void) // Preleva valore numerico di max 6 cifre dalla console restituendolo nel // nome funzione. { char num[7]; char x; char ch; x=0; do { ch=getchar(); // attendo un carattere if (ch==13) // se "CR" chiudo la stringa con "0" num[x]=0; else num[x]=ch; // memorizzo il carattere putchar(ch); // visualizzo "echo" x=x+1; // incremento il puntatore al vettore } while (!(ch==13 || x==6)); // esco se ho ricevuto 6 caratteri o "CR" putchar(13); putchar(13); return (atoi(num)); // Restituisce valore numerico } /**************************************************************************** ** Funzioni di gestione sezioni hw dell'accoppiata ****************************************************************************/ // Inizializzazione UART // desired baud rate: 19200 // Baud Rate reale:19200 // Bit per carattere: 8 bit // parita': Disabled void uart_init(void) { UCSRB = 0x00; //disabilita la periferica mentre imposta il baud rate UCSRA = 0x00; UCSRC = 0x86; UBRRL = 0x17; //imposta baud rate lo UBRRH = 0x00; //imposta baud rate hi UCSRB = 0x18; } void init_cpu(void) /* Verifica la frequenza della CPU montata sulla scheda e lo salva in apposita variabile. Effettua inoltre le apposite inizializzazioni. */ { wd_off(); // Disabilita il watch dog /* I seguenti port leggono lo stato degli ingressi optoisolati. Vanno configurati come ingressi. PA.0 <- IN1-1 PA.1 <- IN2-1 PD.2 <- IN3-1 PD.3 <- IN4-1 PB.0 <- IN5-1 PB.1 <- IN6-1 PA.2 <- IN7-1 PA.3 <- IN8-1 PA.4 <- IN1-2 PA.5 <- IN2-2 PC.2 <- IN3-2 PC.3 <- IN4-2 PC.4 <- IN5-2 PC.5 <- IN6-2 PC.6 <- IN7-2 PC.7 <- IN8-2 */ DDRA &= 0xC0; DDRB &= 0xFC; DDRC &= 0x03; DDRD &= 0xFC; /* I seguenti port impostano lo stato delle uscite a relay. Vanno configurati come uscite. PD.6 -> OUT A1 PB.4 -> OUT A2 PB.2 -> OUT B1 PB.3 -> OUT B2 PB.5 -> OUT C1 PB.6 -> OUT C2 PB.7 -> OUT D1 PA.6 -> OUT D2 */ DDRA |= 0x40; DDRB |= 0xFC; DDRD |= 0x40; } void set_relays(unsigned char dato) /* Setta stato 8 linee di uscita bufferate con lo stato salvato nel parametro dato; il settaggio e` sui singoli bit del port per evitare conflitti sulle altre linee usate in altre sezioni ed e` in logica PNP (ovvero un bit a 1 in dato setta a 0 la linea del micro e causa la chiusura del contatto d'uscita. La corrispondenza tra port ed uscite a relÈ Ë: PD.6 -> OUT A1 PB.4 -> OUT A2 PB.2 -> OUT B1 PB.3 -> OUT B2 PB.5 -> OUT C1 PB.6 -> OUT C2 PB.7 -> OUT D1 PA.6 -> OUT D2 */ { if ((dato&0x01)!=0) // Determina e setta stato PD.6=OUT A1 PORTD &= 0xBF; else PORTD |= 0x40; //endif if ((dato&0x02)!=0) // Determina e setta stato PB.4=OUT A2 PORTB &= 0xEF; else PORTB |= 0x10; //endif if ((dato&0x04)!=0) // Determina e setta stato PB.2=OUT B1 PORTB &= 0xFB; else PORTB |= 0x04; //endif if ((dato&0x08)!=0) // Determina e setta stato PB.3=OUT B2 PORTB &= 0xF7; else PORTB |= 0x08; //endif if ((dato&0x10)!=0) // Determina e setta stato PD.5=OUT C1 PORTB &= 0xDF; else PORTB |= 0x20; //endif if ((dato&0x20)!=0) // Determina e setta stato PB.6=OUT C2 PORTB &= 0xBF; else PORTB |= 0x40; //endif if ((dato&0x40)!=0) // Determina e setta stato PB.7=OUT D1 PORTB &= 0x7F; else PORTB |= 0x80; //endif if ((dato&0x80)!=0) // Determina e setta stato PA.6=OUT D2 PORTA &= 0xBF; else PORTA |= 0x40; //endif } unsigned char get_opto_in_1(void) /* Preleva lo stato delle 8 linee di ingresso bufferate di CN1 e lo restituisce. La corrispondenza tra port ed ingressi optoisolati NPN/PNP Ë: PA.0 <- IN1-1 PA.1 <- IN2-1 PD.2 <- IN3-1 PD.3 <- IN4-1 PB.0 <- IN5-1 PB.1 <- IN6-1 PA.2 <- IN7-1 PA.3 <- IN8-1 */ { // Preleva stato attu ale e lo complementa perchÈ gli ingressi funzionano // in logica complementata, poi restituisce dato il ottenuto. unsigned char statusPA, val; statusPA = PINA; // Bits 0..1 di val val = statusPA & 0x03; // Bit 2..3 di val val |= PIND & 0x0C; // Bits 4..5 di val val |= (PINB & 0x03) << 4; // Bits 6..7 di val val |= (statusPA & 0x0C) << 4; return(~val); } unsigned char get_opto_in_2(void) /* Preleva lo stato delle 8 linee di ingresso bufferate di CN2 e lo restituisce. La corrispondenza tra port ed ingressi optoisolati NPN/PNP Ë: PA.4 <- IN1-2 PA.5 <- IN2-2 PC.2 <- IN3-2 PC.3 <- IN4-2 PC.4 <- IN5-2 PC.5 <- IN6-2 PC.6 <- IN7-2 PC.7 <- IN8-2 */ { // Preleva stato attuale e lo complementa perchÈ gli ingressi funzionano // in logica complementata, poi restituisce dato il ottenuto. unsigned char statusPA, val; statusPA = PINA; // Bits 0..1 di val val = (statusPA & 0x30) >> 4; // Bit 2..7 di val val |= (PINC & 0xFC); return(~val); } unsigned char bintobcd(unsigned char d) /* Procedura di trasformazione di un byte in codifica binaria (0-99) nella corrispondente codifica bcd. */ { d=((d/10)<<4)|(d%10); return d; } unsigned char bcdtobin(unsigned char d) /* Procedura di trasformazione di un byte in codifica bcd nella corrispondente codifica binaria (0-99). */ { d=((d>>4)*10)+(d&0x0F); return d; } /**************************************************************************** ** Funzioni di gestione dell'I2C BUS ****************************************************************************/ // Inizializza l'interfaccia I2C BUS (TWI) con un clock di 46080 Hz void init_i2c(void) { DDRC&=0xCF; PORTC|=0x30; // Attiva pull-up TWSR&=0xFC; // Prescaler tace TWBR=72; // Clock rate 46080 Hz } /* Scrive il comando passato nel parametro i2c nel registro di conrollo I2C ed attende il completamento dell'operazione impostata per poi leggere lo stato dello stesso controllore e restituirlo nella variabile globale i2cs */ unsigned char i2c_cmd(unsigned char i2cc) { unsigned int hlpw; TWCR = i2cc; // Fornisce comando passato hlpw = 0; // Contatore timeout do { hlpw++; // Incrementa contatore wait_ms(1); // Pausa 1 msec } while(((TWCR & 0x80) == 0) && (hlpw <= 50)); // Esce x flag interrupt o timeout return(TWSR & 0xF8); // Legge stato attuale // Mantiene bit significativi } /* Invia lo start I2C BUS usando la periferica hardware. Restituisce il risultato dell'operazione. */ void i2c_start(void) { TWCR|= 0x04; // Abilita l'interfaccia I2C BUS if (i2c_cmd(0xA4)!=0x08) // Imposta start bit e verifica lo stato i2c_err=i2c_err | 0x01; // Imposta errore su start } /* Invia lo start ripetuto sull'I2C BUS usando la periferica hardware. Restituisce il risultato dell'operazione. */ void i2c_repstart(void) { if (i2c_cmd(0xA4)!=0x10) // Imposta start bit e verifica lo stato i2c_err=i2c_err | 0x02; // Imposta errore su start ripetuto } /* Genera lo stop I2C BUS usando la periferica hardware */ void i2c_stop(void) { unsigned int hlpw; TWCR = 0x94; // Genera lo stop hlpw = 0; // Contatore per timeout do { hlpw++; // Incrementa contatore wait_ms(1); // Pausa 1 msec } while(((TWCR & 0x10) != 0) && (hlpw <= 50)); // Esce x stop finito o timeout if (hlpw>50) // Controllo finale dello stato i2c_err=i2c_err | 0x04; // Imposta errore su stop TWCR&=0xFB; // Disattiva controllore I2C } /* Invia lo slave address passato nel parametro sla sull'I2C BUS hardware e verifica eventuali errori, che vengono memorizzati nella variabile globale i2c_err. Il bit sla.0 definisce la direzione dei dati e decide se il controller lavora un modo trasmettitore Master o ricevitore Master. */ void i2c_sla(unsigned char sla) { TWDR=sla; // Scrive lo slave address+R/W bit nel controller if (sla & 0x01) // Verifica la direzione poiche' influenza il codice di ritorno { // Direzione=R -> modo ricevitore Master if (i2c_cmd(0x84)!=0x40) // Invia slave add. e verifica stato per R i2c_err=i2c_err | 0x08; // Imposta errore su slave address // endif } else { // Direzione=W -> modo trasmettitore Master if (i2c_cmd(0x84)!=0x18) // Invia slave add. e verifica stato per W i2c_err=i2c_err | 0x08; // Imposta errore su slave address // endif } //endif } /* Invia un byte su I2C BUS usando la periferica hardware */ void i2c_wr(unsigned char i2c_byte) { TWDR = i2c_byte; // Scrive dato if (i2c_cmd(0x84)!=0x28) // Invia dato e verifica lo stato i2c_err=i2c_err | 0x10; // Imposta errore su trasmissione dato } /* Riceve un dato dall'I2C BUShardware e verifica eventuali errori, che vengono memorizzati nella variabile globale i2c_err. Il parametro ack decide se un bit di Acknowledge deve essere inviato dopo la ricezione. Il dato ricevuto viene restituito. Il controller deve essere in modo ricevitore Master. */ unsigned char i2c_rd(unsigned char ack) { if (ack) // Verifica Acknowledge bit { // Riceve il dato e invia ACK bit if (i2c_cmd(0xC4)!=0x50) // Riceve il dato e verifica lo stato i2c_err=i2c_err | 0x20; // Imposta errore su ricezione dato // endif } else { // Riceve il dato e invia NACK bit if (i2c_cmd(0x84)!=0x58) // Riceve il dato e verifica lo stato i2c_err=i2c_err | 0x20; // Imposta errore su ricezione dato // endif } //endif return TWDR; // Restituisce il dato ricevuto } /* Mostra lo statu attuale degli errori I2C BUS, memorizzato nella variabile globale i2c_err, e lo azzera. */ void i2c_showres(void) { printf("-Errori I2C BUS avvenuti:"); if (i2c_err) { // Mostra errori if (i2c_err & 0x01) // Verifica e mostra errore su start printf(" Start"); // endif if (i2c_err & 0x02) // Verifica e mostra errore su start ripetuto printf(" Start-Ripetuto"); // endif if (i2c_err & 0x04) // Verifica e mostra errore su stop printf(" Stop"); // endif if (i2c_err & 0x08) // Verifica e mostra errore su slave address printf(" Slave-address"); // endif if (i2c_err & 0x10) // Verifica e mostra errore su trasmissione dato printf(" Transmissione-dato"); // endif if (i2c_err & 0x20) // Verifica e mostra errore su ricezione dato printf(" Recezione-dato"); // endif puts(""); // Va a capo } else puts(" nessuno"); // Nessun errore //endif i2c_err=0x00; // Azzera variabile di errore I2C } /* Invia n_out e legge n_in byte dallo slave address I2C BUS indicato usando la periferica hardware. I dati letti vanno nell'array chiamato getData di tipo unsigned char *. */ void i2c_n_receive(unsigned char i2c_slave, unsigned char *getData, unsigned char n_out, unsigned char n_in) { unsigned char dummy; i2c_start(); // Invia lo start i2c_sla(i2c_slave); // Scrive slave address for(dummy = 0; dummy < n_out; dummy++) { i2c_wr(getData[dummy]); // Scrive dato } i2c_repstart(); // Invia il secondo start i2c_sla(i2c_slave | 0x01); // Scrive slave address + R for(dummy = 0; dummy < n_in; dummy++) { if(dummy == n_in - 1) // Ultimo byte da leggere { getData[dummy] = i2c_rd(NACK); // Legge un byte e invia il NACK } else { getData[dummy] = i2c_rd(ACK); // Legge un byte e invia il ACK } } i2c_stop(); // Invia lo stop } /* Invia n_out byte allo slave address I2C BUS indicato usando la periferica hardware. I dati da inviare devono essere passati usando l'array chiamato sendData di tipo unsigned char *. */ void i2c_n_send(unsigned char i2c_slave, unsigned char *sendData, unsigned char n_out) { unsigned char dummy; i2c_start(); // Invia lo start i2c_sla(i2c_slave); // Scrive slave address for(dummy = 0; dummy < n_out; dummy++) { i2c_wr(sendData[dummy]); // Scrive dato } i2c_stop(); } /**************************************************************************** ** Funzioni di gestione del Real Time Clock ****************************************************************************/ void setrtc(unsigned char set,unsigned char ann,unsigned char mes,unsigned char gio,unsigned char ore,unsigned char min,unsigned char sec) /* Setta RTC a bordo del Mini Modulo con i dati passati nei parametri, nel formato a 24 ore ed abilita interrupt ogni secondo. */ { // Start I2C BUS i2c_start(); // Indirizza l'RTC a bordo del Mini Modulo per scrittura i2c_sla(RTCSLA); // Ferma l'orologio i2c_wr(0x00); i2c_wr(0x84); // Setta centinaia di secondi i2c_wr(0x00); // Setta secondi i2c_wr(bintobcd(sec)); // Setta minuti i2c_wr(bintobcd(min)); // Setta ORE,formato 24h i2c_wr(bintobcd(ore)); // Setta giorno e anno i2c_wr(bintobcd(gio)|(ann<<6)); // Setta mese,settimana i2c_wr(bintobcd(mes)|(set<<5)); // Setta timer i2c_wr(0x00); // Stop I2C BUS i2c_stop(); // Salva offset anno su ultima loc. SRAM i2c_start(); i2c_sla(RTCSLA); i2c_wr(0xFF); i2c_wr(ann); i2c_stop(); i2c_start(); i2c_sla(RTCSLA); // Riavvia l'orologio i2c_wr(0x00); i2c_wr(0x00); i2c_stop(); /* risi2c=wr_i2c(RTCSLA,0x01,0x00); // Setta centinaia di secondi risi2c=wr_i2c(RTCSLA,0x02,bintobcd(sec)); // Setta secondi risi2c=wr_i2c(RTCSLA,0x03,bintobcd(min)); // Setta minuti risi2c=wr_i2c(RTCSLA,0x04,bintobcd(ore)); // Setta ORE,formato 24h risi2c=wr_i2c(RTCSLA,0x05,(bintobcd(gio)|(ann<<6))); // Setta giorno e anno risi2c=wr_i2c(RTCSLA,0x06,(bintobcd(mes)|(set<<5)));// Setta mese,settimana risi2c=wr_i2c(RTCSLA,0x07,0x00); // Setta timer risi2c=wr_i2c(RTCSLA,0x00,0x00); // Setta start risi2c=wr_i2c(RTCSLA,0xFF,ann); // Salva offset anno su ultima loc. SRAM */ } void getrtc(unsigned char *set,unsigned char *ann,unsigned char *mes,unsigned char *gio,unsigned char *ore,unsigned char *min,unsigned char *sec) /* Preleva data ed ora attuale dal RTC a bordo del Mini Modulo e le restituisce nei parametri della funzione */ { unsigned char temp; // Start I2C BUS i2c_start(); // Indirizza l'RTC a bordo del Mini Modulo i2c_sla(RTCSLA); // Indirizza il registro 2 i2c_wr(0x02); // Start ripetuto I2C BUS i2c_repstart(); // Indirizza l'RTC a bordo del Mini Modulo per lettura i2c_sla(RTCSLA | 0x01); // Legge e determina secondi temp=i2c_rd(ACK); *sec=bcdtobin(temp); // Legge e determina minuti temp=i2c_rd(ACK); *min=bcdtobin(temp); // Legge e determina ore temp=i2c_rd(ACK); *ore=bcdtobin(temp); // Legge e determina giorno,anno temp=i2c_rd(ACK); *gio=bcdtobin(temp & 0x3F); *ann=(temp & 0xC0)>>6; // Legge e determina giorno settimana e mese temp=i2c_rd(NACK); *set=(temp & 0xE0)>>5; *mes=bcdtobin(temp & 0x1F); // Stop I2C BUS i2c_stop(); // Preleva offset anno da ultima loc. SRAM // Start I2C BUS i2c_start(); // Indirizza l'RTC a bordo del Mini Modulo i2c_sla(RTCSLA); // Indirizza l'ultima locazione della SRAM i2c_wr(0xFF); // Start ripetuto I2C BUS i2c_repstart(); // Indirizza l'RTC a bordo del Mini Modulo per lettura i2c_sla(RTCSLA | 0x01); // Legge e determina secondi temp=i2c_rd(ACK); temp+=*ann; // Ottiene anno con offset temp%=100; // Forza anno con offset a due cifre *ann=temp; // Restituisce anno a due cifre ottenuto // Stop I2C BUS i2c_stop(); /* risi2c=rd_i2c(RTCSLA,0x02,&dr); // Legge e determina secondi *sec=bcdtobin(dr); risi2c=rd_i2c(RTCSLA,0x03,&dr); // Legge e detrmina minuti *min=bcdtobin(dr); risi2c=rd_i2c(RTCSLA,0x04,&dr); // Legge e determina ore *ore=bcdtobin(dr); risi2c=rd_i2c(RTCSLA,0x05,&dr); // Legge e determina giorno,anno *gio=bcdtobin(dr&0x3F); *ann=(dr&0xC0)>>6; risi2c=rd_i2c(RTCSLA,0x06,&dr);// Legge e determina giorno settimana e mese *set=(dr&0xE0)>>5; *mes=bcdtobin(dr&0x1F); risi2c=rd_i2c(RTCSLA,0xFF,&dr); // Preleva offset anno da ultima loc. SRAM dr=dr+*ann; // Ottiene anno con offset dr=dr%100; // Forza anno con offset a due cifre *ann=dr; // Restituisce anno a due cifre ottenuto */ } /* Legge dai resgistri del Real Time Clock data ed ora le visualizza formattate su console. */ void output_rtc(void) { unsigned char set,gio,mes,ann,ore,min,sec; // Variabili per demo RTC getrtc(&set,&ann,&mes,&gio,&ore,&min,&sec); // Preleva RTC switch(set) // Rappresenta data ed ora prelevata { case 0: printf("Domenica "); break; case 1: printf("Lunedi` "); break; case 2: printf("Martedi` "); break; case 3: printf("Mercoledi` "); break; case 4: printf("Giovedi` "); break; case 5: printf("Venerdi` "); break; case 6: printf("Sabato "); break; } // endswitch printf("%2d-",gio); printf("%2d-",mes); printf("20%2d ",ann); printf("%2d:",ore); printf("%2d:",min); printf("%2d\r",sec); } /**************************************************************************** Programma principale ****************************************************************************/ void main(void) { unsigned char set,gio,mes,ann,ore,min,sec; // Variabili per RTC unsigned char t[3],o[3]; // Variabili per temporizzatori unsigned char dw, hlp; init_cpu(); // Inizializza sezioni necessarie della CPU set_relays(0); // Apre i contatti di tutti i relays uart_init(); // Inizializza USART come console _textmode = 1; // Trasforma i \n in \r\n i2c_err=0x00; // Azzera variabile di errore I2C for(;;) { clrscr(); // Pulisce lo schermo puts("Demo 1.1 per GMM AM32 ds221003 + GMB HR168 ds110104"); // Controllo interno check(); // Attiva l'interfaccia I2C BUS init_i2c(); puts(""); puts("Gestione 3 temporizzatori con precisione del secondo; per i primi 2 e`"); puts("definibile lo stato uscite su CN1 mentre il terzo le disattiva."); for (dw=0;dw<3;dw++) { printf("\nTempo %d (1..255,0 disattiva)? ",dw); t[dw]=get_num(); // Preleva e salva tempo settaggio if ((dw!=2) && (t[dw]!=0)) { printf("\nStato uscite (0..255)? "); o[dw]=get_ num(); // Preleva e salva stato uscite } // endif } // endfor o[2]=0; // Predispone azzeramento uscite per terzo temp. puts("\nSecondi trascorsi"); getrtc(&set,&ann,&mes,&gio,&ore,&min,&sec); // Preleva RTC dw=sec; // Inizializza secondi precedenti hlp=0; // Azzera contatore secondi trascorsi while ((t[0]+t[1]+t[2])!=0) // Se almeno un temporizzatore attivo { getrtc(&set,&ann,&mes,&gio,&ore,&min,&sec); // Preleva RTC if (sec!=dw) // Se secondi variati { hlp++; // Incrementa contatore secondi trascorsi printf("%3d\r",hlp); // Rappresenta secondi trascorsi for (dw=0;dw<3;dw++) // Gestisce 3 temporizzatori { if (hlp==t[dw]) { set_relays(o[dw]); t[dw]=0; } // endif } // endfor dw=sec; // Aggiorna secondi precedenti } // endif } // endwhile puts(""); // Attende tasto per ricominiciare ask_waitkey(); } //endfor (;;) // Fine loop infinito }