-
Notifications
You must be signed in to change notification settings - Fork 19
/
adc.c
192 lines (170 loc) · 5.28 KB
/
adc.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
/*
ADC Library 0x05
copyright (c) Davide Gironi, 2013
Released under GPLv3.
Please refer to LICENSE file for licensing information.
*/
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#if defined (__AVR_ATtiny13A__)
#elif defined (__AVR_ATmega8__)
#elif defined (__AVR_ATmega168__) || defined (__AVR_ATmega168P__)
#elif defined (__AVR_ATmega328__) || defined (__AVR_ATmega328P__)
#else
#error "no definitions available for this AVR"
#endif
#include "adc.h"
//complete this if trigger is on
//call adc_setchannel()
//call sei()
//ISR(ADC_vect)
//{
//}
/*
* set an adc channel
*/
void adc_setchannel(uint8_t channel)
{
ADCSRA &= ~(1 << ADEN);
ADMUX = (ADMUX & 0xf8) | (channel & 0x07); //set channel
ADCSRA |= (1 << ADEN);
}
/*
* read from selected adc channel
*/
uint16_t adc_readsel(void)
{
ADCSRA |= (1 << ADSC); // Start conversion
while(ADCSRA & _BV(ADSC));
//while( !(ADCSRA & (1<<ADIF)) ); // Wait for conversion to complete
uint16_t adc = ADC;
//ADCSRA |= (1 << ADIF); // Clear ADIF by writing one to it
return(adc);
}
/*
* read from adc channel
*/
uint16_t adc_read(uint8_t channel)
{
adc_setchannel(channel);
return adc_readsel();
}
/*
* init adc
*/
void adc_init(void)
{
// Set ADC reference
#if defined (__AVR_ATtiny13A__)
#if ADC_REF == 0
ADMUX |= (0 << REFS0); // VCC used as analog reference
#elif ADC_REF == 1
ADMUX |= (1 << REFS0); // Internal Voltage Reference
#endif
#elif defined (__AVR_ATmega8__) || defined (__AVR_ATmega168__) || defined (__AVR_ATmega168P__) || defined (__AVR_ATmega328__) || defined (__AVR_ATmega328P__)
#if ADC_REF == 0
ADMUX |= (0 << REFS1) | (0 << REFS0); // AREF, Internal Vref turned off
#elif ADC_REF == 1
ADMUX |= (0 << REFS1) | (1 << REFS0); // AVCC with external capacitor at AREF pin
#elif ADC_REF == 3
ADMUX |= (1 << REFS1) | (1 << REFS0); // Internal 2.56V Voltage Reference with external cap at AREF
#endif
#else
#error "No processor type defined!"
#endif
// Set ADC prescaler
#if ADC_PRESCALER == 2
ADCSRA |= (0 << ADPS2) | (0 << ADPS1) | (1 << ADPS0); // Prescaler 2
#elif ADC_PRESCALER == 4
ADCSRA |= (0 << ADPS2) | (1 << ADPS1) | (0 << ADPS0); // Prescaler 4
#elif ADC_PRESCALER == 8
ADCSRA |= (0 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); // Prescaler 8
#elif ADC_PRESCALER == 16
ADCSRA |= (1 << ADPS2) | (0 << ADPS1) | (0 << ADPS0); // Prescaler 16
#elif ADC_PRESCALER == 32
ADCSRA |= (1 << ADPS2) | (0 << ADPS1) | (1 << ADPS0); // Prescaler 32
#elif ADC_PRESCALER == 64
ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (0 << ADPS0); // Prescaler 64
#elif ADC_PRESCALER == 128
ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); // Prescaler 128
#endif
// Set ADC justify
#if ADC_JUSTIFY == 'L'
ADMUX |= (1 << ADLAR); // Left adjust ADC result to allow easy 8 bit reading
#elif ADC_JUSTIFY == 'R'
ADMUX |= (0 << ADLAR); // Right adjust
#endif
// Set ADC trigger and mode
#if ADC_TRIGGERON == 1
#if defined (__AVR_ATtiny13A__) || defined (__AVR_ATmega168__) || defined (__AVR_ATmega168P__) || defined (__AVR_ATmega328__) || defined (__AVR_ATmega328P__)
ADCSRB |= (0 << ADTS2) | (0 << ADPS1) | (0 << ADPS0); // Free Running mode
ADCSRA |= (1 << ADATE); // Enable ADC Interrupt
#elif defined (__AVR_ATmega8__)
ADCSRA |= (1 << ADFR); // Set ADC to Free-Running Mode
#endif
ADCSRA |= (1 << ADIE); // Enable ADC Interrupt
#else
ADCSRB |= (0 << ADTS2) | (0 << ADPS1) | (0 << ADPS0); // Free Running mode
#endif
// Enable ADC
ADCSRA |= (1 << ADEN);
//DIDR0 = 0xff;
#if ADC_TRIGGERON == 1
ADCSRA |= (1 << ADSC); // Start conversions
#endif
}
/*
* get reference voltage using bandgap voltage
*/
double acd_getrealvref(void)
{
double intvoltage = 0;
#if defined (__AVR_ATmega8__) || defined (__AVR_ATmega168__) || defined (__AVR_ATmega168P__) || defined (__AVR_ATmega328__) || defined (__AVR_ATmega328P__)
//set bandgap voltage channel, and read value
adc_setchannel(14);
_delay_us(250);
uint16_t adc = adc_readsel();
//calculate internal voltage
intvoltage = ((ADC_BANDGAPVOLTAGE * ADC_REFRES) / adc) / 1000.0;
#endif
return intvoltage;
}
/*
* convert an adc value to a resistence value
*/
long adc_getresistence(uint16_t adcread, uint16_t adcbalanceresistor)
{
if(adcread == 0)
return 0;
else
return (long)((long)(ADC_REFRES*(long)adcbalanceresistor)/adcread-(long)adcbalanceresistor);
}
/*
* convert an adc value to a voltage value
*/
double adc_getvoltage(uint16_t adcread, double adcvref) {
if(adcread == 0)
return 0;
else
return (double)(adcread*adcvref/(double)ADC_REFRES);
}
/*
* exponential moving avarage filter
*
* "newvalue" new adc read value
* "value" old adc filtered value
* return a new filtered value
*
* References:
* Guillem Planissi: Measurement and filtering of temperatures with NTC
*/
#define ADC_EMAFILTERALPHA 30
unsigned int adc_emafilter(unsigned int newvalue, unsigned int value)
{
//use exponential moving avarate Y=(1-alpha)*Y + alpha*Ynew, alpha between 1 and 0
//in uM we use int math, so Y=(63-63alpha)*Y + 63alpha*Ynew and Y=Y/63 (Y=Y>>6)
value = (64-ADC_EMAFILTERALPHA)*value+ADC_EMAFILTERALPHA*newvalue;
value = (value>>6);
return value;
}