Si nous voulons connaître la tension Vdd pour, disons, élaborer une condition "pile trop basse", la manière habituelle serait de définir un pont diviseur résistif sur une broche d'entrée analogique. Ceci utiliserait deux composants et monopoliserait une broche.
Heureusement, sur la plupart des composants, il est possible de mesurer la référence interne VRef, et si nous mesurons avec Vdd comme référence de plage analogique, le résultat est inversement proportionnel à Vdd:
function Low_Bat : boolean; // Check battery
{ Note: Battery sense uses VP6 reference so we always measure 0.6 V,
so a/d value is depending to VDD with the law: n = 0.6 * Max / Vdd,
so the a/d value is reverse proportional to Vdd;
so we can compute Vdd = 0.6 * Max / n;
Power is from a 3.6 V lithium battery.
We fix a low bat value to 3.1 V.
}
const
Max_Ana = 1023; // 10 Bits analog max value
VP6_Ref = 600; // 0.6 V = 600 mV
VP6_Ref_Error = - 25; // -25 mV error on vref (manual adjustement for fine tuning)
Low_Bat_Voltage = 3100; // 3.1 V = 3100 mV
// Low battery trigger value in analog raw binary value
Low_Bat_Trigger = (VP6_Ref + VP6_Ref_Error) * Max_Ana div Low_Bat_Voltage;
var
V : word;
begin
{ A/D init: may be done once at program start-up }
ANSEL := 0; { Set selected channels mask }
ANSELH := 0; { Set selected channels mask }
ADCON1.ADCS := 5; { Set clock selection to FOsc/16 }
ADCON0 := [ADFM, ADON]; { Configure for 10 bits right justified, turn on the A2D module }
VRCON.VP6EN := true; { Activate A/D VP6 reference for Vdd measurement }
// Normally we have to wait a while here for settle time...
ADCON0.CHS := 13; { Select VP6 channel }
delay(5); { Wait 5 µS for A2D amp to settle and capacitor to charge }
ADCON0.GO := true; { Start conversion }
while ADCON0.GO_DONE do;
V := (word(ADRESH) shl 8) or ADRESL;
ADCON0.ADON := false; { Turn off AD to save power }
Low_Bat := V >= Low_Bat_Trigger;
end;