| 1 | /* |
| 2 | wiring_analog.c - analog input and output |
| 3 | Part of Arduino - http://www.arduino.cc/ |
| 4 | |
| 5 | Copyright (c) 2005-2006 David A. Mellis |
| 6 | |
| 7 | This library is free software; you can redistribute it and/or |
| 8 | modify it under the terms of the GNU Lesser General Public |
| 9 | License as published by the Free Software Foundation; either |
| 10 | version 2.1 of the License, or (at your option) any later version. |
| 11 | |
| 12 | This library is distributed in the hope that it will be useful, |
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 15 | Lesser General Public License for more details. |
| 16 | |
| 17 | You should have received a copy of the GNU Lesser General |
| 18 | Public License along with this library; if not, write to the |
| 19 | Free Software Foundation, Inc., 59 Temple Place, Suite 330, |
| 20 | Boston, MA 02111-1307 USA |
| 21 | |
| 22 | Modified 28 September 2010 by Mark Sproul |
| 23 | */ |
| 24 |
|
| 25 | #include "wiring_private.h" |
| 26 | #include "pins_arduino.h" |
| 27 |
|
| 28 | uint8_t analog_reference = DEFAULT; |
| 29 |
|
| 30 | void analogReference(uint8_t mode) |
| 31 | { |
| 32 | // can't actually set the register here because the default setting |
| 33 | // will connect AVCC and the AREF pin, which would cause a short if |
| 34 | // there's something connected to AREF. |
| 35 | analog_reference = mode; |
| 36 | } |
| 37 |
|
| 38 | int analogRead(uint8_t pin) |
| 39 | { |
| 40 | uint8_t low, high; |
| 41 |
|
| 42 | #if defined(analogPinToChannel) |
| 43 | #if defined(__AVR_ATmega32U4__) |
| 44 | if (pin >= 18) pin -= 18; // allow for channel or pin numbers |
| 45 | #endif |
| 46 | pin = analogPinToChannel(pin); |
| 47 | #elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) |
| 48 | if (pin >= 54) pin -= 54; // allow for channel or pin numbers |
| 49 | #elif defined(__AVR_ATmega32U4__) |
| 50 | if (pin >= 18) pin -= 18; // allow for channel or pin numbers |
| 51 | #elif defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega644__) || defined(__AVR_ATmega644A__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644PA__) |
| 52 | if (pin >= 24) pin -= 24; // allow for channel or pin numbers |
| 53 | #else |
| 54 | if (pin >= 14) pin -= 14; // allow for channel or pin numbers |
| 55 | #endif |
| 56 |
|
| 57 | #if defined(ADCSRB) && defined(MUX5) |
| 58 | // the MUX5 bit of ADCSRB selects whether we're reading from channels |
| 59 | // 0 to 7 (MUX5 low) or 8 to 15 (MUX5 high). |
| 60 | ADCSRB = (ADCSRB & ~(1 << MUX5)) | (((pin >> 3) & 0x01) << MUX5); |
| 61 | #endif |
| 62 | |
| 63 | // set the analog reference (high two bits of ADMUX) and select the |
| 64 | // channel (low 4 bits). this also sets ADLAR (left-adjust result) |
| 65 | // to 0 (the default). |
| 66 | #if defined(ADMUX) |
| 67 | #if defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) |
| 68 | ADMUX = (analog_reference << 4) | (pin & 0x07); |
| 69 | #else |
| 70 | ADMUX = (analog_reference << 6) | (pin & 0x07); |
| 71 | #endif |
| 72 | #endif |
| 73 |
|
| 74 | // without a delay, we seem to read from the wrong channel |
| 75 | //delay(1); |
| 76 |
|
| 77 | #if defined(ADCSRA) && defined(ADCL) |
| 78 | // start the conversion |
| 79 | sbi(ADCSRA, ADSC); |
| 80 |
|
| 81 | // ADSC is cleared when the conversion finishes |
| 82 | while (bit_is_set(ADCSRA, ADSC)); |
| 83 |
|
| 84 | // we have to read ADCL first; doing so locks both ADCL |
| 85 | // and ADCH until ADCH is read. reading ADCL second would |
| 86 | // cause the results of each conversion to be discarded, |
| 87 | // as ADCL and ADCH would be locked when it completed. |
| 88 | low = ADCL; |
| 89 | high = ADCH; |
| 90 | #else |
| 91 | // we dont have an ADC, return 0 |
| 92 | low = 0; |
| 93 | high = 0; |
| 94 | #endif |
| 95 |
|
| 96 | // combine the two bytes |
| 97 | return (high << 8) | low; |
| 98 | } |
| 99 |
|
| 100 | // Right now, PWM output only works on the pins with |
| 101 | // hardware support. These are defined in the appropriate |
| 102 | // pins_*.c file. For the rest of the pins, we default |
| 103 | // to digital output. |
| 104 | void analogWrite(uint8_t pin, int val) |
| 105 | { |
| 106 | // We need to make sure the PWM output is enabled for those pins |
| 107 | // that support it, as we turn it off when digitally reading or |
| 108 | // writing with them. Also, make sure the pin is in output mode |
| 109 | // for consistenty with Wiring, which doesn't require a pinMode |
| 110 | // call for the analog output pins. |
| 111 | pinMode(pin, OUTPUT); |
| 112 | if (val == 0) |
| 113 | { |
| 114 | digitalWrite(pin, LOW); |
| 115 | } |
| 116 | else if (val == 255) |
| 117 | { |
| 118 | digitalWrite(pin, HIGH); |
| 119 | } |
| 120 | else |
| 121 | { |
| 122 | switch(digitalPinToTimer(pin)) |
| 123 | { |
| 124 | // XXX fix needed for atmega8 |
| 125 | #if defined(TCCR0) && defined(COM00) && !defined(__AVR_ATmega8__) |
| 126 | case TIMER0A: |
| 127 | // connect pwm to pin on timer 0 |
| 128 | sbi(TCCR0, COM00); |
| 129 | OCR0 = val; // set pwm duty |
| 130 | break; |
| 131 | #endif |
| 132 |
|
| 133 | #if defined(TCCR0A) && defined(COM0A1) |
| 134 | case TIMER0A: |
| 135 | // connect pwm to pin on timer 0, channel A |
| 136 | sbi(TCCR0A, COM0A1); |
| 137 | OCR0A = val; // set pwm duty |
| 138 | break; |
| 139 | #endif |
| 140 |
|
| 141 | #if defined(TCCR0A) && defined(COM0B1) |
| 142 | case TIMER0B: |
| 143 | // connect pwm to pin on timer 0, channel B |
| 144 | sbi(TCCR0A, COM0B1); |
| 145 | OCR0B = val; // set pwm duty |
| 146 | break; |
| 147 | #endif |
| 148 |
|
| 149 | #if defined(TCCR1A) && defined(COM1A1) |
| 150 | case TIMER1A: |
| 151 | // connect pwm to pin on timer 1, channel A |
| 152 | sbi(TCCR1A, COM1A1); |
| 153 | OCR1A = val; // set pwm duty |
| 154 | break; |
| 155 | #endif |
| 156 |
|
| 157 | #if defined(TCCR1A) && defined(COM1B1) |
| 158 | case TIMER1B: |
| 159 | // connect pwm to pin on timer 1, channel B |
| 160 | sbi(TCCR1A, COM1B1); |
| 161 | OCR1B = val; // set pwm duty |
| 162 | break; |
| 163 | #endif |
| 164 |
|
| 165 | #if defined(TCCR1A) && defined(COM1C1) |
| 166 | case TIMER1C: |
| 167 | // connect pwm to pin on timer 1, channel B |
| 168 | sbi(TCCR1A, COM1C1); |
| 169 | OCR1C = val; // set pwm duty |
| 170 | break; |
| 171 | #endif |
| 172 |
|
| 173 | #if defined(TCCR2) && defined(COM21) |
| 174 | case TIMER2: |
| 175 | // connect pwm to pin on timer 2 |
| 176 | sbi(TCCR2, COM21); |
| 177 | OCR2 = val; // set pwm duty |
| 178 | break; |
| 179 | #endif |
| 180 |
|
| 181 | #if defined(TCCR2A) && defined(COM2A1) |
| 182 | case TIMER2A: |
| 183 | // connect pwm to pin on timer 2, channel A |
| 184 | sbi(TCCR2A, COM2A1); |
| 185 | OCR2A = val; // set pwm duty |
| 186 | break; |
| 187 | #endif |
| 188 |
|
| 189 | #if defined(TCCR2A) && defined(COM2B1) |
| 190 | case TIMER2B: |
| 191 | // connect pwm to pin on timer 2, channel B |
| 192 | sbi(TCCR2A, COM2B1); |
| 193 | OCR2B = val; // set pwm duty |
| 194 | break; |
| 195 | #endif |
| 196 |
|
| 197 | #if defined(TCCR3A) && defined(COM3A1) |
| 198 | case TIMER3A: |
| 199 | // connect pwm to pin on timer 3, channel A |
| 200 | sbi(TCCR3A, COM3A1); |
| 201 | OCR3A = val; // set pwm duty |
| 202 | break; |
| 203 | #endif |
| 204 |
|
| 205 | #if defined(TCCR3A) && defined(COM3B1) |
| 206 | case TIMER3B: |
| 207 | // connect pwm to pin on timer 3, channel B |
| 208 | sbi(TCCR3A, COM3B1); |
| 209 | OCR3B = val; // set pwm duty |
| 210 | break; |
| 211 | #endif |
| 212 |
|
| 213 | #if defined(TCCR3A) && defined(COM3C1) |
| 214 | case TIMER3C: |
| 215 | // connect pwm to pin on timer 3, channel C |
| 216 | sbi(TCCR3A, COM3C1); |
| 217 | OCR3C = val; // set pwm duty |
| 218 | break; |
| 219 | #endif |
| 220 |
|
| 221 | #if defined(TCCR4A) |
| 222 | case TIMER4A: |
| 223 | //connect pwm to pin on timer 4, channel A |
| 224 | sbi(TCCR4A, COM4A1); |
| 225 | #if defined(COM4A0) // only used on 32U4 |
| 226 | cbi(TCCR4A, COM4A0); |
| 227 | #endif |
| 228 | OCR4A = val; // set pwm duty |
| 229 | break; |
| 230 | #endif |
| 231 | |
| 232 | #if defined(TCCR4A) && defined(COM4B1) |
| 233 | case TIMER4B: |
| 234 | // connect pwm to pin on timer 4, channel B |
| 235 | sbi(TCCR4A, COM4B1); |
| 236 | OCR4B = val; // set pwm duty |
| 237 | break; |
| 238 | #endif |
| 239 |
|
| 240 | #if defined(TCCR4A) && defined(COM4C1) |
| 241 | case TIMER4C: |
| 242 | // connect pwm to pin on timer 4, channel C |
| 243 | sbi(TCCR4A, COM4C1); |
| 244 | OCR4C = val; // set pwm duty |
| 245 | break; |
| 246 | #endif |
| 247 | |
| 248 | #if defined(TCCR4C) && defined(COM4D1) |
| 249 | case TIMER4D: |
| 250 | // connect pwm to pin on timer 4, channel D |
| 251 | sbi(TCCR4C, COM4D1); |
| 252 | #if defined(COM4D0) // only used on 32U4 |
| 253 | cbi(TCCR4C, COM4D0); |
| 254 | #endif |
| 255 | OCR4D = val; // set pwm duty |
| 256 | break; |
| 257 | #endif |
| 258 |
|
| 259 | |
| 260 | #if defined(TCCR5A) && defined(COM5A1) |
| 261 | case TIMER5A: |
| 262 | // connect pwm to pin on timer 5, channel A |
| 263 | sbi(TCCR5A, COM5A1); |
| 264 | OCR5A = val; // set pwm duty |
| 265 | break; |
| 266 | #endif |
| 267 |
|
| 268 | #if defined(TCCR5A) && defined(COM5B1) |
| 269 | case TIMER5B: |
| 270 | // connect pwm to pin on timer 5, channel B |
| 271 | sbi(TCCR5A, COM5B1); |
| 272 | OCR5B = val; // set pwm duty |
| 273 | break; |
| 274 | #endif |
| 275 |
|
| 276 | #if defined(TCCR5A) && defined(COM5C1) |
| 277 | case TIMER5C: |
| 278 | // connect pwm to pin on timer 5, channel C |
| 279 | sbi(TCCR5A, COM5C1); |
| 280 | OCR5C = val; // set pwm duty |
| 281 | break; |
| 282 | #endif |
| 283 |
|
| 284 | case NOT_ON_TIMER: |
| 285 | default: |
| 286 | if (val < 128) { |
| 287 | digitalWrite(pin, LOW); |
| 288 | } else { |
| 289 | digitalWrite(pin, HIGH); |
| 290 | } |
| 291 | } |
| 292 | } |
| 293 | } |
| 294 |
|
| 295 |
|