Skip to content
jmsmdy edited this page Feb 25, 2019 · 2 revisions

Welcome to the Analog-MIDI-Merge wiki!

ADC Registers Documentation for Arduino Nano

This information is available on page 257 of the ATmega328 datasheet, but we're presenting it here for convenience.

ADMUX Register (controls reference voltage and pin selection)

Bit # 7 6 5 4 3 2 1 0
Bit Name REFS1 REFS0 ADLAR - MUX3 MUX2 MUX1 MUX0
Value 0 1 0 0 M3 M2 M1 M0
Bit(s) Explanation
REFS=01 Use default reference voltage (5V for Arduino Nano, 3.3V for some other boards)
REFS=00 means use external voltage on AREF pin
(beware this can damage your Arduino)
REFS=11 means use internal reference voltage
ADLAR=0 10 bits result from ADC will be stored right-adjust as:
ADCH = 00000R9R8, ADCL = R7R6R5R4R3R2R1R0.
If set to 1, will instead store the result left-adjust as:
ADCH = R9R8R7R6R5R4R3R2, ADCL = R1R0000000
which is useful if you only need the 8 most significant bits
MUX= M3M2M1M0 Represents the analog pin number being read in binary,
e.g. MUX=0000 means pin A0, MUX=0101 means pin A5

ADCSRA Register (controls operating mode, triggering, and clock speed)

BIT # 7 6 5 4 3 2 1 0
BIT NAME ADEN ADSC ADATE ADIF ADIE ADPS2 ADPS1 ADPS0
BIT VALUE 1 0 1 0 1 1 1 1
Bit(s) Explanation
ADEN=1 ADC Enabled (Turned On)
ADSC=0 Start Conversation? Set to 1 to start conversation.
ADATE=1 Auto Trigger Enabled
Conversion is automatically started by trigger indicated in ADTS
ADIF=0 Interrupt Flag
Indicates whether an interrupt has been sent
ADIE=1 Interrupt Enabled
Triggers execution of ISR(ADC_vect) { insert code here } when conversion is ready to read
ADPS=111 Clock Divider set to 128 (around 100ms latency).
ADC Clock is determined from System Clock and ADPS by the formula:
ADC Clock = System Clock ÷ 2ADPS

ADCSRB Register (controls muxing and trigger mode)

BIT # 7 6 5 4 3 2 1 0
BIT NAME - ACME - - - ADTS2 ADTS1 ADTS0
BIT VALUE 0 1 0 0 0 0 0 0
Bit(s) Explanation
ACME=1 Muxing Enabled
ADTS=000 ADC Auto Trigger Source Selection
000 = Free running mode
Free running mode automatically triggers the next conversion when the previous one is finished.

Example Code for Non-Blocking Analog Reads

// Analog Input Variables
char analogInputSelected = 0;                  
unsigned int analogVal[8] = {0,0,0,0,0,0,0,0};

void setup() {
  ADMUX = 0x40 + analogInputSelected;  // 0x40 = 0100000 (Default voltage; Right-adjust)
  ADCSRA = 0xAF;   // 0xAF = 10101111 (ADC On; Auto Trigger On; Interrupt Enabled; Clock Division = 128)
  ADCSRB = 0x40;   // 0x40 = 0100000 (Muxing On; Free running mode)
  bitWrite(ADCSRA, 6, 1);  // Start Conversion by Setting ADSC=1 in ADCSRA
  sei();                   // Enable Global Interrupts 
  Serial.begin(9600); 
  Serial.println("Serial Communication Started");
} /* Decreasing the last three bits of ADCSRA will increase the speed of the ADC, but
     will lose some accuracy. You might want to experiment to find the right balance. */

void loop() {
  char i;
  unsigned long int delaytracker = 0; // Used delay printing to serial
  
  if ( millis() - delaytracker > 1000 ) { // If we've waited at least one second...
    delaytracker = millis();
    Serial.print("Values on A0 ... A7: ");
    for (i = 0; i < 8; i++) {             // Print all the values
      Serial.print(analogVal[i], HEX);  
      Serial.print("---");
    }
    Serial.println("");
  }
  /*Put any code you like here! You can read the values in the array analogVal,
    use them to perform additional calculations. They will update continuously
    in the background, and code here will not be delayed by lengthy analog reads.*/
}


////////////////////////////////////////
//**********Interrupt Routine*********//
//***ADC is in continuous read mode***//
//*Routine triggers when ADC is ready*//
//*Result stored in analogInput array*//
////////////////////////////////////////
ISR(ADC_vect) {
  analogVal[analogInputSelected] = ADCL;       // Store least significant bits
  analogVal[analogInputSelected] += ADCH << 8; // Store most significant bits

  analogInputSelected = (analogInputSelected + 1) % 8; // Select next input pin 
  ADMUX = 0x40 + analogInputSelected; // Tell ADC to read selected pin
}

/* If you only need a few pins, you can speed up the rate at which pins are read
   by using a different method to choose the next input pin here which skips the
   pins you don't need to read. */