1 /*
2 OrangutanAnalog.h - Library for using the analog inputs on the
3 Orangutan LV, SV, SVP, X2, Baby Orangutan B, or 3pi robot. This library
4 also provides a method for reading the temperature sensor on the LV-168.
5 */
6
7 /*
8 * Written by Ben Schmidel, May 27, 2008.
9 * Copyright (c) 2008-2012 Pololu Corporation. For more information, see
10 *
11 * http://www.pololu.com
12 * http://forum.pololu.com
13 * http://www.pololu.com/docs/0J18
14 *
15 * You may freely modify and share this code, as long as you keep this
16 * notice intact (including the two links above). Licensed under the
17 * Creative Commons BY-SA 3.0 license:
18 *
19 * http://creativecommons.org/licenses/by-sa/3.0/
20 *
21 * Disclaimer: To the extent permitted by law, Pololu provides this work
22 * without any warranty. It might be defective, in which case you agree
23 * to be responsible for all resulting costs and damages.
24 */
25
26 #ifndef OrangutanAnalog_h
27 #define OrangutanAnalog_h
28
29 #include <avr/io.h>
30 #include "../OrangutanResources/include/OrangutanModel.h"
31
32 #ifdef __cplusplus
33 #ifdef _ORANGUTAN_SVP
34 #include "../OrangutanSVP/OrangutanSVP.h"
35 #endif
36 #endif
37
38 #define MODE_8_BIT 1
39 #define MODE_10_BIT 0
40
41 // ADC Channels
42
43 #ifdef _ORANGUTAN_SVP
44
45 #define TRIMPOT 128
46 #define CHANNEL_A 129
47 #define CHANNEL_B 130
48 #define CHANNEL_C 131
49 #define CHANNEL_D 132
50
51 #else
52
53 #define TRIMPOT 7
54 #define TEMP_SENSOR 6
55
56 #endif
57
58 #ifdef __cplusplus
59
60 class OrangutanAnalog
61 {
62 public:
63
64 // constructor (doesn't do anything)
65 OrangutanAnalog();
66
67 // set the ADC to run in either 8-bit mode (MODE_8_BIT) or
68 // 10-bit mode (MODE_10_BIT)
setMode(unsigned char mode)69 static inline void setMode(unsigned char mode)
70 {
71 if (mode == MODE_10_BIT)
72 ADMUX &= ~(1 << ADLAR); // right-adjust result (ADC has result)
73 else
74 ADMUX |= 1 << ADLAR; // left-adjust result (ADCH has result)
75 }
76
77 // returns 0 if in 10-bit mode, otherwise returns non-zero. The return
78 // value of this method can be directly compared against the macros
79 // MODE_8_BIT and MODE_10_BIT:
80 // For example: if (getMode() == MODE_8_BIT) ...
getMode()81 static inline unsigned char getMode()
82 {
83 return (ADMUX >> ADLAR) & 1;
84 }
85
86 // take a single analog reading of the specified channel
87 static unsigned int read(unsigned char channel);
88
89 // take a single analog reading of the specified channel and return result in millivolts
90 static unsigned int readMillivolts(unsigned char channel);
91
92 // take 'sample' readings of the specified channel and return the average
93 static unsigned int readAverage(unsigned char channel,
94 unsigned int samples);
95
readAverageMillivolts(unsigned char channel,unsigned int samples)96 static inline unsigned int readAverageMillivolts(unsigned char channel, unsigned int samples)
97 {
98 #ifdef _ORANGUTAN_SVP
99 if (channel > 31)
100 {
101 // We have not implemented averaging of the adc readings from the auxiliary
102 // processor on the SVP, so we will just return a simple reading.
103 return readMillivolts(channel);
104 }
105 #endif
106 return toMillivolts(readAverage(channel, samples));
107 }
108
109 // returns the position of the trimpot (20 readings averaged together).
110 // For all devices except the Orangutan SVP, the trimpot is on ADC channel 7.
111 // On the Orangutan SVP, the trimpot is on the auxiliary processor, so
112 // calling this function can have side effects related to enabling SPI
113 // communication (see the SVP user's guide for more info).
readTrimpot()114 static inline unsigned int readTrimpot()
115 {
116 return readAverage(TRIMPOT, 20);
117 }
118
readTrimpotMillivolts()119 static inline unsigned int readTrimpotMillivolts()
120 {
121 #ifdef _ORANGUTAN_SVP
122 return OrangutanSVP::getTrimpotMillivolts();
123 #else
124 return toMillivolts(readTrimpot());
125 #endif
126 }
127
128 // the following method can be used to initiate an ADC conversion
129 // that runs in the background, allowing the CPU to perform other tasks
130 // while the conversion is in progress. The procedure is to start a
131 // conversion on a channel with startConversion(channel), and then
132 // poll isConverting in your main loop. Once isConverting() returns
133 // a zero, the result can be obtained through a call to conversionResult().
134 // If use_internal_reference is set to true, the function will use the
135 // internal 1.1V voltage reference on the ATmega48/168/328 or the internal
136 // 2.56V voltage reference on the ATmega324/644/1284; otherwise, it uses
137 // the AVCC pin as a reference.
138 // *** NOTE ***: Some Orangutans and 3pis have their AREF pin connected directly to VCC.
139 // On these Orangutans, you must not use the internal voltage reference as
140 // doing so will short the internal reference voltage to VCC and could damage
141 // the AVR. It is safe to use the internal reference voltage on the
142 // Orangutan SVP.
143 static void startConversion(unsigned char channel, unsigned char use_internal_reference = 0);
144
145 // returns 1 if the ADC is in the middle of an conversion, otherwise
146 // returns 0
isConverting()147 static inline unsigned char isConverting()
148 {
149 return (ADCSRA >> ADSC) & 1;
150 }
151
152 // returns the result of the previous ADC conversion.
153 static unsigned int conversionResult();
154
155 // returns the result of the previous ADC conversion in millivolts.
156 static unsigned int conversionResultMillivolts();
157
158 // sets the value used to calibrate the conversion from ADC reading
159 // to millivolts. The argument calibration should equal VCC in millivolts,
160 // which can be automatically measured using the function readVCCMillivolts():
161 // e.g. setMillivoltCalibration(readVCCMillivolts());
162 static void setMillivoltCalibration(unsigned int calibration);
163
164 // averages ten ADC readings of the fixed internal 1.1V bandgap voltage
165 // and computes VCC from the results. This function returns VCC in millivolts.
166 // Channel 14 is internal 1.1V BG on ATmega48/168/328, but bit 5 of ADMUX is
167 // not used, so channel 30 is equivalent to channel 14. Channel 30 is the internal
168 // 1.1V BG on ATmega324/644/1284.
169 static unsigned int readVCCMillivolts();
170
171 // converts the specified ADC result to millivolts
172 static unsigned int toMillivolts(unsigned int adcResult);
173
174 // SVP: returns the voltage of the battery in millivolts, as retrieved from
175 // the auxiliary processor. Calling this function will have side effects
176 // related to enabling the SPI module. See the SVP User's Guide for details.
177 #ifdef _ORANGUTAN_SVP
readBatteryMillivolts_SVP()178 static inline unsigned int readBatteryMillivolts_SVP()
179 {
180 return OrangutanSVP::getBatteryMillivolts();
181 }
182
readBatteryMillivolts()183 static inline unsigned int readBatteryMillivolts()
184 {
185 return readBatteryMillivolts_SVP();
186 }
187
188 #elif defined(_ORANGUTAN_X2)
189
190 // X2: returns the voltage of the battery in millivolts using
191 // 10 averaged samples.
192 static unsigned int readBatteryMillivolts_X2();
193
readBatteryMillivolts()194 static inline unsigned int readBatteryMillivolts()
195 {
196 return readBatteryMillivolts_X2();
197 }
198
199 #else
200
201 // 3pi: returns the voltage of the battery in millivolts using
202 // 10 averaged samples.
203 static unsigned int readBatteryMillivolts_3pi();
204
205 // SV-168/SV-328: returns the voltage of the battery in millivolts
206 // using 10 averaged samples.
207 static unsigned int readBatteryMillivolts_SV();
208
209 // This version of the function is included because the 3pi was
210 // originally the only supported board with battery voltage
211 // sensing. Instead of using this one, reading the battery
212 // voltage should be done with the board-specific functions above.
readBatteryMillivolts()213 static inline unsigned int readBatteryMillivolts()
214 {
215 return readBatteryMillivolts_3pi();
216 }
217
218 // returns the output of the Orangutan LV's temperature sensor in tenths of a
219 // degree F or C (20 readings averaged together). The temperature sensor
220 // is on ADC channel 6.
221 static int readTemperatureF();
222 static int readTemperatureC();
223
224 #endif // _ORANGUTAN_SVP
225 };
226
227 extern "C" {
228 #endif // __cplusplus
229
set_analog_mode(unsigned char mode)230 static inline void set_analog_mode(unsigned char mode)
231 {
232 if (mode == MODE_10_BIT)
233 ADMUX &= ~(1 << ADLAR); // right-adjust result (ADC has result)
234 else
235 ADMUX |= 1 << ADLAR; // left-adjust result (ADCH has result)
236 }
get_analog_mode(void)237 static inline unsigned char get_analog_mode(void)
238 {
239 return (ADMUX >> ADLAR) & 1;
240 }
241 unsigned int analog_read(unsigned char channel);
242 unsigned int analog_read_millivolts(unsigned char channel);
243 unsigned int analog_read_average(unsigned char channel, unsigned int samples);
244 unsigned int analog_read_average_millivolts(unsigned char channel, unsigned int samples);
245 void start_analog_conversion(unsigned char channel);
analog_is_converting(void)246 static inline unsigned char analog_is_converting(void)
247 {
248 return (ADCSRA >> ADSC) & 1;
249 }
250 unsigned int analog_conversion_result(void);
251 unsigned int analog_conversion_result_millivolts(void);
252 void set_millivolt_calibration(unsigned int calibration);
253 unsigned int read_vcc_millivolts(void);
254 unsigned int to_millivolts(unsigned int analog_result);
255 unsigned int read_trimpot(void);
256 unsigned int read_trimpot_millivolts(void);
257
258 #ifdef _ORANGUTAN_SVP
259
260 unsigned int read_battery_millivolts_svp(void);
read_battery_millivolts(void)261 static inline unsigned int read_battery_millivolts(void)
262 {
263 return read_battery_millivolts_svp();
264 }
265
266 #elif defined(_ORANGUTAN_X2)
267
268 unsigned int read_battery_millivolts_x2(void);
read_battery_millivolts(void)269 static inline unsigned int read_battery_millivolts(void)
270 {
271 return read_battery_millivolts_x2();
272 }
273
274 #else
275
276 int read_temperature_f(void);
277 int read_temperature_c(void);
278
279 unsigned int read_battery_millivolts_3pi(void);
read_battery_millivolts(void)280 static inline unsigned int read_battery_millivolts(void)
281 {
282 return read_battery_millivolts_3pi();
283 }
284 unsigned int read_battery_millivolts_sv(void);
285 unsigned int read_battery_millivolts_sv168(void);
286
287 #endif
288
289 #ifdef __cplusplus
290 }
291 #endif
292
293 #endif // OrangutanAnalog_h
294
295 // Local Variables: **
296 // mode: C++ **
297 // c-basic-offset: 4 **
298 // tab-width: 4 **
299 // indent-tabs-mode: t **
300 // end: **
301