{ **************************************************************** * File: gmbi2c.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 * * 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 09.03.05 * **************************************************************** Questo demo permette di comunicare con disposivi I2C BUS collegati a CN8. E' possibile leggere e scrivere byte ad un qualsiasi slave address ed address inseriti da console. In particolare, in lettura il byte ricevuto viene visualizzato, mentre in caso di scrittura il dato inserito viene spedito. Rel 1.1 - by Graziano Gaiba Demo per comunicazione I2C BUS usando una GMB HR168 pilotata da un Mini Modulo GMM 4620 } { ***************** Definizioni del compilatore ****************** } program gmbi2c; { *************** Dichiarazione delle contanti ******************* } const RTCSLA:byte = $A0; { ******************* Dichiarazione delle Variabili ******************** } // Variabili di uso generico var chr_in, scelta: byte; txt: string[3]; // Usate per la gestione dell'I2C BUS hardware i2c_buffer: array[10] of byte; i2c_to_send, i2c_to_receive, i2c_slave: byte; Label for_ever; { ******************* 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; // Verifica che il parametro in ingresso sia una cifra esadecimale function is_HEX_digit(valore: byte): byte; var flag: byte; begin flag := 0; if (valore >=48) and (valore <= 57) then begin flag := 1; end; if (valore >= 65) and (valore <= 70) then begin flag := 1; end; if (valore >= 97) and (valore <= 102) then begin flag := 1; end; Result := flag; end; // Restituisce il valore di una singola cifra esadecimale ASCII. // NON verifica che il parametro in ingresso sia una cifra esadecimale function HEX_val(valore: byte): byte; begin valore := valore - 48; if valore > 9 then begin valore := valore - 17; if valore > 5 then begin valore := valore - 32; end; valore := valore + 10; end; Result := valore; end; {Inserimento di un valore esadecimale fino a quattro cifre. Il parametro in ingresso e' il numero di cifre, restituisce una word contenente il valore immesso. Gestisce il backspace (ASCII 08) ed accetta cifre in input da '0' a '9', da 'a' a 'f' e da 'A' a 'F'. Iniva un carattere di bell (ASCII 07) quando riceve un dato non accettabile per l'input, o si tenta un inserimento o una cancellazione fuori dal range ammesso. } function inputHEX(n_char: byte): word; var str_input: array[6] of byte; idx, chr_input: byte; pow_of_16: array[5] of word; valore: word; begin pow_of_16[1] := 1; pow_of_16[2] := 16; pow_of_16[3] := 256; pow_of_16[4] := 4096; // Indice deve partire da 1 idx := 1; Inc(n_char); // Nessun carattere in input chr_input := 0; // Valore iniziale valore := 0; // Continua finche' non riceve un carattere CR while chr_input <> 13 do begin // Se un dato e' pronto if usart_data_ready = 1 then begin // Leggilo chr_input := USART_Read; // Se e' backspace (ASCII BS) if chr_input = 8 then begin // e il buffer non e' vuoto if idx > 1 then begin // Invia dato letto USART_Write(chr_input); // Cancella carattere USART_Write(32); USART_Write(chr_input); // Elimina ultimo dato letto Dec(idx); end else begin // Carattere bell per indicare un errore USART_Write(7); end; end; // Se CR ricevuto, elabora il valore e restituiscilo if chr_input = 13 then begin n_char := 0; while idx > 1 do begin Dec(idx); Inc(n_char); valore := valore + word(HEX_val(str_input[n_char])) * pow_of_16[idx]; end; end else begin // Se il carattere puo' essere inserito if idx < n_char then begin // Se il dato ricevuto e' valido: // 0..9 o 'a'..'f' o 'A'..'F' if is_HEX_digit(chr_input) = 1 then begin // Invia il dato letto USART_Write(chr_input); // Memorizzalo nel buffer di ingresso str_input[idx] := chr_input; // Punta alla posizione successiva Inc(idx); end; end else begin // Carattere bell per indicare un errore USART_Write(7); end; end; end; end; print_CRLF; Result := valore; end; { ********************** Programma principale *************************** } begin Init_cpu; // Spegne i relays set_relays(0); // Inizializza periferica I2C BUS hardware i2cbusinit; for_ever: clrscr; print_USART('Demo I2C BUS Rel 1.1 per GMM 4620 rel 120304 e GMB HR168 rel 110104'); print_crlf; print_crlf; print_USART('1) Invio'); print_crlf; print_USART('2) Ricezione'); print_crlf; print_crlf; repeat begin print_USART('Scelta: '); scelta := inputHEX(1); end; until (scelta > 0) and (scelta < 3); print_crlf; print_crlf; print_USART('Inserire slave address in esadecimale: '); i2c_slave := inputHEX(2); print_CRLF; print_USART('Quanti bytes vanno inviati (0 a 9)? '); i2c_to_send := inputHEX(1); for chr_in := 1 to i2c_to_send do begin print_USART('Inserire (in esadecimale) il dato n. '); ByteToStr(chr_in, txt); print_USART(txt); print_USART(': '); i2c_buffer[chr_in - 1] := inputHEX(2); end; if scelta = 1 then begin i2cbuswrite(i2c_slave, i2c_to_send, i2c_buffer); end else begin print_USART('Quanti bytes vanno ricevuti (0 a 9)? '); i2c_to_receive := inputHEX(1); i2cbusread(i2c_slave, i2c_to_send, i2c_to_receive, i2c_buffer); print_CRLF; for chr_in := 1 to i2c_to_receive do begin print_USART('Dato (decimale) ricevuto n. '); ByteToStr(chr_in, txt); print_USART(txt); print_USART(': '); ByteToStr(i2c_buffer[chr_in - 1], txt); print_USART(txt); print_CRLF; end; end; print_CRLF; wait_key; goto for_ever; end.