mirror of
https://github.com/licsber/micropython.git
synced 2024-09-20 09:00:23 +08:00
0a4cc24b2e
Makes sure that classes described in these separate files are properly designated as belonging to "pyb" module in indexes.
143 lines
5.7 KiB
ReStructuredText
143 lines
5.7 KiB
ReStructuredText
.. currentmodule:: pyb
|
|
.. _pyb.ADC:
|
|
|
|
class ADC -- analog to digital conversion
|
|
=========================================
|
|
|
|
.. only:: port_pyboard
|
|
|
|
Usage::
|
|
|
|
import pyb
|
|
|
|
adc = pyb.ADC(pin) # create an analog object from a pin
|
|
val = adc.read() # read an analog value
|
|
|
|
adc = pyb.ADCAll(resolution) # creale an ADCAll object
|
|
val = adc.read_channel(channel) # read the given channel
|
|
val = adc.read_core_temp() # read MCU temperature
|
|
val = adc.read_core_vbat() # read MCU VBAT
|
|
val = adc.read_core_vref() # read MCU VREF
|
|
|
|
|
|
Constructors
|
|
------------
|
|
|
|
|
|
.. only:: port_pyboard
|
|
|
|
.. class:: pyb.ADC(pin)
|
|
|
|
Create an ADC object associated with the given pin.
|
|
This allows you to then read analog values on that pin.
|
|
|
|
Methods
|
|
-------
|
|
|
|
.. only:: port_pyboard
|
|
|
|
.. method:: adc.read()
|
|
|
|
Read the value on the analog pin and return it. The returned value
|
|
will be between 0 and 4095.
|
|
|
|
.. method:: adc.read_timed(buf, timer)
|
|
|
|
Read analog values into ``buf`` at a rate set by the ``timer`` object.
|
|
|
|
``buf`` can be bytearray or array.array for example. The ADC values have
|
|
12-bit resolution and are stored directly into ``buf`` if its element size is
|
|
16 bits or greater. If ``buf`` has only 8-bit elements (eg a bytearray) then
|
|
the sample resolution will be reduced to 8 bits.
|
|
|
|
``timer`` should be a Timer object, and a sample is read each time the timer
|
|
triggers. The timer must already be initialised and running at the desired
|
|
sampling frequency.
|
|
|
|
To support previous behaviour of this function, ``timer`` can also be an
|
|
integer which specifies the frequency (in Hz) to sample at. In this case
|
|
Timer(6) will be automatically configured to run at the given frequency.
|
|
|
|
Example using a Timer object (preferred way)::
|
|
|
|
adc = pyb.ADC(pyb.Pin.board.X19) # create an ADC on pin X19
|
|
tim = pyb.Timer(6, freq=10) # create a timer running at 10Hz
|
|
buf = bytearray(100) # creat a buffer to store the samples
|
|
adc.read_timed(buf, tim) # sample 100 values, taking 10s
|
|
|
|
Example using an integer for the frequency::
|
|
|
|
adc = pyb.ADC(pyb.Pin.board.X19) # create an ADC on pin X19
|
|
buf = bytearray(100) # create a buffer of 100 bytes
|
|
adc.read_timed(buf, 10) # read analog values into buf at 10Hz
|
|
# this will take 10 seconds to finish
|
|
for val in buf: # loop over all values
|
|
print(val) # print the value out
|
|
|
|
This function does not allocate any memory.
|
|
|
|
The ADCAll Object
|
|
-----------------
|
|
|
|
.. only:: port_pyboard
|
|
|
|
Instantiating this changes all ADC pins to analog inputs. The raw MCU temperature,
|
|
VREF and VBAT data can be accessed on ADC channels 16, 17 and 18 respectively.
|
|
Appropriate scaling will need to be applied. The temperature sensor on the chip
|
|
has poor absolute accuracy and is suitable only for detecting temperature changes.
|
|
|
|
The ``ADCAll`` ``read_core_vbat()`` and ``read_core_vref()`` methods read
|
|
the backup battery voltage and the (1.21V nominal) reference voltage using the
|
|
3.3V supply as a reference. Assuming the ``ADCAll`` object has been Instantiated with
|
|
``adc = pyb.ADCAll(12)`` the 3.3V supply voltage may be calculated:
|
|
|
|
``v33 = 3.3 * 1.21 / adc.read_core_vref()``
|
|
|
|
If the 3.3V supply is correct the value of ``adc.read_core_vbat()`` will be
|
|
valid. If the supply voltage can drop below 3.3V, for example in in battery
|
|
powered systems with a discharging battery, the regulator will fail to preserve
|
|
the 3.3V supply resulting in an incorrect reading. To produce a value which will
|
|
remain valid under these circumstances use the following:
|
|
|
|
``vback = adc.read_core_vbat() * 1.21 / adc.read_core_vref()``
|
|
|
|
It is possible to access these values without incurring the side effects of ``ADCAll``::
|
|
|
|
def adcread(chan): # 16 temp 17 vbat 18 vref
|
|
assert chan >= 16 and chan <= 18, 'Invalid ADC channel'
|
|
start = pyb.millis()
|
|
timeout = 100
|
|
stm.mem32[stm.RCC + stm.RCC_APB2ENR] |= 0x100 # enable ADC1 clock.0x4100
|
|
stm.mem32[stm.ADC1 + stm.ADC_CR2] = 1 # Turn on ADC
|
|
stm.mem32[stm.ADC1 + stm.ADC_CR1] = 0 # 12 bit
|
|
if chan == 17:
|
|
stm.mem32[stm.ADC1 + stm.ADC_SMPR1] = 0x200000 # 15 cycles
|
|
stm.mem32[stm.ADC + 4] = 1 << 23
|
|
elif chan == 18:
|
|
stm.mem32[stm.ADC1 + stm.ADC_SMPR1] = 0x1000000
|
|
stm.mem32[stm.ADC + 4] = 0xc00000
|
|
else:
|
|
stm.mem32[stm.ADC1 + stm.ADC_SMPR1] = 0x40000
|
|
stm.mem32[stm.ADC + 4] = 1 << 23
|
|
stm.mem32[stm.ADC1 + stm.ADC_SQR3] = chan
|
|
stm.mem32[stm.ADC1 + stm.ADC_CR2] = 1 | (1 << 30) | (1 << 10) # start conversion
|
|
while not stm.mem32[stm.ADC1 + stm.ADC_SR] & 2: # wait for EOC
|
|
if pyb.elapsed_millis(start) > timeout:
|
|
raise OSError('ADC timout')
|
|
data = stm.mem32[stm.ADC1 + stm.ADC_DR] # clear down EOC
|
|
stm.mem32[stm.ADC1 + stm.ADC_CR2] = 0 # Turn off ADC
|
|
return data
|
|
|
|
def v33():
|
|
return 4096 * 1.21 / adcread(17)
|
|
|
|
def vbat():
|
|
return 1.21 * 2 * adcread(18) / adcread(17) # 2:1 divider on Vbat channel
|
|
|
|
def vref():
|
|
return 3.3 * adcread(17) / 4096
|
|
|
|
def temperature():
|
|
return 25 + 400 * (3.3 * adcread(16) / 4096 - 0.76)
|
|
|
|
|