' **************************************************************** ' * File: k51termo.bas - Ver. 1.1 * ' * Compilatore: PIC Basic PRO * ' * IDE: MicroCode Studio Plus * ' * Versione Compilatore: 2.45 * ' * 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 10.02.05 * ' **************************************************************** ' ' Questo demo permette di pilotare una periferica I2C BUS a bordo della K51-AVR, ' DS1621, attraverso il modulo mini-BLOCK GMB HR84 ed un mini modulo grifo(r). ' Il Ds1621 e' un termometro digitale programmabile, con risoluzione di mezzo ' grado Celsius, tutte le operazioni di programmazione e acquisizione della ' temperatura avvengono tramite l'interfaccia seriale sincrona I2C BUS. ' Il demo mostra sui display a 7 segmenti della K51-AVR la temperatura misurata. ' ' ' Rel 1.1 - by Graziano Gaiba ' Demo per l'utilizzo del DS1621 a bordo della K51-AVR usando una GMB HR168 ' pilotata da un Mini Modulo GMM 4620 ' ' ' ***************** Definizioni del compilatore ****************** ' DEFINE OSC 10 ' Frequenza oscillatore 9,8304 MHz DEFINE HSER_RCSTA 90h ' Abilita EUSART in ricezione DEFINE HSER_TXSTA 20h ' Abilita EUSART in trasmissione DEFINE HSER_BAUD 19200 ' Baud Rate ' ' *************** Dichiarazione delle contanti ******************* ' I2C_BUFFER_SIZE con 10 Saa1064 con $38 ' Slave address SAA1064 Wsaa1064 con $70 ' Slave address SAA1064 in Write Rsaa1064 con $71 ' Slave address SAA1064 in Read '****************** Indirizzi registri Saa1064 ******************** Ctb con 0 ' Registro di controllo Dig1 con 1 ' Cifra 1 Dig2 Con 2 ' Cifra 2 Dig3 Con 3 ' Cifra 3 Dig4 Con 4 ' Cifra 4 ' ' ********************************************************************** ' Ds1621 con $4C ' Slave address DS1621 Wds1621 con $98 ' Slave address DS1621 in Write Rds1621 con $99 ' Slave address DS1621 in Read ' ***************** Lista comandi del DS1621 *************************** Cfg con $AC ' Registro di configurazione DS1621 Rtemp con $AA ' Lettura temperatura in 2 bytes Strct con $EE ' Inizia conversione temperatura Stpct con $22 ' Stop temperature conversion ' ' ' ******************* Dichiarazione delle Variabili ******************** ' ' Variabili di uso generico i var byte c var byte scelta var byte di var byte do var byte ' ' Usata dalle procedure di gestione I/O port_val var byte ' Valore letto o da scrivere nell'I/O ' ' Usate per la gestione dell'I2C BUS hardware i2c_buffer var byte[I2C_BUFFER_SIZE] i2c_to_send var byte i2c_to_receive var byte i2c_val var byte i2c_data var byte i2c_slave var byte i2c_addr var byte i2c_cnt var byte ' ' Cifre della temperatura Centinaia var byte Decine var byte Unita var byte ' ' Conversione letta da DS1621 Th var byte Tl var byte ' ' '********************** Programma principale *************************** ' main: gosub Init_cpu ' Spegne i relays port_val = 0 gosub set_relays ' Inizializza la periferica hardware I2C BUS gosub i2cbusinit ' Inizializza le periferiche a bordo della K51-AVR gosub k51_init ' Pulisce lo schermo gosub clrscr for_ever: gosub Leggi_temperatura gosub vis_temp goto for_ever end ' ' ******************* Definizione delle procedure ********************* ' ' ' Inizializzazione direzione segnali della CPU Init_cpu: 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.0 = 1 trisa.1 = 1 trisa.4 = 1 trisb.0 = 1 trisb.1 = 1 trisc.0 = 1 trisc.1 = 1 trisc.5 = 1 ' 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 & $03 ' Le uscite relays di CN4 sono: ' OUT D1 <-> RA3 ' OUT D2 <-> RC2 (J10 in posizione 3-4) trisa.3 = 0 trisc.2 = 0 return ' ' ' Pulisce lo schermo, inviando 25 volte CR + LF. clrscr: for i= 0 to 24 hserout [13, 10] next i return ' ' ' Chiede la pressione di un tasto chiede_tasto: hserout ["Premere un tasto..."] chiede_tasto_loop: hserin 1, chiede_tasto_loop, [i] return ' ' ' 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) set_relays: ' I relays sono pilotati in logica complementata , quindi anche port_val ' deve essere complementato port_val = port_val ^ $ff portb.4 = port_val.0 portb.5 = port_val.1 portb.6 = port_val.2 portb.7 = port_val.3 portb.3 = port_val.4 portb.2 = port_val.5 porta.3 = port_val.6 portc.2 = port_val.7 return ' ' ' Inizializza I2C BUS hardware I2CBUSInit: ' ' Inizializza I2C BUS ' Configura RC3 e RC4 come inputs trisc.3 = 1 trisc.4 = 1 ' Abilita modula SSP in master I2C BUS mode, clock 50 kHz sspstat.6 = 0 sspadd = $32 sspcon1 = $28 return ' ' ' Genera I2C BUS start I2CBUSStart: sspcon2.0 = 1 I2CBUSStartLoop: if sspcon2.0 = 1 then I2CBUSStartLoop pir1.3 = 0 return ' ' ' Genera I2C BUS start ripetuta I2CBUSRepStart: sspcon2.1 = 1 I2CBUSRepStartLoop: if sspcon2.1 = 1 then I2CBUSRepStartLoop pir1.3 = 0 return ' ' ' Genera I2C BUS stop I2CBUSStop: sspcon2.2 = 1 I2CBUSStopLoop: if sspcon2.2 = 1 then I2CBUSStopLoop pir1.3 = 0 return ' ' ' Invia il contenuto della variabile i2c_data all'I2C BUS I2CBUSSend: sspbuf = i2c_data I2CBUSSendSynch: ' Attende completamento dell'ultima operaziane dell'interfaccia hardware I2C if pir1.3 = 0 then I2CBUSSendSynch pir1.3 = 0 return ' ' ' Legge un dato da I2C BUS e lo restituisce nella variabile i2c_data I2CBUSGet: sspcon2.3 = 1 I2CBusGetLoop: if sspcon2.3 = 1 then I2CBusGetLoop i2c_data = sspbuf I2CBUSGetSynch: ' Attende completamento dell'ultima operaziane dell'interfaccia hardware I2C if pir1.3 = 0 then I2CBUSGetSynch pir1.3 = 0 return ' ' ' Invia NOT acknowledge I2CBUSNACK: ' Invia NOT acknowledge... sspcon2.5 = 1 sspcon2.4 = 1 ' Attende completamento dell'ultima operaziane dell'interfaccia hardware I2C I2CBUSNACKSynch: if pir1.3 = 0 then I2CBUSNACKSynch pir1.3 = 0 return ' ' ' Invia acknowledge I2CBUSACK: ' Invia acknowledge... sspcon2.5 = 0 sspcon2.4 = 1 ' Attende completamento dell'ultima operaziane dell'interfaccia hardware I2C I2CBUSACKSynch: if pir1.3 = 0 then I2CBUSNACKSynch pir1.3 = 0 return ' ' ' Indica che un acknowledge atteso non e' stato ricevuto. I2CBUSNotAck: hserout ["Acknowledge non ricevuto.", 13, 10] ' Disabilita I2CBUS sspcon1.5 = 0 return ' ' ' 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. I2CBUSReadByte: ' ' Genera I2CBUS Start. gosub i2cbusstart ' Invia Slave Address i2c_data = i2c_slave gosub i2cbussend ' Se acknowledge non ricevuto, segnala un errore if sspcon2.6 = 1 then I2CBUSNotAck ' Invia indirizzo i2c_data = i2c_addr gosub i2cbussend ' Se acknowledge non ricevuto, segnala un errore if sspcon2.6 = 1 then I2CBUSNotAck ' Genera I2CBUS Start ripetuto gosub i2cbusrepstart ' Invia Slave Address per la lettura i2c_data = i2c_slave | $01 gosub i2cbussend ' Se acknowledge non ricevuto, segnala un errore if sspcon2.6 = 1 then I2CBUSNotAck ' ricewve il dato gosub i2cbusget i2c_val = i2c_data ' Invia NOT acknowledge. gosub I2CBUSNACK ' Genera stop gosub i2cbusstop return ' ' ' 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. I2CBUSWriteByte: ' ' Genera I2CBUS Start. gosub i2cbusstart ' Invia Slave Address per scrittura i2c_data = i2c_slave gosub i2cbussend ' Se acknowledge non ricevuto, segnala un errore if sspcon2.6 = 1 then I2CBUSNotAck ' Invia indirizzo i2c_data = i2c_addr gosub i2cbussend ' Se acknowledge non ricevuto, segnala un errore if sspcon2.6 = 1 then I2CBUSNotAck ' Invia dato i2c_data = i2c_val gosub i2cbussend ' Se acknowledge non ricevuto, segnala un errore if sspcon2.6 = 1 then I2CBUSNotAck ' Genera stop gosub i2cbusstop return ' ' ' Invia una sequenza di bytes ad un dispositivo I2C BUS. ' Lo slave address deve essere contentuo nella variabile i2c_slave. ' I dati da inviare vanno memorizzati nell'array i2c_buffer. ' L'utente puo' cambiare la dimensione dell'array modificando I2C_BUFFER_SIZE. ' Il numero di bytes da inviare va memorizzato nella variabile i2c_to_send. ' L'utente deve verifcare che non avvengano eventuali overflows. I2CBUSWrite: ' ' Genera I2CBUS Start. gosub i2cbusstart ' Invia Slave Address in scrittura i2c_data = i2c_slave gosub i2cbussend ' Se acknowledge non ricevuto, segnala un errore if sspcon2.6 = 1 then I2CBUSNotAck for i2c_cnt = 0 to i2c_to_send - 1 ' Invia dati i2c_data = i2c_buffer[i2c_cnt] gosub i2cbussend ' Se acknowledge non ricevuto, segnala un errore if sspcon2.6 = 1 then I2CBUSNotAck next i2c_cnt ' Genera stop gosub i2cbusstop return ' ' ' Legge una sequenza di bytes da un dispositivo I2C BUS. ' Lo slave address deve essere contentuo nella variabile i2c_slave. ' I dati da inviare vanno memorizzati nell'array i2c_buffer. ' L'utente puo' cambiare la dimensione dell'array modificando I2C_BUFFER_SIZE. ' I dati ricevuti vengono memorizzati nello stesso array. ' Il numero di bytes da inviare va memorizzato nella variabile i2c_to_send. ' Il numero di bytes da ricevere va memorizzato nella variabile i2c_to_receive. ' L'utente deve verifcare che non avvengano eventuali overflows. I2CBUSRead: ' ' Generat I2CBUS Start. gosub i2cbusstart ' Invia Slave Address in scrittura i2c_data = i2c_slave gosub i2cbussend ' Se acknowledge non ricevuto, segnala un errore if sspcon2.6 = 1 then I2CBUSNotAck for i2c_cnt = 0 to i2c_to_send - 1 ' Invia dati i2c_data = i2c_buffer[i2c_cnt] gosub i2cbussend ' Se acknowledge non ricevuto, segnala un errore if sspcon2.6 = 1 then I2CBUSNotAck next i2c_cnt ' Genera I2CBUS Start ripetuto. gosub i2cbusrepstart ' Invia Slave Address in lettura i2c_data = i2c_slave | $01 gosub i2cbussend ' Se acknowledge non ricevuto, segnala un errore if sspcon2.6 = 1 then I2CBUSNotAck for i2c_cnt = 0 to i2c_to_receive - 1 ' Legge i dati gosub i2cbusget i2c_buffer[i2c_cnt] = i2c_data if i2c_cnt == i2c_to_receive - 1 then ' Invia NOT acknowledge. gosub I2CBUSNACK else ' Invia acknowledge. gosub I2CBUSaCK endif next i2c_cnt ' Invia lo stop gosub i2cbusstop return ' ' ' Inizializzazione delle periferiche a bordo della K51-AVR K51_init: ' ' Configurazione del controller dei display a 7 segmenti SAA 1064 ' gosub i2cbusstart i2c_data = rsaa1064 gosub i2cbussend gosub i2cbusget gosub i2cbusnack gosub i2cbusstop if i2c_data <> 0 then k51_init ' i2c_slave = wsaa1064 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] = 0 i2c_buffer[3] = 0 i2c_buffer[4] = 0 i2c_buffer[5] = 0 i2c_to_send = 6 gosub i2cbuswrite ' ' Configurazione del termometro DS 1621 ' ' Inizializza termometro i2c_slave = Wds1621 i2c_addr = cfg gosub i2cbuswritebyte ' ' Legge registro di configurazione del DS 1621 ' i2c_slave = wds1621 i2c_addr = cfg gosub i2cbusreadbyte ' Se la conversione e' abilitata, falla partire if i2c_val.0 == 0 then begin_conversion ' Se la conversione non e' abilitata, abilitarla i2c_slave = wds1621 i2c_addr = cfg i2c_val = %00001010 ' Scrive registro configurazione ' bit1= 1 polarita' "1" ' bit0= 0 conversione continua gosub i2cbuswritebyte Begin_conversion: i2c_slave = wds1621 i2c_buffer[0] = strct i2c_to_send = 1 gosub i2cbuswrite return ' ' ' Questa procedura converte 1 byte da 0 a 255 in temperatura dove da ' 0 a 125 sono gradi centigradi positivi (+0..+125), mentre da 255 a 201 sono ' gradi centigradi negativi (-0...-55), in pratica il bit7 indica il segno, ' i gradi negativi si ottengono con il complemento. Es: Not 255=0, Not 201=54 Cifre: if th <= 127 then temppositive ' Se la temperatura e' negativa, aggiustare il valore facendone ' il complemento a 1 th = th ^ $FF ' Attivo il segno meno Centinaia = 10 goto temp_if1 TempPositive: if th <= 99 then temp1 ' Se e' uguale o superiore a 100, attivo le centinaia Centinaia = 1 ' Sottraggo 100 th = th - 100 goto temp_if1 Temp1: ' Non supera 99, spengo la cifra delle centinaia Centinaia = 11 Temp_if1: if th <= 9 then temp2 ' Supera 9, ricavo la cifra delle decine Decine = th / 10 ' Ricavo le unita' c = Decine * 10 Unita = th - c goto cifre_esci Temp2: if Centinaia <> 11 then temp3 ' Less than 9 and Centinaia off, also Decine off Decine = 11 goto Cifre_Unita_vale_0 Temp3: if Centinaia <> 10 then temp4 ' Minore di 9 e centinaia spente, cifra delle decine spenta Decine = 11 goto Cifre_Unita_vale_0 Temp4: ' Minore di 9 e negativa, cifra delle decine spenta Decine = 0 Cifre_Unita_vale_0: ' Unita Unita = th Cifre_esci: return ' ' ' Visualizzazione della temperatura sui display a 7 segmenti Vis_temp: ' Separa il valore di temperatura in W0 in tre cifre: ' Centinaia, Decine e Unita gosub cifre ' Converte il valore decimale in codifica a 7 segmenti di = Centinaia gosub dec_to_7seg Centinaia = di ' Converte il valore decimale in codifica a 7 segmenti di = Decine gosub dec_to_7seg Decine = di ' Converte il valore decimale in codifica a 7 segmenti di = Unita gosub dec_to_7seg Unita = di ' ' Invia il valore di temperatura converitito in codifica a 7 ' segmenti al driver dei display a 7 segmenti i2c_slave = Wsaa1064 i2c_buffer[0] = dig1 i2c_buffer[1] = Centinaia i2c_buffer[2] = Decine i2c_buffer[3] = Unita | $80 if tl == $80 then ' Scrive 5 i2c_buffer[4] = $6D else ' Scrive 0 i2c_buffer[4] = $3F endif i2c_to_send = 5 gosub i2cbuswrite return Dec_to_7Seg: lookup di, [$3F, $06, $5B, $4F, $66, $6D, $7D, $07, $7F, $6F, $40, $00], di return ' ' ' Lettura della temperatura misurata dal DS1621 in Th e Tl Leggi_temperatura: i2c_slave = wds1621 i2c_buffer[0] = rtemp i2c_to_send = 1 i2c_to_receive = 2 gosub i2cbusread th = i2c_buffer[0] tl = i2c_buffer[1] return