' **************************************************************** ' * File: k51da.pbas - Ver. 1.1 * ' * Compilatore: mikroBasic for PIC by mikroElektronica * ' * IDE: mikroBasic for PIC by mikroElektronica * ' * Versione Compilatore: 1.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 28.02.05 * ' **************************************************************** ' ' Questo demo permette di pilotare una periferica I2C BUS a bordo della K51-AVR, ' PCF8591, attraverso il modulo mini-BLOCK GMB HR84 ed un mini modulo grifo(r). ' Il PCF8591 e' dotato di una uscita analogica D/A con risoluzione ad 8 bit, ' tutte le operazioni di attivazione avvengono tramite l'interfaccia seriale ' sincrona I2C BUS. ' Il demo permette di impostare quale livello di tensione avere in uscita ' tramite la tastiera del PC, e scrive 'da' sui display a 7 segmenti della ' K51-AVR per indicare il funzionamento del demo. ' ' ' Rel 1.1 - by Graziano Gaiba ' Demo per l'utilizzo del PCF8591 a bordo della K51-AVR usando una GMB HR168 ' pilotata da un Mini Modulo GMM 4620 ' ' ' ***************** Definizioni del compilatore ****************** ' program k51ad4ch ' ' *************** Dichiarazione delle contanti ******************* ' const ASC_plus = $2B const ASC_minus = $2D const Saa1064 = $38 ' Slave address SAA1064 const Wsaa1064 = $70 ' Slave address SAA1064 in Write const Rsaa1064 = $71 ' Slave address SAA1064 in Read '****************** Indirizzi registri Saa1064 ******************** const Ctb = 0 ' Registro di controllo const Dig1 = 1 ' Cifra 1 const Dig2 = 2 ' Cifra 2 const Dig3 = 3 ' Cifra 3 const Dig4 = 4 ' Cifra 4 ' ' ********************************************************************** ' const Pcf8591 = $48 ' Slave address PCF8591 const Wpcf8591 = $90 ' Slave address PCF8591 in Write const Rpcf8591 = $91 ' Slave address PCF8591 in Read ' ' ' ******************** Variables declaration ********************* ' ' Usate per la gestione dell'I2C BUS hardware dim i2c_buffer as byte[10] ' ' Livello di tensione in uscita dal D/A dim DA_output as byte ' ' ' ******************* Definizione delle procedure ********************* ' ' ' Inizializzazione direzione segnali della CPU sub procedure 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 and $03 ' Le uscite relays di CN4 sono: ' OUT D1 <-> RA3 ' OUT D2 <-> RC2 (J10 in posizione 3-4) trisa.3=0 trisc.2=0 ' Inizialzza modulo USART (8 bit, 19200 baud rate, ' no parity) Usart_init(19200) end sub ' ' ' Invia una stringa di caratteri alla porta seriale sub procedure print_USART(dim byref txt as char[255]) dim i as byte dim l as byte l = txt[0] for i = 1 to l USART_Write(txt[i]) next i end sub ' ' ' Invia CR + LF sub procedure print_CRLF USART_Write(10) USART_Write(13) end sub ' ' ' Pulisce lo schermo, inviando 25 volte CR + LF. sub procedure clrscr dim i as byte for i = 0 to 24 print_CRLF next i end sub ' ' ' Chiede la pressione di un tasto sub procedure wait_key dim c as byte print_usart("Premere un tasto...") do nop loop until USART_Data_Ready = 1 c = USART_Read end sub ' ' ' 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) sub procedure set_relays(dim port_val as byte) ' I relays sono pilotati in logica complementata , quindi anche port_val ' deve essere complementato port_val=port_val xor $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 end sub ' ' ' Inizializza I2C BUS hardware sub procedure 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 end sub ' ' ' Genera I2C BUS start sub procedure I2CBUSStart sspcon2.0=1 while sspcon2.0=1 wend pir1.3=0 end sub ' ' ' Genera I2C BUS start ripetuta sub procedure I2CBUSRepStart sspcon2.1=1 while sspcon2.1=1 wend pir1.3=0 end sub ' ' ' Genera I2C BUS stop sub procedure I2CBUSStop sspcon2.2=1 while sspcon2.2=1 wend pir1.3=0 end sub ' ' ' Invia il contenuto della variabile i2c_data all'I2C BUS sub procedure I2CBUSSend(dim i2c_data as byte) sspbuf=i2c_data ' Attende completamento dell'ultima operaziane dell'interfaccia hardware I2C while pir1.3=0 wend pir1.3=0 end sub ' ' ' Legge un dato da I2C BUS e lo restituisce sub function I2CBUSGet as byte sspcon2.3=1 while sspcon2.3=1 wend result=sspbuf ' Attende completamento dell'ultima operaziane dell'interfaccia hardware I2C while pir1.3=0 wend pir1.3=0 end sub ' ' ' Invia NOT acknowledge sub procedure I2CBUSNACK ' Invia NOT acknowledge... sspcon2.5=1 sspcon2.4=1 ' Attende completamento dell'ultima operaziane dell'interfaccia hardware I2C while pir1.3=0 wend pir1.3=0 end sub ' ' ' Invia acknowledge sub procedure I2CBUSACK ' Invia acknowledge... sspcon2.5=0 sspcon2.4=1 ' Attende completamento dell'ultima operaziane dell'interfaccia hardware I2C while pir1.3=0 wend pir1.3=0 end sub ' ' ' Indica che un acknowledge atteso non e' stato ricevuto. sub procedure I2CBUSNotAck print_USART("Acknowledge not received.") print_crlf ' Disabilita I2CBUS sspcon1.5=0 end sub ' ' ' 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. sub function I2CBUSReadByte(dim i2c_slave as byte, dim i2c_addr as byte) as byte ' ' Genera I2CBUS Start i2cbusstart ' Invia Slave Address i2cbussend(i2c_slave) ' Se acknowledge non ricevuto, segnala un errore if sspcon2.6=1 then I2CBUSNotAck end if ' Invia indirizzo i2cbussend(i2c_addr) ' Se acknowledge non ricevuto, segnala un errore if sspcon2.6=1 then I2CBUSNotAck end if ' Genera I2CBUS Start ripetuto i2cbusrepstart ' Invia Slave Address per la lettura i2cbussend(i2c_slave or $01) ' Se acknowledge non ricevuto, segnala un errore if sspcon2.6=1 then I2CBUSNotAck end if ' Riceve il dato result = i2cbusget ' Invia NOT acknowledge. I2CBUSNACK ' Genera stop i2cbusstop end sub ' ' ' 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. sub procedure I2CBUSWriteByte(dim i2c_slave as byte, dim i2c_addr as byte, dim i2c_data as byte) ' ' Genera I2CBUS Start i2cbusstart ' Invia Slave Address i2cbussend(i2c_slave) ' Se acknowledge non ricevuto, segnala un errore if sspcon2.6=1 then I2CBUSNotAck end if ' Invia indirizzo i2cbussend(i2c_addr) ' Se acknowledge non ricevuto, segnala un errore if sspcon2.6=1 then I2CBUSNotAck end if ' Invia il dato i2cbussend(i2c_data) ' Se acknowledge non ricevuto, segnala un errore if sspcon2.6=1 then I2CBUSNotAck end if ' Genera stop i2cbusstop end sub ' ' ' 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. sub procedure I2CBUSWrite(dim i2c_slave as byte, dim byref i2c_buffer as byte[10], dim i2c_to_send as byte) dim i2c_cnt as byte ' ' Genera I2CBUS Start i2cbusstart ' Invia Slave Address i2cbussend(i2c_slave) ' Se acknowledge non ricevuto, segnala un errore if sspcon2.6=1 then I2CBUSNotAck end if for i2c_cnt=0 to i2c_to_send - 1 ' Invia il dato i2cbussend(i2c_buffer[i2c_cnt]) ' Se acknowledge non ricevuto, segnala un errore if sspcon2.6=1 then I2CBUSNotAck end if next i2c_cnt ' Genera stop i2cbusstop end sub ' ' ' 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. sub procedure I2CBUSRead(dim i2c_slave as byte, dim byref i2c_buffer as byte[10], dim i2c_to_send as byte, dim i2c_to_receive as byte) dim i2c_cnt as byte ' ' Genera I2CBUS Start. i2cbusstart ' Invia Slave Address i2cbussend(i2c_slave) ' Se acknowledge non ricevuto, segnala un errore if sspcon2.6=1 then I2CBUSNotAck end if for i2c_cnt=0 to i2c_to_send - 1 ' Invia il dato i2cbussend(i2c_buffer[i2c_cnt]) ' Se acknowledge non ricevuto, segnala un errore if sspcon2.6=1 then I2CBUSNotAck end if next i2c_cnt ' Genera I2CBUS Start ripetuto i2cbusrepstart ' Invia Slave Address per la lettura i2cbussend(i2c_slave or $01) ' Se acknowledge non ricevuto, segnala un errore if sspcon2.6=1 then I2CBUSNotAck end if for i2c_cnt=0 to i2c_to_receive - 1 ' Legge il dato i2c_buffer[i2c_cnt] = i2cbusget if i2c_cnt = i2c_to_receive - 1 then ' Invia NOT acknowledge. I2CBUSNACK else ' Invia acknowledge. I2CBUSaCK end if next i2c_cnt ' Invia lo stop i2cbusstop end sub ' ' ' Inizializzazione delle periferiche a bordo della K51-AVR sub procedure K51_init dim dummy as byte ' ' Configurazione del controller dei display a 7 segmenti SAA 1064 ' do I2CBUSstart I2CBUSSend(rsaa1064) dummy = I2CBUSGet I2CBUSNACK I2CBUSStop loop 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] = 94 i2c_buffer[3] = 119 i2c_buffer[4] = 0 i2c_buffer[5] = 0 i2cbuswrite(wsaa1064, i2c_buffer, 6) end sub ' ' ' Converte una cifra decimalenella rappresentazione a 7-segmenti sub function DecTo7Seg(dim value as byte) as byte dim temp as byte select case value case 0 temp = $3F case 1 temp = $06 case 2 temp = $5B case 3 temp = $4F case 4 temp = $66 case 5 temp = $6D case 6 temp = $7D case 7 temp = $07 case 8 temp = $7F case 9 temp = $6F case 10 temp = $77 case 11 temp = $7C case 12 temp = $39 case 13 temp = $5E case 14 temp = $79 case 15 temp = $71 end select Result = temp end sub ' ' ' Divide in due parti il parametro: ' Nibble_h (nibble alto) e Nibble_l (nibble basso) sub procedure Cifre(dim figure as byte, dim byref nibble_h as byte, dim byref nibble_l as byte) nibble_h = figure div 16 nibble_l = figure and $0F end sub ' ' ' Visualizza due cifre esadecimali sul display a 7 segmenti sub procedure Vis_num(dim figure as byte) dim nibble_h as byte dim nibble_l as byte 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, i2c_buffer, 3) end sub ' ' ' Selezione del livello di tensione in uscita dal D/A sub procedure DA_level(dim byref da_output as byte) dim ser_input as byte if USART_Data_Ready = 1 then ser_input = USART_Read end if if ser_input = ASC_plus then Inc(da_output) end if if ser_input = ASC_minus then Dec(da_output) end if end sub ' ' ' Imposta il livello di tensione desiderato in uscita. ' Il range della tensione va da 0 a 5 V, la risoluzione del PWM e'8 bit ' quindi il range di uscita viene mappato into interamente nel range ' di valori ammesso per il tipo di variabile usato, ovvero da 0 a 255. sub procedure Set_out(dim livello_uscita as byte) ' Attivazione PWM i2cbuswritebyte(wpcf8591, $40, livello_uscita) end sub ' '********************** Programma principale *************************** ' main: 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 display a 7 segmenti l'indice dell'uscita PWM.") print_CRLF print_USART("Premere + per incrementare l'uscita, Premere - per decrementare l'uscita") ' da_output = 0 for_ever: set_out(da_output) vis_num(da_output) da_level(da_output) goto for_ever end.