/* ********************************************************************** ** Programma: rs232.c - Versione : 1.2 - 24 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 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 AT89c4051. 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 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 /************************************************************************/ // 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 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 /********* 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 } }