' **************************************************************** ' * File: uk_gmb_ad.pbas - Ver. 1.1 * ' * Compiler: mikroBasic for PIC by mikroElektronica * ' * IDE: mikroBasic for PIC by mikroElektronica * ' * Compiler Version: 1.1.5.0 * ' * Boards: 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 23.02.05 * ' **************************************************************** ' ' This demo offers two possibilities: calibration or acquisition. ' First action determinates a calibration coefficent using an ' external reference voltage provided by the user and stored it ' in Mini Module internal EEPROM. ' Second action fetches calibration coefficent from EEPROM, ' acquires and shows continuously on console the analog input ' combination, both uncalibrated and calibrated. ' Demo can be used without problems with range 0..5 V and 0..20 V. ' ' Rel 1.1 - by Graziano Gaiba ' Demo program of calibrated A/D conversion with GMB HR168 driven ' by Mini Module GMM 4620 ' ' ' ******************** Compiler definitions ********************** ' program uk_gmb_ad ' ' ******************* Constants declaration ********************** ' const ASC_c = 99 const ASC_cU = 67 ' ' ******************** Variables declaration ********************* ' ' Generic variables dim i as byte dim d_in as byte dim ad_result as word ' ' ' Used for calibration of A/D converter dim Quant_err as word dim Vref_mV as word dim Vref_cmb as word dim sum_cmb as word dim KCal as word ' ' ' **************** Procedures definition ****************** ' ' ' CPU and signals directions initialization sub procedure Init_cpu ' Initialize portc for hardware I2C BUS peripheral trisc.3 = 0 trisc.4 = 0 portc.3 = 1 portc.4 = 1 ' ADCON1=$0f ' Imposta come I/O digitale i pin AN0..12 CMCON=$07 ' Imposta come I/O digitale RA0..4 ' Optocoupled Inputs of CN1 are: ' 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 ' Optocoupled Inputs of CN2 are: ' 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 ' Relay outputs of CN3 are: ' OUT A1 <-> RB4 ' OUT A2 <-> RB5 ' OUT B1 <-> RB6 ' OUT B2 <-> RB7 ' OUT C1 <-> RB3 ' OUT C2 <-> RB2 trisb=trisb and $03 ' Relay outputs of CN4 are: ' OUT D1 <-> RA3 ' OUT D2 <-> RC2 (J10 in position 3-4) trisa.3=0 trisc.2=0 ' Initialize module USART (8 bit, 19200 baud rate, ' no parity) Usart_init(19200) end sub ' ' ' Send a string of characters to the serial port 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 ' ' ' Send CR + LF sub procedure print_CRLF USART_Write(10) USART_Write(13) end sub ' ' ' Clear screen, sending 25 times CR + LF. sub procedure clrscr for i = 0 to 24 print_CRLF next i end sub ' ' ' Asks for a key press sub procedure wait_key dim c as byte print_usart("Press a key...") do nop loop until USART_Data_Ready = 1 c = USART_Read end sub ' ' Conversion of A/D channel stored in variable ad_channel. ' Result in variable ad_result. ' Before calling this procedure, A/D converter peripheral must be ' configured and enabled. sub function AD_Conversion(dim ad_channel as byte) as word dim ad_result as word adcon0.2 = ad_channel.0 adcon0.3 = ad_channel.1 adcon0.4 = ad_channel.2 adcon0.5 = ad_channel.3 adcon0.1 = 1 do nop loop until adcon0.1 = 0 ad_result = word(adresh << 8) + word(adresl) Result = ad_result end sub ' ' ' Procedure to set the status of the relays on connectors CN3 and CN4. ' According to the bits of port_val, each relay is turned ON ' (contact closed) or OFF (contact open). ' Bits of port_val have this meanging: ' -- CN3 ' port_val.0 drives relay OUT A1 ' port_val.1 drives relay OUT A2 ' port_val.2 drives relay OUT B1 ' port_val.3 drives relay OUT B2 ' port_val.4 drives relay OUT C1 ' port_val.5 drives relay OUT C2 ' -- CN4 ' port_val.6 drives relay OUT D1 ' port_val.7 drives relay OUT D2 ' ' Each bit has the following meaning: ' bit Meaning ' 0 Relay turned OFF (contact open) ' 1 Relay turned ON (contact closed) sub procedure set_relays(dim port_val as byte) ' Relays are driven in complemented logic, so port_val must be ' complemented too 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 ' ' ' Inputs a positive decimal vale of up to five digits. ' Input parameter is number of digits, it returns a word ' containing the value input by te user. ' It can manage backspace (ASCII 08) and accepts digits from ' '0' to '9'. ' It sends a bell character (ASCII 07) when receives a character ' not acceptable for input, or user tries to input or delete out ' of possible range. 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 ' Index must start from 1 idx = 1 Inc(n_char) ' No character in input chr_input = 0 ' Starting value value = 0 ' Loop until CR is received while chr_input <> 13 ' If a data is ready if usart_data_ready = 1 then ' Read it chr_input = USART_Read ' If backspace (ASCII BS) if chr_input = 8 then ' and buffer is not empty if idx > 1 then ' Send data read USART_Write(chr_input) ' Delete character USART_Write(32) USART_Write(chr_input) ' delete last input data Dec(idx) else ' Bell to indicate an error USART_Write(7) end if end if ' If CR received, elaborate the value and return it 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 ' If character can be input if idx < n_char then ' If data received is in valid range: ' 0..9 if (chr_input >= 48) or(chr_input <= 57) then ' Send data read USART_Write(chr_input) ' Store it in input buffer str_input[idx] = chr_input ' Point to next position Inc(idx) end if else ' Bell to indicate an error USART_Write(7) end if end if end if wend print_CRLF Result = value end sub ' ' ' Sends its argument to the serial port as two hexadecimal figures. sub procedure print_HEX_2(dim value as byte) dim tmp as byte ' Most significant nibble tmp = value >> 4 ' If greater than 9, transform it in a char from 'A' if tmp > 9 then tmp = tmp + 55 else ' Transform it in a char from '0' tmp = tmp + 48 end if USART_Write(tmp) ' ' Least significant nibble tmp = value and $0f ' If greater than 9, transform it in a char from 'A' if tmp > 9 then tmp = tmp + 55 else ' Transform it in a char from '0' tmp = tmp + 48 end if USART_Write(tmp) end sub ' '************************** Main Program ******************************* ' main: Init_cpu ' Turn OFF relays set_relays(0) for_ever: clrscr print_USART("Analog input demo Rel 1.1 for GMM 4620 rel 120304 and GMB HR168 rel 110104") print_CRLF print_CRLF print_USART("Analog input pin is pin 8 of CN7.") print_CRLF print_USART("According to J11 input range can be 0 to 5 V or 0 to 20 V") print_CRLF print_USART("Analog input section of GMB HR168 is based on precision components anyway") print_CRLF print_USART("subject to small tollerances.") print_CRLF print_USART("To compensate such tollerances it is suggersted to acquire analog input") print_CRLF print_USART("through a software calibration.") print_CRLF print_USART("Calibration coefficent is stored in the last 8 locations of CPU internal") print_CRLF print_USART("EEPROM, which are reserved.") print_CRLF print_CRLF print_USART("Select mode: Acquisition or Calibration (a/c): ") do nop loop until USART_Data_Ready = 1 i = USART_Read print_CRLF adcon1 = 0 adcon2 = $88 ' Enable A/D converter adcon0.0 = 1 if (i = ASC_c) or (i = ASC_cU) then print_USART("Connect J11 in 2-3.") print_CRLF print_USART("Connect analog reference signal close to full scale (20 V) to pin 8 of CN7.") print_CRLF Vref_input: print_USART("Input the value of reference signal, in mV (19000-20000): ") vref_mv = inputDEC(5) if vref_mv < 16000 then print_USART("Vref must be more than 16000 mV for proper calibration.") print_CRLF goto Vref_input end if ' Calibration procedure ' First: calculate combination of reference voltage if vref_mv > 5000 then vref_cmb = (vref_mv * 1023) / 20000 else vref_cmb = (vref_mv * 1023) / 5000 end if ' Second: make 64 measures of the voltage connected and obtain ' an average value sum_cmb = 0 for i = 0 to 64 ad_result = ad_conversion(4) sum_cmb = sum_cmb + ad_result next i ' Last: calculate a calibration coefficent using the average of the 64 ' measurements and the combination of reference voltage sum_cmb = sum_cmb >> 6 kcal = vref_cmb - sum_cmb ' Store the calibration coefficent in locations 03f8H and 03f9H ' of internal EEPROM EEPROM_write($3f8, hi(kcal)) EEPROM_write($3f9, lo(kcal)) print_USART("Calibration completed.") print_CRLF print_CRLF end if ' ' Acquisition ' Read calibration coefficent from internal EEPROM d_in = EEPROM_read($3f8) i = EEPROM_read($3f9) kcal = word(d_in << 8) + word(i) quant_err = 1023 / kcal print_USART("Uncalibrated and calibrated combinations are continuously visualized.") print_CRLF print_USART("Press a key to exit...") print_CRLF print_CRLF print_USART("Not calibrated Calibrated") print_CRLF ' Visualization loop do ad_result = ad_conversion(4) print_USART(" ") print_HEX_2(hi(ad_result)) print_HEX_2(lo(ad_result)) ad_result = ad_result - (ad_result / quant_err) print_USART(" ") print_HEX_2(hi(ad_result)) print_HEX_2(lo(ad_result)) USART_Write(13) delay_ms(200) loop until USART_Data_Ready = 1 i = USART_Read goto for_ever end.