/* ********************************************************************** ** Programma: ad11ch.c - Versione : 1.2 - 23 Luglio 2003 ** ** Compilatore : uC/51 Ver. 1.10.7 ** ** Scheda : K51-AVR e microcontrollore ATMEL AT89c4051 ** ** 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 visulizza una canale analogico su 11, gestiti da IC12 (TLC2543), la visualizzazione avviene nel formato esadecimale, dove tramite T1 e T2 si seleziona il canale da convertire, T1 incrementa mentre T2 decrementa. Ad ogni pressione di un tasto viene emesso un seganle acustico. Nei display viene visualizzato prima il canale in conversione, di seguito il valore del canale convertito a 12bit in esadecimale. La presente versione e' adatta al microcontrollore ATMEL AT89c4051. 05.06.2000 by Adriano Pedrielli (per la sola K51) (Versione originale in BASCOM 8051) 23.07.2003 by Graziano Gaiba Traduzione in uC/51 e versione per ATMEL AT89c4051. */ #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 /***************** Elenco indirizzi per PCF8591 ***********************/ #define Pcf8591 0x48 // Slave address PCF8591 #define Wpcf8591 0x90 // Slave address PCF8591 in Write #define Rpcf8591 0x91 // Slave address PCF8591 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 AT89c4051 bit unsigned char SDA @ 0x97; // Pin SDA=P1.7 bit unsigned char SCL @ 0x96; // Pin SCL=P1.6 // Variabili globali gestione tasti e buzzer bit unsigned char T1 @ 0x95; // P1.5 bit unsigned char T2 @ 0x94; // P1.4 bit unsigned char T3 @ 0x93; // P1.3 bit unsigned char BUZ @ 0xB5; // P3.5 // Variabili globali gestione A/D converter TLC 2543 bit unsigned char Cs @ 0x92; // P1.2 PIN 14 segnale di Chip Select per IC12 bit unsigned char Clk @ 0x91; // P1.1 PIN 13 seganle di Clock per IC12 bit unsigned char Din @ 0x90; // P1.0 PIN 12 segnale di Dato In per IC12 bit unsigned char Dout @ 0xB7; // P3.7 PIN 11 seganle di Dato Out per IC12 /********* 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 dati 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 dati 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 } 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); } /******************* Gestione del A/D converter ************************* Questa procedura esegue il colloquio seriale con IC12 (TLC2543), ad ogni impulso di Clock trasmette un bit e ne leggie un altro. Parametri: Ingresso : adin as byte, indica il dato da trasmettere a IC12 Uscita : indica il valore convertito a 12 bit 0..FFF(0V..+Vref) ************************************************************************/ unsigned int ad12(unsigned char adin) { unsigned int adout; unsigned char i; adout = 0; // azzero il valore convertito Cs = 0; // abbaso il segnale CS for(i=0; i<12; i++) // eseguo 12 cicli { Clk = 0; // abbasso il Clock if(adin & 0x80) // testo il bit7 di Adin { Din = 1; // setto a 1 il segnale per IC12 } else // altrimeti { Din = 0; // setto a 0 il segnale per IC12 End If } adin = (adin & 0x7F) << 1; // elimino il bit7 e shift a sinistra di 1 Clk = 1; // alzo il segnale di Clock if(Dout) // testo se dato da IC12 e' uguale a 1 { adout = adout | 1; // attivo il bit0 di Adout } if(i!=11) // non sono nel ciclo 12 { adout<<=1; // shift a sinistra di 1 } } // fine ciclo Clk = 0; // abbasso il Clock Cs = 1; // alzo il CS return adout; } /******************* Conversione analogica ****************************** Questa procedura permette di eseguire una conversione analogica a 12 bit su IC12 (TLC2543), in tutti e 11 canali esterni del componente. Parametri: Ingresso : ch as byte, indica il canale da convertire 0..10 Uscita : indica il valore convertito a 12 bit 0..FFF(0V..+Vref) ************************************************************************/ unsigned int adc(unsigned char ch) // Gestione dell'A/D converter { if(ch>10) { ch=10; // Il canale e' 10 al massimo } ch=(ch >> 4) | 0x08; // Seleziono conversione a 12 bit ad12(ch); // Leggo la conversione precedente ritardo(1); // Ritardo di almeno 100 usec return ad12(ch); // Restituisce conversione attuale } // Converte un valore da 0 a 255 in due cifre esadecimali a 4 bit void cifre(unsigned char v, unsigned char *c1, unsigned char *c2) { *c1=(v & 0xf0) >> 4; *c2=v & 0x0f; } /***************** Converte un numero da 0 a 15 in 7 segmenti *********** Questa procedura converte una cifra da 0 a 15 nel formato 7 segmenti. Parametri: Ingresso : valore da 0 a 15 Uscita : valore in formato 7 segmenti. ************************************************************************/ unsigned char digit(unsigned char n) { if(n < 16) { return cifra_7seg[n]; // legge in tabella il valore } else { return 0; // Se la cifra supera 15 spegne il display } } /************************ Visualizza un word in HEX *********************** Questa procedura permette di visualizzare una word in esadecimale. Nei primi 2 display (DY1 e DY2) viene visualizzato il byte alto, mentre nei 2 rimanenti il byte basso (DY3 e DY4). nei due display a destra. Es: 65535= FFFFH, 257= 101H ecc. Parametri: Ingresso : numero da visualizzare in HEX Uscita : nulla **************************************************************************/ void vis_word(unsigned int t) { unsigned char h, l; // Scomposizione in 2 nibble della parte alta di t cifre(t>>8, &h, &l); 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(h)); // Scrive in DY1 il nibble piu' significativo rdi2c_bit(); wri2c_byte(digit(l)); // Scrive in DY1 il nibble successivo rdi2c_bit(); // Scomposizione in 2 nibble della parte bassa di t cifre(t & 0xff, &h, &l); wri2c_byte(digit(h)); // Scrive in DY3 il nibble piu' significativ rdi2c_bit(); wri2c_byte(digit(l)); // Scrive in DY4 il nibble successivo rdi2c_bit(); stopi2c(); // Stop sequence } /******************* Conversione analogica ****************************** Questa procedura permette di visualizzare quale canale risulata essere in conversione, scrivendo "C", "H", ed il numero del canale in Hex. Parametri: Ingresso : t, indica il canale in conversione 0..10 Uscita : nessuna **************************************************************************/ void vis_ch(unsigned char t) { 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(0); // Spegne DY1 rdi2c_bit(); wri2c_byte(0x39); // Scrive "C" su DY2 rdi2c_bit(); wri2c_byte(0x76); // Scrive "H" su DY3 rdi2c_bit(); wri2c_byte(digit(t)); // Trasforma in "7 segmenti" ed invia 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 } } // Effettua le operazioni associate ai tasti void gestioneTasti(unsigned char *c) { if(debounceT1()) // Se T1 premuto { buzzer(50); // Emette un suono if(*c<10) // Incrementa il canale... { (*c)++; } else { *c=0; // ...o riportalo a zero } } if(debounceT2()) // Se T2 premuto { buzzer(50); // Emette un suono if(*c) // Decrementa il canale... { (*c)--; } else { *c=10; // ...o lo riporta a 10 } } } void main(void) { unsigned char i, c; 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 demo_init(); // Inizializzazione periferiche c=0; while(TRUE) // Infinite Loop { for(i=0; i<10; i++) { vis_ch(c); // Visualizza il canale gestioneTasti(&c); // Effettua le operazioni associate ai tasti ritardo(50); // Ritardo per visualizzazione } // end for() for(i=0; i<35; i++) { vis_word(adc(c)); // Visualizza conversione del canale in c gestioneTasti(&c); // Effettua le operazioni associate ai tasti ritardo(50); // Ritardo per visualizzazione } } // end while(TRUE) }