Multi Inputs Analog using ADMUX

Hello everyone,
I'm newbie in setting of the registers.
I use MEGA2560, I wrote this code as follows for one analog sensor, I want to add 3 others Analogs Sensors like that :
ADMUX |= (0 & 0x04); // A3
ADMUX |= (0 & 0x01); // A6
ADMUX |= (0 & 0x02); //A5

But I'm confused how I can send the values of these sensors separately (successively or together) to serial print.

For rephrasing my question :
I used the value stored in ADCH/ADCL register for showing the value of one sensor, but for many ones how I can do?
Thanks for your help

unsigned long t, t0;
volatile int nbData=300;
int data[300];


void setup()
{
  Serial.begin(115200);
  ADCSRA = 0;             
  ADCSRB = 0;             
  ADMUX |= (0 & 0x07);  //A0
  **ADMUX |= (0 & 0x04);    // A3**
**  ADMUX |= (0 & 0x01);  // A6**
**  ADMUX |= (0 & 0x02);  //A5**
  
  ADMUX |= (1 << REFS0);  
  ADMUX |= (1 << ADLAR);  
 
             
  
  ADCSRA |= (1 << ADATE); 
  ADCSRA |= (1 << ADIE);  
  ADCSRA |= (1 << ADEN);  
  ADCSRA |= (1 << ADSC); 


}

ISR(ADC_vect)
{
 byte x = ADCH;  

}
 
void loop()
{
  noInterrupts();
  nbData; 
  interrupts();


  for(int i=0; i<nbData; i++){
        
      data[i]=  ADCH;
      
  }
  t = micros()-t0; 
  
  SendToSerial();
}

void SendToSerial()
{
    
     for (int x = 0 ; x <nbData; x++){
          Serial.println(data[x]);
     }

}

The Mega and most other Arduinos only have one A/D converter, so you can not set these all at once only one will be switched in.
The code
ADMUX |= (0 & 0x04); // A3
ADMUX |= (0 & 0x01); // A6
ADMUX |= (0 & 0x02); //A5
Only uses the logical or operations so that when you set them one after another the logic 1's in the ADMUX register will accumulate. So suppose ADMUX contained a value of zero, then:-
ADMUX |= (0 & 0x04);
would set bit 2 to a 1, if this is followed by
ADMUX |= (0 & 0x01);
then bit 2 and bit zero would be set , if this is followed by
ADMUX |= (0 & 0x02);
then bit 2, 1, and zero would be set
When doing this sort of thing you must use the logical AND operation to clear out (set to zero) all the mux address lines to zero than put the value you want with the OR.

You can't.
You can only set one multiplexer address at a time, and only read back the one value from the A/D.

1 Like

Thanks Grump_Mike for your reply,
if I understand :
I can't use all sensors at a time, but we can use one after another.
When the value stored in the ADCH, I read it by serial print, after that I set this register to Zéro and restarting the operation for the next value coming from another sensor.

ADMUX :
I'm not sure to understand your example to set the bit of ADMUX for switching between the values, please can you detailed this point ?
Thank you

Correct.

No need to do that it gets replaced by the next conversion.

The OR operation sets selected bits
The AND operation clears selected bits
The XOR operation inverts selected bits

See reply #8 in this thread for a full explanation
Analog reading whit registers - #7 by Grumpy_Mike

1 Like

Thank you Grumpy_Mike.
I will See your reply #8
https://forum.arduino.cc/t/analog-reading-whit-registers/922403/7

Hello
I come back to this topic, I modified my previous code for reading Analog InputsA0, A1, A2, A3 using variable Chn and array to switch between inputs in the ADMUX registre, but in the serial print , I have only the numbre 15,
For me, by this code as blow, l must have the value of A0, A1, A2 after A3.
may be I missing some things, do you can help me?
thanks for help
the code is :

unsigned long t, t0;
volatile int nbData=300;
int data[300];
int Chn;
int arr [] = {0x00, 0x01, 0x02, 0x03};

void setup()
{
  Serial.begin(115200);
  ADCSRA = 0;             
  ADCSRB = 0;             

  ADMUX |= (1 << REFS0);  
  ADMUX |= (1 << ADLAR);  
 
  ADCSRA |= (1 << ADATE); 
  ADCSRA |= (1 << ADIE);  
  ADCSRA |= (1 << ADEN);  
  ADCSRA |= (1 << ADSC); 

}

ISR(ADC_vect)
{
 byte x = ADCH;  

}
 
void loop()
{
  noInterrupts();
  nbData; 
  interrupts();

for (int i=0;i<4 ; i++) {
      Chn = arr[i];  
      ADMUX = Chn;
      ADMUX_Function();
     
   }
}

void ADMUX_Function()
{

 for(int i=0; i<nbData; i++){
        
      data[i]=  (ADCH << 2) + (ADCL & 3);
   }
  t = micros()-t0; 
  
  SendToSerial();

}

void SendToSerial()
{
    
     for (int x = 0 ; x <nbData; x++){
            Serial.println(data[x]);
     }

}

/*
for (int counter = 10; counter > 0; --counter)
 {
  delay(1000);
  Num_Write(counter-1);
 }
 */
type or paste code here

Lots wrong with this without even looking at the use of registers.

  noInterrupts();
  nbData; 
  interrupts();

The variable nbData is just an int containing the value 300. So what is it doing just being on a line my itself? Answer it is doing nothing.

ISR(ADC_vect)
{
 byte x = ADCH;  
}

This also does nothing. The variable x is declared as a byte but is never used. The compiler can see this so it removes it. You should not declare variables in an ISR, they should be declared outside any function and have the volatile prefix. But then as I say you never use it. What do you want to do here. I imagine you should set a flag that indicates an A/D conversion cycle has been completed. Then in the non ISR code you should check this flag has been set before reading the registers and then clear it. This is normally done with a while structure.

The code

     for (int x = 0 ; x <nbData; x++){
            Serial.println(data[x]);

Declares a new variable x, this is a different variable to that used in the ISR function.

The line

      ADMUX = Chn;

Is wrong. After all I said about only changing the bits in the lower 3 bits in the ADMUX register, you use this and stamp over Bit 5 – ADLAR: ADC Left Adjust Result, you might want this to be 0 or 1. If you want it to be zero then it is fine, but not if you want it to be one.

This code

  t = micros()-t0; 

Dose nothing so why do you have it?
You need to read Section 26.8.3 ADCSRA – ADC Control and Status Register A on page 285 of the data sheet.
Then take the code

  ADCSRA |= (1 << ADATE); 
  ADCSRA |= (1 << ADIE);  
  ADCSRA |= (1 << ADEN);  
  ADCSRA |= (1 << ADSC); 

And replace it with
ADCSRA = 0xXX
where 0xXX is the number ( in hexadecimal for convenience ) that corresponds to all the bits you want setting as a zeros and ones.

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.