/* ********************************************************************** ** Programma: Rtcseg51.c - Versione: 1.2 - 24 Luglio 2003 ** ** Compilatore : uC/51 Ver. 1.10.7 ** ** Scheda : K51-AVR e microcontrollore ATMEL AT89c51 o superiori ** ** 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 ** ** sales@grifo.it tech@grifo.it grifo@grifo.it ** ** ** ** Realizzato da: Graziano Gaiba ** ********************************************************************** Questo programma permette di visualizzare RTC o orologio IC7(PCF8583) nei 4 display a 7 seg. Per inpostare RTC si utilizzano i tasti T2 e T3, precisamente con T2 si incrementano la cifra delle ore, mentre con T3 la cifra dei minuti. Ad ogni pressione di uno dei 2 tasti viene azzerato il conteggio dei secondi. Tramite il tasto T1 si passa alla visualizzazione dei secondi o della ora. Ad ogni pressione di un tasto viene emesso un seganle acustico. Non viene gestita la data ed aventuale allarme. La presente versione e' adatta al microcontrollore ATMEL AT89c51 o superiori. 05.06.2000 by Adriano Pedrielli (per la sola K51) (Versione originale in BASCOM 8051) 24.07.2003 by Graziano Gaiba Traduzione in uC/51 e versione per ATMEL AT89c51 o superiori. */ #include #include #include #define FALSE 0x00 // Valori booleani #define TRUE 0xFF #define LF 0x0A #define CRET 0x0D /***************** Elenco indirizzi per Saa1064 ***********************/ #define Saa1064 0x38 // Slave address SAA1064 #define Wsaa1064 0x70 // Slave address SAA1064 in Write #define Rsaa1064 0x71 // Slave address SAA1064 in Read #define Ctb 0x00 // Ind. Control byte #define Dig1 0x01 // Ind. Digit 1 #define Dig2 0x02 // Ind. Digit 2 #define Dig3 0x03 // Ind. Digit 3 #define Dig4 0x04 // Ind. Digit 4 /************************************************************************/ #define Rtc 0x50 // Slave address RTC PCF8583 #define Wrtc 0xA0 // Slave address RTC PCF8583 in Write #define Rrtc 0xA1 // Slave address RTC PCF8583 in Read // Valori di inizializzazione dell'SAA1064 #define saa1064_init_length 0x06 // Lunghezza sequenza inizializzazione const unsigned char saa1064_init[]={ Ctb, // Punto al registro di controllo 0x27, // = 0b00100111 // bit0 =1 dynamic mode // bit1 =1 digit 1+3 not blanked // bit2 =1 digit 2+4 not blanked // bit3 =0 no test segment // bit4 =0 no 3mA segment current // bit5 =1 6mA segment current // bit6 =0 no 12mA segment current // bit7 =0 indifferente 0, // scrive DY1 off 0, // scrive DY2 off 0, // scrive DY3 off 0 // scrive DY4 off }; // Codici per convertire una cifra da 0 a F nella codifica a 7 segmenti const unsigned char cifra_7seg[]={0x3F,0x06,0x5B,0x4F,0x66, 0x6D,0x7D,0x07,0x7F,0x6F, 0x77,0x7C,0x39,0x5E,0x79,0x71}; // Variabili globali gestione I2C BUS con ATMEL AT89c51 o superiori bit unsigned char SDA @ 0xB6; // Pin SDA=P3.6 bit unsigned char SCL @ 0xB7; // Pin SCL=P3.7 // Variabili globali gestione tasti e buzzer bit unsigned char T1 @ 0x90; // P1.0 bit unsigned char T2 @ 0x91; // P1.1 bit unsigned char T3 @ 0x92; // P1.2 bit unsigned char BUZ @ 0xB5; // P3.5 /*************************** Variabili Globali *****************************/ char unsigned bit d_dot; // Controlla lo stato del punto decimale near unsigned char secondi; // Ultimo valore dei secondi char unsigned bit secondi_ora; // Visualizza orario o secondi /********* Funzioni di utility generale e di gestione sezioni hw ***********/ void iniser(unsigned long baud) /* Inizializza la linea seriale con: Bit x chr = 8 Stop bit = 1 Parity = None Baud rate = baud usando come baud rate generator il timer 1. */ { SCON=0x052; // Modo 1, abilita ricevitore TMOD&=0x00F; // Timer 1 in modo auto-reload TMOD|=0x020; TR1=0; // Stop al TIMER 1 TH1=256-((2*11059200)/(384*baud)); // baud a 14.7456 MHz PCON=PCON|0x080; // Setta SMOD=1 per baud rate alti TR1=1; // Start al TIMER 1 } void clrscr(void) /* Effettua la funzione di clear screen per una generica console */ { unsigned char r; putc(CRET); for (r = 0 ; r < 25 ; r++) { putc(LF); // Trasmette 25 Line Feed } //endfor } void waitkey(void) /* Rappresenta messaggio ed attende pressione tasto */ { printf("Premere tasto per continuare.."); getc(); puts(""); } void ritardo(unsigned int rit) /* Effettua un ritardo software di rit millisecondi, calibrato su un Clock di CPU da 14.7456 MHz, a seconda della CPU montata. */ { unsigned int r,rit1ms; rit1ms=100; // Valore sperimentale per ritardo di 1 msec. con 80c32 do { for (r=0 ; r0); } void riti2c(void) /* Genera ritardo per comunicazione sincrona in I2CBUS. */ { #asm nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop #endasm } void starti2c(void) /* Genera sequenza di start per I2C BUS */ { SCL = 0; // Genera sequenza di start SDA = 1; riti2c(); SCL = 1; SDA = 0; riti2c(); SCL = 0; } void stopi2c(void) /* Genera sequenza di stop per I2C BUS */ { SCL = 0; // Genera sequenza di stop SDA = 0; riti2c(); SCL = 1; SDA = 1; riti2c(); SCL = 0; } void wri2c_bit(unsigned char i2cbit) /* Serializza il bit D0 di i2cbit su I2C BUS */ { SCL = 0; // Setta SDA e genera impulso positivo su SCL SDA = i2cbit; riti2c(); SCL = 1; riti2c(); SCL = 0; } unsigned char rdi2c_bit(void) /* Deserializza un bit da I2C BUS e lo salva in D0 del risultato */ { unsigned char biti2c; SDA = 1; // Evita conflitti su acquisizione SDA SCL = 0; // Assicura stato SCL riti2c(); SCL = 1; // Genera impulso positivo su SCL e su questo legge SDA biti2c = SDA; riti2c(); SCL = 0; return biti2c; } void wri2c_byte(unsigned char i2cbyte) /* Serializza il byte i2cbyte su I2C BUS */ { unsigned char b; for (b = 1; b <= 8; b++) { if ((i2cbyte & 0x80) == 0) // Determina e setta bit b wri2c_bit(0); else wri2c_bit(1); i2cbyte = i2cbyte << 1; } } unsigned char rdi2c_byte(void) /* Deserializza un byte da I2C BUS e lo salva nel risultato */ { unsigned char b,tmp; tmp = 0; for (b = 1; b <= 8; b++) { tmp = tmp << 1; tmp = tmp | rdi2c_bit(); // Preleva e salva bit b } return tmp; } unsigned char wr_i2c(unsigned char i2csla,unsigned char i2cadd,unsigned char i2cdat) /* Scrive il byte i2cdat all'indirizzo i2caddr del dispositivo I2C BUS che ha uno slave address i2csla. Restituisce flag booleano che indica il risultato dell'operazione: 0=corretta,1=errata. */ { unsigned char i2cris; i2cris = 0; // Setta risultato corretto starti2c(); // Fornisce sequenza di start wri2c_byte(i2csla); // Fornisce slave address+W i2cris = i2cris | rdi2c_bit(); // Controlla ACK su slave address+W wri2c_byte(i2cadd); // Fornisce address i2cris = i2cris | rdi2c_bit(); // Controlla ACK su address wri2c_byte(i2cdat); // Fornisce dato i2cris = i2cris | rdi2c_bit(); // Controlla ACK su dato stopi2c(); // Fornisce sequenza di stop return i2cris; // Restituisce risultato operazione } unsigned char rd_i2c(unsigned char i2csla,unsigned char i2cadd,unsigned char *i2cdat) /* Legge il byte i2cdat dall'indirizzo i2caddr del dispositivo I2C BUS che ha uno slave address i2csla. Restituisce flag booleano che indica il risultato dell'operazione: 0=corretta,1=errata. */ { unsigned char i2cris; i2cris = 0; // Setta risultato corretto starti2c(); // Fornisce sequenza di start wri2c_byte(i2csla); // Fornisce slave address+W i2cris = i2cris | rdi2c_bit(); // Controlla ACK su slave address+W wri2c_byte(i2cadd); // Fornisce address i2cris = i2cris | rdi2c_bit(); // Controlla ACK su address starti2c(); // Fornisce sequenza di start wri2c_byte(i2csla | 0x01); // Fornisce slave address+R i2cris = i2cris | rdi2c_bit(); // Controlla ACK su slave address+R *i2cdat = rdi2c_byte(); // Preleva dato stopi2c(); // Fornisce sequenza di stop return i2cris; // Restituisce risultato operazione } // Invia allo slave address indicato (primo parametro) il numero di bytes indicato // (terzo parametro) memorizzati a partire dall'indirizzo indicato (secondo // parametro). // Non fa nulla se indicati 0 dati. // Restituisce flag booleano che indica il risultato dell'operazione: // 0=corretta,1=errata. unsigned char i2c_invia(unsigned char slave, unsigned char *dati, unsigned char ndati) { unsigned char i2cris, i; if(! ndati) // Se ndati e' zero, esce return 0; i2cris=0; starti2c(); // Sequenza di start wri2c_byte(slave); // Invia lo slave address i2cris|=rdi2c_bit(); // Controlla ACK i=0; while(ndati--) // Invia ndati bytes { wri2c_byte(dati[i++]); // Invia lo slave address i2cris|=rdi2c_bit(); // Controlla ACK } stopi2c(); // Sequenza di stop return i2cris; // Restituisce il risultato } // Invia allo slave address indicato (primo parametro) il numero di bytes indicato // (terzo parametro) memorizzati a partire dall'indirizzo indicato (secondo // parametro), poi si aspetta di ricevere in risposta il numero di bytes indicati // nel quarto parametro e li memorizza a partire dall'indirizzo prima specificato. // Non fa nulla se indicati 0 dati in arrivo e in invio. // Restituisce flag booleano che indica il risultato dell'operazione: // 0=corretta,1=errata. unsigned char i2c_ricevi(unsigned char slave, unsigned char *dati, unsigned char ndati_out, unsigned char ndati_in) { unsigned char i2cris, i; if((! ndati_in) && (! ndati_out)) // Se ndati_in e ndati_out sono zero,esce return 0; i2cris=0; // Invia i dati starti2c(); // Sequenza di start wri2c_byte(slave); // Invia lo slave address i2cris|=rdi2c_bit(); // Controlla ACK i=0; while(ndati_out--) // Invia ndati_out bytes { wri2c_byte(dati[i++]); // Invia lo slave address i2cris|=rdi2c_bit(); // Controlla ACK } // Riceve i dati starti2c(); wri2c_byte(slave | 0x01); // Fornisce slave address+R i2cris|=rdi2c_bit(); // Controlla ACK su slave address+R i=0; while(ndati_in--) // Riceve ndati_in bytes { dati[i++]=rdi2c_byte(); // Legge il dato if(ndati_in) { wri2c_bit(0); // Invia ACK } else { wri2c_bit(1); // Ultimo dato da leggere, invia NACK } } stopi2c(); // Sequenza di stop return i2cris; // Restituisce il risultato } 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; } /***************** Converte un numero da 0 a 9 in 7 segmenti *********** Questa procedura converte una cifra da 0 a 9 nel formato 7 segmenti. Parametri: Ingresso : valore da 0 a 9 Uscita : valore in formato 7 segmenti. ************************************************************************/ unsigned char digit(unsigned char n) { if(n < 10) { return cifra_7seg[n]; // legge in tabella il valore } else { return 0; // Se la cifra supera 9 spegne il display } } /***************** Converte un numero BCD in due cifre ************** Questa procedura converte un numero BCD da 0 a 153 (DEC 0-99) in due cifre separate, e restituisce il valore decimale, in questo modo si possono rappresentare. Se il numero supera 153, le due cifre assumono il valore 10 che indica display 7 seg. spento. Parametri: Ingresso : v, valore da 0 a 153 BCD ( Decimale 0..99) Uscita : d, cifra delle decine u, cifra delle unita v, contiene il valore in decimale del BCD ************************************************************************/ void cifre(unsigned char *v, unsigned char *d, unsigned char *u) { if(*v < 154) // risulta minore di 154 BCD( 100 in DEC) { *d = *v >> 4; // Ricavo la cifra delle decine *u = *v & 0x0F; // Ricavo la cifra delle unita *v = *d *10 + *u; // Ricavo il valore in decimale } else { *d = 10; // Spengo la cifra delle decine *u = 10; // Spengo la cifra delle unita *v = 0; // Azzero il valore Decimale } } /*********************** Visualizza 2 numeri BCD *********************** Questa procedura permette di visualizzare due numeri BCD che in decimale hanno 2 cifre. Es: BCD 153= Dec. 99 Durante lo scorrere del tempo, ad gni variazione di secondi accende o spegne il decimal point su DY2. Parametri: Ingresso : N1 as byte, valore primo numero N2 as byte, valore secondo numero Uscita : nulla ************************************************************************/ void vis_2num(unsigned char n1, unsigned char n2) { unsigned char v, d, u, d1, u1; v=n1; cifre(&v, &d, &u); // Scomposizione in due cifre BCD if(! d) // Spegne la cifra se vale 0 { d=10; } v=n2; cifre(&v, &d1, &u1); starti2c(); // Start sequence wri2c_byte(Wsaa1064); // Slave address rdi2c_bit(); // Controlla ACK su slave address+R wri2c_byte(Dig1); // Primo digit rdi2c_bit(); wri2c_byte(digit(d)); // Scrive in DY1 il nibble piu' significativo rdi2c_bit(); // Scrive in DY2 il nibble successivo e gestisce il punto decimale wri2c_byte(digit(u) | (d_dot ? 0x80 : 0x00)); rdi2c_bit(); // Scomposizione in 2 nibble della parte bassa wri2c_byte(digit(d1)); // Scrive in DY3 il nibble piu' significativ rdi2c_bit(); wri2c_byte(digit(u1)); // Scrive in DY4 il nibble successivo rdi2c_bit(); stopi2c(); // Stop sequence } // Attiva il buzzer per il tempo specificato, in millisecondi void buzzer(unsigned int t) { BUZ=0; ritardo(t); BUZ=1; } // Effettua un debouncing su T1 e ne restituisce lo stato: // 1 se e' premuto // 0 se non e' premuto unsigned char debounceT1(void) { unsigned char status; unsigned int steps; if(T1) // Se T1 non premuto... { return 0; // ...restituisci che non e' premuto } else { status=1; // Indica che e' premuto steps=20; // Controlla per 20 volte while(status) { if(T1) // Se T1 non e' premuto... { status=0; // ...esci dal loop } if(! steps--) // Se abbiamo fatto steps controlli... { break; // ...esci } ritardo(5); // Ritardo tra le verifiche } return status; // Restituisce lo stato di T1 } } // Effettua un debouncing su T2 e ne restituisce lo stato: // 1 se e' premuto // 0 se non e' premuto unsigned char debounceT2(void) { unsigned char status; unsigned int steps; if(T2) // Se T2 non premuto... { return 0; // ...restituisci che non e' premuto } else { status=1; // Indica che e' premuto steps=20; // Controlla per 20 volte while(status) { if(T2) // Se T2 non e' premuto... { status=0; // ...esci dal loop } if(! steps--) // Se abbiamo fatto steps controlli... { break; // ...esci } ritardo(5); // Ritardo tra le verifiche } return status; // Restituisce lo stato di T2 } } // Effettua un debouncing su T3 e ne restituisce lo stato: // 1 se e' premuto // 0 se non e' premuto unsigned char debounceT3(void) { unsigned char status; unsigned int steps; if(T3) // Se T3 non premuto... { return 0; // ...restituisci che non e' premuto } else { status=1; // Indica che e' premuto steps=20; // Controlla per 20 volte while(status) { if(T3) // Se T3 non e' premuto... { status=0; // ...esci dal loop } if(! steps--) // Se abbiamo fatto steps controlli... { break; // ...esci } ritardo(5); // Ritardo tra le verifiche } return status; // Restituisce lo stato di T3 } } void getrtc(unsigned char *ore,unsigned char *min,unsigned char *sec) /* Preleva data ed ora attuale dal RTC e le restituisce nei parametri della funzione */ { unsigned char dummy; rd_i2c(Wrtc,0x02,sec); // Legge secondi rd_i2c(Wrtc,0x03,min); // Legge minuti rd_i2c(Wrtc,0x04,ore); // Legge ore rd_i2c(Wrtc,0x05,&dummy); // Legge giorno,anno rd_i2c(Wrtc,0x06,&dummy); // Legge giorno settimana e mese } void setrtc(unsigned char ore,unsigned char min,unsigned char sec) /* Setta RTC con i dati passati nei parametri, nel formato a 24 ore ed abilita interrupt ogni secondo. */ { wr_i2c(Wrtc,0x00,0x84); // Setta stop wr_i2c(Wrtc,0x01,0x00); // Setta centinaia di secondi wr_i2c(Wrtc,0x02,bintobcd(sec)); // Setta secondi wr_i2c(Wrtc,0x03,bintobcd(min)); // Setta minuti wr_i2c(Wrtc,0x04,bintobcd(ore)); // Setta ORE,formato 24h wr_i2c(Wrtc,0x05,(bintobcd(1)|(1<<6))); // Setta giorno e anno wr_i2c(Wrtc,0x06,(bintobcd(1)|(1<<5))); // Setta mese,settimana wr_i2c(Wrtc,0x07,0x00); // Setta timer wr_i2c(Wrtc,0x00,0x00); // Setta start } void demo_init(void) { unsigned char i; // Attende accensione SAA1064 do { starti2c(); wri2c_byte(Rsaa1064); rdi2c_bit(); i = rdi2c_byte(); wri2c_byte(1); // Not Acknowledge stopi2c(); } while(i); // Invia la sequenza di inizializzazione dell'SAA1064 i2c_invia(Wsaa1064, saa1064_init, saa1064_init_length); } void main(void) { unsigned char ore,min,sec; // Variabili per RTC ritardo(2); iniser(19200); TI=0; RI=0; // Commentare se si usa la seriale in polling (SIOTYPE=p oppure k) ES=1; // Abilita interrupt porta seriale EA=1; // Abilitazione interrupt clrscr(); demo_init(); // Inizializzazione periferiche secondi_ora=1; d_dot=0; ore=12; min=35; sec=0; secondi=0; // Inizializzazione RTC setrtc(ore,min,sec); while(1) // Loop ifinito { if(debounceT1()) // Se T1 premuto { secondi_ora=!secondi_ora; // Passa dalle ore ai secondi e viceversa } if(debounceT2()) // Se T2 premuto { ore=bcdtobin(ore); min=bcdtobin(min); if(ore==23) { ore=0; } else { ore++; } setrtc(ore, min, 0); buzzer(50); // Il buzzer suona per 50 millisecondi sec=secondi=0; } if(debounceT3()) // Se T2 premuto { ore=bcdtobin(ore); min=bcdtobin(min); if(min==59) { min=0; } else { min++; } setrtc(ore, min, 0); buzzer(50); // Il buzzer suona per 50 millisecondi sec=secondi=0; } getrtc(&ore,&min,&sec); // Preleva RTC (valori in BCD) if(sec!=secondi) // Se siamo nel secondi successivo { d_dot=!d_dot; // Complementa il punto decimale secondi=sec; // Memorizza il secondo } if(secondi_ora) { vis_2num(ore,min); // Visualizza ore e minuti } else { vis_2num(154, sec); // Spegne le prime due cifre e // visualizza i secondi } } }