1+ //
2+ // FILE: AsyncAnalog.cpp
3+ // AUTHOR: Rob Tillaart
4+ // VERSION: 0.1.1
5+ // DATE: 2018-09-05
6+ // PURPOSE: async version of analogRead, prevent blocking wait
7+ //
8+ // backgrounder
9+ // https://www.avrfreaks.net/forum/tut-c-newbies-guide-avr-adc?name=PNphpBB2&file=viewtopic&t=56429
10+ //
11+ // HISTORY:
12+ // 0.1.0 2018-09-05 initial version, based upon analogRead()
13+ // 0.1.1 2020-03-26 minor refactor
14+ //
15+
16+ #include " AsyncAnalog.h"
17+
18+
19+ #if defined(ARDUINO_ARCH_AVR)
20+
21+ AsyncAnalog::AsyncAnalog (const uint8_t pin)
22+ {
23+ _pin = pin;
24+ #if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
25+ if (_pin >= 54 ) _pin -= 54 ;
26+ #else
27+ if (_pin >= 14 ) _pin -= 14 ;
28+ #endif
29+ }
30+
31+ void AsyncAnalog::start ()
32+ {
33+ #if defined(ADCSRB) && defined(MUX5)
34+ // the MUX5 bit of ADCSRB selects whether we're reading from channels
35+ // 0 to 7 (MUX5 low) or 8 to 15 (MUX5 high).
36+ ADCSRB = (ADCSRB & ~(1 << MUX5)) | (((_pin >> 3 ) & 0x01 ) << MUX5);
37+ #endif
38+
39+ #if defined(ADMUX)
40+ // set the analog reference (high two bits of ADMUX) and select the
41+ // channel (low 4 bits). this also sets ADLAR (left-adjust result)
42+ // to 0 (the default).
43+ ADMUX = (DEFAULT << 6 ) | (_pin & 0x07 );
44+ #endif
45+
46+ sbi (ADCSRA, ADSC);
47+ }
48+
49+
50+ bool AsyncAnalog::ready ()
51+ {
52+ // ADSC is cleared when the conversion finishes
53+ return bit_is_set (ADCSRA, ADSC) == 0 ;
54+ }
55+
56+
57+ int AsyncAnalog::value ()
58+ {
59+ // we have to read ADCL first; doing so locks both ADCL
60+ // and ADCH until ADCH is read. reading ADCL second would
61+ // cause the results of each conversion to be discarded,
62+ // as ADCL and ADCH would be locked when it completed.
63+ int low = ADCL;
64+ int high = ADCH;
65+ // combine the two bytes
66+ return (high << 8 ) | low;
67+ }
68+
69+ #endif // ARDUINO_ARCH_AVR
70+
71+ // -- END OF FILE --
0 commit comments