{ **************************************************************** * File: gmbad.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 09.03.05 * **************************************************************** Questo demo offre due operativita' per la linea di ingresso analogico su CN7: calibrazione o acquisizione. La prima calcola un coefficiente di calibrazione grazie ad un segnale di riferimento esterno fornito dall'utente, e lo salva nella EEPROM interna del Mini Modulo. La seconda preleva il coefficiente di calibrazione dalla EEPROM, acquisice e rappresenta di continuo sulla console la combinazione dell'ingresso analogico, sia calibrato che non calibrato. Il demo puo' essere usato indifferentemente con range 0..2,5 V e 0..10 V. Rel 1.1 - by Graziano Gaiba Demo per effettuare conversioni A/D calibrate usando una GMB HR168 pilotata da un Mini Modulo GMM 4620 } { ***************** Definizioni del compilatore ****************** } program gmbad; { *************** Dichiarazione delle contanti ******************* } const ASC_c: byte = 99; const ASC_cU: byte = 67; { ******************* Dichiarazione delle Variabili ******************** } // Variabili di uso generico var chr_in, d_in: byte; ad_result: word; // Usate per la calibrazione dell'A/D converter Quant_err, Vref_mV, Vref_cmb: word; sum_cmb, KCal: word; Label for_ever; { ******************* 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; {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. } function inputDEC(n_char: byte): word; var str_input:array[6] of byte; idx, chr_input: byte; pow_of_10:array[6] of word; value: word; begin 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 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); value := value + word((str_input[n_char] - 48)) * pow_of_10[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 if (chr_input >= 48) or(chr_input <= 57) 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 := value; 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; {Conversione di un canale A/D memorizzato nella variabile ad_canale. Il risultato e' una word che viene restituita. Prima di chiamare questa procedura, la periferica A/D converter deve essere configurata ed abilitata. } function AD_Conversione(ad_canale: byte): word; var ad_risultato: word; begin { adcon0.2 = ad_channel.0 adcon0.3 = ad_channel.1 adcon0.4 = ad_channel.2 adcon0.5 = ad_channel.3 } if TestBit(ad_canale, 0) = 0 then begin ClearBit(adcon0, 2); end else begin SetBit(adcon0, 2); end; if TestBit(ad_canale, 1) = 0 then begin ClearBit(adcon0, 3); end else begin SetBit(adcon0, 3); end; if TestBit(ad_canale, 2) = 0 then begin ClearBit(adcon0, 4); end else begin SetBit(adcon0, 4); end; if TestBit(ad_canale, 3) = 0 then begin ClearBit(adcon0, 5); end else begin SetBit(adcon0, 5); end; SetBit(adcon0, 1); repeat begin nop; end; until TestBit(adcon0, 1) = 0; ad_risultato := word(adresh shl 8) + word(adresl); Result := ad_risultato; end; { ********************** Programma principale *************************** } begin Init_cpu; // Spegne i relays set_relays(0); for_ever: clrscr; print_USART('Demo ingresso analogico Rel 1.1 for GMM 4620 rel 120304 e GMB HR168 rel 110104'); print_CRLF; print_CRLF; print_USART('Ingresso analogico: il pin 8 di CN7.'); print_CRLF; print_USART('A seconda di J11 il range di input puo` essere da 0 a 5 V o da 0 a 20 V.'); print_CRLF; print_USART('La sezione analogic di GMB HR168 e` basata su componenti di precisione'); print_CRLF; print_USART('comunque soggetti a piccole tolleranze.'); print_CRLF; print_USART('Per compensarle e` preferibile acquisire l`ingresso analogico tramite'); print_CRLF; print_USART('calibrazione software.'); print_CRLF; print_USART('Il coefficiente di calibrazione viene memorizzato nelle ultime 8 locazioni'); print_CRLF; print_USART('della EEPROM interna della CPU, che sono riservate.'); print_CRLF; print_CRLF; print_USART('Selezione modo: Acquisizione o Calibrazione (a/c): '); repeat begin nop; end; until USART_Data_Ready = 1; chr_in := USART_Read; print_CRLF; adcon1 := 0; adcon2 := $88; // Abilita A/D converter SetBit(adcon0,0); if (chr_in = ASC_c) or (chr_in = ASC_cU) then begin print_USART('Collegare J11 in 2-3.'); print_CRLF; print_USART('Collegare segnale di riferimento vicino al fondo scala (20 V) a pin 8 di CN7.'); print_CRLF; repeat begin print_USART('Inserire il valore del segnale di riferimento, in mV (19000-20000): '); vref_mv := inputDEC(5); if vref_mv < 16000 then begin print_USART('Il segnale di riferimento deve essere superiore a 16000 mV.'); print_CRLF; end; end; until vref_mv >= 16000; // Procedura di calibrazione. // Primo: calcolare la combinazione del segnale di riferimento. if vref_mv > 5000 then begin vref_cmb := (vref_mv * 1023) div 20000; end else begin vref_cmb := (vref_mv * 1023) div 5000; end; // Secondo: effettuare 64 misure del segnale di riferimento e calcolarne // la media. sum_cmb := 0; for chr_in := 0 to 63 do begin ad_result := ad_conversione(4); sum_cmb := sum_cmb + ad_result; end; // Ultimo: calcolare il coefficiente di calibrazione usando la media // delle 64 misure e la combinazione teorica del segnale di riferimento sum_cmb := sum_cmb shr 6; kcal := vref_cmb - sum_cmb; // Memorizza il coefficiente di calibrazione nelle locazione 03f8H e // 03f9H della EEPROM interna. eeadrh := $03; EEPROM_write($f8, Hi(kcal)); EEPROM_write($f9, Lo(kcal)); print_USART('Calibration completed.'); print_CRLF; print_CRLF; end; // Acquisizione // Lettura del coefficiente di calibrazione dalla EEPROM interna. eeadrh := $03; d_in := EEPROM_read($f8); chr_in := EEPROM_read($f9); kcal := word(d_in shl 8) + word(chr_in); quant_err := 1023 div kcal; print_USART('Combinazione NON calibrata e calibrata vengono mostrate continuamente.'); print_CRLF; print_USART('Premere un tasto per uscire...'); print_CRLF; print_CRLF; print_USART('NON calibrata Calibrata'); print_CRLF; // Ciclo visualizzazione repeat begin ad_result := ad_conversione(4); print_USART(' '); print_HEX_2(Hi(ad_result)); print_HEX_2(Lo(ad_result)); ad_result := ad_result - (ad_result div quant_err); print_USART(' '); print_HEX_2(Hi(ad_result)); print_HEX_2(Lo(ad_result)); USART_Write(13); delay_ms(200); end; until USART_Data_Ready = 1; chr_in := USART_Read; goto for_ever; end.