' **************************************************************** ' * File: gmbtmp .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 11.02.05 * ' **************************************************************** ' ' GMM 4620 provided with Real Time Clock. ' Questo Demo permette di gestire tre temporizzatori che agiscono ' sulle uscite bufferate di CN3 e CN4. ' In dettaglio da console per tutti i temporizzatori si puo` stabilire ' l'attivazione e l'intervallo di tempo in secondi, mentre solo per ' i primi due e` inseribile la combinazione d'uscita; il terzo invece ' disattiva tutte le uscite. ' NOTA: L'ultima locazione della SRAM dell'RTC ($FF) e' riservata. ' ' Rel 1.1 - by Graziano Gaiba ' Demo di attivita' temporizzate 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 ******************* ' RTCSLA con $A0 I2C_BUFFER_SIZE con 10 ' ' ******************* Dichiarazione delle Variabili ******************** ' ' Variabili di uso generico i var byte scelta var byte di var byte do var byte ' ' ' Usate per la gestione delle attivita' temporizzate act1_enable var bit act2_enable var bit act3_enable var bit act1_time var byte act2_time var byte act3_time var byte act1_val var byte act2_val 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 ' ' Usato dalla gestione RTC bin_bcd var byte ' Usato per le conversione binario/BCD rtc_anno var byte rtc_mese var byte rtc_settimana var byte rtc_giorno var byte rtc_ora var byte rtc_minuto var byte rtc_secondo 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 for_ever: gosub clrscr ' Azzera l'abilitazione delle attivita' temporizzate act1_enable = 0 act2_enable = 0 act3_enable = 0 hserout ["Demo attivita' temporizzate Rel 1.1 per GMM 4620 rel 120304 e GMB HR168 rel 110104", 13, 10, 13, 10] hserout ["Si possono abilitare tre attivita': le prime due impostatno lo stato dei relays", 13, 10] hserout ["ad un valore che viene specificato, la terza azzera lo stato dei relays.", 13, 10] hserout ["Viene inserito il secondo al quale ogni attivita' abilitata deve scattare", 13, 10] hserout ["e lo stato dei relays che verra' impostato.", 13, 10] hserout ["RTC viene inizializzato all'ora 12:00:00", 13, 10, 13, 10] ' hserout ["Abilitare attivita' temporizzata 1 (s/n)? "] hserin [i] hserout [i, 13, 10] if i == "s" or i == "S" then act1_enable = 1 hserout ["Secondo di attivazione (digitare due cifre)? "] hserin [dec2 act1_time] hserout [dec2 act1_time, 13, 10] hserout ["Stato relays da impostare (due cifre esadecimali MAIUSCOLE)? "] hserin [hex2 act1_val] hserout [hex2 act1_val, 13, 10] endif ' hserout ["Abilitare attivita' temporizzata 2 (s/n)? " ] hserin [i] hserout [i, 13, 10] if i == "s" or i == "S" then act2_enable = 1 hserout ["Secondo di attivazione (digitare due cifre)? "] hserin [dec2 act2_time] hserout [dec2 act2_time, 13, 10] hserout ["Stato relays da impostare (due cifre esadecimali MAIUSCOLE)? "] hserin [hex2 act2_val] hserout [hex2 act2_val, 13, 10] endif ' hserout ["Abilitare attivita' temporizzata 3 (s/n)? " ] hserin [i] hserout [i, 13, 10] if i == "s" or i == "S" then act3_enable = 1 hserout ["Secondo di attivazione (digitare due cifre)? "] hserin [dec2 act3_time] hserout [dec2 act3_time, 13, 10] endif ' Imposta RTC a 12:00:00 rtc_settimana = 0 rtc_giorno = 1 rtc_mese = 1 rtc_anno = 1 rtc_ora = 12 rtc_minuto = 0 rtc_secondo = 0 gosub set_rtc timed_activity_loop: gosub get_rtc ' if act1_enable then ' Se il secondo attuale e' uguale al secondo di attivazione if rtc_secondo == act1_time then port_val = act1_val gosub set_relays endif endif ' if act2_enable then ' Se il secondo attuale e' uguale al secondo di attivazione if rtc_secondo == act2_time then port_val = act2_val gosub set_relays endif endif ' if act3_enable then ' Se il secondo attuale e' uguale al secondo di attivazione if rtc_secondo == act3_time then port_val = 0 gosub set_relays endif endif ' hserout [dec2 rtc_ora, ":", dec2 rtc_minuto, ".", dec2 rtc_secondo, 13] pause 100 goto timed_activity_loop goto for_ever end ' ' **************** Procedures definition ****************** ' ' ' 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 ' ' ' Converte un numero da decimale a BCD. ' Il valore da convertire deve essere messo nella variabile bin_to_bcd. ' Il risultato della conversione viene messo nella variabile bin_to_bcd. bin_to_bcd: bin_bcd = ((bin_bcd / 10) << 4) | (bin_bcd // 10) return ' ' ' Converte un numero da BCD a decimale ' Il valore da convertire deve essere messo nella variabile bin_to_bcd. ' Il risultato della conversione viene messo nella variabile bin_to_bcd. bcd_to_bin: bin_bcd = ((bin_bcd >> 4 ) * 10) + (bin_bcd & $0F) return ' ' ' Imposta ora e data sull'RTC I2C BUS PCF8583 set_rtc: i2c_slave = RTCSLA ' i2c_addr = $0 i2c_val = $84 gosub i2cbuswritebyte ' risi2c=wr_i2c(RTCSLA,0x00,0x84); // Setta stop i2c_addr = $1 i2c_val = $0 gosub i2cbuswritebyte ' risi2c=wr_i2c(RTCSLA,0x01,0x00); // Setta centinaia di secondi bin_bcd = rtc_secondo gosub bin_to_bcd i2c_val = bin_bcd i2c_addr = $2 gosub i2cbuswritebyte ' risi2c=wr_i2c(RTCSLA,0x02,bintobcd(sec)); // Setta secondi bin_bcd = rtc_minuto gosub bin_to_bcd i2c_val = bin_bcd i2c_addr = $3 gosub i2cbuswritebyte ' risi2c=wr_i2c(RTCSLA,0x03,bintobcd(min)); // Setta minuti bin_bcd = rtc_ora gosub bin_to_bcd i2c_val = bin_bcd i2c_addr = $4 gosub i2cbuswritebyte ' risi2c=wr_i2c(RTCSLA,0x04,bintobcd(ore)); // Setta ORE,formato 24h bin_bcd = rtc_giorno gosub bin_to_bcd i2c_val = bin_bcd i2c_addr = $5 gosub i2cbuswritebyte ' risi2c=wr_i2c(RTCSLA,0x05,bintobcd(gio)); // Setta giorno ed anno=0 bin_bcd = rtc_mese gosub bin_to_bcd i2c_val = bin_bcd | (rtc_settimana << 5) i2c_addr = $6 gosub i2cbuswritebyte ' risi2c=wr_i2c(RTCSLA,0x06,(bintobcd(mes)|(set<<5))); // Setta mese,settimana i2c_val = $0 i2c_addr = $7 gosub i2cbuswritebyte ' risi2c=wr_i2c(RTCSLA,0x07,0x00); // Setta timer i2c_val = $0 i2c_addr = $0 gosub i2cbuswritebyte ' risi2c=wr_i2c(RTCSLA,0x00,0x00); // Setta start i2c_val = rtc_anno i2c_addr = $ff gosub i2cbuswritebyte ' risi2c=wr_i2c(RTCSLA,0xFF,ann); // Salva offset anno su ultima loc. SRAM 'return ' ' Legge ora e data dall'RTC I2C BUS PCF8583 get_rtc: i2c_slave = RTCSLA ' i2c_addr = $2 gosub i2cbusreadbyte bin_bcd = i2c_val gosub bcd_to_bin rtc_secondo = bin_bcd ' risi2c=rd_i2c(RTCSLA,0x02,&dr); // Legge e determina secondi ' *sec=bcdtobin(dr); i2c_addr = $3 gosub i2cbusreadbyte bin_bcd = i2c_val gosub bcd_to_bin rtc_minuto = bin_bcd ' risi2c=rd_i2c(RTCSLA,0x03,&dr); // Legge e detrmina minuti ' *min=bcdtobin(dr); i2c_addr = $4 gosub i2cbusreadbyte bin_bcd = i2c_val gosub bcd_to_bin rtc_ora = bin_bcd ' risi2c=rd_i2c(RTCSLA,0x04,&dr); // Legge e determina ore ' *ore=bcdtobin(dr); i2c_addr = $5 gosub i2cbusreadbyte bin_bcd = i2c_val & $3f gosub bcd_to_bin rtc_giorno = bin_bcd rtc_anno = (i2c_val & $c0) >> 6 ' risi2c=rd_i2c(RTCSLA,0x05,&dr); // Legge e determina giorno ed offset anno ' *gio=bcdtobin(dr&0x3F); ' *ann=(dr&0xC0)>>6; i2c_addr = $6 gosub i2cbusreadbyte bin_bcd = i2c_val & $1f gosub bcd_to_bin rtc_settimana = (i2c_val & $e0) >> 5 rtc_mese = bin_bcd ' risi2c=rd_i2c(RTCSLA,0x06,&dr); // Legge e determina giorno settimana e mese ' *set=(dr&0xE0)>>5; ' *mes=bcdtobin(dr&0x1F); i2c_addr = $ff gosub i2cbusreadbyte rtc_anno = (i2c_val + rtc_anno) // 100 ' risi2c=rd_i2c(RTCSLA,0xFF,&dr); // Preleva offset anno da ultima loc. SRAM ' dr=dr+*ann; // Ottiene anno con offset ' dr=dr%100; // Forza anno con offset a due cifre ' *ann=dr; // Restituisce anno a due cifre ottenuto 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