/* ********************************************************************** * File: k51ppo.c - Rel. 1.1 con uC/51 V. 1.10.15 * * Schede: K51 & AVR con GMB HR168 e GMM AC2 * * GRIFO(R) via Dell'Artigiano 8/6 40016 S. Giorgio di Piano (BO) * * Tel. +39 051 892052 Fax. +39 051 893661 * * http://www.grifo.com http://www.grifo.it * * sales@grifo.it tech@grifo.it grifo@grifo.it * * by Graziano Gaiba del 05.03.04 * ********************************************************************** 05/03/04: k51ppo.c - Rel. 1.1 - By Graziano Gaiba This demo allows to drive an I2C BUS peripheral on board of K51-AVR, PCF8574, through mini-BLOCK module GMB HR168 and grifo(r) mini module. PCF 8574 is an I/O expander that allows to drive 8 TTL digital lines, both as input and as output, all the operations of read and write are performed through synchronous serial interface I2C BUS. This demo activates in sequence one line at a time, creating the classic bit shift to the right and to the left, and writes 'out' on the 7 segments display of K51-AVR, near the characters 'out'. N.B. Per evitare problemi non eseguire operazioni complesse su una singola riga, specialmente all'interno di procedure sui relativi parametri e/o variabili locali. */ #include "canary.h" #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 PCF8574A o P *********************/ /* Esistono due versioni con slave address incompatibili di PCF8574, la A e la P. Selezionare di seguito quella desiderata. */ // Indirizzi per PCF8574A /* #define Pcf8574 0x3C // Slave address PCF8574A #define Wpcf8574 0x78 // Slave address PCF8574A in Write #define Rpcf8574 0x79 // Slave address PCF8574A in Read */ // Indirizzi per PCF8574P #define Pcf8574 0x24 // Slave address PCF8574P #define Wpcf8574 0x48 // Slave address PCF8574P in Write #define Rpcf8574 0x49 // Slave address PCF8574P 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 92, // writes 'o' 28, // writes 'u' 120, // writes 't' 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 @ 0xA1; // Pin SDA=P2.1 bit unsigned char SCL @ 0xA0; // Pin SCL=P2.0 /********* 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*14745600)/(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 init_cpu(void) /* Verifica la CPU montata sulla scheda e lo salva in apposita variabile. Effettua inoltre le apposite inizializzazioni: seriale, wait, ecc. */ { CKCON=0x00; // Setta X1 clock mode = standard mode AUXR=0x0C; // Seleziona ERAM su area dati esterna EECON=0x00; // Disabilita EEPROM del micro } 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 } 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 i, d; ritardo(2); init_cpu(); iniser(19200); clrscr(); demo_init(); // Inizializzazione periferiche while(TRUE) // Infinite Loop { i=0x01; d=~i; // Per pilotaggio di LEDs in logica negata // Ad esempio con la DEB 01 o la TIO 16 while(i) { i2c_invia(Wpcf8574, &d, 1); // Invia il dato al PCF8574 i<<=1; // Shift a sinistra d=~i; ritardo(500); // Per rendere visibile lo shift } i=0x80; d=~i; // Per pilotaggio di LEDs in logica negata // Ad esempio con la DEB 01 o la TIO 16 while(i) { i2c_invia(Wpcf8574, &d, 1); // Invia il dato al PCF8574 i>>=1; // Shift a destra d=~i; ritardo(500); // Per rendere visibile lo shift } } }