' **************************************************************** ' * File: gmbiob.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 * ' * 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 01.03.05 * ' **************************************************************** ' ' Questo Demo permette di utilizzare immediatamente sia le uscite che gli ' ingressi bufferati disponibili rispettivamente su CN3, CN4 ' e CN1, CN2 di GMB HR168. ' Tramite la console si puo' visualizzare lo stato dei sedici ingressi NPN/PNP ' oppure settare lo stato degli otto relays di uscita. ' Inoltre vengono applicate le funzionalita' evolute offerte dal Mini Modulo, ' ad esempio: ingressi contati via hardware, ecc. ' ' ' Rel 1.1 - by Graziano Gaiba ' Demo di utilizzo delle periferiche bufferate di I/O usando una GMB HR168 ' pilotata da un Mini Modulo GMM 4620 ' ' ' ***************** Definizioni del compilatore ****************** ' program gmbiob ' ' *************** Dichiarazione delle costanti ******************* ' const ASC_1 = 49 const ASC_2 = 50 ' ' ******************* Dichiarazione delle Variabili ******************** ' ' Variabili di uso generico dim chr_in as byte dim scelta as byte dim d_in as byte dim d_out as byte ' ' ' Usate dagli interrupts dim cnt_int0 as byte dim cnt_int1 as byte ' ' ' Usate dai Timers dim cnt_tmr1_int 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 ' ' ' Procedura che legge lo stato degli ingressi optoisolati del connettore CN1. ' I bit di port_val hanno il seguente significato: ' port_val.0 indica lo stato di IN1-1 ' port_val.1 indica lo stato di IN2-1 ' port_val.2 indica lo stato di IN3-1 ' port_val.3 indica lo stato di IN4-1 ' port_val.4 indica lo stato di IN5-1 ' port_val.5 indica lo stato di IN6-1 ' port_val.6 indica lo stato di IN7-1 ' port_val.7 indica lo stato di IN8-1 ' ' A seconda del valore dei bits di port_val, ogni input viene indicato come. ' aperto o chiuso. Ogni bit ha il seguente significato: ' bit Significato ' 0 Contatto aperto ' 1 Contatto chiuso sub function get_opto_1 as byte dim port_val as byte port_val.0 = porta.0 port_val.1 = porta.1 port_val.2 = portb.0 port_val.3 = portb.1 port_val.4 = porta.4 port_val.5 = portc.0 port_val.6 = portc.1 port_val.7 = portc.5 ' Gli ingressi optoisolati sono pilotati in logica complementata, ' quindi anche port_val deve essere complementato port_val = port_val xor $ff Result = port_val end sub ' ' ' Procedura che legge lo stato degli ingressi optoisolati del connettore CN2. ' I bit di port_val hanno il seguente significato: ' port_val.0 indica lo stato di IN1-2 ' port_val.1 indica lo stato di IN2-2 ' port_val.2 indica lo stato di IN3-2 ' port_val.3 indica lo stato di IN4-2 ' port_val.4 indica lo stato di IN5-2 ' port_val.5 indica lo stato di IN6-2 ' port_val.6 indica lo stato di IN7-2 ' port_val.7 indica lo stato di IN8-2 ' ' A seconda del valore dei bits di port_val, ogni input viene indicato come. ' aperto o chiuso. Ogni bit ha il seguente significato: ' bit Significato ' 0 Contatto aperto ' 1 Contatto chiuso sub function get_opto_2 as byte dim port_val as byte ' Gli ingressi optoisolati sono pilotati in logica complementata, ' quindi anche port_val deve essere complementato port_val = portd xor $ff Result = port_val end sub ' ' ' Invia i suoi argomenti alla porta seriale come due cifre esadecimali. sub procedure print_HEX_2(dim value as byte) dim tmp as byte ' Nibble piu' significativo tmp = value >> 4 ' Se maggiore di 9, trasformalo in un carattere a partire da 'A' if tmp > 9 then tmp = tmp + 55 else ' Trasformalo in un carattere a partire da '0' tmp = tmp + 48 end if USART_Write(tmp) ' ' Nibble meno significativo tmp = value and $0f ' Se maggiore di 9, trasformalo in un carattere a partire da 'A' if tmp > 9 then tmp = tmp + 55 else ' Trasformalo in un carattere a partire da '0' tmp = tmp + 48 end if USART_Write(tmp) end sub ' ' ' Verifica che il parametro in ingresso sia una cifra esadecimale sub function is_HEX_digit(dim v as byte) as byte dim flag as byte flag = 0 if (v >=48) and (v <= 57) then flag = 1 end if if (v >= 65) and (v <= 70) then flag = 1 end if if (v >= 97) and (v <= 102) then flag = 1 end if Result = flag end sub ' ' ' Restituisce il valore di una singola cifra esadecimale ASCII. ' NON verifica che il parametro in ingresso sia una cifra esadecimale sub function HEX_val(dim v as byte) as byte v = v - 48 if v > 9 then v = v - 17 if v > 5 then v = v - 32 end if v = v + 10 end if Result = v end sub ' ' ' 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. sub function inputHEX(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_16 as word[5] dim value as word 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 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 + HEX_val(str_input[n_char]) * pow_of_16[idx] wend else ' Se il carattere puo' essere inserito if idx < n_char then ' Se il dato ricevuto e' valido: ' 0..9 o 'a'..'f' o 'A'..'F' if is_HEX_digit(chr_input) = 1 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 ' ' ' Demo degli ingressi digitali optoisolati sub procedure digital_inputs clrscr print_USART("Demo sezione ingressi optoisolati") print_CRLF print_CRLF print_USART("Viene visualizzato continuamente lo stato degli ingressi di CN1 e CN2.") print_CRLF print_USART("Premere un tasto per uscire.") print_CRLF print_CRLF print_USART("CN1 CN2") print_CRLF do d_in = get_opto_1 print_USART(" ") print_HEX_2(d_in) d_in = get_opto_2 print_USART(" ") print_HEX_2(d_in) USART_Write(13) Delay_ms(200) loop until USART_Data_Ready = 1 chr_in = USART_Read print_CRLF print_CRLF ' ' print_USART("IN3 e IN4 di CN1 sono collegati rispettivamente agli interrupt INT0 e INT1.") print_CRLF print_USART("Ogni fronte calante sugli ingressi attiva il rispettivo interrupt, che") print_CRLF print_USART("incrementa un contatore. I contatori sono visualizzati continuamente.") print_CRLF print_USART("Premere un tasto per uscire.") print_CRLF print_CRLF print_USART("Conteggio di: INT0 INT1") print_CRLF ' Disabilita priorita' degli interrupts rcon.7 = 0 ' Attiva INT0 e INT1 sui fronti calanti intcon2.6 = 0 intcon2.5 = 0 ' Abilita INT0 e INT1 intcon.4 = 1 intcon3.3 = 1 ' Abilitazione interrupt periferiche e globale intcon.6 = 1 intcon.7 = 1 ' Inizializza contatori interrupts cnt_int0 = 0 cnt_int1 = 0 do print_USART(" ") print_HEX_2(cnt_int0) print_USART(" ") print_HEX_2(cnt_int1) USART_Write(13) Delay_ms(50) loop until USART_Data_Ready = 1 chr_in = USART_Read print_CRLF print_CRLF ' Disabilitazione interrupt periferiche e globale intcon.7 = 0 intcon.6 = 0 ' Disabilita INT0 e INT1 intcon3.3 = 0 intcon.4 = 0 ' ' print_USART("IN5 e IN6 di CN1 sono collegati rispettivamente al clock esterno di") print_CRLF print_USART("Timer 0 e Timer 1.") print_CRLF print_USART("Ogni fronte calante per Timer 0 e fronte crescente per Timer 1 attivano") print_CRLF print_USART("la periferica che incrementa il rispettivo registro di contatore hardware.") print_CRLF print_USART("Inoltre, gli overflow di Timer 1 generano un interrupt che viene contato.") print_CRLF print_USART("Tutti i contatori sono visualizzati continuamente.") print_CRLF print_USART("Premere un tasto per uscire.") print_CRLF print_CRLF print_USART("Valore di: Timer 0 Timer 1 Conteggio di: Timer 1 overflow interrupt") print_CRLF ' Inizializza contatori tmr0h = 0 tmr0l = 0 tmr1h = $ff tmr1l = $f0 ' Inizializza contatore interrupt di Timer 1 cnt_tmr1_int = 0 ' Configura Timer 0 a 16 bit, trigger fronti calanti di T0CKI, no prescaler t0con = $b8 ' Configura Timer 1 per trigger fronti calanti di T13CKI, no prescaler t1con = $83 ' Disabilita priorita' degli interrupts rcon.7 = 0 ' Abilita interrupt su overflow di Timer 1 pie1.0 = 1 ' Abilita interrupt di periferica e interrupt globali intcon.6 = 1 intcon.7 = 1 do print_USART(" ") print_HEX_2(tmr0h) print_HEX_2(tmr0l) print_USART(" ") print_HEX_2(tmr1h) print_HEX_2(tmr1l) print_USART(" ") print_HEX_2(cnt_tmr1_int) USART_Write(13) Delay_ms(50) loop until USART_Data_Ready = 1 chr_in = USART_Read print_CRLF print_CRLF ' Disabilitazione interrupt globale e periferiche intcon.7 = 0 intcon.6 = 0 ' Disabilita interrupt su overflow di Timer 1 pie1.0 = 0 end sub ' ' ' Gestore di tutti gli interrupts sub procedure interrupt if intcon.1 = 1 then intcon.1 = 0 cnt_int0 = cnt_int0 + 1 end if if intcon3.0 = 1 then intcon3.0 = 0 cnt_int1 = cnt_int1 + 1 end if if pir1.0 = 1 then pir1.0 = 0 cnt_tmr1_int = cnt_tmr1_int + 1 end if end sub ' ' ' Demo gestione uscite a relay sub procedure relay_outputs clrscr print_USART("Demo gestione uscite a relay") print_CRLF print_CRLF do print_USART("Inserire due cifre esadecimali per stato relays (00 esce): ") d_out = inputHEX(2) set_relays(d_out) loop until d_out = 0 end sub ' '********************** Programma principale *************************** ' main: Init_cpu ' Spegne i relays set_relays(0) for_ever: clrscr print_CRLF print_CRLF print_USART("Demo I/O bufferato Rel 1.1 per GMM 4620 rel 120304 ed GMB HR168 rel 110104") print_CRLF print_CRLF print_USART("1) Ingressi digitali") print_CRLF print_USART("2) Uscite relays") print_CRLF input_scelta: print_CRLF print_USART("Scelta: ") do nop loop until USART_Data_Ready = 1 scelta = USART_Read select case scelta case ASC_1 digital_inputs case ASC_2 relay_outputs case else goto input_scelta end select goto for_ever end.