{ **************************************************************** * File: gmbiob.ppas - Ver. 1.1 * * Compilatore: mikroPascal for PIC by mikroElektronica * * IDE: mikroPascal for PIC by mikroElektronica * * Versione Compilatore: 2.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 08.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 contanti ******************* } const ASC_1:byte = 49; const ASC_2:byte = 50; { ******************* Dichiarazione delle Variabili ******************** } // Variabili di uso generico var chr_in, scelta, d_in, d_out: byte; // Usate dagli interrupts cnt_int0, cnt_int1: byte; // Usate dai Timers cnt_tmr1_int: byte; Label input_scelta; { ******************* Definizione delle procedure ********************* } // Inizializzazione direzione segnali della CPU procedure Init_cpu; begin 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 := trisa or $13; trisb := trisb or $03; trisc := trisc or $23; { 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 := trisa and $f7; trisc := trisc and $fb; // Inizialzza modulo USART (8 bit, 19200 baud rate, // no parity) Usart_init(19200); end; // Invia una stringa di caratteri alla porta seriale procedure print_USART(var txt: string[100]); var temp1, temp2: byte; begin temp1 := txt[0]; for temp2 := 1 to temp1 do begin USART_Write(txt[temp2]); end; end; // Invia CR + LF procedure print_CRLF; begin USART_Write(10); USART_Write(13); end; // Pulisce lo schermo, inviando 25 volte CR + LF. procedure clrscr; var temp: byte; begin for temp := 0 to 24 do begin print_CRLF; end; end; // Chiede la pressione di un tasto procedure wait_key; var temp: byte; begin print_usart('Premere un tasto...'); repeat begin nop; end; until USART_Data_Ready = 1; temp := USART_Read; end; { 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) } procedure set_relays(port_val: byte); begin // I relays sono pilotati in logica complementata , quindi anche port_val // deve essere complementato port_val:=port_val xor $ff; if TestBit(port_val, 0) = 0 then begin ClearBit(portb, 4); end else begin SetBit(portb, 4); end; if TestBit(port_val, 1) = 0 then begin ClearBit(portb, 5); end else begin SetBit(portb, 5); end; if TestBit(port_val, 2) = 0 then begin ClearBit(portb, 6); end else begin SetBit(portb, 6); end; if TestBit(port_val, 3) = 0 then begin ClearBit(portb, 7); end else begin SetBit(portb, 7); end; if TestBit(port_val, 4) = 0 then begin ClearBit(portb, 3); end else begin SetBit(portb, 3); end; if TestBit(port_val, 5) = 0 then begin ClearBit(portb, 2); end else begin SetBit(portb, 2); end; if TestBit(port_val, 6) = 0 then begin ClearBit(porta, 3); end else begin SetBit(porta, 3); end; if TestBit(port_val, 7) = 0 then begin ClearBit(portc, 2); end else begin SetBit(portc, 2); end; end; {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 } function get_opto_1: byte; var port_val: byte; begin if TestBit(porta, 0) = 0 then begin ClearBit(port_val, 0); end else begin SetBit(port_val, 0); end; if TestBit(porta, 1) = 0 then begin ClearBit(port_val, 1); end else begin SetBit(port_val, 1); end; if TestBit(portb, 0) = 0 then begin ClearBit(port_val, 2); end else begin SetBit(port_val, 2); end; if TestBit(portb, 1) = 0 then begin ClearBit(port_val, 3); end else begin SetBit(port_val, 3); end; if TestBit(porta, 4) = 0 then begin ClearBit(port_val, 4); end else begin SetBit(port_val, 4); end; if TestBit(portc, 0) = 0 then begin ClearBit(port_val, 5); end else begin SetBit(port_val, 5); end; if TestBit(portc, 1) = 0 then begin ClearBit(port_val, 6); end else begin SetBit(port_val, 6); end; if TestBit(portc, 5) = 0 then begin ClearBit(port_val, 7); end else begin SetBit(port_val, 7); end; // 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; {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 } function get_opto_2: byte; var port_val: byte; begin // Gli ingressi optoisolati sono pilotati in logica complementata, // quindi anche port_val deve essere complementato port_val := portd xor $ff; Result := port_val; end; // Invia i suoi argomenti alla porta seriale come due cifre esadecimali. procedure print_HEX_2(value: byte); var tmp: byte; begin // Nibble piu' significativo tmp := value shr 4; // Se maggiore di 9, trasformalo in un carattere a partire da 'A' if tmp > 9 then begin tmp := tmp + 55; end else begin // Trasformalo in un carattere a partire da '0' tmp := tmp + 48; end; 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 begin tmp := tmp + 55; end else begin // Trasformalo in un carattere a partire da '0' tmp := tmp + 48; end; USART_Write(tmp); end; // Verifica che il parametro in ingresso sia una cifra esadecimale function is_HEX_digit(valore: byte): byte; var flag: byte; begin flag := 0; if (valore >=48) and (valore <= 57) then begin flag := 1; end; if (valore >= 65) and (valore <= 70) then begin flag := 1; end; if (valore >= 97) and (valore <= 102) then begin flag := 1; end; Result := flag; end; // Restituisce il valore di una singola cifra esadecimale ASCII. // NON verifica che il parametro in ingresso sia una cifra esadecimale function HEX_val(valore: byte): byte; begin valore := valore - 48; if valore > 9 then begin valore := valore - 17; if valore > 5 then begin valore := valore - 32; end; valore := valore + 10; end; Result := valore; end; {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. } function inputHEX(n_char: byte): word; var str_input: array[6] of byte; idx, chr_input: byte; pow_of_16: array[5] of word; valore: word; begin 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 valore := 0; // Continua finche' non riceve un carattere CR while chr_input <> 13 do begin // Se un dato e' pronto if usart_data_ready = 1 then begin // Leggilo chr_input := USART_Read; // Se e' backspace (ASCII BS) if chr_input = 8 then begin // e il buffer non e' vuoto if idx > 1 then begin // Invia dato letto USART_Write(chr_input); // Cancella carattere USART_Write(32); USART_Write(chr_input); // Elimina ultimo dato letto Dec(idx); end else begin // Carattere bell per indicare un errore USART_Write(7); end; end; // Se CR ricevuto, elabora il valore e restituiscilo if chr_input = 13 then begin n_char := 0; while idx > 1 do begin Dec(idx); Inc(n_char); valore := valore + word(HEX_val(str_input[n_char])) * pow_of_16[idx]; end; end else begin // Se il carattere puo' essere inserito if idx < n_char then begin // Se il dato ricevuto e' valido: // 0..9 o 'a'..'f' o 'A'..'F' if is_HEX_digit(chr_input) = 1 then begin // 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; end else begin // Carattere bell per indicare un errore USART_Write(7); end; end; end; end; print_CRLF; Result := valore; end; // Demo degli ingressi digitali optoisolati procedure digital_inputs; begin clrscr; print_USART('Demo sezione ingressi optoisolati'); print_CRLF; print_CRLF; print_USART('Viene visualizzato continuamente '); print_USART('lo stato degli ingressi di CN1 e '); print_USART('CN2.'); print_CRLF; print_USART('Premere un tasto per uscire.'); print_CRLF; print_CRLF; print_USART('CN1 CN2'); print_CRLF; repeat begin d_in := get_opto_1; USART_Write(' '); print_HEX_2(d_in); d_in := get_opto_2; print_USART(' '); print_HEX_2(d_in); USART_Write(13); Delay_ms(200); end; until USART_Data_Ready = 1; chr_in := USART_Read; print_CRLF; print_CRLF; print_USART('IN3 e IN4 di CN1 sono collegati '); print_USART('rispettivamente agli interrupt '); print_USART('INT0 e INT1.'); print_CRLF; print_USART('Ogni fronte calante sugli '); print_USART('ingressi attiva il rispettivo '); print_USART('interrupt, che'); print_CRLF; print_USART('incrementa un contatore. I '); print_USART('contatori sono visualizzati '); print_USART('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 ClearBit(rcon,7); // Attiva INT0 e INT1 sui fronti calanti ClearBit(intcon2,6); ClearBit(intcon2,5); // Abilita INT0 e INT1 SetBit(intcon,4); SetBit(intcon3,3); // Abilitazione interrupt periferiche e globale SetBit(intcon,6); SetBit(intcon,7); // Inizializza contatori interrupts cnt_int0 := 0; cnt_int1 := 0; repeat begin print_USART(' '); print_HEX_2(cnt_int0); print_USART(' '); print_HEX_2(cnt_int1); USART_Write(13); Delay_ms(50); end; until USART_Data_Ready = 1; chr_in := USART_Read; print_CRLF; print_CRLF; // Disabilitazione interrupt periferiche e globale ClearBit(intcon,7); ClearBit(intcon,6); // Disabilita INT0 e INT1 ClearBit(intcon3,3); ClearBit(intcon,4); print_USART('IN5 e IN6 di CN1 sono collegati '); print_USART('rispettivamente al clock esterno'); print_USART(' di'); print_CRLF; print_USART('Timer 0 e Timer 1.'); print_CRLF; print_USART('Ogni fronte calante per Timer 0 '); print_USART('e fronte crescente per Timer 1 '); print_USART('attivano'); print_CRLF; print_USART('la periferica che incrementa il '); print_USART('rispettivo registro di contatore'); print_USART(' hardware.'); print_CRLF; print_USART('Inoltre, gli overflow di Timer 1'); print_USART(' generano un interrupt che viene'); print_USART(' contato.'); print_CRLF; print_USART('Tutti i contatori sono '); print_USART('visualizzati continuamente.'); print_CRLF; print_USART('Premere un tasto per uscire.'); print_CRLF; print_CRLF; print_USART('Valore di: Timer 0 Timer 1 '); print_USART('Conteggio di: Timer 1 overflow'); print_USART(' 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 ClearBit(rcon,7); // Abilita interrupt su overflow di Timer 1 SetBit(pie1,0); // Abilita interrupt di periferica e interrupt globali SetBit(intcon,6); SetBit(intcon,7); repeat begin 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); end; until USART_Data_Ready = 1; chr_in := USART_Read; print_CRLF; print_CRLF; // Disabilitazione interrupt globale e periferiche ClearBit(intcon,7); ClearBit(intcon,6); // Disabilita interrupt su overflow di Timer 1 ClearBit(pie1,0); end; // Gestore di tutti gli interrupts procedure interrupt; begin if (intcon and $02) = $02 then begin intcon := intcon and $fd; Inc(cnt_int0); end; if (intcon3 and $01) = $01 then begin intcon3 := intcon3 and $fe; Inc(cnt_int1); end; if (pir1 and $01) = $01 then begin pir1 := pir1 and $fe; Inc(cnt_tmr1_int); end; end; // Demo gestione uscite a relay procedure relay_outputs; begin clrscr; print_USART('Demo gestione uscite a relay'); print_CRLF; print_CRLF; repeat begin print_USART('Inserire due cifre '); print_USART('esadecimali per stato'); print_USART(' relays (00 esce): '); d_out := inputHEX(2); set_relays(d_out); end; until d_out = 0; end; { ********************** Programma principale *************************** } begin Init_cpu; // Spegne i relays set_relays(0); repeat begin 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: '); repeat begin nop; end; until USART_Data_Ready = 1; scelta := USART_Read; case scelta of ASC_1: digital_inputs; ASC_2: relay_outputs else goto input_scelta; end; end; until False; end.