/* ********************************************************************** ** Programma: rs232_51.c - Versione : 1.2 - 24 Luglio 2003 ** ** Compilatore : uC/51 Ver. 1.10.7 ** ** Scheda : K51-AVR e microcontrollore ATMEL AT89c51 o superiore ** ** 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 invia sulla linea seriale, impostata a 19200 baud, il carattere "1" se viene premuto il tasto T1 o il carattere "2" se viene premuto il tasto T2. Inoltre visualizza sul display a 7 segmenti il valore numerico in esadecimale dell'ultimo byte ricevuto dalla porta seriale. Questa versione del programma e' adatta ad essere utilizzata sui microcontrollori ATMEL AT89c51 o superiore. 15.07.2003 by Graziano Gaiba (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 superiore. */ #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 /************************************************************************/ // 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 /********* 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 } // 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 byte in HEX *********************** Questa procedura permette di visualizzare un byte nel formato esadecimale nei due display a destra. Es: 255= FFH, 32= 20H ecc. Parametri: Ingresso : numero da visualizzare in HEX Uscita : nulla **************************************************************************/ void vis_byte(unsigned char t) { unsigned char h, l; cifre(t, &h, &l); // Scomposizione in 2 nibble del valore di t // Nibble alto e nibble basso 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(0); // Spegne DY2 rdi2c_bit(); wri2c_byte(digit(h)); // Trasforma in "7 segmenti" ed invia a DY3 rdi2c_bit(); wri2c_byte(digit(l)); // Trasforma in "7 segmenti" ed invia a DY4 rdi2c_bit(); stopi2c(); // Stop sequence } /************************ 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 } // 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=10; // Controlla per 10 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=10; // Controlla per 10 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 } } 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 v; 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 v=0; while(1) // Loop forever { if(debounceT1()) // Se viene premuto il tasto T1 { putc('1'); // Invia il carattere '1' } if(debounceT2()) // Se viene premuto il tasto T2 { putc('2'); // Invia il carattere '2' } if(kbhit()) // Se arriva un carattere dalla seriale { v=getc(); // Leggilo } vis_byte(v); // Visualizza codice dell'ultimo carattere } }