You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
110 lines
2.5 KiB
110 lines
2.5 KiB
/** @file adc.c
|
|
@author M. P. Hayes, UCECE
|
|
@date 23 April 2013
|
|
@brief Simple ADC using a comparator and RC network.
|
|
*/
|
|
#include "avr/io.h"
|
|
#include "pio.h"
|
|
#include "delay.h"
|
|
#include "adc.h"
|
|
|
|
/**
|
|
This requires a capacitor connected from AIN0 (P1-3) to ground
|
|
(P1-1) and a resistor connected from AIN0 (P1-3) to PD5 (P1-7).
|
|
The unknown input voltage is applied to AIN3 (P1-6).
|
|
|
|
It operates by applying a fixed voltage from PD5 (5 V, assuming the
|
|
UCFK4 is powered from USB) to the capacitor and timing how long it
|
|
takes for the capacitor voltage to exceed the unknown voltage using
|
|
the comparator.
|
|
|
|
Here's the typical usage for two channels.:
|
|
|
|
adc_init ();
|
|
adc_enable (ADC_CHANNEL1);
|
|
adc_enable (ADC_CHANNEL2);
|
|
|
|
adc_measure (ADC_CHANNEL1);
|
|
|
|
wait until capacitor discharged
|
|
|
|
adc_measure (ADC_CHANNEL2);
|
|
|
|
Note adc_measure blocks until the voltage on the capacitor exceeds
|
|
the voltage being measured. adc_measure cannot be called again
|
|
until the capacitor is discharged. This could be greatly sped up
|
|
by using another PIO directly connected to the capacitor. Better
|
|
still, since PD1 shares the same pin as AIN0, it can be configured
|
|
as a low output to more rapidly discharge the capacitor.
|
|
|
|
From the IBIS file it appears that a PIO can sink/source 60 mA
|
|
(typ) at 25 deg. C. The datasheet says that the maximum PIO DC
|
|
current is 40 mA.
|
|
|
|
*/
|
|
|
|
#ifndef ADC_CHARGE_PIO
|
|
#define ADC_CHARGE_PIO PIO_DEFINE(PORT_D, 5)
|
|
#endif
|
|
|
|
#ifndef ADC_CAPACITANCE
|
|
#define ADC_CAPACITANCE 4.7e-9
|
|
#endif
|
|
|
|
#ifndef ADC_RESISTANCE
|
|
#define ADC_RESISTANCE 37e3
|
|
#endif
|
|
|
|
#define ADC_TIME_CONSTANT_US (ADC_CAPACITANCE * ADC_RESISTANCE * 1e6)
|
|
|
|
/* This is not defined in io32u2.h */
|
|
#ifndef ACMUX
|
|
#define ACMUX _SFR_MEM8(0x7D)
|
|
#endif
|
|
|
|
void adc_init(void)
|
|
{
|
|
pio_config_set(ADC_CHARGE_PIO, PIO_OUTPUT_LOW);
|
|
|
|
/* Disable digital input for AIN0. */
|
|
DIDR1 |= BIT(0);
|
|
|
|
/* By default the analog comparator is enabled but let's enable it. */
|
|
ACSR &= BIT(7);
|
|
}
|
|
|
|
|
|
void adc_enable(uint8_t adc_channel)
|
|
{
|
|
/* Disable digital input for selected channel. */
|
|
DIDR1 |= BIT(adc_channel);
|
|
}
|
|
|
|
|
|
void adc_disable(uint8_t adc_channel)
|
|
{
|
|
/* Enable digital input for selected channel. */
|
|
DIDR1 &= ~BIT(adc_channel);
|
|
}
|
|
|
|
|
|
uint8_t adc_measure(uint8_t adc_channel)
|
|
{
|
|
uint8_t count;
|
|
|
|
count = 0;
|
|
|
|
/* Select desired channel. */
|
|
ACMUX = adc_channel - 1;
|
|
|
|
pio_output_high (ADC_CHARGE_PIO);
|
|
|
|
while (! (ACSR & BIT(ACO)))
|
|
count++;
|
|
|
|
pio_output_low (ADC_CHARGE_PIO);
|
|
|
|
return count;
|
|
}
|
|
|