How to sample the AVR's ADC in an array?

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

I'm quite new to C language. I'm trying out to figure out how can I sample my voltage readings like V[1],V[2],V[3] taken in a successive orders, so I can get its rms/average values.

How to implement this in C code? using array?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
int V[10];
int i;
for (i = 0; i < 10; i++)
{
    V[i] = GetADC();
}

[Edited error.]

Regards,
Steve A.

The Board helps those that help themselves.

Last Edited: Fri. Jun 10, 2011 - 04:12 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

That should be

V[i] = GetADC(); 

:)

"I may make you feel but I can't make you think" - Jethro Tull - Thick As A Brick

"void transmigratus(void) {transmigratus();} // recursio infinitus" - larryvc

"It's much more practical to rely on the processing powers of the real debugger, i.e. the one between the keyboard and chair." - JW wek3

"When you arise in the morning think of what a privilege it is to be alive: to breathe, to think, to enjoy, to love." -  Marcus Aurelius

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

Steve

In the for loop, shouldn't that be V[i] = GetADC(); ?

edit - oops - Larry beat me to it...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
#define INBUF 10

   int i, x[INBUF];

   ADCSRA = 0x87;    
   ADMUX = 0x40; 
   ADCSRA |= (1<<ADSC); 

   while(!(ADCSRA & 0x10)); 

   for(i=0; i
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I did something similiar, a zero crossing to get out of the loop and rms the values, but the LCD seems to display alien characters, using this code.

	

while (1)

	{
		
		Vbias=25;
		unsigned int n=0;
		unsigned int zero=0;	
		

		while (zero<2)    
		{ 

			ADCSRA = 0xC0;   //start conversion
			while((ADCSRA & 0x40)!=0){}  //wait adc conversion
			DL = ADCL;
			DH = ADCH;
			DH = DH << 8;
			ADC_Value = DH | DL;

			if (ADC_Value<5)		//check power off
			{
				LCD_puts("0V");
				zero++;
			}

			LCD_puts("processing");

			Vsample =(((ADC_Value*10)/1024)-Vbias)*16;

			if ((Vsample<5) & (Vsample >-5))		//zero crossing window
			{
			zero++;
			}


			Vraw[n]=(Vsample*Vsample);
			n++;


		}	


		unsigned int i=0;
		Vtemp=0;

		while (i<(n+1))
		{

		Vtemp=Vtemp+Vraw[i];
		i++;
		}
		
		Vtemp=Vtemp/n;
		voltage=sqrt(Vtemp);
		


  		char buffer[100];
		sprintf(buffer,"%.dV",voltage);
  	    LCD_puts(buffer);
		


    }

    return 0; 
}
Last Edited: Fri. Jun 10, 2011 - 08:08 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ExcuseMe, Fix your code tags please.

"I may make you feel but I can't make you think" - Jethro Tull - Thick As A Brick

"void transmigratus(void) {transmigratus();} // recursio infinitus" - larryvc

"It's much more practical to rely on the processing powers of the real debugger, i.e. the one between the keyboard and chair." - JW wek3

"When you arise in the morning think of what a privilege it is to be alive: to breathe, to think, to enjoy, to love." -  Marcus Aurelius

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

While you haven't shown an entire program and you haven't said which C compiler it is I think it's avr-gcc as you are using a feature of C99 in there (the only alternative is IAR). As such:

         DL = ADCL;
         DH = ADCH;
         DH = DH << 8;
         ADC_Value = DH | DL;

would be much simpler as:

         ADC_Value = ADCW;

I'd also be a bit suspicious of:

       Vsample =(((ADC_Value*10)/1024)-Vbias)*16;

ADC_Value is going to be 0..1023. say it is 1023 then 1023*10 is 10230 and 10230/1024 is 9 (it's really 9.9 but the .9 is lost). So this is only going to produce 10 different readings across the entire ADC range. You are throwing away most of the resolution of the ADC - maybe this doesn't matter to you or you even intended it this way but I guess my point is "be wary of integer division".

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

Then what should be the efficient way to do it? if its a 10-bit resolution and Vref is 1.1?

How do I get the voltage to the input of ADC?

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

Work in terms of scaled integers. Treat "full scale" (that is a reading of 1023) as 1100 (which you will later divide by 1000 to get 1.100). So you might think:

reading = ADC/1024 * 1100;

but when dealing with integer arithmetic you should always do the multiplies before the divides, so re-arrange that as:

reading = (ADC * 1100UL) / 1024;

If you now read 1023 then you get 1023*1100=1125300 and then divide by 1024 gives: 1098 which you can later display as 1.098

Say the ADC read 587 then 587*1100=645700 and divide by 1024 gives 630 which you would then display as 0.630V

etc.

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

Quote:
but the LCD seems to display alien characters
sprintf won't work correctly unless you link with the appropriate libraries (and null terminate the buffer).

--greg
Still learning, don't shout at me, educate me.
Starting the fire is easy; the hardest part is learning how to keep the flame!

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

I'm using an 8-bit microcontroller, does it mean i can process max 8-bits? which is 0 to 256?

Can such a large number of 1125300 can be processed?
If yes what the max?

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

ExcuseMe wrote:
I'm using an 8-bit microcontroller, does it mean i can process max 8-bits? which is 0 to 256?

Can such a large number of 1125300 can be processed?
If yes what the max?


No.

It's a 10bit ADC so 0 - 1023 steps
and 8bits = 0 - 255 not 0 - 256

Almost any number can be 'processed' you just need to supply the logic to deal with huge numbers yourself.

--greg
Still learning, don't shout at me, educate me.
Starting the fire is easy; the hardest part is learning how to keep the flame!

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

Thanks all for the valueble information.

I am using the AVR butterfly.My Vcc is 3V and Vref is 1.1V. Can the ADC support from 0-5V like other normal atmel?

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

ExcuseMe wrote:
Thanks all for the valueble information.

I am using the AVR butterfly.My Vcc is 3V and Vref is 1.1V. Can the ADC support from 0-5V like other normal atmel?


No. I very much doubt it.
Shoving an analogue voltage signal through a converter thats running at a lower voltage will probably be bad.
Check the datasheet, it should tell you.

--greg
Still learning, don't shout at me, educate me.
Starting the fire is easy; the hardest part is learning how to keep the flame!

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

the MCU datasheet says its okay, but the mcu itself is own the dev.kit and its running on 3V. I heard its bad to use 5V.

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

the UL stands for unsigned long int. When should I use it how do I use it like u did in a computation?

When the result is expected to be large?

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

Quote:

clawson, whats the UL for?

I'm not going to tell you - if you have a decent guide to C programming you should be able to find out.

(but I will say that AVRs, unlike the PC world where a lot of example C software and books are focussed, have int's that are only 16 bits wide so signed can hold only -32768..+32767 and unsigned can hold only 0..65535. If you generate numbers bigger than this range you make need to spill into an unsigned long. This "problem" generally doesn't occur on PCs where int is 32bits wide (the width of a long on AVR) and can hold 0..4,294,967,295 so numeric overflow in the middle of a calculation is seldom a problem. If "signed" that range is -2147483648..+2147483647 - but that still holds some pretty big numbers!)

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

Thanks, I would appreciate it for the directions.

Just one question, if ADC_Value is a long int, it won't spill if I do that calcualtion right? Hence, I do not need to put the UL anymore?