Now that there’s low-power vccRead() code to measure the current power supply voltage, we can finally get a bit more valuable info from the radioBlip sketch, which sends out one packet per minute.
So here’s a new radioBlip2 sketch which combines both functions. To support more test nodes, I’m adding a byte to the payload for a unique node ID, as well as a byte with the measured voltage level:
As a quick test I used a JeeNode without regulator, running off an electrolytic 1000 µF cap, charged to 5V via a USB BUB, and then disconnected (this is running the RFM12B module beyond its 3.8V max specs, BTW):
Here’s a dump of the received packets:
L 16:56:32.032 usb-A600dVPp OK 17 1 0 0 0 1 209
L 16:57:35.859 usb-A600dVPp OK 17 2 0 0 0 1 181
L 16:58:39.543 usb-A600dVPp OK 17 3 0 0 0 1 155
L 16:59:43.029 usb-A600dVPp OK 17 4 0 0 0 1 134
L 17:00:46.323 usb-A600dVPp OK 17 5 0 0 0 1 115
L 17:01:49.431 usb-A600dVPp OK 17 6 0 0 0 1 98
L 17:02:52.314 usb-A600dVPp OK 17 7 0 0 0 1 82
L 17:03:55.016 usb-A600dVPp OK 17 8 0 0 0 1 66
L 17:04:57.526 usb-A600dVPp OK 17 9 0 0 0 1 50
Or, more graphically, as voltage – showing 8 minutes before the sketch runs out of juice:
This consumes only marginally more power than without the VCC measurements: the original radioBlip sketch lasted 1 minute longer under similar conditions, i.e. one extra packet transmission.
This might give more insight in how long a long-running sketch will last, by extrapolating discharge curves (if their shapes are known, of course). One minor remark: could you include x-axis labels also next time (and maybe units)? =)
Well, 2V is about as low as the ATmega and the RFM12B will go on 8 MHz, so there is not really any extrapolation we can do. Regarding the horizontal axis: as I said, it’s 8 minutes, i.e. 1 minute per tick.
For the extrapolation I was referring to longer-running sketches, such as the one on the LiPo battery. Of course you’re not touching that until it dies, but if you do other tests that might run longer than a few minutes, the current battery level that gets transmitted with this new sketch might give an indication on how long that test will be running—just as you could more or less predict the 8 minutes by looking at the curve for the first 4.
Ah, ok, understand. Note that a LiPo does not behave entirely like a capacitor – it tends to hold its voltage for quite a while, before dropping off at the end. But there’s also another trick I’ll be using: I’m going to measure the voltage before and after the packet transmission. The difference gives an indication of the strength of the supply (loosely speaking). As the battery gets near-empty, I expect the difference before and after to increase, since a transmission briefly needs a fairly hight current.
At 5V/8MHz the AVR pulls ~5mA or 25mW. If you put a 2.7V linear LDO in, the AVR would pull ~3mA or 15mW (assuming the same 5V input). Would this be beneficial at all or does the dropout voltage + quiescent current end up costing more than running at a constantly lower voltage saves?
Also, when you compile this radioblip sketch, do you still compile it with F_CPU=16000000? I guess it doesn’t matter unless you’re using serial or delay() timing.
It’s an idea, but I suspect it won’t help us that much. Low-dropout regulators can get into a weird mode and draw lots of current when the input is too low, see https://jeelabs.org/2011/06/21/mcp1702-current-draw/
Also, the regulator has a quiescent current draw of its own. The MCP1702/1703 are very low, only 2 µA (about the same as the vccRead() call adds when averaged out) – you’d have to check this when picking one.
Another consideration: when the voltage drops, you could still have the ATmega run and make decisions, such as not using the RFM12B while the voltage is in the low range, so that the power level has a chance to recover. That would work down to 1.8V.
So all in all, I’d have to respond with a resounding “I don’t know which is better”.
Yes, sketch gets compiled for 16 MHz through the Arduino IDE. Serial and delay() tend not to be used in this context, i.e. remote and go to sleep where possible. Small delayMicroseconds() calls can still be done by adjusting the arg for it.
Using this technique to measure Vcc – how can you still measure external Analogue voltages (without resetting the reference voltage and having to wait for it to stabilise) ? Is everything referenced to 1.1V (as-is) – so to measure (say) a 6V input would I need a 6 to 1 divider ?
As I understand it, the trick to measure battery voltage here is by having Vcc (of the Arduino) as reference voltage, not the 1V1 band gap reference. Then that 1V1 internal reference is measured, where full-scale ADC (1023) is not 3V3, or 5V, but the current battery level (Vcc). The 1V1 is always 1V1, so the measured ADC value for that 1V1 can be used to calculate Vcc (see the links in yesterday’s (May 12th) post).
IOW, any other analogue input is measured relative to Vcc, so to accurately measure another external voltage, you should either a) Switch the ADC to use the 1V1 as reference, instead of Vcc; then you do need that 6:1 divider (be sure to include a small capacitor parallel to the “lower” resistor to mitigate noise) b) Use JCW’s approach to measure Vcc, then measure the analogue input (which is relative to that Vcc) and use both measurements to calculate the analogue input. Here of course you also need to make sure that the voltage you want to measure is below Vcc.
So, if you don’t want to change reference voltage, you should first measure the internal band gap reference of 1V1, calculate Vcc, then measure the external analogue input and calculate the voltage.
Spot on, Geert. An earlier comment mentioned that switching AREF can take a few ms in some cases, so it’s probably not a good idea to constantly switch. So my suggestion would be to use VCC as reference, and then do the corrections via the value obtained from vccRead() when getting a reading. If the battery voltage is fairly stable, then vccRead() won’t even have to be called all that often.
Thanks for the explanation Geert. So yes I will still need a divider as I’m trying to track the input from a solar panel which by necessity will be greater than Vcc when charging… – and as I want to measure both then reading Vcc first then the input as per your method above will work much better than switching ARef.
I just spend quite some time trying to use RadioBlip2 (revision “calculation tweak, trick avoids divide by zero”)
And it was not sending any packets at all. Because I am using the original fuse settings I used: #define SEND_MODE 2 But still no valid packet were being send out.
After some debugging I fixed the problem by adding the lines of code:
while (!rf12_canSend())
rf12_recvDone();
Now it works perfectly.
Is this waiting only required with SEND_MODE 2 ?
If so maybe it is a good idea to add a conditional execution of this code to fix the problem.
Oops, you’re right, over-ambituous pruning. I’ve checked-in the fix, thx.
Note that you need to change the fuses for the new logic to kick in, otherwise the brown-out detector will force the ATmega into a reset below 2.7V. Then again, it should all work fine if you just want to use this with higher voltages.
No problem. Very fast on the fix checkin-in.
I did not (yet) remove my voltage regulator (working with Jeenode smd). Is it also possible to use the “power voltage” instead of the Vcc voltage as the voltage reference? Or could I do a hardware bypass without removing the voltage regulator?
Just removed the voltage regulator. Default accuracy is not even that bad: Voltage meter: 3,66 Bandgap method: 3,70
The DX lithium solar cell does not drop in voltage at all before or after sending (at least at this charge level).