PDA

View Full Version : Referral to ULPWU/PLVD code per AN879??



jellis00
- 21st July 2009, 21:28
Am programming a 16F690 chip using PicBasic Pro. My application is battery powered (3 ea NiMH AA batteries) and I am using a Low Drop Out regulator with very low quiescent power to provide Vdd = 3.3 vdc to the MCU and peripherals. I want to monitor the battery voltage with PICBasic code whenever the chip is not in SLEEP mode and then flash a red LED if the battery voltage has dropped to 3.5 volts. The 16F690 doesn't have a PLVD module. Therefore, I have been studying the Microchip AN879 application note on how to use the ULPWU module of the 16F690 as a Programmable Low-voltage Detect circuit. However, I am struggling trying to figure out how to convert the algorithm described in AN879 to PicBasic.

Do any of you have or can you point me to any PICBasic coding examples to do this or another way to do the battery monitor/low voltage detect function I need in the 16F690??

Darrel Taylor
- 21st July 2009, 23:16
The 16F690 has an internal 0.6V reference that can be turned ON/OFF from the VRCON register.

With VREF+ set to VDD, you can use the 0.6V reference to measure the PIC's VDD voltage. Which goes something like this ...

VDD VAR WORD

VRCON.4 = 1 ; Turn 0.6V reference ON
PAUSEUS 100 ; Allow VP6 to settle
ADCIN 15, VDD ; get VP6 analog reading (10-bit)
VRCON.4 = 0 ; Turn 0.6V reference OFF
VDD = 6138 / VDD ; convert to voltage

The variable VDD now holds the VDD voltage *10 (3.3V = 33).
The formula is the same for any VDD voltage.

Then ...

IF VDD < 32 THEN GOSUB LowVoltage ; if less than 3.2V

This then tells you when the battery voltage has gone below the LDO's "Drop-Out".
Or you can set it to any other voltage (lower than normal VDD) as required.

hth,

jellis00
- 22nd July 2009, 21:26
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?



'************************************************* ***************
'* 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

Darrel Taylor
- 22nd July 2009, 21:45
OOPS, my bad!

The VP6 channel is 13, not 15.
So use this instead ...
ADCIN 13,ADINPUT

It's channel 15 on a 16F887, so I got confused.
<br>

Darrel Taylor
- 22nd July 2009, 21:55
Oh I forgot to answer the 6138 question.

6138 comes from 0.6 * 1023 = 613.8
In order to get 1 decimal of precision, multiply * 10 for 6138.
<br>

jellis00
- 22nd July 2009, 22:41
Thanks Darrell. I should have caught that channel number myself. I was able to test this thoroughly by incrementally changing the Vthr constant in the code and correspondingly incrementing the target voltage in the PICKIT2. It now works like a charm.

Thanks also for answering my question about the 6138/VDD calculation. I now understand the algorithm completely.

Let me say how much I appreciate your frequent and outstanding support to the forum. I use it extensively and really do appreciate it.:D

Darrel Taylor
- 23rd July 2009, 02:12
SWEET!

I expect to receive 1% of the value of that resistor and capacitor you saved. :D
<br>

boban
- 18th November 2012, 14:30
Hello, I have found this post, because I want to do the same. I have 16F690 battery powered system and I want to detect low battery caase. I have Implemented the code like described here, but it somehow doesn't work:

'read baterry
VRCON.4 = 1 ; Turn 0.6V reference ON
PAUSEUS 200 ; Allow VP6 to settle
ADCIN 13, temp_word ; get VP6 analog reading (10-bit)
VRCON.4 = 0 ; Turn 0.6V reference OFF
VDD = 6138 / temp_word ; convert to voltage ve vdd je 25 = 2,5 V
temp_data[9] = (VDD DIG 1) + $30
temp_data[10] = "."
temp_data[11] = (VDD DIG 0) + $30
temp_data[12] = 13
temp_data[13] = 10

But it somehow doesn't work. If powerred with 3.3 V I have in VDD 42, if powerred from exhausted bateries with total voltage 2.4 V I have there 4 and if powered from new bateries with 3.1 V I have there 4. Do you have any idea, why it is doesn't work?
Bob

Darrel Taylor
- 18th November 2012, 18:42
I imagine that you are only seeing 2 digits of a much larger number that was calculated wrong because either the A/D wasn't set up right or a variable size is wrong.
Make sure you have these in your program.

temp_word VAR WORD
VDD VAR WORD

DEFINE ADC_BITS 10
ADCON0.7 = 1

boban
- 18th November 2012, 21:11
Wow, super, it's working now. I didn't specified the

DEFINE ADC_BITS 10
ADCON0.7 = 1

Thanks a lot, I really apreciated you quick answer and help!!!

bob

johnny
- 15th December 2013, 15:19
Hello I've just recently joined and found this post after a lot of research because I am wanting to do the same. I am using the chip 16F690 and I want to detect low battery also. I would be using 5volts to power on the chip and would want to detect 3.7volts or any voltage as long as its lower than 5volts when the voltage has dropped and the led would be used as the output to indicate this or a multimeter showing the voltage if possible. I have Implemented the code that has been provided by 'jelliss00' in the MPLAB software to build but the program but isn't working. If any of you can give guidance to me on developing the program I would really appreciate. :)

Demon
- 15th December 2013, 17:10
It would help if you posted your entire code, which PBP version and assembler. A schematic of your circuit is always a good idea.

Robert

johnny
- 22nd December 2013, 17:31
7183

Hi sorry about the late reply I have added the schematic and included the programming below. The Led would turn on when the potentiometer has been adjusted and the voltage comes to 2.5volts as I would be using comparator to detect voltage. The software I am using is MPLAB IDE version 8.92. The program doesn't seem to work I would appreciate your help on this.

list p=16F690
include "p16F690.inc"
radix dec

;***** CONFIGURATION
; ext reset, no code protect, no watchdog, 4 MHz int clock
__CONFIG _MCLRE_ON & _CP_OFF & _WDT_OFF & _IOSCFS_OFF & _IntRC_OSC_RB4EN
; pin assignments
#define LED PORTC,3 ; indicator LED on RC3
constant nLED=3 ; (port bit 3)

;***** RC CALIBRATION
RCCAL CODE 0x3FF ; processor reset vector
res 1 ; holds internal RC cal value, as a movlw k
;***** RESET VECTOR ************************************************** ***
RESET CODE 0x000 ; effective reset vector
movwf OSCCAL ; apply internal RC factory calibration

;***** MAIN PROGRAM ************************************************** ***
;***** Initialisation
start
; configure ports
movlw ~(1<<nLED) ; configure LED pin (only) as an output
tris PORTC

; configure comparator 1
movlw 1<<C1PREF|1<<C1NREF|1<<C1POL|1<<C1ON
; +ref is C1IN+ (C1PREF = 1)
; -ref is C1IN- (C1NREF = 1)
; normal polarity (C1POL = 1)
; comparator on (C1ON = 1)
movwf CM1CON0 ; -> C1OUT = 1 if C1IN+ > C1IN-

;***** Main loop
main_loop
; display comparator output
btfsc CM1CON0,C1OUT ; if comparator output high
bsf LED ; turn on LED
btfss CM1CON0,C1OUT ; if comparator output low
bcf LED ; turn off LED
; repeat forever
goto main_loop

END

Demon
- 22nd December 2013, 17:48
To start:

Labels end with colons.

Assembler must be delimitted with ASM.

Is this really PIC BASIC?

Robert

Edit: PORTC.3 <--- period, not comma