{ **************************************************************** * File: k51ppi.ppas - Ver. 1.1 * * Compilatore: mikroPascal for PIC by mikroElektronica * * IDE: mikroPascal for PIC by mikroElektronica * * Versione Compilatore: 2.1.6.0 * * Schede: GMM 4620 + GMB HR168 + K51-AVR * * 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 * * by Graziano Gaiba 08.03.05 * **************************************************************** Questo demo permette di pilotare una periferica I2C BUS a bordo della K51-AVR, PCF8574, attraverso il modulo mini-BLOCK GMB HR84 ed un mini modulo grifo(r). Il PCF8574 e' un I/O expander che permette di pilotare 8 linee digitali TTL sia in ingresso che in uscita, tutte le operazioni di lettura e scrittura avvengono tramite l'interfaccia seriale sincrona I2C BUS. Il demo permette di acquisire lo stato delle otto linee digitali TTL e lo visualizza sui display a 7 segmenti della K51-AVR, accanto alla scritta 'in'. Rel 1.1 - by Graziano Gaiba Demo per l'utilizzo del PCF 8574 a bordo della K51-AVR usando una GMB HR168 pilotata da un Mini Modulo GMM 4620 } { ***************** Definizioni del compilatore ****************** } program k51ppi; { *************** Dichiarazione delle contanti ******************* } const Saa1064:byte = $38; // Slave address SAA1064 const Wsaa1064:byte = $70; // Slave address SAA1064 in Write const Rsaa1064:byte = $71; // Slave address SAA1064 in Read //****************** Indirizzi registri Saa1064 ******************** const Ctb:byte = 0; // Registro di controllo const Dig1:byte = 1; // Cifra 1 const Dig2:byte = 2; // Cifra 2 const Dig3:byte = 3; // Cifra 3 const Dig4:byte = 4; // Cifra 4 // // ********************************************************************** // //const Pcf8574:byte = $3C; // Slave address PCF8574A //const Wpcf8574:byte = $78; // Slave address PCF8574A in Write //const Rpcf8574:byte = $79; // Slave address PCF8574A in Read const Pcf8574:byte = $24; // Slave address PCF8574P const Wpcf8574:byte = $48; // Slave address PCF8574P in Write const Rpcf8574:byte = $49; // Slave address PCF8574P in Read { ******************* Dichiarazione delle Variabili ******************** } // Variabili di uso generico var d_in: byte; // Usate per la gestione dell'I2C BUS hardware i2c_buffer: array[10] of byte; { ******************* Definizione delle procedure ********************* } // Inizializzazione direzione segnali della CPU procedure Init_cpu; begin ADCON1 :=$0f; // Imposta come I/O digitale i pin AN0..12 CMCON :=$07; // Imposta come I/O digitale RA0..4 { Gli ingressi optoisolati di CN1 sono: IN1-1 <-> RA0 IN2-1 <-> RA1 IN3-1 <-> RB0 IN4-1 <-> RB1 IN5-1 <-> RA4 IN6-1 <-> RC0 IN7-1 <-> RC1 IN8-1 <-> RC5 } trisa := trisa or $13; trisb := trisb or $03; trisc := trisc or $23; { Gli ingressi optoisolati di CN2 sono: IN1-2 <-> RD0 IN2-2 <-> RD1 IN3-2 <-> RD2 IN4-2 <-> RD3 IN5-2 <-> RD4 IN6-2 <-> RD5 IN7-2 <-> RD6 IN8-2 <-> RD7 } trisd := $ff; { Le uscite relays di CN3 sono: OUT A1 <-> RB4 OUT A2 <-> RB5 OUT B1 <-> RB6 OUT B2 <-> RB7 OUT C1 <-> RB3 OUT C2 <-> RB2 } trisb := trisb and $03; { Le uscite relays di CN4 sono: OUT D1 <-> RA3 OUT D2 <-> RC2 (J10 in posizione 3-4) } trisa := trisa and $f7; trisc := trisc and $fb; // Inizialzza modulo USART (8 bit, 19200 baud rate, // no parity) Usart_init(19200); end; // Invia una stringa di caratteri alla porta seriale procedure print_USART(var txt: string[100]); var temp1, temp2: byte; begin temp1 := txt[0]; for temp2 := 1 to temp1 do begin USART_Write(txt[temp2]); end; end; // Invia CR + LF procedure print_CRLF; begin USART_Write(10); USART_Write(13); end; // Pulisce lo schermo, inviando 25 volte CR + LF. procedure clrscr; var temp: byte; begin for temp := 0 to 24 do begin print_CRLF; end; end; // Chiede la pressione di un tasto procedure wait_key; var temp: byte; begin print_usart('Premere un tasto...'); repeat begin nop; end; until USART_Data_Ready = 1; temp := USART_Read; end; { Procedura per impostare lo stato dei relays sui connettori CN3 e CN4. A seconda del valore dei bits di port_val, ogni relay viene attivato (contatto chiuso) o disattivato (contatto aperto). I bit di port_val hanno il seguente significato: -- CN3 port_val.0 pilota il relay OUT A1 port_val.1 pilota il relay OUT A2 port_val.2 pilota il relay OUT B1 port_val.3 pilota il relay OUT B2 port_val.4 pilota il relay OUT C1 port_val.5 pilota il relay OUT C2 -- CN4 port_val.6 pilota il relay OUT D1 port_val.7 pilota il relay OUT D2 Ogni bit ha il seguente significato: bit Significato 0 Relay disattivato (contatto aperto) 1 Relay attivato (contatto chiuso) } procedure set_relays(port_val: byte); begin // I relays sono pilotati in logica complementata , quindi anche port_val // deve essere complementato port_val:=port_val xor $ff; if TestBit(port_val, 0) = 0 then begin ClearBit(portb, 4); end else begin SetBit(portb, 4); end; if TestBit(port_val, 1) = 0 then begin ClearBit(portb, 5); end else begin SetBit(portb, 5); end; if TestBit(port_val, 2) = 0 then begin ClearBit(portb, 6); end else begin SetBit(portb, 6); end; if TestBit(port_val, 3) = 0 then begin ClearBit(portb, 7); end else begin SetBit(portb, 7); end; if TestBit(port_val, 4) = 0 then begin ClearBit(portb, 3); end else begin SetBit(portb, 3); end; if TestBit(port_val, 5) = 0 then begin ClearBit(portb, 2); end else begin SetBit(portb, 2); end; if TestBit(port_val, 6) = 0 then begin ClearBit(porta, 3); end else begin SetBit(porta, 3); end; if TestBit(port_val, 7) = 0 then begin ClearBit(portc, 2); end else begin SetBit(portc, 2); end; end; // Inizializza I2C BUS hardware procedure I2CBUSInit; begin // Inizializza I2C BUS // Configura RC3 e RC4 come inputs SetBit(trisc, 3); SetBit(trisc, 4); // Abilita modula SSP in master I2C BUS mode, clock 50 kHz ClearBit(sspstat, 6); sspadd := $32; sspcon1 := $28; end; // Genera I2C BUS start procedure I2CBUSStart; begin SetBit(sspcon2, 0); while TestBit(sspcon2, 0) = 1 do begin nop; end; ClearBit(pir1, 3); end; // Genera I2C BUS start ripetuta procedure I2CBUSRepStart; begin SetBit(sspcon2, 1); while TestBit(sspcon2, 1) = 1 do begin nop; end; ClearBit(pir1, 3); end; // Genera I2C BUS stop procedure I2CBUSStop; begin SetBit(sspcon2, 2); while TestBit(sspcon2, 2) = 1 do begin nop; end; ClearBit(pir1, 3); end; // Invia il contenuto della variabile i2c_data all'I2C BUS procedure I2CBUSSend(i2c_data: byte); begin sspbuf := i2c_data; // Attende completamento dell'ultima operaziane dell'interfaccia hardware I2C while TestBit(pir1, 3) = 0 do begin nop; end; ClearBit(pir1, 3); end; // Legge un dato da I2C BUS e lo restituisce function I2CBUSGet: byte; begin SetBit(sspcon2, 3); while TestBit(sspcon2, 3) = 1 do begin nop; end; Result := sspbuf; // Attende completamento dell'ultima operaziane dell'interfaccia hardware I2C while TestBit(pir1, 3) = 0 do begin nop; end; ClearBit(pir1, 3); end; // Invia NOT acknowledge procedure I2CBUSNACK; begin // Invia NOT acknowledge... SetBit(sspcon2, 5); SetBit(sspcon2, 4); // Attende completamento dell'ultima operaziane dell'interfaccia hardware I2C while TestBit(pir1, 3) = 0 do begin nop; end; ClearBit(pir1, 3); end; // Invia acknowledge procedure I2CBUSACK; begin // Invia acknowledge... ClearBit(sspcon2, 5); SetBit(sspcon2, 4); // Attende completamento dell'ultima operaziane dell'interfaccia hardware I2C while TestBit(pir1, 3) = 0 do begin nop; end; ClearBit(pir1, 3); end; // Indica che un acknowledge atteso non e' stato ricevuto. procedure I2CBUSNotAck; begin print_USART('Acknowledge non ricevuto.'); print_crlf; // Disabilita I2CBUS ClearBit(sspcon1, 5); end; {Legge un byte dal dispositivo il cui slave address e' contenuto nella variable i2c_slave e il cui indirizzo e' contenuto nella variabile i2c_addr. Il dato letto viene messo nella variabile i2c_val. } function I2CBUSReadByte(i2c_slave: byte; i2c_addr: byte): byte; begin // Genera I2CBUS Start i2cbusstart; // Invia Slave Address i2cbussend(i2c_slave); // Se acknowledge non ricevuto, segnala un errore if TestBit(sspcon2, 6) = 1 then begin I2CBUSNotAck; end; // Invia indirizzo i2cbussend(i2c_addr); // Se acknowledge non ricevuto, segnala un errore if TestBit(sspcon2, 6) = 1 then begin I2CBUSNotAck; end; // Genera I2CBUS Start ripetuto i2cbusrepstart; // Invia Slave Address per la lettura i2cbussend(i2c_slave or $01); // Se acknowledge non ricevuto, segnala un errore if TestBit(sspcon2, 6) = 1 then begin I2CBUSNotAck; end; // Riceve il dato Result := i2cbusget; // Invia NOT acknowledge. I2CBUSNACK; // Genera stop i2cbusstop; end; {Scrive un byte al dispositivo il cui slave address e' contenuto nella variablie i2c_slave e il cui indirizzo e' contenuto nella variabile i2c_addr. Il dato da scrivere viene messo nella variabile i2c_val. } procedure I2CBUSWriteByte(i2c_slave: byte; i2c_addr: byte; i2c_data: byte); begin // Genera I2CBUS Start i2cbusstart; // Invia Slave Address i2cbussend(i2c_slave); // Se acknowledge non ricevuto, segnala un errore if TestBit(sspcon2, 6) = 1 then begin I2CBUSNotAck; end; // Invia indirizzo i2cbussend(i2c_addr); // Se acknowledge non ricevuto, segnala un errore if TestBit(sspcon2, 6) = 1 then begin I2CBUSNotAck; end; // Invia il dato i2cbussend(i2c_data); // Se acknowledge non ricevuto, segnala un errore if TestBit(sspcon2, 6) = 1 then begin I2CBUSNotAck; end; // Genera stop i2cbusstop; end; {Invia una sequenza di bytes ad un dispositivo I2C BUS. Lo slave address deve essere contentuo nella variabile i2c_slave. L'utente puo' cambiare la dimensione dell'array nella lista parametri. Il numero di bytes da inviare va nella variabile i2c_to_send. L'utente deve verifcare che non avvengano eventuali overflow. } procedure I2CBUSWrite(i2c_slave: byte; i2c_to_send:byte; var i2c_buffer: array[10] of byte); var i2c_cnt:byte; begin // Genera I2CBUS Start i2cbusstart; // Invia Slave Address i2cbussend(i2c_slave); // Se acknowledge non ricevuto, segnala un errore if TestBit(sspcon2, 6) = 1 then begin I2CBUSNotAck; end; for i2c_cnt := 0 to i2c_to_send - 1 do begin // Invia il dato i2cbussend(i2c_buffer[i2c_cnt]); // Se acknowledge non ricevuto, segnala un errore if TestBit(sspcon2, 6) = 1 then begin I2CBUSNotAck; end; end; // Genera stop i2cbusstop; end; {Legge una sequenza di bytes da un dispositivo I2C BUS. Lo slave address va nella variabile i2c_slave. L'utente puo' cambiare la dimensione dell'array nella lista parametri. I dati ricevuti vengono memorizzati nello stesso array. Il numero di bytes da inviare va nella variabile i2c_to_send. Il numero di bytes da ricevere va nella variabile i2c_to_receive. L'utente deve verificare che non avvengano eventuali overflow. } procedure I2CBUSRead(i2c_slave: byte; i2c_to_send: byte; i2c_to_receive: byte; var i2c_buffer: array[10] of byte); var i2c_cnt: byte; begin // Genera I2CBUS Start. i2cbusstart; // Invia Slave Address i2cbussend(i2c_slave); // Se acknowledge non ricevuto, segnala un errore if TestBit(sspcon2, 6) = 1 then begin I2CBUSNotAck; end; for i2c_cnt := 0 to i2c_to_send - 1 do begin // Invia il dato i2cbussend(i2c_buffer[i2c_cnt]); // Se acknowledge non ricevuto, segnala un errore if TestBit(sspcon2, 6) = 1 then begin I2CBUSNotAck; end; end; // Genera I2CBUS Start ripetuto i2cbusrepstart; // Invia Slave Address per la lettura i2cbussend(i2c_slave or $01); // Se acknowledge non ricevuto, segnala un errore if TestBit(sspcon2, 6) = 1 then begin I2CBUSNotAck; end; for i2c_cnt := 0 to i2c_to_receive - 1 do begin // Legge il dato i2c_buffer[i2c_cnt] := i2cbusget; if i2c_cnt = i2c_to_receive - 1 then begin // Invia NOT acknowledge. I2CBUSNACK; end else begin // Invia acknowledge. I2CBUSaCK; end; end; // Invia lo stop i2cbusstop; end; // Inizializzazione delle periferiche a bordo della K51-AVR procedure K51_init; var dummy: byte; begin // Configurazione del controller dei display a 7 segmenti SAA 1064 repeat begin I2CBUSstart; I2CBUSSend(rsaa1064); dummy := I2CBUSGet; I2CBUSNACK; I2CBUSStop; end; until dummy = 0; i2c_buffer[0] := ctb; // Punta al registro di controllo i2c_buffer[1] := %00100111; // bit0 =1 dynamic mode // bit1 =1 cifre 1+3 non spente // bit2 =1 cifre 2+4 non spente // bit3 =0 no test segmenti // bit4 =0 no corrente segmenti 3mA // bit5 =1 corrente segmenti 6mA // bit6 =0 no corrente segmenti 12mA // bit7 =0 indifferente i2c_buffer[2] := 48; i2c_buffer[3] := 84; i2c_buffer[4] := 0; i2c_buffer[5] := 0; i2cbuswrite(wsaa1064, 6, i2c_buffer); end; // Converte una cifra decimalenella rappresentazione a 7-segmenti function DecTo7Seg(value: byte): byte; var temp: byte; begin case value of 0: temp := $3F; 1: temp := $06; 2: temp := $5B; 3: temp := $4F; 4: temp := $66; 5: temp := $6D; 6: temp := $7D; 7: temp := $07; 8: temp := $7F; 9: temp := $6F; 10: temp := $77; 11: temp := $7C; 12: temp := $39; 13: temp := $5E; 14: temp := $79; 15: temp := $71; end; Result := temp; end; // Divide in due parti il parametro: // Nibble_h (nibble alto) e Nibble_l (nibble basso) procedure Cifre(figure: byte; var nibble_h: byte; var nibble_l: byte); begin nibble_h := figure div 16; nibble_l := figure and $0F; end; // Visualizza due cifre esadecimali sul display a 7 segmenti // e in piu' il numero del canale A/D da convertire procedure Vis_num(figure: byte); var nibble_h, nibble_l: byte; begin cifre(figure, nibble_h, nibble_l); nibble_h := DecTo7Seg(nibble_h); nibble_l := DecTo7Seg(nibble_l); // Invia il valore codificato in 7 segmenti // al driver dei display a 7 segmenti i2c_buffer[0] := dig3; i2c_buffer[1] := nibble_h; i2c_buffer[2] := nibble_l; i2cbuswrite(Wsaa1064, 3, i2c_buffer); end; { ********************** Programma principale *************************** } begin Init_cpu; // Spegne i relays set_relays(0); // Inizializza periferica I2C BUS hardware I2Cbusinit; // Inizializza periferiche I2C BUS a bordo della K51-AVR k51_init; // Pulisce lo schermo clrscr; print_USART('Visualizza sui 7 segmenti lo stato degli ingressi TTL del PCF 8574 su CN1...'); repeat begin // Legge lo stato degli ingressi TTL del PCF 8574 i2cbusstart; i2cbussend(wpcf8574); i2cbusrepstart; i2cbussend(rpcf8574); d_in := i2cbusget; i2cbusnack; i2cbusstop; // Visualizza in esadecimale sul display a 7 segmenti il valore // dello stato degli ingressi TTL del PCF 8574 vis_num(d_in); end; until False; end.