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