' VOLTAGE MONITOR is an unusual circuit in that the monitoring is done backwards!
' There are situations when you want to monitor your own battery voltage and
' shut down the circuit at a critical voltage. The program gives you a 3 digit
' output from "430" (+4.30 volts) to "600" (+6.00 volts) which makes it easy to
' act on just about any voltage. The beauty of the program is in its ability to
' accurately calculate an offset for a voltage reference since they are all
' different when you look at the exact reference voltage, (eg. a 3.3v regulator
' can be as low as 3.247 volts which would throw off your reading significantly).
' The only critical part of this circuit is during the actual programming. You
' must ensure you are powering the circuit with exactly 5.00 volts! After that,
' it is fully calibrated to read any voltage at any time. Accuracy AND display
' resolution down to 1/100 volt!
' The conventional method for doing this trick would require using the 1 and only
' Vref pin (GPIO.1) on the 12F675 and another GPIO pin for the ADC reading.
' That's too many pins, plus, you can't IN CIRCUIT PROGRAM if you have a voltage
' constantly going to GPIO.1's "CLOCK" pin. You would have to disconnect this
' voltage source every time you dump a new program with this routine attached.
' Obviously, this is not a good way to go.
' The other method would be to power the chip with an LDO (Low Drop Out) regulator.
' A great Vreg is the LM1117 at 3.3v that will stay regulated down to 4.37 volts
' of course "brown-out" is to be disabled and you need to use two 1% resistors to
' form an accurate voltage divider for the input. Remember that the voltage
' reference chip (LM1117) would be powering the chip so that means that the 1024
' steps of the 10-bit ADC can not go above 3.3 volts. Because the +5v battery is
' over this ADC ceiling of 3.3 volts, you have to give the ADC input something
' less via the divider network. This is still not a great way to monitor voltage.
' Here's a better way to monitor your own voltage using only an inexpensive LDO
' 3.3 volt regulator (LM-1117), only one pin (any of the 6 available), and a few
' lines of code. Of course you must have a PIC with EEPROM. This routine was
' written specifically for the 12F675 since there are so few pins to work with.
' First set the ADCON0 to use Vdd for the 'reference'. And yes, it'll be changing
' all the time which in turn, changes the 10-bit scale. Hang-on... it gets real
' simple, real fast. This is where things go backwards. The uP reads the +3.3v
' all the time and never changes, however the ADC result will change because the
' ratio of the ADC ladder is changing due to Vdd changing! This is what's backwards.
' There are three "knowns" or "givens" so we can easily solve for the fourth.
' The three "givens" are: "REFERENCE" at 3.3 volts, "RESOLUTION" at 1024 and the
' "ADC" reading. All we need to do is solve for the 4th or "X". The trick is to
' use a little high school math to simply "Solve for X". This is not complicated1
' ADC Resolution "X"
' -------------- : ------------------
' ADC Result Voltage Reference
' Do the typical "cross multiply" to get a one line formula of:
' (Resolution) x (Voltage Reference) = (ADC Result_x)
' Now to plug in some numbers and divide by the "X":
' (This example of all four sections filled in equates to a +5.00 volt battery)
' 1024 "X"
' ------ : ------
' 665 3.3 (665 is an ADC result of an exact 5 volt power supply)
' Now we have 665_x = 3325. Now solve for X by dividing 3325 by 665 = +5.00v
' Since the RESOLUTION and VOLTAGE REFERENCE don't change we have a constant of
' 3325 and only need one line of code after the ADC finishes, but we're also
' dealing with a decimal point which we can't work with. The section below
' labeled "Calculate" does repetitive division using the "//" (modulus) function.
' It doesn't give you the digits to the right of the decimal, rather, you get
' what's left over from the first division as a whole number. You then do it
' again and again to get three whole numbers. I've multiplied the first digit by
' 100 to make room for two "place settings" for simple addition at the end of a
' "tens" digit (the second division) and lastly, the third digit being the "units"
' We jus add 'em right up. If the number is +4.27 volts, the three digits would
' be "400" + "20" "7". Your program just looks for the three digits to manipulate
' when to act on any voltage. Simple!
' This program will create an "offset" to compensate for one of the "knowns" that
' really IS NOT a great known... the voltage regulator! It can vary significantly
' since the spec is quite loose for our purposes, however, it will not vary once
' you have it in circuit. The problem is you can't rely on the rated 3.3 volt
' value. This is why we will run the calibration step in the middle of the program
' on the VERY FIRST run through. It will create an offset and store it in memory
' for any subsequent cold start. Because the actual programming is critical on
' this calibration step, you MUST verify you have a very solid +5.00 volts on the
' chip. In effect, the program assumess it's getting 5 volts during the routine.
' That's about it... the last few notes are for connections to the chip, etc. If
' you have any feedback or questions, please email to Frank Miller at
' [email protected]
' NOTE: Before dumping the program to the 12F675, make sure you have EXACTLY +5v
' on the board since the calibration step is run first to correct the variance
' on the 3.3 volt regulator. This "offset" value is subsequently put into EEPROM
' for read-back on any future power-up, maintaining accurate voltage readings.
' If you notice your voltage readout is off a 'tad' from your volt meter reading
' it means your programming voltage was off by that same amount.
' LCD is SEETRON (Scott Edwards 4-Line LCD Serial LCD backpack) and powered
' from the Epic programmer. (It's ok... not much of a load!) You can't easily
' use the incoming 5v supply to power the LCD because when the supply
' volts drop below 4.6v, the LCD gets goofy.
' CONNECTIONS TO IC PINS:
' Pin 2: LCD serial backpack
' Pin 3: LM-1117 Low Drop Out voltage regulator
' For demonstration purposes, you'll notice that the progam is using 462 bytes
' of space, almost half of the 1000 total, however, in use there is no need for
' knowing this info, so the program space drops dramatically in half.
'**************************************************************** '* Name : 12F675 One Pin Voltage Monitor.BAS * '* Author : Frank Miller "Pulsar" * '* Email : [email protected] * '* Date : 7/30/2004 * '* Version : 1.0 * '**************************************************************** '------------------------------------------------------------------------------- VARIABLES: Sample var word ' ADC voltage reading (Pin 3 set by ADCON0) Group var word ' Collection of 20 ADC readings to average Base var word ' Sample voltage reading x 5 volts Volts var WORD ' Manipulated as a 2 digit reading (46 = +4.6v) Volts_1 var word ' 100's (1st voltage digit) Volts_2 var word ' 10's (2nd voltage digit) Volts_3 var word ' 1's (3rd voltage digit) Remain var word ' Remainder used loop_cnt var byte ' Used in ADC routine to capture 20 readings LCD var GPIO.5 ' 4-Line "Scott Edwards LCD" backpack on pin 2 TRISIO = %010000 ' LCD (pin 1 = gpio.5) and Vref (pin 3 = gpio.4) eeprom 0, [0, 0] ' Program forces first 2 memory locations to "0" LCD_SETUP: ' Print labels once for a flicker-free display SEROUT LCD, 4, [12, 14] ' 4 = baud, 12 = clear screen, 14 = backlight on serout LCD, 4, [16, 144, " BASE = "] ' 16 = put cursor at "144" location serout LCD, 4, [16, 164, "SAMPLE = "] ' 20 characters per line serout LCD, 4, [16, 184, " VOLTS = "] ' 4th line would start at "204" '--------------------------------------------------------------------------- ANSEL = %00110010 ' Analog Select Register (page 42) ' MSB 0 = n/a "0" ' 0 = FRC select (bit 3) "011" ' 1 = FRC select (bit 2) ' 1 = FRC select (bit 1) ' 0 = analog input select (bit 4 of 4) "0010" ' 0 = analog input select (bit 3 of 4) ' 1 = analog input select (bit 2 of 4) ' 0 = analog input select (bit 1 of 4) '--------------------------------------------------------------------------- ADCON0 = %10001101 ' ADC input on GPIO.4/AN3/pin3 (page 41) ' MSB 1 = Right Justify "1" ' 0 = Vdd as voltage reference "0" ' 0 = n/a "00" ' 0 = n/a ' 1 = select channel 03 (bit 2 of 2) "11" ' 1 = select channel 03 (bit 1 of 2) ' 0 = conversion status (see routine) "0" ' LSB 1 = A/D converter module is on "1" '------------------------------------------------------------------------------- ADC: Let Sample = 0 ' Clear any prior values Let Group = 0 for loop_cnt = 1 to 20 ' Take 20 readings for better accuracy ADCON0.1 = 1 ' Setup for manual ADC technique NOT_DONE: if ADCON0.1 = 1 then not_done ' Waiting for completion of cycle pause 10 ' Give the reading a little settling time sample.highbyte = ADRESH Sample.lowbyte = ADRESL pause 10 let Group = Group + Sample ' Collecting 20 samples next loop_cnt ' Continue back up for another reading let sample = Group/20 ' Accurate averaged reading to work with '------------------------------------------------------------------------------- CHECK_CALIBRATION: ' Check for a stored value for BASE Read 0, base.byte0 ' Read EEPROM memory locations 0 & 1 to form read 1, base.byte1 ' a 16-bit word from 2 bytes for "BASE" value if base = 0 then ' If nothing there, do the calibration Base = sample * 5 ' Sample x 5! Set power supply exactly to 5v! Write 0, BASE.byte0 ' Put lower BASE value into EEPROM address 0 write 1, base.byte1 ' Put higher BASE value into EEPROM address 1 endif ' End of capturing the BASE value '------------------------------------------------------------------------------- CALCULATE: Let Volts_1 = Base / sample ' This is the FIRST of three digits Let Volts_1 = Volts_1 * 100 ' Make a place holder for 2nd & 3rd digits Let remain = base // sample * 10 ' Get the modulus (//) and multiply x 10 '------------------------------- Let Volts_2 = Remain / sample ' This is the SECOND of three digits Let Volts_2 = Volts_2 * 10 ' Make a place holder for 2nd & 3rd digits let remain = remain // sample * 10' Get the modulus (//) and multiply x 10 '------------------------------- Let Volts_3 = remain / Sample ' This is the THIRD of three digits Let Volts=Volts_1+Volts_2+volts_3 ' 3-digit number with 1/100 volt accuracy DISPLAY: serout LCD, 4, [16, 153, #base] serout LCD, 4, [16, 173, #Sample] serout LCD, 4, [16, 193, #volts] goto adc
Re: SERIN2 Receiving Wrong Data
The sending device has the typical 18F4550 USB setup and it is set to "Define OSC 48". The receiving device is set to "DEFINE OSC 16".
rsocor01 Yesterday, 19:56