About ADC input

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

int main (void) 
{  DDRC=0xFF;
   PORTC=0xFF; 

   ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); // Set ADC prescalar to 128 - 125KHz sample rate @ 16MHz 

   ADMUX |= (1 << REFS0); // Set ADC reference to AVCC 
   ADMUX |= (1 << ADLAR); // Left adjust ADC result to allow easy 8 bit reading 

   // No MUX values needed to be changed to use ADC0 

   ADCSRA |= (1 << ADATE);  
   ADCSRA |= (1 << ADEN);  // Enable ADC 
   ADCSRA |= (1 << ADSC);  // Start A2D Conversions 

   for(;;)  // Loop Forever 
   {  if ((230

I wrote the above program to test to capture the value of ADC0.It is work. But I also want to capture the value of ADC1, ADC2 and ADC3 also. How can I write the program? Thanks a lot.

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

Quote:
It is work

I'm not sure how! That code sets ADSC and then immediately takes a reading without waiting for a signal that the conversion has completed?!? You either need to wait for ADSC to transition back from 1 to 0 (preferred) or wait for ADIF to become set (but then you have to write it to clear it which adds code/complexity).

You also seem to have ignored this bit of the datasheet:

When ADCL is read, the ADC Data Register is not updated until ADCH is read. Consequently,
if the result is left adjusted and no more than 8-bit precision is required, it is
sufficient to read ADCH. Otherwise, ADCL must be read first, then ADCH.

(but the GCC header files will usually provide ADC or ADCW which is a composite 16 biut register (with 10 bits used) that hides the read order thing from you anyway)

As for reading the other channels - each time before you set ADSC to start a conversion you need to mask the channel selection bits into ADMUX

Cliff

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

Thanks~~ :D
I also want to know how to clear the ADCH value when ADC0 switch to ADC1?? (if ADC0 is 100 and ADC1 is 0, I read ADC0 value at ADCH first and read ADC1 value at ADCH, how to clear the ADCH value before reading ADC1 value)

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

The only time what's in ADCH (and ADCL) is of any relevance is just after a conversion has completed (that is ADSC has gone 0-1-0) so what's in it from the last conversion is irrelevant. If you mean how do you store the readings from the different channels the usual way would be to use an array:

unsigned int readings[8];
unsigned char i;

for (i=0; i<8; i++) {
 ADMUX = (ADMUX & 0xF8) + i;
 ADCSRA |= (1 << ADSC);  
 while (ADCSRA & (1 << ADSC));  
 readings[i] = ADC;
}

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

Sorry for having so many questions.
I am a newbie to use Atmega16.
I wrote a program below, but the PORTC and PORTD will change at the same time. I just want PORTC is changed by ADC0 and PORTD is changed by ACD1. Now, if I change the ADC0 input voltage, PORTC and PORTD will change together. How to correct the program to solve the problems. Thanks a lot.

#include  
void in2(void)
{ ADMUX=0x61;
 
  if ((230
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You seem to be ignoring all my previous posts?!? What is the point of me suggesting things if you ignore them?

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

I am so sorry about that, I haven't ignored any your posts. Because I just use C language in a short period of time and don't know how to correct the program. I am sorry. :cry:

Is the value of ADC only can be clear after reading all ADCH and ADCL value? How to wait for a signal that the conversion has completed? How to wait for ADSC to transition back from 1 to 0?

thanks~

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

Quote:
How to wait for ADSC to transition back from 1 to 0?

But that's my point I showed you that in the following taken from a post above:

unsigned int readings[8]; 
unsigned char i; 

for (i=0; i<8; i++) { 
 ADMUX = (ADMUX & 0xF8) + i; 
 ADCSRA |= (1 << ADSC);  
 while (ADCSRA & (1 << ADSC));  
 readings[i] = ADC; 
}

The while() loop in there is waiting for ADSC to go back from 1 to 0

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

What clawson explained is the proper way.
But if you just dont want to make it complex just put some delay(1ms) after u change ADMUX :mrgreen: .
But remember it is not efficient :(

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

I changed the program like this, but it also doesn't work. What wrong with the program? Thanks a lot

#include  

int main (void) 
{  unsigned int readings[8]; 
   unsigned char i; 
   DDRC=0xFF; 
   PORTC=0xFF; 
   DDRD=0xFF; 
   PORTD=0xFF; 

   ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); // Set ADC prescalar to 128 - 125KHz sample rate @ 16MHz 

   ADMUX |= (1 << REFS0); // Set ADC reference to AVCC 
    

   ADCSRA |= (1 << ADATE);  
   ADCSRA |= (1 << ADEN);  // Enable ADC 
   ADCSRA |= (1 << ADSC);  // Start A2D Conversions 

   for(;;)  // Loop Forever 
   {  for (i=0; i<8; i++) { 
      ADMUX = (ADMUX & 0xF8) + i; 
      ADCSRA |= (1 << ADSC);  
      while (ADCSRA & (1 << ADSC));  
      readings[i] = ADC; 
                          } 
      
      if ((750
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Looks like your trying to this, from what i can see. I havent tried it but it should work.

ive made the code as easy to understand as possible.

Your lucky i was bored.

#include 

void ports_Init(void)
{
	DDRC=0xFF;
	PORTC=0xFF;
	DDRD=0xFF;
	PORTD=0xFF;
}

void setADC(void)
{
	ADCSRA |= (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0);  /* Prescaler and adc enable*/
}

void getADC(int channel)
{
	ADMUX = channel;	/*passed ADMUX*/

	ADCSRA |= (1<<ADSC);			/*Dummy sample, because we changed the channel*/
	while (!(ADCSRA & (1<<ADIF)));  /*wait until sample completes*/
	
	ADCSRA |= (1<<ADSC);			/*Proper sample*/
	while (!(ADCSRA & (1<<ADIF)));	/*wait until sample completes*/
}

int main(void)
{
	ports_Init(); /*initialise PORT*/
   	setADC();     /*initialise ADC*/
   
	for(;;)  /*Loop Forever*/
	{  
		getADC(0b01100000);			/*get sample ADC0. set the ADMUX value in the instance.*/
		PORTC = ADCH; 				/*copy ADCH to PORTC*/

		getADC(0b01100001);			/*get sample ADC0*/
		PORTD = ADCH; 				/*copy ADCH to PORTC*/
	}
}

Dont forget to disable the JTAGEN fuse.

- Tony B. Sydney, Australia.
tbaz2679@mail.usyd.edu.au

Status: Supporting the GNU

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

Thanks a lot~ :) Ub3r
I used your program and also disable the JTAGEN fuse, but PORTC and PORTD also will show the result of ADC0 and ADC1 together(if just connect ADC0, PORTC and PORTD will show the same result), they cannot show the result respectively.
How to change it?? Thanks again~~

#include  

void ports_Init(void) 
{ 
   DDRC=0xFF; 
   PORTC=0xFF; 
   DDRD=0xFF; 
   PORTD=0xFF; 
} 

void setADC(void) 
{ 
   ADCSRA |= (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0);  /* Prescaler and adc enable*/ 
} 

void getADC(int channel) 
{ 
   ADMUX = channel;   /*passed ADMUX*/ 

   ADCSRA |= (1<<ADSC);         /*Dummy sample, because we changed the channel*/ 
   while (!(ADCSRA & (1<<ADIF)));  /*wait until sample completes*/ 
    
   ADCSRA |= (1<<ADSC);         /*Proper sample*/ 
   while (!(ADCSRA & (1<<ADIF)));   /*wait until sample completes*/ 
} 

int main(void) 
{  MCUCSR=0x80;  /*disable the JTAGEN fuse*/
   ports_Init(); /*initialise PORT*/ 
      setADC();     /*initialise ADC*/ 
    
   for(;;)  /*Loop Forever*/ 
   {  
      getADC(0b01100000);         /*get sample ADC0. set the ADMUX value in the instance.*/ 
      PORTC = ADCH;             /*copy ADCH to PORTC*/ 

      getADC(0b01100001);         /*get sample ADC1*/ 
      PORTD = ADCH;             /*copy ADCH to PORTD*/ 
   } 
} 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It works now.
Thanks a lot~~

I also want to ask some question.
My output is connected to two motor. Different value from ADC0 or ADC1 will produce different speed of motors(higher value, faster speed), what is the easier way to do it?