Changing ADC channels (round robin) question

Go To Last Post
4 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi Freaks,

I am using ADC channel 5 of M328P to start with and after a certain number of timer ticks, changing over to channel 4. Here is my code:


void ADC_init()
  {
       ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0) | (1 << ADATE); // Set ADC prescaler to 128 - 125KHz sample rate @ 16MHz
       ADMUX = (1 << REFS0) | (1 << MUX2) | (1 << MUX0); // Set ADC reference to AVCC,select channel 5
   //using all 10 bit of ADC; so do not left justify the ADC value
       DIDR0 = (1 << ADC5D); //turn off the digital driver
   // No MUX values needed to be changed to use ADC0
       ADCSRA |= (1 << ADEN);  // Enable ADC
   }

void ADC1_init()

   {
      //ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0) | (1 << ADATE); // Set ADC prescaler to 128 - 125KHz sample rate @ 16MHz
        ADMUX = (1 << REFS0) | (0 << MUX3) | (1 << MUX2) | (0 << MUX1) | (0 << MUX0); // Set ADC reference to AVCC,select channel 5
   //using all 10 bit of ADC; so do not left justify the ADC value
        DIDR0 = (1 << ADC4D); //turn off the digital driver
   // No MUX values needed to be changed to use ADC0
     //ADCSRA |= (1 << ADEN);  // Enable ADC
     //ADCSRA |= (1 << ADSC);
   }


void timer_init()
  {

    TCCR1B |= (1 << WGM12);
    TIMSK1  |= (1 << OCIE1A);

     sei();

     OCR1A = 10000; //Count for 1s @ 8MHz and prescalar of 256//was 10000
//tested with PORTB0 - 3 LED's looks good
//Use a count of 2000 for 3.686MHz and prescalar of 256

     TCCR1B |= (1 << CS12) | (0 << CS11) | (0 << CS10);

   }

ISR(TIMER1_COMPA_vect)
   {

    PORTC += 1;
    flag = 1;
    pin_count++;
    count++;
							 if (count > 16)
							    {
							       PORTB = ~(1 << PORTB0) | (1 << PORTB1); //change this from PB0,PB1 for M48 to PORTB0 and PORTB1 for M328P
					
								ADC1_init();
                                          
								}
                               						
     }
----------------------------
MAIN:
int main (void)
    {
      
	   DDRC = 0x0F;
	   DDRD = 0xC0; 
	   DDRB = 0xFF;
	   PORTC = 0x00;
	   PORTD = 0x00;
	   PORTB = 0x01;
	  
	  
           USART0_init();
	   ADC_init(); 
	   timer_init();

          for(;;)
            {
			  	  
	       _delay_ms(100);
			  
    	     ADCSRA |= (1 << ADSC);
					                          ADC_dummy = ADC;

So the timer counts one second ticks. After the 16th second, I want to turn on ADC channel 4. I am using the ADC1_init function to change over to channel 4. I only have the ADMUX selection in this init function. This is my last measurement so I do not need channel 5 again.

I am starting all the conversions in the for(;;) loop in main and then collecting my ADC value.

However, I see that channel 5 works just fine but when the count becomes 17, I do not get any reading out of the ADC.

What is missing?
I am also reading the round robin posts in this forum but is there something obvious that is wrong here? I am trying to avoid the ADC interrupt (as it is free running hence collecting the value in main).

Appreciate any help.
Thanks.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

How very confused. Why not just:

if (count_is_right) {
 ADMUX &= 0xF8; // clear existing channel selection
 ADMUX |= (new_channel & 0x07);
}

There's no need to reinit the entire ADC just to change the channel.

Also something has gone very very wrong in your main() code - the code is all over the place and the end is missing?

Also why the fixed 100ms delay between readings? Why not just wait for the device to signal that the previous conversion has completed (ADSC returns to 0 or ADIF goes to 1) ?

Cliff

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I just posted the relevant parts of main. There is an end to it.

Would that 100 ms hurt? I agree I could use ADIF.

I tried this and it did not work:

#define new_channel 0x04					
           if (count > 16)
								{
							                PORTB = ~(1 << PORTB0) | (1 << PORTB1); //change this from PB0,PB1 for M48 to PORTB0 and PORTB1 for M328P
		          ADMUX &= 0xF8;
				  					   ADMUX |= (new_channel & 0x07);
									   //DIDR0 = (1 << ADC4D);
                                         
								 }

I even tried to turn off the digital driver and that did not work either.

Should I start the conversion in my timer as well?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If you don't need samples more often than the timer frequency then, yes, triggering ADSC there may be the way to proceed.