' **************************************************************** ' * File: gmbrtc.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 * ' **************************************************************** ' ' GMM 4620 e' dotata di un Orologio in Tempo Reale, RTC, di bordo, ' che e' tamponato mediante la batteria al Litio di bordo, scollegabile. ' Tale componente puo' essere utilizzato per la schedulazione di ' sequenze di operazioni o per creare etichette temporali da associare ' a determinati eventi. ' L'interfaccia tra RTC e CPU e' in I2C BUS. ' Il programma Demo GMBRTC permette di utilizzare immediatamente la ' funzioinalita' dell'orologio, sia in lettura che in scrittura, ' mediante una serie di funzioni largamente commentate. ' Dette funzioni si preoccupano sia di comunicare con il componente, ' sia di visualizzare i dati. ' NOTA: L'ultima locazione della SRAM dell'RTC ($FF) e' riservata. ' ' ' Rel 1.1 - by Graziano Gaiba ' Demo di utilizzo dell'RTC I2C BUS usando una GMB HR168 ' pilotata da un Mini Modulo GMM 4620 ' ' ' ***************** Definizioni del compilatore ****************** ' program gmbrtc ' ' *************** Dichiarazione delle contanti ******************* ' const RTCSLA = $A0 const ASC_s = $73 const ASC_sU = $53 ' ' ******************* Dichiarazione delle Variabili ******************** ' ' Variabili di uso generico dim i as byte dim s as string[3] ' ' Usate per la gestione dell'RTC dim rtc_anno as byte dim rtc_mese as byte dim rtc_settimana as byte dim rtc_giorno as byte dim rtc_ora as byte dim rtc_minuto as byte dim rtc_secondo 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 ' ' ' Indica che un acknowledge atteso non e' stato ricevuto. sub procedure I2CBUSNotAck print_USART("Acknowledge non ricevuto.") print_crlf ' Disables 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 restituito. sub function I2CBUSReadByte(dim i2c_slave as byte, dim i2c_addr as byte) as byte dim b as byte sspcon1.5 = 0 sspcon1.5 = 1 ' ' Genera I2CBUS Start. I2C_start ' Invia Slave Address if I2C_wr(i2c_slave) <> 0 then ' Se acknowledge non ricevuto, segnala un errore I2CBUSNotAck end if ' Invia indirizzo if I2C_wr(i2c_addr) <> 0 then ' Se acknowledge non ricevuto, segnala un errore I2CBUSNotAck end if ' Genera I2CBUS Start ripetuto. I2C_Repeated_Start ' Invia Slave Address per la lettura if I2C_wr(i2c_slave or $01) <> 0 then ' Se acknowledge non ricevuto, segnala un errore I2CBUSNotAck end if ' Riceve il dato e invia NOT acknowledge b = I2C_Rd(0) ' Genera stop I2C_Stop Result = b 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) sspcon1.5 = 0 sspcon1.5 = 1 ' ' Genera I2CBUS Start. I2C_start ' Invia Slave Address if I2C_wr(i2c_slave) <> 0 then ' Se acknowledge non ricevuto, segnala un errore I2CBUSNotAck end if ' Invia indirizzo if I2C_wr(i2c_addr) <> 0 then ' Se acknowledge non ricevuto, segnala un errore I2CBUSNotAck end if ' Invia il dato if I2C_wr(i2c_data) <> 0 then ' Se acknowledge non ricevuto, segnala un errore I2CBUSNotAck end if ' Genera stop I2C_Stop end sub ' ' ' Inserimento di un valore decimale fino a cinque 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'. ' 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. sub function inputDEC(dim n_char as byte) as word dim str_input as byte[6] dim idx as byte dim chr_input as byte dim pow_of_10 as word[6] dim value as word pow_of_10[1] = 1 pow_of_10[2] = 10 pow_of_10[3] = 100 pow_of_10[4] = 1000 pow_of_10[5] = 10000 ' Indice deve partire da 1 idx = 1 Inc(n_char) ' Nessun carattere in input chr_input = 0 ' Valore iniziale value = 0 ' Continua finche' non riceve un carattere CR while chr_input <> 13 ' Se un dato e' pronto if usart_data_ready = 1 then ' Leggilo chr_input = USART_Read ' Se e' backspace (ASCII BS) if chr_input = 8 then ' e il buffer non e' vuoto if idx > 1 then ' Invia dato letto USART_Write(chr_input) ' Cancella carattere USART_Write(32) USART_Write(chr_input) ' Elimina ultimo dato letto Dec(idx) else ' Carattere bell per indicare un errore USART_Write(7) end if end if ' Se CR ricevuto, elabora il valore e restituiscilo if chr_input = 13 then n_char = 0 while idx > 1 Dec(idx) Inc(n_char) value = value + (str_input[n_char] - 48) * pow_of_10[idx] wend else ' Se il carattere puo' essere inserito if idx < n_char then ' Se il dato ricevuto e' valido: ' 0..9 if (chr_input >= 48) or(chr_input <= 57) then ' 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 if else ' Carattere bell per indicare un errore USART_Write(7) end if end if end if wend print_CRLF Result = value end sub ' ' ' Imposta data e ora sull'RTC I2C BUS PCF8583. ' Salva offset anno sull'ultima locazione SRAM, le otto ultime ' locazioni della SRAM sono riservate sub procedure set_rtc(dim rtc_settimana as byte, dim rtc_giorno as byte, dim rtc_mese as byte, dim rtc_anno as byte, dim rtc_ora as byte, dim rtc_minute as byte, dim rtc_secondo as byte) dim dummy as byte ' Ferma RTC I2CBUSWriteByte(RTCSLA,$0,$84) ' Setta centinaia di secondi i2cbuswritebyte(RTCSLA,$1,$0) ' Setta secondi dummy = Dec2Bcd(rtc_secondo) i2cbuswritebyte(RTCSLA,$2,dummy) ' Setta minuti dummy = Dec2Bcd(rtc_minuto) i2cbuswritebyte(RTCSLA,$3,dummy) ' Setta ORE,formato 24h dummy = Dec2Bcd(rtc_ora) i2cbuswritebyte(RTCSLA,$4,dummy) ' Setta giorno ed anno = 0 dummy = Dec2Bcd(rtc_giorno) i2cbuswritebyte(RTCSLA,$5,dummy) ' Setta mese,settimana dummy = Dec2Bcd(rtc_mese) dummy = dummy or (rtc_settimana << 5) i2cbuswritebyte(RTCSLA,$6,dummy) ' Setta timer mode i2cbuswritebyte(RTCSLA,$7,0) ' Start RTC i2cbuswritebyte(RTCSLA,$0,0) ' Salva offset anno su ultima locazione SRAM i2cbuswritebyte(RTCSLA,$ff,rtc_anno) end sub ' ' ' Legge ora e data dall'RTC I2C BUS PCF8583. ' Legge offset anno dall'ultima locazione SRAM, le otto ultime ' locazioni della SRAM sono riservate sub procedure get_rtc(dim byref rtc_settimana as byte, dim byref rtc_giorno as byte, dim byref rtc_mese as byte, dim byref rtc_anno as byte, dim byref rtc_ora as byte, dim byref rtc_minuto as byte, dim byref rtc_secondo as byte) dim dummy as byte ' Legge e determina secondi rtc_secondo = Bcd2Dec(i2cbusreadbyte(RTCSLA, $2)) ' Legge e determina minuti rtc_minuto = Bcd2Dec(i2cbusreadbyte(RTCSLA, $3)) ' Legge e determina ore rtc_ora = Bcd2Dec(i2cbusreadbyte(RTCSLA, $4)) ' Legge e determina giorno ed offset ann dummy = i2cbusreadbyte(RTCSLA, $5) rtc_anno = (dummy and $c0) >> 6 dummy = dummy and $3f rtc_giorno = Bcd2Dec(dummy) ' Legge e determina giorno settimana e mese dummy = i2cbusreadbyte(RTCSLA, $6) rtc_settimana = (dummy and $e0) >> 5 dummy = dummy and $1f rtc_mese = Bcd2Dec(dummy) ' Calcuola anno nel range 00..99 ' Offset dell'anno e' nella locazione $FF della SRAM interna del PCF. ' Le otto ultime locazioni della SRAM sono riservate. dummy = i2cbusreadbyte(RTCSLA, $ff) rtc_anno = (dummy + rtc_anno) mod 100 end sub ' '********************** Programma principale *************************** ' main: ' Init_cpu ' Spegne i relays set_relays(0) ' Inizializza la periferica hardware I2C BUS I2C_init(100000) for_ever: clrscr print_USART("Demo RTC I2C BUS Rel 1.1 per GMM 4620 rel 120304 e GMB HR168 rel 110104") print_CRLF print_CRLF print_USART("Ora e data memorizzate nel modulo RTC in I2C BUS vengono visualizzate") print_CRLF print_USART("continuamente.") print_CRLF print_USART("Si desidera impostare ora e data nell'RTC (s/n)? ") do nop loop until USART_Data_Ready = 1 i = USART_Read USART_Write(i) if (i = ASC_s) or (i = ASC_sU) then print_CRLF print_CRLF print_USART("Giorno della settimana (0 Domenica, 1 Lunedi', .. , 6 Sabato): ") rtc_settimana = inputDEC(1) print_USART("Giorno: ") rtc_giorno = inputDEC(2) print_USART("Mese: ") rtc_mese = inputDEC(2) print_USART("Anno: 20") rtc_anno = inputDEC(2) print_USART("Ora: ") rtc_ora = inputDEC(2) print_USART("Minuto: ") rtc_minuto = inputDEC(2) print_USART("Secondo: ") rtc_secondo = inputDEC(2) print_CRLF set_rtc(rtc_settimana,rtc_giorno,rtc_mese,rtc_anno,rtc_ora, rtc_minuto,rtc_secondo) end if print_CRLF vis_rtc_loop: get_rtc(rtc_settimana,rtc_giorno,rtc_mese,rtc_anno,rtc_ora, rtc_minuto,rtc_secondo) select case rtc_settimana case 0 print_USART("Domenica ") case 1 print_USART("Lunedi' ") case 2 print_USART("Martedi' ") case 3 print_USART("Mercoledi' ") case 4 print_USART("Giovedi' ") case 5 print_USART("Venerdi' ") case 6 print_USART("Sabato ") end select ' Stampa giorno ByteToStr(rtc_giorno,s) if length(s) = 1 then print_USART("0") end if print_USART(s) print_USART(".") ' Stampa mese ByteToStr(rtc_mese,s) if length(s) = 1 then print_USART("0") end if print_USART(s) print_USART(".20") ' Stampa anno ByteToStr(rtc_anno,s) if length(s) = 1 then print_USART("0") end if print_USART(s) print_USART(" ") ' Stampa ora ByteToStr(rtc_ora,s) if length(s) = 1 then print_USART("0") end if print_USART(s) print_USART(":") ' Stampa minuto ByteToStr(rtc_minuto,s) if length(s) = 1 then print_USART("0") end if print_USART(s) print_USART(".") ' Stampa secondo ByteToStr(rtc_secondo,s) if length(s) = 1 then print_USART("0") end if print_USART(s) USART_Write(13) goto vis_rtc_loop goto for_ever end.