mBuino program that shows how to read VCC using the blink of a LED

Dependencies:   USBDevice mbed

mBuino PowerMeter

This program shows how to read the current voltage on the 3V3 (VCC) pin of mBuino using the blink of a LED.

Since mBuino uses the VCC voltage as reference for analog reads, all readings are relative. To get an absolute reading an external reference voltage is needed. An easy way to get an external reference is by using a zener-diode with proper characteristics.

Not having such a zener around made me look for alternatives. I found some on this page: http://www.talkingelectronics.com/projects/200TrCcts/200TrCcts.html#52

/media/uploads/maxint/reference_voltage_using_diode.jpg

Use a LED!

The most interesting method I found was to use the LEDs on mBuino! All needed to use this is an extra connection. I used a 100R resistor as connection between pin 14 and LED6. Pin 14 is the small dot right above the one of the version number. Alternatively you can also use an external LED or (zener)-diode. The picture below shows both the added resistor as well as an external LED/resistor circuit. /media/uploads/maxint/mbuino_powermeter.jpg

Serial USB

The picture above shows a USB cable connected to mBuino. When mBuino is powered via USB and nothing else is connected to VCC, power comes from the 3v3 regulator. The VCC reading will then be around its maximum. USB is used to display the readings on the USB serial console. Note that for this the USB serial driver and a terminal application such as Putty is required. When using the console the spacebar can be hit to switch between pin14+LED6 and pin15 with an external LED/resistor via pin4.

See the code comments for more information.

Committer:
maxint
Date:
Fri Aug 07 08:56:06 2015 +0000
Revision:
4:853634e0d433
Parent:
3:9e93f14db34d
added some comments

Who changed what in which revision?

UserRevisionLine numberNew contents of line
maxint 1:0434198567a4 1 /*
maxint 1:0434198567a4 2 ** mBuino_PowerMeter
maxint 1:0434198567a4 3 **
maxint 1:0434198567a4 4 ** This program shows how to read the current voltage on the 3V3 (VCC) pin of mBuino using the blink of a LED.
maxint 1:0434198567a4 5 **
maxint 4:853634e0d433 6 ** Since mBuino uses the VCC voltage as reference for analog reads, all readings are relative.
maxint 1:0434198567a4 7 ** To get an absolute reading an external reference voltage is needed.
maxint 1:0434198567a4 8 ** An easy way to get an external reference is by using a zener-diode with proper characteristics.
maxint 1:0434198567a4 9 ** Not having such a zener around made me look for alternatives. I found some on this page:
maxint 1:0434198567a4 10 ** http://www.talkingelectronics.com/projects/200TrCcts/200TrCcts.html#52
maxint 1:0434198567a4 11 ** The most interesting method I found was to use the LEDs on mBuino
maxint 1:0434198567a4 12 ** See the code comments and this programs homepage for more information.
maxint 2:7a501b777146 13 ** https://developer.mbed.org/users/maxint/code/mBuino_PowerMeter/
maxint 1:0434198567a4 14 **
maxint 1:0434198567a4 15 ** 0.1.150801 First version made for mBuino on mbed.org by maxint on 1-aug-2015
maxint 1:0434198567a4 16 **
maxint 1:0434198567a4 17 ** Feel free to use this code anyway you want, but please acknowledge my work by mentioning maxint as creator.
maxint 1:0434198567a4 18 **
maxint 1:0434198567a4 19 */
maxint 1:0434198567a4 20
maxint 1:0434198567a4 21
maxint 0:5ed29b03d6ce 22 #include "mbed.h"
maxint 0:5ed29b03d6ce 23 #include "USBSerial.h"
maxint 0:5ed29b03d6ce 24
maxint 0:5ed29b03d6ce 25 // The USB virtual serial port is used for debugging. Note: driver required, see http://developer.mbed.org/handbook/USBSerial
maxint 0:5ed29b03d6ce 26 USBSerial serialUSB(0x1f00, 0x2012, 0x0001, false); // Virtual serial port over USB, set connect_blocking to false to allow starting without PC
maxint 0:5ed29b03d6ce 27 #define USBSERIAL_DEBUG 1
maxint 0:5ed29b03d6ce 28
maxint 0:5ed29b03d6ce 29 DigitalOut LED[] = {(LED1), (LED2), (LED3), (LED4), (LED5), (LED6), (LED7)};// declare 7 LEDs
maxint 0:5ed29b03d6ce 30
maxint 0:5ed29b03d6ce 31 float readVCC(PinName nAnalogIn=P0_14, PinName nLed=LED6, int nBlinkDelayMsec=0, float ftVrefInit=1.91)
maxint 0:5ed29b03d6ce 32 { // Unlike Arduino, mBuino v1.5 has no internal reference voltage for analog reads.
maxint 0:5ed29b03d6ce 33 // As all analog reads are relative to VCC, it would be nice to be able to tell the VCC
maxint 0:5ed29b03d6ce 34 // Additionally knowing the current VCC is critical for battery operated applications.
maxint 0:5ed29b03d6ce 35
maxint 0:5ed29b03d6ce 36 // Please note that the voltage on the 3v3 pin is always lower than 3.3V as diodes D10 and D11
maxint 0:5ed29b03d6ce 37 // are between the actual VCC of the 3.3V regulator and that of the CR2032 battery.
maxint 4:853634e0d433 38 // Measured voltages are 2.85V when powered by USB or lower when powered by battery.
maxint 0:5ed29b03d6ce 39 // When mBuino has its LEDs on, or when an external device is using VCC, the voltage will be lower too.
maxint 0:5ed29b03d6ce 40
maxint 0:5ed29b03d6ce 41 // The current VCC voltage can be determined by using analogIn to read a known reference voltage.
maxint 0:5ed29b03d6ce 42 // One way to get a reference voltage is by connecting a led via a resistor between VCC and GND.
maxint 0:5ed29b03d6ce 43 // The voltage over the led is (more or less) constant (about 1.7V, depending on the kind of LED).
maxint 0:5ed29b03d6ce 44 // This constant voltage can be measured by using a multimeter.
maxint 1:0434198567a4 45 // Measured voltages are e.g. 1,77V for a yellow led, 1,66 for a red led and 1,73 for a green led (and 1K resistor).
maxint 0:5ed29b03d6ce 46 // See http://www.talkingelectronics.com/projects/200TrCcts/200TrCcts.html#52 for more methods.
maxint 0:5ed29b03d6ce 47 //
maxint 0:5ed29b03d6ce 48 // As mBuino already has LEDs we can use them as a reference by connecting P0_14 to the left leg of LED7 or LED6.
maxint 0:5ed29b03d6ce 49 // To avoid potential damage and to allow PWM on LED7 a 100R resistor can be used to make the connection.
maxint 0:5ed29b03d6ce 50 // Note: P0_14 is the tiny dot right above the 1 of the printed version number.
maxint 0:5ed29b03d6ce 51 // See https://developer.mbed.org/platforms/Outrageous-Circuits-mBuino/ for pin-outs and schematics
maxint 0:5ed29b03d6ce 52 //
maxint 0:5ed29b03d6ce 53 AnalogIn ana(nAnalogIn); // TODO: can be made static for better speed?
maxint 0:5ed29b03d6ce 54 DigitalOut ledBlink(nLed); // TODO: can be made static for better speed?
maxint 0:5ed29b03d6ce 55 float ftVoltage, ftVref;
maxint 0:5ed29b03d6ce 56 bool fLedStatus;
maxint 0:5ed29b03d6ce 57
maxint 0:5ed29b03d6ce 58 fLedStatus=ledBlink; // remember status of the led so we can set it back
maxint 0:5ed29b03d6ce 59 ledBlink=1; // put a high voltage on LED7 so we can measure it as a reference voltage and use that to calculate the VCC
maxint 0:5ed29b03d6ce 60 if(nBlinkDelayMsec!=0)
maxint 0:5ed29b03d6ce 61 wait_ms(nBlinkDelayMsec); // allow some time to reach full voltage level (when using no delay the reading can be a bit lower)
maxint 0:5ed29b03d6ce 62 ftVoltage=ana.read();
maxint 0:5ed29b03d6ce 63 ftVref=ftVrefInit; // assume reference voltage on ana14 to be 1.91V, e.g. by connecting is via a 100R resistor to the left leg of LED7
maxint 0:5ed29b03d6ce 64 #ifdef USBSERIAL_DEBUG
maxint 0:5ed29b03d6ce 65 serialUSB.printf("Vref %1.2f / Vread %1.2f%% ~~> ", ftVref, ftVoltage*100);
maxint 0:5ed29b03d6ce 66 #endif
maxint 0:5ed29b03d6ce 67
maxint 0:5ed29b03d6ce 68 // Some silly trial and error compensations. Note: this compensation is not very precise!
maxint 0:5ed29b03d6ce 69 // TODO: improve the compensation to get more accurate readings. Now final readings may differ up to 0.10V from
maxint 1:0434198567a4 70 // actual values, depending on the reference voltage, length of the blink, resistor and LED used, VCC-level and probably temperature.
maxint 0:5ed29b03d6ce 71 if(!fLedStatus && nBlinkDelayMsec<=10)
maxint 0:5ed29b03d6ce 72 ftVref+=(0.05-nBlinkDelayMsec/200.0); //compensate for lower voltage due to short delays.
maxint 0:5ed29b03d6ce 73 ftVref-=(0.04+(ftVoltage-0.66)/4); // compensation: Vref is slightly lower on low voltages.
maxint 0:5ed29b03d6ce 74
maxint 0:5ed29b03d6ce 75 // Calculate the VCC by dividing the Vref by the analog reading
maxint 0:5ed29b03d6ce 76 ftVoltage=ftVref/ftVoltage;
maxint 0:5ed29b03d6ce 77
maxint 0:5ed29b03d6ce 78 ledBlink=fLedStatus; // restore led7 to its original status
maxint 0:5ed29b03d6ce 79 return(ftVoltage);
maxint 0:5ed29b03d6ce 80 }
maxint 0:5ed29b03d6ce 81
maxint 1:0434198567a4 82
maxint 1:0434198567a4 83 void ledFlash(uint8_t nLed, float ftDelay=0.005)
maxint 1:0434198567a4 84 {
maxint 1:0434198567a4 85 if(nLed>6) nLed=6;
maxint 1:0434198567a4 86 LED[nLed]=!LED[nLed];
maxint 1:0434198567a4 87 wait(ftDelay);
maxint 1:0434198567a4 88 LED[nLed]=!LED[nLed];
maxint 1:0434198567a4 89 }
maxint 1:0434198567a4 90
maxint 1:0434198567a4 91 void SweepAllLeds(uint8_t nMaxLeds=7, bool fLeftToRight=true, float flDelay=0.1)
maxint 0:5ed29b03d6ce 92 { // light all leds up from left to rigth or vise-versa and then switch them off from reverse direction
maxint 0:5ed29b03d6ce 93 // leds on, left to right
maxint 1:0434198567a4 94 if(nMaxLeds>7) nMaxLeds=7;
maxint 1:0434198567a4 95 for(int n=0; n<nMaxLeds; n++)
maxint 0:5ed29b03d6ce 96 {
maxint 1:0434198567a4 97 LED[fLeftToRight?n:nMaxLeds-1-n] = 1; // turn on
maxint 0:5ed29b03d6ce 98 wait(flDelay); // delay
maxint 0:5ed29b03d6ce 99 }
maxint 0:5ed29b03d6ce 100 // leds off, right to left
maxint 0:5ed29b03d6ce 101 for(int n=0; n<7; n++)
maxint 0:5ed29b03d6ce 102 {
maxint 1:0434198567a4 103 LED[!fLeftToRight?n:nMaxLeds-1-n] = 0; // turn off
maxint 0:5ed29b03d6ce 104 wait(flDelay); // delay
maxint 0:5ed29b03d6ce 105 }
maxint 0:5ed29b03d6ce 106 }
maxint 0:5ed29b03d6ce 107
maxint 0:5ed29b03d6ce 108
maxint 0:5ed29b03d6ce 109 main()
maxint 0:5ed29b03d6ce 110 {
maxint 0:5ed29b03d6ce 111 // Minimal voltage on 3v3 pin is about 1.8V. Below this mBuino may react weird or stop working.
maxint 0:5ed29b03d6ce 112 // Default reference for voltage on mBuino's LEDs is 1.91v, measurement pin is P0_14.
maxint 0:5ed29b03d6ce 113 // Press any key on USB-serial to switch to 1.85v and pin P0_15 for external (green) LED.
maxint 0:5ed29b03d6ce 114 float ftVmin=1.80, ftVled=1.91, ftVcc;
maxint 0:5ed29b03d6ce 115 PinName pinAnalog=P0_14, pinLed=LED6;
maxint 0:5ed29b03d6ce 116 Timer t;
maxint 0:5ed29b03d6ce 117
maxint 0:5ed29b03d6ce 118 // small initial delay to show all leds are working and to allow USB connection
maxint 0:5ed29b03d6ce 119 SweepAllLeds();
maxint 1:0434198567a4 120 SweepAllLeds(7, false,0.02);
maxint 0:5ed29b03d6ce 121 SweepAllLeds();
maxint 0:5ed29b03d6ce 122
maxint 4:853634e0d433 123 // flash a led while waiting for console response as we
maxint 0:5ed29b03d6ce 124 t.start();
maxint 4:853634e0d433 125 while(!serialUSB.readable() && (t.read_ms() <= 3000))
maxint 4:853634e0d433 126 {
maxint 0:5ed29b03d6ce 127 serialUSB.printf(".");
maxint 0:5ed29b03d6ce 128 ledFlash(0);
maxint 0:5ed29b03d6ce 129 wait(0.1);
maxint 0:5ed29b03d6ce 130 }
maxint 0:5ed29b03d6ce 131
maxint 4:853634e0d433 132 // show status on console and give instructions
maxint 1:0434198567a4 133 serialUSB.printf("\r\n=== mBuino PowerMeter ==== \r\n");
maxint 0:5ed29b03d6ce 134 serialUSB.printf("Measuring LED pin %d [%1.2fV] using pin %d\r\n", pinLed, ftVled, pinAnalog);
maxint 0:5ed29b03d6ce 135 serialUSB.printf("Hit spacebar to change to LED pin 4 [1.85V] using pin 15.\r\n");
maxint 4:853634e0d433 136
maxint 4:853634e0d433 137 // perform voltage readings, indicate voltage level and process serial console input
maxint 0:5ed29b03d6ce 138 while(true)
maxint 0:5ed29b03d6ce 139 {
maxint 0:5ed29b03d6ce 140 //ftVCC=readVCC(); // float readVCC(PinName nAnalogIn=P0_14, PinName nLed=LED6, int nBlinkDelayMsec=0, float ftVrefInit=1.91)
maxint 0:5ed29b03d6ce 141 ftVcc=readVCC(pinAnalog, pinLed, 0, ftVled);
maxint 0:5ed29b03d6ce 142 serialUSB.printf("VCC: %1.2fV\r\n", ftVcc);
maxint 0:5ed29b03d6ce 143
maxint 4:853634e0d433 144 // indicate voltage level using all 7 LEDs on mBuino
maxint 0:5ed29b03d6ce 145 if(ftVcc>ftVmin)
maxint 0:5ed29b03d6ce 146 {
maxint 0:5ed29b03d6ce 147 uint8_t uLed=0;
maxint 0:5ed29b03d6ce 148 if(ftVcc>=1.90) uLed=1;
maxint 0:5ed29b03d6ce 149 if(ftVcc>=2.00) uLed=2;
maxint 0:5ed29b03d6ce 150 if(ftVcc>=2.20) uLed=3;
maxint 0:5ed29b03d6ce 151 if(ftVcc>=2.40) uLed=4;
maxint 0:5ed29b03d6ce 152 if(ftVcc>=2.60) uLed=5;
maxint 0:5ed29b03d6ce 153 if(ftVcc>=2.75) uLed=6;
maxint 1:0434198567a4 154 SweepAllLeds(uLed+1);
maxint 0:5ed29b03d6ce 155 ledFlash(uLed);
maxint 0:5ed29b03d6ce 156 wait(1);
maxint 0:5ed29b03d6ce 157 }
maxint 0:5ed29b03d6ce 158 else
maxint 4:853634e0d433 159 { // battery is very low: show rapid flashing
maxint 0:5ed29b03d6ce 160 ledFlash(0);
maxint 0:5ed29b03d6ce 161 wait(0.25);
maxint 0:5ed29b03d6ce 162 }
maxint 0:5ed29b03d6ce 163
maxint 4:853634e0d433 164 // process serial console input
maxint 0:5ed29b03d6ce 165 if(serialUSB.readable())
maxint 0:5ed29b03d6ce 166 { // switch pins when is spacebar is hit
maxint 3:9e93f14db34d 167 if(serialUSB.getc()==' ')
maxint 0:5ed29b03d6ce 168 {
maxint 0:5ed29b03d6ce 169 pinLed=(pinLed==P0_4?LED6:P0_4);
maxint 1:0434198567a4 170 //ftVled=(ftVled!=1.85?1.85f:1.91f); // hmm, weird bug; no conditional assignment on floats?
maxint 0:5ed29b03d6ce 171 if(ftVled!=1.91f) ftVled=1.91f; else ftVled=1.85f;
maxint 0:5ed29b03d6ce 172 pinAnalog=(pinAnalog==P0_15?P0_14:P0_15);
maxint 0:5ed29b03d6ce 173 serialUSB.printf("Switched to measuring LED pin %d [%1.2fV] using pin %d\r\n", pinLed, ftVled, pinAnalog);
maxint 0:5ed29b03d6ce 174 }
maxint 0:5ed29b03d6ce 175 else
maxint 0:5ed29b03d6ce 176 {
maxint 0:5ed29b03d6ce 177 serialUSB.printf("Hit spacebar to switch between pins (4/15 or LED6/14).\r\n");
maxint 0:5ed29b03d6ce 178 }
maxint 0:5ed29b03d6ce 179 }
maxint 0:5ed29b03d6ce 180 }
maxint 0:5ed29b03d6ce 181 }