For the last few days I have been playing with the micro:bits builtin capability to measure analog voltages on P0, P1 & P2 (you can set up some of the other IO lines as analog inputs but this is a bit of an involved process and best avoided if possible).
** WARNING ** – YOU MUST ENSURE THAT ANY VOLTAGE APPLIED TO THE MICRO:BIT DOES NOT EXCEED THE SUPPLY RAIL [TYPICALLY 3V] DOING SO WILL RESULT IN DAMAGE TO YOUR MICRO:BIT
By default the analog converter in the micro:bit is referenced to the micro:bit supply rail and is configured for 10 bit operation. Hence the following code;
from microbit import * a = pin0.read_analog() print(a) display.scroll(str(a))
will return 1023 if you connect the 3V & P0 pads together, irrespective of battery condition of if you power via the micro USB connector. For many applications this is fine and using the micro:bits 3V supply as the source voltage for any analog experiments is the best way to minimize risk of damage the the micro:bit.
However if you want to measure a voltage not derived from the micro:bits supply things can become a bit more problematic. It’s fine if you can power the micro:bit from a constant source – for instance a phone mains power adapter, but not so good if you are running from a battery. This because as the ADC (analog to digit converter) reference voltage will drop as the battery discharges resulting in a change to the count value returned. For instance assuming a new set of batteries provides 3V, a 1.5V source on P0 would return 512, but if the battery voltage drops to 2.5V the reading would change to 614 counts. To get around this the ADC in the micro:bit can be configured to reference an internal fixed 1.2V voltage reference. This means the count value will not vary with a changing supply voltage.
In it’s basic setup this would mean a voltage of 1.2V on P0 would give a result of 1023. However 0-1.2V is quite a small range so the ADC circuit includes a configurable ‘pre-scaler’ to help us. Configuring this to 3:1 we get full scale ADC range of 0-3.6V. It is important to note however that the rule of keeping the maximum voltage applied to a micor:bit input pin at or below the supply rail still applies.
The following code will setup the ADC to use the internal reference on P0 together with a 3:1 pre-scaler.
Code to demo using the micro:bit internal ADC reference # based on material and help from Carlos Pereira Atencio https://gist.github.com/microbit-carlos/ # David Saul 2017. Released to the public domain. from microbit import * NRF_ADC_BASE = 0x40007000 NRF_ADC_CONFIG = NRF_ADC_BASE + 0x504 # functions used to modify ADC setup @micropython.asm_thumb def reg_read(r0): ldr(r0, [r0, 0]) @micropython.asm_thumb def reg_bit_clear(r0, r1): ldr(r2, [r0, 0]) bic(r2, r1) str(r2, [r0, 0]) # change ADC config for pin0 # mbed configured: 10bit, input 1/3, ref 1/3 vdd, enable ADC in AIN4-P0.03-pin0 pin0.read_analog() #Set ref voltage to internal ref 1.2V (band gap), set bits 5-6 to 0x00 reg_bit_clear(NRF_ADC_CONFIG, 0x60) print("ADC config should be 0x100A: {:#010x}".format(reg_read(NRF_ADC_CONFIG))) #variable definition vt = 0 # raw / scaled analog value vf = "0000" # measured voltage as a formatted string cal = 352 # calibration variable # cal is calculated as (Vin / raw count)*10000 while True vt = pin0.read_analog() print ('raw count = ',vt) # the following lines of code scale the measured value and derive a # string (vf) that equates to it - there are simpler ways to do this # but this method avoids the use of floating variables which are very # inefficient on cards like the micro:bit vt = int((vt * cal)/1000) vs = str(vt) if vt > 1000: vf = vs[0:2]+'.'+vs[2:3] elif vt > 100 : vf = vs[0:1]+'.'+vs[1:3] elif vt > 10 : vf = '0.'+vs elif vt > 1 : vf = '0.0'+vs else : vf = '0.000' vf = vf+"V" print ('Scaled', vf) display.scroll(vf) sleep(2000)
The ‘keep to the rail voltage’ is a generally safe but slight simplification of the ADC operating rules. If you are looking to work with source voltages not limited to the micro:bit supply rail there are specific rules you need to be aware of to avoid damaging your micro:bit. A number of discussion threads have been written on these [ probably because it’s not very understandable in the NORDIC chip datasheet ] one example which is ‘relatively’ clear is https://devzone.nordicsemi.com/question/102/what-voltage-range-can-be-measured-with-the-adc/