Darrell, first of all thanks so much for your input. I really like your algorithm much better than the Microchip AN869 approach to a PLVD because it is simpler and also doesn't require an additional Resistor and Capictor.
I have implemented your algorithm into the code attached below and tried to test it using the 16F690 in a PICKIT2 LPDV board. It compiles and programs the board/16F690 with no problem, but the testing shows there must be a problem in the code, which I will explain.
To ensure accurate testing I calibrated my PICKIT2 per their instructions with a voltmeter and made sure it puts out exactly 4.8 volts to the target ch when 4.8 volts is selected in the PICKIT2 Voltage selector. I have attached a picture of the PICKIT2 screen during the test for reference.
Notice that I have inserted some WRITE statements in the code to enable me to READ the different variables at certain points in the code execution.
These read values are shown in HEX in the EEPROM memory locations at the bottom of the PICKIT2 screen:
Address 11 is ADINPUT = hex A0 = decimal 160
Address 13/14 is VDD = hex 0027 = decimal 38; which is equivalent to the code calculation 6138/ADINPUT = 6138/160 = 38.36 => 3.84 volts.
Address 17 is Vthr = hex 2F = decimal 47; which is as it should be based on the constant value being set as 47 in the variable declarations.
However, this testing shows the calculated VDD to be 3.84 volts when the voltmeter on the calibrated PICKIT2 input to the VDD on the chip is showing exactly 4.80 volts. This then causes the IF-THEN statement to incorrectly trigger the Low Voltage warning subroutine that blinks the LED. I have double checked my code and can't find why the A/D is measuring the wrong value. In fact, to equal the calibrated 4.8 volt input the ADINPUT reading by the A/D would have to be decimal 127 instead of the measured 160. Can you see any mistakes in my code that would cause this measurement error? If you have a PICKIT2 with the LPDV board you should be able to use this code to replicate my testing.
One thing in your algorithm I didn't quite understand was where the value 6138 comes from in the calculation 6138/ADINPUT that converts the A/D measurement to voltage. Can you please explain?
Code:
'****************************************************************
'* Name : DT_VoltageMonitor.BAS *
'* Author : [select VIEW...EDITOR OPTIONS] *
'* Notice : Copyright (c) 2009 *
'* : All Rights Reserved LodeStar Assoc. Inc. *
'* Date : 7/21/2009 *
'* Version : 1.0 *
'* Size : 226 words *
'* Notes : Adapted from Darrell Taylor's code in order to *
'* : monitor a battery pack input from 4ea NiMH AA *
'* : batteries that is normall fully charged at 4.8vdc.*
'****************************************************************
' ---------[ Device Declaration & CONFIG settings]-----------------------------
ASM ; 16F690
ifdef PM_USED ; For PM assembler
device INTRC_OSC_NOCLKOUT ; Oscillator Selection
device FCMEN_OFF ; Fail-Safe Clock Monitor
device IESO_OFF ; Internal External Switchover
device BOD_OFF ; Brown-out Detect
device CPD_OFF ; Data Code Protection
device PROTECT_OFF ; Code Protection
device MCLR_OFF ; Master Clear Reset
device PWRT_ON ; Power-up Timer
device WDT_OFF ; Watchdog Timer
else ; For MPASM assembler
cfg= _INTRC_OSC_NOCLKOUT ; Oscillator Selection
cfg=cfg& _FCMEN_OFF ; Fail-Safe Clock Monitor
cfg=cfg& _IESO_OFF ; Internal External Switchover
cfg=cfg& _BOR_OFF ; Brown-out Reset
cfg=cfg& _CPD_OFF ; Data Code Protection
cfg=cfg& _CP_OFF ; Code Protection
cfg=cfg& _MCLRE_OFF ; Master Clear Reset
cfg=cfg& _PWRTE_ON ; Power-up Timer
cfg=cfg& _WDT_OFF ; Watchdog Timer
__CONFIG cfg
endif
ENDASM
' The above config is inteded to set CONFIG = %0000000000000000 for hex 00C4 or
' FCMEN off(0), IESO off(0), BOR off(00), CPD off(1), CP off(1), /MCLR is
' digital input(0), /PWRTE on(0), WDTE off(0), FOSC<2:0> (100).
' -----------------------[ Set Registers & Ports ]-----------------------------
' Set ADCON registers for A/D converter
ADCON0 = %10110101
' ADCON0.7 = ADFM = 1 ' 10-bit result is right justified
' ADCON0.6 = VCFG = 0 ' Set VREF+ to VDD
' CHS<3:0> = 1101 ' Select 0.6V Ref channel
ADCON1 = %00110000 ' Select FRC as A/D conversion clock source
' Set FOSC=1MHz to stay inside recommended TAD range when not in SLEEP mode
OSCCON = %01000001
' Set ANSEL register to make RA1 analog input
ANSEL= %11110011 ' Set PortA to Analog I/O to save power during Sleep but
' leave Bits 2 & 3 as digital for RA2 and RA3 interrupts
ANSELH= %11111111 ' Analog module enabled to save power during Sleep
DEFine ADC_BITS 10
' -----------------[ Declare Variables & Aliases ]-----------------------------
led2 VAR PORTC.1 ' Set RC1 as LED indicator of low battery condition
ADINPUT VAR WORD ' Stores VP6 value as sampled by ADC
VDD VAR WORD ' Stores VDD value as converted from ADINPUT
Vthr CON 47 ' Set threshold (4.7v) to trigger low voltage warning
b0 VAr vdd.byte1 ' LSB of VDD when right justified
b1 var VDD.Byte0 ' MSB of VDD when right justified
Main:
VRCON.4 = 1 ' Turn 0.6V reference ON
PAUSEUS 100 ' Allow VP6 to settle
ADCIN 15,ADINPUT ' Get VP6 analog reading (10-bit)
VRCON.4 = 0 ' Turn 0.6V reference OFF
WRITE 11,ADINPUT
VDD = 6138/ADINPUT ' convert input reading to VDD voltage
' VDD now holds the measured VDD voltage * 10 (i.e., 3.4V = 34)
' The formula is the same for any VDD voltage.
' Assume normal VDD = +4.8vdc direct from fully charged battery pack input
WRITE 13,b0 ' Remove comments on Write statements for test only
WRITE 14,b1
Write 17,Vthr
IF VDD < Vthr THEN
GOSUB LowVoltage ' if VDD less than 4.7v
EndIF
GOTO Main
'------------------------------Subroutines-------------------------------------
LowVoltage:
' If Battery is low..flash low battery monitor light
HIGH led2
PAUSE 125
Low led2
Pause 500
RETURN
END
Bookmarks