This library provides a quick and easy way to set up an ADC on AVR
microcontrollers and retrieve the values in 8-bit or 10-bit format in an
interrupt driven fashion.
Nowadays even the cheapest microcontroller has a build-in ADC (Analog to Digital Converter). An ADC converts analog signals into digital signals and can be used in a wide range of applications like recording a signal from a microphone into a digital format, reading light sensors like an LDR (light dependent resistor), measuring current consumption, reading temperature or humidity sensors, etc. All these requires voltage measurements that an ADC can do.
Contents
- Library Structure
- ADC Characteristics
- ADC Channels
- Calculating resistor values for voltage divider with filter cap (optional)
- ADC power supply and voltage reference pin
- ADC values
- Calculating values for INITDLY and SAMPLEN
- Library Usage
- ADC Setup
- Set ADC voltage reference
- Set ADC resolution
- Start ADC conversion
- Disable ADC
- Enable ADC
- Freerun mode
- Check conversion complete
- Read ADC value
- ADC to Volts
- Measure power supply (VCC) without a pin
- ADC Noise Reduction Sleep Mode
- ADC Auto Trigger Source
- Set Initialization Delay
- Set Sampling Length
- Sample Accumulation
- Select Sample Capacitance
- Set ADC Duty Cycle
- Set Window Comparator Mode
- Run in Standby
- Get Accumulator Size
- Code example for non-UPDI devices
- Code example for UPDI devices
- Download
Library Structure
In version 2 I have added support for newer types of AVR microcontrollers that
have new and exciting features. I will be referring to them as UPDI and
non-UPDI devices because older architectures such as ATmega328 don't have an
UPDI interface, whereas newer models, such as ATiny402, are programmable via
UPDI interface. Given the major differences between the two classes of
microcontrollers, there are library functions that are specific to only one
class.The library refers to non-UPDI devices as Class 0 and UPDI devices as
Class 1.
ADC Characteristics
ADC Channels
Most microcontrollers have only one ADC peripheral and multiple analog input pins, and each one can be connected to different analog sources, but only one at a time can be internally sampled, by means of multiplexing. This pins can also be used as digital pins. No resistor is required when taking voltage measurements. In case resistors are used, the datasheet recommends that the impedance should not exceed 10k. Care must be taken that the voltage to this pins must not exceed VCC. If the microcontroller is powered from 5V, don't put more than 5V on the pins. In case that higher voltages are to be measured resistor dividers should be used.
An ADC channel is not necessarily an analog pin. It can also be an internal
source, such as a temperature sensor (provided that the microcontroller has
one), ground or a voltage reference. Consult the datasheet to know what
channel number to use when using the library.
Example from ATtiny402 datasheet |
Calculating resistor values for voltage divider with filter cap (optional)
Calculating output impedance for ADC involves a bit of math especially when adding a filter capacitor, so I have made a spreadsheet for LibreOffice for this purpose. Select a value for top resistor (R1) and the calculator will recommend a value for R2 and show the output impedance.
A filter capacitor can be used to remove potential noise, but that can be done
in software by averaging samples and on newer AVR microcontrollers, even in
hardware.
The formula is from an answer to this stackexchange question:
https://electronics.stackexchange.com/questions/313325/upper-limit-for-resistance-values-in-voltage-divider.
ADC power supply and voltage reference pin
The ADC has it's own pins for power supply named AVCC and AGND. The AVCC pin is recommended to be connected to VCC through an LC filter for noise suppression.
The AREF pin can be used in two ways and both require a 100n decoupling capacitor to ground:
- By default the ADC register is configured to use an external reference voltage from this pin. If you apply a voltage to this pin you must avoid setting the ADC to use an internal reference as this will cause a short circuit between them.
-
The second method is to use one of the internal voltage references such as
VCC, 2.56V and 1.1V. Not all avr microcontrollers have all of them. Consult
the datasheet to see which ones are available for your device.
ADC power connections with LC filter and analog ground plane |
Important thing to know when using ATmega324PB
ADC and the ADC values are always at maximum value or 0x03FF
By default the AREF pin on ATmega324PB is disabled and only internal voltage references can be used. To enable the AREF pin, the GPIOEN pin in the ADCSRB register must be set to 0 because the default value is 1. Many people including myself have spent hours trying to figure out why the ADC is not working and here's why.
Here is the datasheet for ATmega324PB revision DS40001908A
and here is the datasheet with revision DS40001892A
The GPIOEN bit is missing in the newer revision. The library will set this bit
low for you if using ATmega324PB and external reference voltage.
ADC values
Most AVR microcontrollers have 10 bit ADC resolution but 8 bit resolution can be used also. Suppose that the voltage reference is set to VCC 5V and you measure a potentiometer with 10 bit ADC resolution. The minimum value returned by the ADC will be 0 - meaning ground - and the maximum value will be 2^10-1 = 1023 (meaning 5V). The returned value will be between 0 and 1023. This value can be converted to a voltage using the following formula, but most of the time this is not needed.
V = ADCvalue * (Vref / ADCresolution)
To find out the minimum voltage that can be measured depending on the ADC resolution, divide voltage reference by the maximum ADC value. For 10 bit resolution and 5V Vref
Calculating values for INITDLY and SAMPLEN
There are places in the datasheet where they recommend minimum values for Initialization Delay (INITDLY) and Sample Length (SAMPLEN) like this:
INITDLY ≥ 32 µs × fCLK_ADC
SAMPLEN ≥ 32 µs × fCLK_ADC
You might wonder how to calculate the register value. The formula for this is:
32E-6 * (F_CPU / ADC_PRESCALER)
Example: F_CPU is 3.33MHz (default clock frequency on UPDI devices) and the ADC prescaler is 4, then the ADC clock is: 3333333 / 4 = 833333 Hz.
Register value is then: 32E-6 (convert microseconds to seconds) * 833333Hz = 26.66. The closest Initialization Delay register value is 32.
When calculating Sample Length you need to subtract 2 from the
calculated value because by default, the sampling time is two CLK_ADC cycles
and this register value adds up to those 2 default cycles.
Library Usage
ADC Setup
Used to set the prescaler, and to enable ADC interrupt, the ADC peripheral and global interrupts. The prescaler is used by the ADC peripheral to generate the ADC clock, by dividing the main clock by the prescaler value which can be one of the following macros that are equal to a register value not a prescaler number:
ADC_PRESCALER_256 ADC_PRESCALER_128 ADC_PRESCALER_64 ADC_PRESCALER_32 ADC_PRESCALER_16 ADC_PRESCALER_8 ADC_PRESCALER_4 ADC_PRESCALER_2
Prescaler 256 is not available on all microcontrollers. Check the datasheet for your particular device.
The prescaler value depends on the F_CPU (main clock frequency) and the desired ADC clock frequency that gives the ADC sampling rate. First decide on what the ADC clock frequency must be. When using only 8-bit resolution, the ADC clock can be higher than when using 10-bit. Here is what the datasheets recommend:
"By default, the successive approximation circuitry requires an input clock
frequency between 50kHz and 200kHz to get maximum resolution. If a lower
resolution than 10 bits is needed, the input clock frequency to the ADC can
be higher than 200kHz to get a higher sample rate." - from ATmega328PB datasheet.
"The ADC requires an input clock frequency between 50 kHz and 1.5 MHz for maximum resolution. If a lower resolution than 10 bits is selected, the input clock frequency to the ADC can be higher than 1.5 MHz to get a higher sample rate." - from ATtiny202 -402 datasheet.
Suppose the F_CPU is 16MHz and desired ADC clock 200kHz. To find the closest prescaler divide the main clock by the ADC clock:
16000000 / 200000 = 80
Since there is no prescaler with the value 80, we need to find the closest one which is 64. Using a 64 prescaler the ADC clock will be:
16000000 / 64 = 250000
If 250kHz is not acceptable select the 128 prescaler which will give 125kHz ADC frequency.
void adcSetup(uint16_t adc_prescaler)
Parameters
adc_prescaler
Must be one of the provided macros that represent a register value.
Set ADC voltage reference
The internal voltage reference must be decoupled by an external capacitor at
the AREF pin to improve noise immunity. If the user has a fixed voltage source
connected to the AREF pin, the user may not use the other reference voltage
options in the application, as they will be shorted to the external voltage.
If no external voltage is applied to the AREF pin, the user may switch between
internal voltage references. The first ADC conversion result after switching
reference voltage source may be inaccurate, and the user is advised to discard
this result.
void adcReference(uint8_t vref)
Parameters
vref
Can be one of following macros, provided it is supported by your microcontroller:
ADC_VREF_VCC ADC_VREF_INTERNAL_0V55 ADC_VREF_INTERNAL_1V1 ADC_VREF_INTERNAL_1V5 ADC_VREF_INTERNAL_2V5 ADC_VREF_INTERNAL_2V56 ADC_VREF_INTERNAL_2V56_NOCAP ADC_VREF_INTERNAL_2V56_WCAP ADC_VREF_INTERNAL_4V3 ADC_VREF_EXTERNAL
These macros represent a register value and not an integer equal to the voltage they suggest.
Set ADC resolution
ADC resolution in bits.
void adcResolution(uint8_t res)
Parameters
res
The ADC resolution that can be an integer 8 or 10, or a macro: ADC_8bit, ADC_10bit. Default value is 10-bit.
Start ADC conversion
Start an ADC conversion on the given channel. When available, disables digital input for the given ADC pin for a more accurate sampling. Uses ADC Noise Reduction Sleep Mode if enabled.
On UPDI devices the digital input buffer should be disabled by the user as the datasheet recommends:
"The digital input buffer should be disabled on the pin used as input for the ADC to disconnect the digital domain from the analog domain to obtain the best possible ADC results. This is configured by the port I/O Pin Controller."
For example if the analog pin is on port A pin 0:
PORTA.PIN0CTRL = PORT_ISC_INPUT_DISABLE_gc;
void adcStartConversion(uint8_t channel)
Parameters
channel
ADC channel that can be an analog pin or the internal temperature sensor.
Disable ADC
Disables the ADC to reduce power consumption.
void adcDisable(void)
Enable ADC
Re-enable the ADC to increase power consumption.
void adcEnable(void)
Freerun mode
Enable the FREERUN mode. adcStartConversion() must be used once to set
the ADC channel and trigger the conversion.
void adcFreeRun(uint8_t freerun)
Parameters
freerun
Set 1 to enable FREERUN mode or 0 to disable. Available macros:
ADC_FREERUN_DISABLED ADC_FREERUN_ENABLED
Check conversion complete
Returns 1 if ADC conversion is complete.
uint8_t adcIsReady(void)
Read ADC value
Returns the ADC value stored in a buffer written by the ADC interrupt routine.
uint16_t adcReadValue(void)
Return: if ADC resolution is 8-bit the value will be between 0-255, or
0-1023 when 10-bit resolution is used.
ADC to Volts
Convert an ADC value to a value in Volts.
float adcToVoltage(uint16_t adc_value, float vref)
Parameters
adc_value
The ADC value.
vref
ADC voltage reference.
Return: converted value in Volts.
Measure power supply (VCC) without a pin
Measure power supply voltage without a pin. Especially useful in battery powered applications. Instead of an ADC pin to measure the power supply voltage, the ADC measures the internal 1.1 voltage (Vbg) and the measured voltage - VCC - is used as a reference voltage. Since one voltage is known (1.1V) the other one (VCC) will be calculated.
The ADC needs to be configured before using his function. ADC reference voltage is set inside the function as VCC.
This function is based on: Microchip - AN2447 - Measure VCC/Battery Voltage Without Using I/O Pin on tinyAVR and megaAVR.
float adcMeasureVCC(uint8_t adc_channel, float vref)
Parameters
adc_channel
Internal 1.1V reference channel number. For example on ATmega328PB this is 0b1110 which converted to hex is 0xE.
vref
Reference voltage which is 1.1 in most cases but some microcontrollers have 1.3 instead.
Return: measured power supply in volts.
ADC Noise Reduction Sleep Mode
Enable/disable ADC Noise Reduction Sleep Mode. The function will set up a flag and when the adcStartConversion() will be used, the CPU will be put into sleep mode from which it will exit when the conversion is complete. Only available on non-UPDI devices.
Before using adcStartConversion() make sure that UART is done
transmitting, otherwise after the CPU exits from sleep mode the resumed UART
will be out of sync.
"The ADC features a noise canceler that enables conversion during sleep mode to reduce noise induced from the CPU core and other I/O peripherals."
"If no other interrupts occur before the ADC conversion completes, the ADC interrupt will wake up the CPU and execute the ADC Conversion Complete interrupt routine. If another interrupt wakes up the CPU before the ADC conversion is complete, that interrupt will be executed, and an ADC Conversion Complete interrupt request will be generated when the ADC conversion completes. The CPU will remain in active mode until a new sleep command is executed."
"The ADC will not be automatically turned off when entering other sleep modes
than Idle mode and ADC Noise Reduction mode. The user is advised to write zero
to ADCRSA.ADEN before entering such sleep modes to avoid excessive power
consumption."
void adcUseNoiseReduction(uint8_t sleep)
Parameters
sleep
Available macros:
ADC_NOISE_REDUCTION_ENABLED ADC_NOISE_REDUCTION_DISABLED
ADC Auto Trigger Source
Selects ADC auto trigger source. Only available on non-UPDI devices. UPDI
devices features the EVSYS module. adsStartConversion() should be used
to select the ADC channel. It is important to include the ISR with the
appropriate interrupt vector in dependence of the trigger source. For example
if Timer0 Compare Match A is selected then include ISR(TIMER0_COMPA_vect){ }
in your code.
void adcAutoTrigger(uint8_t trig_source)
Parameters
trig_source
One of the available macros that represent register values:
ADC_TRIG_NONE // Automatic Triggering Disabled ADC_TRIG_AC // Analog Comparator ADC_TRIG_EXT_INT0 // External Interrupt Request 0 ADC_TRIG_TIM0_CMPA // Timer/Counter0 Compare Match A ADC_TRIG_TIM0_OVF // Timer/Counter0 Overflow ADC_TRIG_TIM1_CMPB // Timer/Counter1 Compare Match B ADC_TRIG_TIM1_OVF // Timer/Counter1 Overflow ADC_TRIG_TIM1_CAPEV // Timer/Counter1 Capture Event
Set Initialization Delay
Set the initialization/start-up delay before the first sample when enabling
the ADC or changing to an internal reference voltage. Setting this delay will
ensure that the reference, MUXes, etc. are ready before starting the first
conversion. The initialization delay will also take place when waking up from
deep sleep to do a measurement. The delay is expressed as a number of CLK_ADC
cycles.
void adcSetInitDelay(uint16_t init_delay)
Parameters
init_delay
Available macros:
ADC_DLY0 // Delay 0 CLK_ADC cycles ADC_DLY16 // Delay 16 CLK_ADC cycles ADC_DLY32 // Delay 32 CLK_ADC cycles ADC_DLY64 // Delay 64 CLK_ADC cycles ADC_DLY128 // Delay 128 CLK_ADC cycles ADC_DLY256 // Delay 256 CLK_ADC cycles
Set Sampling Length
Extend the ADC sampling length in a number of CLK_ADC cycles. By default, the
sampling time is two CLK_ADC cycles. Increasing the sampling length allows
sampling sources with higher impedance. The total conversion time increases
with the selected sampling length.
void adcSetSampleLength(uint8_t sample_length)
Parameters
sample_length
Integer from 0 to 31 representing ADC clocks.
Sample Accumulation
The ADC supports sampling in bursts where a configurable number of conversion results are accumulated into a single ADC result (sample accumulation). Further, a sample delay can be configured to tune the ADC sampling frequency associated with a single burst. This to tune the sampling frequency away from any harmonic noise aliased with the ADC sampling frequency (within the burst) from the sampled signal. An automatic sampling delay variation feature can be used to randomize this delay to slightly change the time between samples.
More information on this subject can be found in the application note from
Microchip:
Noise Countermeasures for ADC Applications - AN2551.
void adcSetSampleAccumulation(uint8_t samples_nr, uint8_t samp_dly, uint8_t samp_dly_auto)
Parameters
samples_nr
Number of samples for the accumulator to take. Available macros:
ADC_SAMP_ACC_NONE // No accumulation ADC_SAMP_ACC_2 // 2 results accumulated ADC_SAMP_ACC_4 // 4 results accumulated ADC_SAMP_ACC_8 // 8 results accumulated ADC_SAMP_ACC_16 // 16 results accumulated ADC_SAMP_ACC_32 // 32 results accumulated ADC_SAMP_ACC_64 // 64 results accumulated
samp_dly
Sampling Delay Selection. These bits define the delay between consecutive ADC samples. The programmable Sampling Delay allows modifying the sampling frequency during hardware accumulation, to suppress periodic noise sources that may otherwise disturb the sampling. The SAMPDLY field can also be modified automatically from one sampling cycle to another, by setting the ASDV bit. The delay is expressed as CLK_ADC cycles. The sampling cap is kept open during the delay.
Integer from 0 to 15 or one of the available macros:
ADC_SAMP_DLY_0 ADC_SAMP_DLY_1 ADC_SAMP_DLY_2 ADC_SAMP_DLY_3 ADC_SAMP_DLY_4 ADC_SAMP_DLY_5 ADC_SAMP_DLY_6 ADC_SAMP_DLY_7 ADC_SAMP_DLY_8 ADC_SAMP_DLY_9 ADC_SAMP_DLY_10 ADC_SAMP_DLY_11 ADC_SAMP_DLY_12 ADC_SAMP_DLY_13 ADC_SAMP_DLY_14 ADC_SAMP_DLY_15
samp_dly_auto
Automatic Sampling Delay Variation. Writing this bit to '1' enables automatic sampling delay variation between ADC conversions. The purpose of varying sampling instant is to randomize the sampling instant and thus avoid standing frequency components in the frequency spectrum. The value of the SAMPDLY bits are automatically incremented by one after each sample. When the Automatic Sampling Delay Variation is enabled and the SAMPDLY value reaches 0xF, it wraps around to 0x0.
Available macros:
ADC_SAMP_DLY_AUTO_ENABLED ADC_SAMP_DLY_AUTO_DISABLED
Select Sample Capacitance
Select the sample capacitance, and hence, the input impedance. The best value is dependent on the reference voltage and the application's electrical properties.
void adcSelectSampleCapacitance(uint8_t sample_capacitance)
Parameters
sample_capacitance
Available macros:
ADC_SAMP_CAP_10pf // Recommended for reference voltage values below 1V. ADC_SAMP_CAP_5pf // Reduced size of sampling capacitance. Recommended for higher reference voltages.
Set ADC Duty Cycle
Set the duty cycle of the ADC clock. ADCclk > 1.5 MHz requires a minimum operating voltage of 2.7V.
void adcSetDutyCycle(uint8_t duty_cycle)
Parameters
duty_cycle
Available macros:
ADC_DUTY_CYCLE_50 // 50% Duty Cycle must be used if ADCclk > 1.5 MHz ADC_DUTY_CYCLE_25 // 25% Duty Cycle (high 25% and low 75%) must be used // for ADCclk < or = 1.5 MHz (default register value)
In this case, the default register value is 1 not 0, thus the default duty cycle is 25%.
Set Window Comparator Mode
The ADC can raise the WCOMP flag in the Interrupt and Flag register (ADCn.INTFLAG) and request an interrupt (WCOMP) when the result of a conversion is above and/or below certain thresholds. The available modes are:
• The result is under a threshold
• The result is over a threshold
• The result is inside a window (above a lower threshold, but below the upper one)
• The result is outside a window (either under the lower or above the upper
threshold)
When accumulating multiple samples, the comparison between the result and the
threshold will happen after the last sample was acquired. Consequently, the
flag is only raised once, after taking the last sample of the accumulation.
void adcWindowComparator(uint8_t mode, uint16_t winlt, uint16_t winht)
Parameters
mode
Enables and defines when the interrupt flag is set in Window Comparator mode. RESULT is the 16-bit accumulator result. WINLT and WINHT are 16-bit lower threshold value and 16-bit higher threshold value, respectively. Available macros:
ADC_WINDOW_NONE // No Window Comparison (default) ADC_WINDOW_BELOW // RESULT < WINLT ADC_WINDOW_ABOVE // RESULT > WINHT ADC_WINDOW_INSIDE // WINLT < RESULT < WINHT ADC_WINDOW_OUTSIDE // RESULT < WINLT or RESULT > WINHT)
winlt
Window Comparator Low Threshold.
winht
Window Comparator High Threshold.
Run in Standby
Configure whether the ADC needs to run when the chip is in Standby Sleep mode.
void adcRunInStandBy(uint8_t run_stby)
Parameters
run_stby
Available macros:
ADC_RUNSTBY_DISABLED ADC_RUNSTBY_ENABLED
Get Accumulator Size
Returns the number of samples that the accumulator is set to take. Useful to multiply the winlt and winht arguments for adcWindowComparator() with the returned value, or to divide the ADC value by.
uint8_t adcAccSize(void)
Code example for non-UPDI devices
In this example the ADC is configured in auto triggering mode where timer 0
triggers an ADC conversion in hardware every 1ms. The time interval can be
changed according to your project. For example you could measure an external
temperature sensor every 1 second without CPU intervention. The CPU is only
used to check when a conversion is ready and to do something with the ADC
value.
// Not necessary in this project but useful. // See https://www.programming-electronics-diy.xyz/2024/01/defining-fcpu.html #ifndef F_CPU #warning "F_CPU not defined. Define it in project properties." #elif F_CPU != 16000000 #warning "Wrong F_CPU frequency!" #endif #include <util/delay.h> #include "adc.h" #include "uart.h" int main(void){ // Local variables uint16_t adc_val = 0; float voltage = 0.0; // USART Initialization UART_begin(&uart0, 115200, UART_ASYNC, UART_NO_PARITY, UART_8_BIT); // ADC initialization // 16000000 / 128 = 125kHz ADC clock adcSetup(ADC_PRESCALER_128); // 10-bit ADC resolution adcResolution(ADC_10bit); // Enable/Disable ADC Noise Reduction Sleep Mode adcUseNoiseReduction(ADC_NOISE_REDUCTION_ENABLED); // Select voltage reference adcReference(ADC_VREF_VCC); // Select Timer/Counter0 Compare Match A as an auto trigger adcAutoTrigger(ADC_TRIG_TIM0_CMPA); // Select ADC channel as ADC0 pin adcStartConversion(0); // Configure Timer0 to trigger a compare match interrupt every 1ms TCCR0A = 1 << WGM01; // CTC mode TCCR0B = (_BV(CS01) | _BV(CS00)); // 64 prescaler OCR0A = ((F_CPU / 64) / 1000) - 1; // 1000 is the frequency in Hz TIMSK0 = (1 << OCIE0A); // Enable interrupt //adcFreeRun(ADC_FREERUN_ENABLED); while(1){ // Wait for ADC conversion complete if(adcIsReady()){ // Read the ADC value adc_val = adcReadValue(); // Convert ADC to V. Reference voltage is VCC 5V voltage = adcToVoltage(adc_val, 5); // Send value over UART UART_sendString(&uart0, "V = "); UART_sendFloat(&uart0, voltage, 3); UART_sendString(&uart0, ", ADC = "); UART_sendFloat(&uart0, adc_val, 3); UART_send(&uart0, '\n'); _delay_ms(1000); // Start a new conversion on ADC0 // Not necessary in FREERUN mode or auto trigger mode //adcStartConversion(0); } } } // Necessary for auto trigger mode ISR(TIMER0_COMPA_vect){ //PORTD |= 1<<7; //PORTD &= ~(1<<7); }
Code example for UPDI devices
// Not necessary in this project but useful. // See https://www.programming-electronics-diy.xyz/2024/01/defining-fcpu.html #ifndef F_CPU #warning "F_CPU not defined. Define it in project properties." #elif F_CPU != 3333333 #warning "Wrong F_CPU frequency!" #endif #include <util/delay.h> #include "adc.h" #include "uart.h" int main(void){ // Local variables uint16_t adc_val = 0; float voltage = 0.0; // Set TX pin as output PORTA.DIR |= PIN6_bm; // The digital input buffer should be disabled on the pin used as input for the ADC to disconnect the digital // domain from the analog domain to obtain the best possible ADC results. This is configured by the port - I/O Pin Controller. PORTA.PIN2CTRL = PORT_ISC_INPUT_DISABLE_gc; // USART Initialization UART_begin(&uart0, 115200, UART_ASYNC, UART_NO_PARITY, UART_8_BIT); // ADC initialization adcSetup(ADC_PRESCALER_32); // 10-bit ADC resolution adcResolution(ADC_10bit); // Use internal 4.3V voltage reference adcReference(ADC_VREF_INTERNAL_4V3); // Initialization delay (optional) //adcSetInitDelay(ADC_DLY32); // Sampling length (optional) //adcSetSampleLength(4); // Reduced size of sampling capacitance. Recommended for reference voltages higher than 1V. adcSelectSampleCapacitance(ADC_SAMP_CAP_5pf); // Number of samples in a burst that will be averaged. // Useful for noise filtering. All done in hardware. adcSetSampleAccumulation(ADC_SAMP_ACC_8, ADC_SAMP_DLY_0, ADC_SAMP_DLY_AUTO_DISABLED); // Configure the window comparator. The ADC interrupt will only be triggered // when the ADC result is inside this window: greater than 780 or smaller than 800. // The size of the accumulator must be taken into account which is returned by adcAccSize(), // and in this example is 8. Don't use 780 * ADC_SAMP_ACC_8. adcWindowComparator(ADC_WINDOW_INSIDE, 780 * adcAccSize(), 800 * adcAccSize()); while(1){ // Wait for ADC conversion complete if(adcIsReady()){ // Read the ADC value adc_val = adcReadValue(); // Convert ADC to V. Reference voltage is 4.3 // Do not use ADC_VREF_INTERNAL_4V3 instead of 4.3 voltage = adcToVoltage(adc_val / adcAccSize(), 4.3); // Send value over UART UART_sendString(&uart0, "V: "); UART_sendFloat(&uart0, voltage, 3); UART_sendString(&uart0, ", ADC: "); UART_sendFloat(&uart0, adc_val / adcAccSize(), 3); UART_send(&uart0, '\n'); _delay_ms(1000); // Start a new conversion on pin 2 adcStartConversion(2);
} } }
Download
Changelog and license can be found at the beginning of the header files | ||
adc v2.1 | ||
adc.h | ||
adc.c | ||
Other Links | ||
UART library project page | Useful to display ADC values on a serial terminal. | |
AVR internal temperature sensor library |
|
|
Changelog | ||
v2.1 |
31-01-2024: - included function adcMeasureVCC() for measuring VCC without a pin. |
|
v2.0 |
29-01-2024: - added support for modern AVR (UPDI devices). Tested on tinyAVR402. |
No comments:
Post a Comment