Skip to content

Commit

Permalink
Modified the library to work with the Arduino Leonardo. Testing has n…
Browse files Browse the repository at this point in the history
…ow been done on the Uno and Leonardo.
  • Loading branch information
Mark Rose authored and Mark Rose committed Jan 28, 2015
1 parent 23efdb3 commit b704f23
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 64 deletions.
81 changes: 27 additions & 54 deletions AnalogScanner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -126,55 +126,25 @@ int AnalogScanner::getPinIndex(int pin) {
}
}

// Gets the Arduino pin number corresponding to an
// analog input index. For example, 0 corresponds to
// A0, 1 to A1, and so on.
int AnalogScanner::getPinForIndex(int index) {
switch (index) {
case 0: return A0;
case 1: return A1;
case 2: return A2;
case 3: return A3;
case 4: return A4;
case 5: return A5;
case 6: return A6;
case 7: return A7;

#ifdef A8
case 8: return A8;
#endif

#ifdef A9
case 9: return A9;
#endif

#ifdef A10
case 10: return A10;
#endif

#ifdef A11
case 11: return A11;
#endif

#ifdef A12
case 12: return A12;
#endif

#ifdef A13
case 13: return A13;
#endif

#ifdef A14
case 14: return A14;
// Gets the pin number for a pin or channel.
// Code from wiring_analog.c, lines 44-57.
uint8_t AnalogScanner::normalizePin(uint8_t pin) {
#if defined(analogPinToChannel)
#if defined(__AVR_ATmega32U4__)
if (pin >= 18) pin -= 18; // allow for channel or pin numbers
#endif

#ifdef A15
case 15: return A15;
pin = analogPinToChannel(pin);
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
if (pin >= 54) pin -= 54; // allow for channel or pin numbers
#elif defined(__AVR_ATmega32U4__)
if (pin >= 18) pin -= 18; // allow for channel or pin numbers
#elif defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega644__) || defined(__AVR_ATmega644A__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644PA__)
if (pin >= 24) pin -= 24; // allow for channel or pin numbers
#else
if (pin >= 14) pin -= 14; // allow for channel or pin numbers
#endif

default:
return A0;
}
return pin;
}

// Creates a new instance of the analog input scanner. Initializes
Expand All @@ -201,10 +171,11 @@ void AnalogScanner::setCallback(int pin, void (*p)(int index, int pin, int value
// Sets the scan order for the analog pins. The same pin may
// be specified multiple times if a pin should be sampled more
// often.
void AnalogScanner::setScanOrder(int n, int order[]) {
void AnalogScanner::setScanOrder(int n, const int order[]) {
scanOrderSize = min(SCAN_ORDER_MAX, n);
for (int i=0; i < scanOrderSize; ++i) {
scanOrder[i] = getPinIndex(order[i]);
requestedPins[i] = order[i];
normalizedPins[i] = normalizePin(order[i]);
}
}

Expand All @@ -228,7 +199,7 @@ void AnalogScanner::beginScanning() {
pCurrentScanner = this;
sbi(ADCSRA, ADEN); // Enable the ADC.
delay(1);
cbi(ADMUX, ADLAR); // Make sure the ADC value it right-jusitified.
cbi(ADMUX, ADLAR); // Make sure the ADC value is right-justified.
sbi(ADCSRA, ADIE); // Enable ADC complete interrupts.

startNextScan();
Expand All @@ -247,12 +218,13 @@ void AnalogScanner::startNextScan() {
if (++currentIndex >= scanOrderSize) {
currentIndex = 0;
}
int index = scanOrder[currentIndex];
currentPin = requestedPins[currentIndex];
int pin = normalizedPins[currentIndex];
#ifdef MUX5
// Set whether we're reading from inputs 0-7 or 8-15.
ADCSRB = (ADCSRB & ~(1 << MUX5)) | (((index >> 3) & 0x01) << MUX5);
ADCSRB = (ADCSRB & ~(1 << MUX5)) | (((pin >> 3) & 0x01) << MUX5);
#endif
ADMUX = (analogRef << 6) | (index & 7);
ADMUX = (analogRef << 6) | (pin & 7);
sbi(ADCSRA, ADSC); // Start the ADC conversion.
}
}
Expand All @@ -262,15 +234,16 @@ void AnalogScanner::processScan() {
// We must read ADCL first, which locks ADCH until it is read.
int low = ADCL;
int high = ADCH;
int index = scanOrder[currentIndex];
int index = getPinIndex(currentPin);
int pin = currentPin;
values[index] = (high << 8) | low;

// Invoke the next scan before the callback, to make the
// read rate more uniform.
startNextScan();

if (pCallback[index] != NULL) {
pCallback[index](index, getPinForIndex(index), values[index]);
pCallback[index](currentIndex, pin, values[index]);
}
}

Expand Down
21 changes: 17 additions & 4 deletions AnalogScanner.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
//
// See the accompanying documentation for API details.

#include <stdint.h>

class AnalogScanner {

private:
Expand All @@ -41,20 +43,27 @@ class AnalogScanner {
static const int ANALOG_INPUTS = 15;

// The maximum length of the analog input scan order.
static const int SCAN_ORDER_MAX = 50;
static const int SCAN_ORDER_MAX = 10;

// The analog input values.
volatile int values[ANALOG_INPUTS];

// The scan order. the same pin may be specified multiple
// times, in order to read some pins more often.
int scanOrder[SCAN_ORDER_MAX];
volatile uint8_t requestedPins[SCAN_ORDER_MAX];

// The normalized pin values for each pin to be scanned.
// See AnalogScanner::normalizePin().
volatile uint8_t normalizedPins[SCAN_ORDER_MAX];

// The size of the scan order.
int scanOrderSize;

// The current index within the scan order.
int currentIndex;
volatile int currentIndex;

// The current pin being scanned.
volatile uint8_t currentPin;

// An array of pointers to callback routines invoked when
// new values are available.
Expand All @@ -73,6 +82,10 @@ class AnalogScanner {
// index. For example, 0 corresponds to pin A0.
int getPinForIndex(int index);

// Converts a pin or channel number to a standardized form needed
// to form the mask for the ADC.
uint8_t normalizePin(uint8_t pin);

// Processes a new ADC input value for the current scan pin.
void processScan();

Expand All @@ -91,7 +104,7 @@ class AnalogScanner {
// Sets the scan order. A single pin may be specified
// multiple times in the scan order to increase the rate
// at which it is read.
void setScanOrder(int n, int order[]);
void setScanOrder(int n, const int order[]);

// Gets the most recently read value for an analog pin.
int getValue(int pin);
Expand Down
15 changes: 9 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,6 @@ Then, read the latest analog values whenever you like.
delay(100); // Wait for new values.
}

Calls expecting a pin number also accept a zero-relative pin index, where 0=A0, 1=A1, and so on. You can either pass the pin number constant defined by the Arduino libraries (A3, for example), or the corresponding analog pin index (3, for example).

**Note:** If you use a pin index that is not supported, zero will be used instead.

Examples
--------
The `examples/` subdirectory contains `analog_read_all.ino`, an example program that reads each analog input available on the Uno repeatedly (A0 through A6). The values are written to `Serial` once per second.
Expand All @@ -101,7 +97,9 @@ soon as new values are read.

scanner.setCallback(A0, processValue);

The index value is in the range 0 through 15, and represents the zero-relative pin index, where 0=A0 though 15=A15. (Different processors support different numbers of analog pins.) The pin value is the Arduino pin definition constant, from A0 through A15.
The index value is the zero-relative index of the scan in the pin scan order which was specified. (Different processors support different numbers of analog pins.) The pin value is the pin number specified in the scan order, from A0 through A15.

**NOTE:** Channel numbers can be used instead of pin numbers. See wiring_analog.c for details about how the actual pin index is calculated. This library uses the same method.

**WARNING:** The call to the callback function is processed from within the ADC interrupt handler. This can happen as often as 10,000 times per second, if only one analog pin is in the scan order. The processing function must operate quickly and return. Further, it should not invoke other libraries that are relatively slow, such as `Serial`. Do not write debugging output from the callback handler or you will likely hang the Arduino.

Expand Down Expand Up @@ -144,7 +142,7 @@ A pin may appear more than once in the scan order to read the pin more frequentl


### `int getValue(int pin)`
Gets the most recently read value for an analog pin number or pin index.
Gets the most recently read value for an analog pin number.

### `void setAnalogReference(int reference)`
Sets the analog voltage reference. See the built-in
Expand All @@ -158,3 +156,8 @@ be invoked by the ADC interrupt handling code.
### `void endScanning()`
Ends scanning the analog pins. Disables the ADC to save
power.

Release Notes
-------------
* 2015-01-27 - Modified the library to work with the Arduino Leonardo. Testing has now been done on the Uno and Leonardo.
* 2014-10-17 - Updated the example program to work with the Arduino IDE.

0 comments on commit b704f23

Please sign in to comment.