Forum Menu




 


Log in Problems?
New User? Sign Up!
AVR Freaks Forum Index

Post new topic   Reply to topic
View previous topic Printable version Log in to check your private messages View next topic
Author Message
loutek
PostPosted: Jun 04, 2011 - 02:20 PM
Rookie


Joined: Dec 28, 2008
Posts: 47
Location: Italy

Hi all, I want to read a multiple ADC input without using interrupt.CPU running at 8 Mhz
I use this sub:
Code:
uint16_t Read_ADC (uint8_t ch)  {
ADMUX = (1<<REFS0);   //AVCC as ADC Voltage Reference
  ADCSRA = (1<<ADEN) | (1<< ADPS2); //enable ADC, prescale 16
ch = ch&0b00000111;
ADMUX |= ch;
 
  ADCSRA |= (1<<ADSC);
  while (!(ADCSRA & (1<<ADIF)));
  ADCSRA |= (1<<ADIF);
  return ADC;
  }

read the input value and in main:
Code:
int main() {
   DDRB = 0xFF;
   uint16_t ADC_result = 0;
   int i;
    USART_init();
   adc_Init();
   while (1) {
      for (i = 0; i < 3; i++) { //start the scan...
         ADC_result = Read_ADC(i); //and read the result
         switch (i) { ...then i use the value to do something
.........


But nothing happens.
However if I remove the for loop and
Code:
ADC_result = Read_ADC(0);

i can read the ADC value.
Any suggestion?

thank you
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Jun 04, 2011 - 02:23 PM
10k+ Postman


Joined: Jul 18, 2005
Posts: 62281
Location: (using avr-gcc in) Finchingfield, Essex, England

Not enough context. Show more of the code and explain "nothing happens" and how you are observing that.

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
loutek
PostPosted: Jun 04, 2011 - 02:48 PM
Rookie


Joined: Dec 28, 2008
Posts: 47
Location: Italy

By now i just want to read a voltage on ADC0 and ADC1 and turn on/off a led.
Code:

nt main() {
   DDRB = 0xFF;
   uint16_t ADC_result = 0;
   int i;
    USART_init();
   adc_Init();
   while (1) {
      for (i = 1; i < 3; i++) {
         ADC_result = Read_ADC(i);
         switch (i) {
         case 1:
            if (ADC_result < 120) {
               PORTB = 0x01;
                   
            }
            else if (ADC_result > 150) {
               PORTB = 0x00;
               
            }

         case 2:
            if (ADC_result < 120) {
               PORTB = 0x01;
                   
            }
            else if (ADC_result > 150) {
               PORTB = 0x00;
               
            }

         }
      }
      }
      return 0;
   }

no led is turned on/off
Thank
 
 View user's profile Send private message  
Reply with quote Back to top
Koshchi
PostPosted: Jun 04, 2011 - 05:06 PM
10k+ Postman


Joined: Nov 17, 2004
Posts: 13828
Location: Vancouver, BC

Quote:
By now i just want to read a voltage on ADC0 and ADC1 and turn on/off a led.
Code:
for (i = 1; i < 3; i++) {
         ADC_result = Read_ADC(i);
But this reads ACD1 and ADC2.

_________________
Regards,
Steve A.

The Board helps those that help themselves.
 
 View user's profile Send private message  
Reply with quote Back to top
loutek
PostPosted: Jun 04, 2011 - 07:11 PM
Rookie


Joined: Dec 28, 2008
Posts: 47
Location: Italy

@koshch
you're right... But not working at all
Code:
for (i=0; i 2; i++)

i'll try another solution...
 
 View user's profile Send private message  
Reply with quote Back to top
Visovian
PostPosted: Jun 04, 2011 - 08:43 PM
Posting Freak


Joined: Aug 07, 2007
Posts: 1474
Location: Czech

deleted
 
 View user's profile Send private message  
Reply with quote Back to top
Visovian
PostPosted: Jun 04, 2011 - 08:58 PM
Posting Freak


Joined: Aug 07, 2007
Posts: 1474
Location: Czech

Quote:
ADMUX = (1<<REFS0); //AVCC as ADC Voltage Reference
ADCSRA = (1<<ADEN) | (1<< ADPS2); //enable ADC, prescale 16
ch = ch&0b00000111;
ADMUX |= ch;

Error, look here
http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=107120&highlight=
 
 View user's profile Send private message  
Reply with quote Back to top
loutek
PostPosted: Jun 27, 2011 - 10:19 AM
Rookie


Joined: Dec 28, 2008
Posts: 47
Location: Italy

Thank you all...
Ok... Reading other posts it is better to use interrupt.
So that's my way:
Code:

/*
 ATmega16 @ 8 Mhz
 PORTA as ADC
 PORTB leds
           */

#include <avr/io.h>
#include <avr/interrupt.h>
#include <inttypes.h>

volatile uint8_t adc_result[8];
volatile uint8_t input = 0; // both var. volatite because shared by main and ISR ...clawson FAQ #1

void ADC_init(void);

int main(void) {
   DDRB = 0xFF; // PORTB as Out
   ADC_init();  //init ADC
   sei(); // enable all interrupts
   ADCSRA |= (1 << ADSC); // first ADC conversion

   while (1) {

      if (adc_result[0] > 150) {
         PORTB = 0x01;
      } else if (adc_result[0] < 150) {
         PORTB = 0x00;
      }

      if (adc_result[1] > 150) {
         PORTB = 0x02;
      } else if (adc_result[1] < 150) {
         PORTB = 0x00;
      }
   }
   return 0;
}

ISR( ADC_vect ) {
   adc_result[input] = ADCH; // input 0, first result, 8 bits
   if (input < 8)
   input++;
   else
   input = 0;

   ADMUX |= input; // next input
   ADCSRA |= ( 1 << ADSC ); // next conversion
}

void ADC_init() {
    ADMUX |= (1 << ADLAR) | (1 << REFS0); // left adj. and AVcc as reference
   ADCSRA = (1 << ADEN) | (1 << ADIE) | (1 << ADPS2); // Enable ADC, interrupt, prescaler 16
}


...but I can't see any led on. Sad
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Jun 27, 2011 - 10:41 AM
10k+ Postman


Joined: Jul 18, 2005
Posts: 62281
Location: (using avr-gcc in) Finchingfield, Essex, England

Quote:

ADMUX |= input; // next input

You never clear the previous channel setting. Suggest you use:
Code:
ADMUX = (1 << ADLAR) | (1 << REFS0) | channel;

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
indianajones11
PostPosted: Jun 27, 2011 - 11:11 AM
Raving lunatic


Joined: Nov 28, 2004
Posts: 3552
Location: San Diego, Ca

Also, one time code should be done... once . Put

Code:
ADMUX = (1<<REFS0);   //AVCC as ADC Voltage Reference
  ADCSRA = (1<<ADEN) | (1<< ADPS2); //enable ADC, prescale 16
in your adc_init() ( which you already did, so no need to repeat the same stuff ). It's just a waste of time / memory to do it the way you did .

Your code with the switch is not right, time to open your C book and look at that.

_________________
1) Studio 4.18 build 716 (SP3)
2) WinAvr 20100110
3) PN, all on Doze XP... For Now
A) Avr Dragon ver. 1
B) Avr MKII ISP, 2009 model
C) MKII JTAGICE ver. 1
 
 View user's profile Send private message  
Reply with quote Back to top
loutek
PostPosted: Jun 27, 2011 - 07:35 PM
Rookie


Joined: Dec 28, 2008
Posts: 47
Location: Italy

Hello, when I start debuging the changed code
Code:

#include <avr/io.h>
#include <avr/interrupt.h>
#include <inttypes.h>

volatile uint8_t adc_result[8];
volatile uint8_t input = 0; // both var. volatite because shared by main and ISR ...clawson FAQ #1


int main(void) {
   DDRB = 0xFF; // PORTB as Out
   ADMUX |= (1 << ADLAR) | (1 << REFS0); // left adj. and AVcc as reference
   ADCSRA = (1 << ADEN) | (1 << ADIE) | (1 << ADPS2); // Enable ADC, interrupt, prescaler 16
   sei(); // enable all interrupts
   ADCSRA |= (1 << ADSC); // first ADC conversion
   while (1) {
      if (adc_result[0] > 120) {
         PORTB = 0x01;
      } else if (adc_result[0] < 120) {
         PORTB = 0x00;
      }

      if (adc_result[1] > 120) {
         PORTB = 0x02;
      } else if (adc_result[1] < 120) {
         PORTB = 0x00;
      }
     
   }
   return 0;
}

ISR( ADC_vect ) {
   adc_result[input] = ADCH; // input 0, first result, 8 bits
   if (input < 8)
   input++;
   else
   input = 0;

   ADMUX |= (input & 0x07); // next input and mask the bits
   ADCSRA |= ( 1 << ADSC ); // next conversion

     }

I can see in the I/O view no ADSC setted by
Code:
ADCSRA |= (1 << ADSC); // first ADC conversion
instruction
I think code is correct but I can't check where is my error or what I can't understand.

Thank you
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Jun 27, 2011 - 07:41 PM
10k+ Postman


Joined: Jul 18, 2005
Posts: 62281
Location: (using avr-gcc in) Finchingfield, Essex, England

Quote:

I start debuging

Simulator or real hardware debugging?

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
loutek
PostPosted: Jun 27, 2011 - 07:46 PM
Rookie


Joined: Dec 28, 2008
Posts: 47
Location: Italy

...real hardware debugging. I test hardware too and things work... i think it's a programming issue..
Thank you very much for reply.
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Jun 27, 2011 - 07:59 PM
10k+ Postman


Joined: Jul 18, 2005
Posts: 62281
Location: (using avr-gcc in) Finchingfield, Essex, England

Quote:

ADMUX |= (input & 0x07); // next input and mask the bits

This is not right - you are NOT clearing the previous channel selection - presumably you did not understand my previous answer?

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
indianajones11
PostPosted: Jun 27, 2011 - 10:43 PM
Raving lunatic


Joined: Nov 28, 2004
Posts: 3552
Location: San Diego, Ca

I doubt that you put a breakpoint and then single-stepped into the ADSC being set, because you didn't see it , but you didn't say the ISR DIDN'T fire , OR that you didn't get adc_values . If you run the debugger at full speed, there's plenty you'll miss, if that's what you're doing .

Anyway, you're bouncing all around with these code versions and it's not a good move to go from non-working code to a more complex non-working version ( ISR ).

How are ALL your MCU adc pins connected and which debugger do you use ? Put adc_result in the watch window and breakpoint after it should get a value in the ISR .

You don't see any LEDs on, but only superman could since it would be too fast for you to see . You have no delays for when it's on / off .

_________________
1) Studio 4.18 build 716 (SP3)
2) WinAvr 20100110
3) PN, all on Doze XP... For Now
A) Avr Dragon ver. 1
B) Avr MKII ISP, 2009 model
C) MKII JTAGICE ver. 1
 
 View user's profile Send private message  
Reply with quote Back to top
loutek
PostPosted: Jun 29, 2011 - 02:27 PM
Rookie


Joined: Dec 28, 2008
Posts: 47
Location: Italy

to clear the previus channel:
Code:
 
ISR( ADC_vect ) {
   for (input=0; input <8; input++) {
        input = ADMUX;
        input &= 0x07;
        adc_result[input] = ADCH;
        ADMUX++;
      ADCSRA |= (1 << ADSC); // next ADC conversion
     }
    ADMUX &= 0xF0;
    }


Now if a simulator debug i can see ADSC setted, in real debug with avr dragon no ADSC is setted Confused Confused
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Jun 29, 2011 - 02:29 PM
10k+ Postman


Joined: Jul 18, 2005
Posts: 62281
Location: (using avr-gcc in) Finchingfield, Essex, England

Your code makes no sense whatsoever?!?

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
loutek
PostPosted: Jun 29, 2011 - 02:37 PM
Rookie


Joined: Dec 28, 2008
Posts: 47
Location: Italy

Quote:
Your code makes no sense whatsoever?!?

...Ok I give it up...
 
 View user's profile Send private message  
Reply with quote Back to top
Kartman
PostPosted: Jun 29, 2011 - 03:14 PM
Raving lunatic


Joined: Dec 30, 2004
Posts: 8763
Location: Melbourne,Australia

Go back to your original code and fix the problems. Have you read the datasheet onthe part you're using? It is all pretty simple, but you're making some fundamental mistakes.
 
 View user's profile Send private message  
Reply with quote Back to top
JohanEkdahl
PostPosted: Jun 29, 2011 - 04:05 PM
10k+ Postman


Joined: Mar 27, 2002
Posts: 18545
Location: Lund, Sweden

In your latest code, what is the point with doing
Code:
        ADMUX++;

?
Youre at the end of the loop, just about to iterate and increment input which will then be assigned to ADMUX.
 
 View user's profile Send private message Visit poster's website 
Reply with quote Back to top
clawson
PostPosted: Jun 29, 2011 - 04:36 PM
10k+ Postman


Joined: Jul 18, 2005
Posts: 62281
Location: (using avr-gcc in) Finchingfield, Essex, England

Johan,

That's just one of many things. He's clearly using interrupts yet switches to a polling method in the ISR. That polling method, rather sadly does not actually poll the thing it's supposed to. And, as you say, the ADMUX++ thing is just plain odd given that he already has an iterator. As I said previously:
Quote:

Your code makes no sense whatsoever

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
indianajones11
PostPosted: Jun 30, 2011 - 05:27 AM
Raving lunatic


Joined: Nov 28, 2004
Posts: 3552
Location: San Diego, Ca

You keep saying you don't see ADSC set or LEDs come on, but you didn't do ANY of the things I suggested either, huh ( I'm banking that you don't REALLY know how to use the debugger / IDE in a totally correct way and it's part of your confusion with the i/o view. Another time for THAT though. ) ? STOP changing ( supposedly ) non-working code into different versions ( It makes no sense for you to do the for{} in the ISR, considering all it needs is an inc. of the index. You went from ( bad ? ) to definitely worse with that 1. ) .

DON'T enable any ISRs, do the init() and in your while(1) JUST have an led turn ON at a threshold value ( verify what the # should be with a DVM ), disable the adc and NOTHING ELSE ( for now ) in the while loop . That means take the for loop OUT. Whether this works ( should ) or not, don't change it until it's working ( post ALL the code and let's work with that. Don't make any functions yet, keep it out in the open for now. ). Make sure you're connected to CHANNEL 0. Modify your OP code version and tell us what happens with THAT . After starting the conversion, do these before the while(1):

Code:
while( ADCSRA & ( 1<< ADSC ) ); // wait under conversion done
adc_result[0] = ADCH;  // Then test if this is > 120

Is your adc hooked up right based on the REF bits, and do you have the cap. on the Aref pin ( you never answered my question about all that Rolling Eyes ) ?

_________________
1) Studio 4.18 build 716 (SP3)
2) WinAvr 20100110
3) PN, all on Doze XP... For Now
A) Avr Dragon ver. 1
B) Avr MKII ISP, 2009 model
C) MKII JTAGICE ver. 1
 
 View user's profile Send private message  
Reply with quote Back to top
loutek
PostPosted: Jun 30, 2011 - 08:59 AM
Rookie


Joined: Dec 28, 2008
Posts: 47
Location: Italy

@ indianajones11

Thank you very much for the reply (and patience!!)
as soon as possible I will do what you suggest me.


L.
 
 View user's profile Send private message  
Reply with quote Back to top
loutek
PostPosted: Jun 30, 2011 - 09:38 PM
Rookie


Joined: Dec 28, 2008
Posts: 47
Location: Italy

Quote:
DON'T enable any ISRs, do the init() and in your while(1) JUST have an led turn ON at a threshold value ( verify what the # should be with a DVM ), disable the adc and NOTHING ELSE ( for now ) in the while loop

Code:

#include <avr/io.h>

int main(void) {
   DDRB = 0xFF;
   ADMUX |= (1 << REFS0) | (1 << ADLAR); //AVCC as ref. and left adj.
   ADCSRA |= (1 << ADEN) | (1 << ADPS2) | (1 << ADPS1); //enable ADC, prescale to 64: 125 kHz @ 8 Mhz
    ADCSRA |= (1 << ADSC); // start conversion
   while (1) {
      if (ADCH < 120) {
         PORTB |= 0x01;
         } else if (ADCH > 120) {
            PORTB = 0x00;
         }
      ADCSRA &=~ (1<<ADEN);  //disable ADC
   }
   return 0;
}

Quote:

After starting the conversion, do these before the while(1):

Code:
while( ADCSRA & ( 1<< ADSC ) ); // wait under conversion done
adc_result[0] = ADCH; // Then test if this is > 120

Code:

#include <avr/io.h>

int main(void) {
       int result = 0;
   DDRB = 0xFF;
   ADMUX |= (1 << REFS0) | (1 << ADLAR); //AVCC as ref. and left adj.
   ADCSRA |= (1 << ADEN) | (1 << ADPS2) | (1 << ADPS1); //enable ADC, prescale to 64: 125 kHz @ 8 Mhz
    ADCSRA |= (1 << ADSC); // start conversion
    while( ADCSRA & ( 1<< ADSC ) ); // wait under conversion done
    result = ADCH
   while (1) {
      if (result < 120) {
         PORTB |= 0x01;
         } else if (result > 120) {
            PORTB = 0x00;
         }
      ADCSRA &=~ (1<<ADEN);  //disable ADC
   }
   return 0;
}


I always see a led turn ON... I think I should
Code:

ADCSRA |= (1 << ADSC); // start conversion
    while( ADCSRA & ( 1<< ADSC ) ); // wait under conversion done

in the while (1) loop and then
Code:
ADCSRA |= (1 << ADIF);
as the datasheet says to clear ADIF by writing a logical one to the flag.

Thank you.
 
 View user's profile Send private message  
Reply with quote Back to top
indianajones11
PostPosted: Jun 30, 2011 - 10:24 PM
Raving lunatic


Joined: Nov 28, 2004
Posts: 3552
Location: San Diego, Ca

Good work ! I use ADSC since it auto-clears when a convert is done. ADIF takes an extra line, but works too. You can redo it for constant converts in the while, just code it right. Don't just try ANYTHING, THINK(!!) about stuff at each point and come up with code that makes sense ( BE the cpu ), if you have to do it line by line . Don't write alot of code and then test it... do it little by little. My point in asking you to code what you have NOW is start with something you KNOW works and go from there.

NOW you can think about using a for loop ( NO Switch or anything else yet ! )to read X number of values into your array and when the loop's done, use dragon to confirm that ALL channels, that you want, are there. Build it gradually and then you're ready to try it with an ISR ( ADC_ISR isn't the best way, like you state from 1 of your posts, it's used IF NEEDED that's all. ). You now know better from this thread what should/shouldn't go in the init() / read() AND the correct way to change channels. Put your init() and read() back in when you're ready.

If you want to see ADSC clr in i/o view, open disassembly window and breakpoint or run...cursor to the line just below that loop. Running full speed, it sets/clrs too fast and it just appears to always be set.

_________________
1) Studio 4.18 build 716 (SP3)
2) WinAvr 20100110
3) PN, all on Doze XP... For Now
A) Avr Dragon ver. 1
B) Avr MKII ISP, 2009 model
C) MKII JTAGICE ver. 1
 
 View user's profile Send private message  
Reply with quote Back to top
Koshchi
PostPosted: Jul 01, 2011 - 07:35 AM
10k+ Postman


Joined: Nov 17, 2004
Posts: 13828
Location: Vancouver, BC

Quote:
Code:
while( ADCSRA & ( 1<< ADSC ) ); // wait under conversion done
in the while (1) loop and then
Code:
ADCSRA |= (1 << ADIF);

as the datasheet says to clear ADIF by writing a logical one to the flag.
If you are checking the ADSC flag, there is no need to clear the ADIF flag. You only need to do that if it is the ADIF flag that you are checking.

_________________
Regards,
Steve A.

The Board helps those that help themselves.
 
 View user's profile Send private message  
Reply with quote Back to top
eventhorizon
PostPosted: Jul 08, 2011 - 06:04 PM
Newbie


Joined: Jul 08, 2011
Posts: 8


Hi! For multiple ADC's what I did was instead of iterating the ADMUX to switch the ADC input, I connected several sensors between a different ports to a single ADC port. And what I meant by that is PD0 to PC0, PD1 to PC0, PD2 to PC0.... Instead of connecting your sensor from Vcc to your ADC input, you get power from some other port and then switch those ports. I would happily code and make a schematic of it for you guys you you'd like
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Jul 08, 2011 - 06:14 PM
10k+ Postman


Joined: Jul 18, 2005
Posts: 62281
Location: (using avr-gcc in) Finchingfield, Essex, England

So you are multiplexing externally when the AVR contains an multiplexer internally? Very odd?!?

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
eventhorizon
PostPosted: Jul 08, 2011 - 06:39 PM
Newbie


Joined: Jul 08, 2011
Posts: 8


Well yes, given that you have like 2 or more sensors to read, you'd eventually use several ADC pins too. With that for an atmega8 with only 5 ADC pins, could be increased to <5 * unused_ports> (now who would use that much sensors...)
 
 View user's profile Send private message  
Reply with quote Back to top
eventhorizon
PostPosted: Jul 08, 2011 - 06:41 PM
Newbie


Joined: Jul 08, 2011
Posts: 8


BTW, I'm not sure if you could read two or more ADC pins at-the-same-time. By externally multiplexing the sensors, you could scan 2 or more sensors in parallel, or what ever combination you want.
 
 View user's profile Send private message  
Reply with quote Back to top
Kartman
PostPosted: Jul 09, 2011 - 03:23 AM
Raving lunatic


Joined: Dec 30, 2004
Posts: 8763
Location: Melbourne,Australia

Eventhorizon, there is only 1 adc but there is a number of analog inputs on the AVR. You can only convert one at a time.
 
 View user's profile Send private message  
Reply with quote Back to top
eventhorizon
PostPosted: Jul 09, 2011 - 11:14 AM
Newbie


Joined: Jul 08, 2011
Posts: 8


Yes Kartman I'm aware of that. I just gave another method of reading multiple sensors through 1 ADC by multiplexing sensors externally. Say, an ATMega8 only has 5 ADC pins, but you need to scan 10 sensors, you could use 5 other ports for 1 ADC, then another 5 on another ADC. It's not the conventional way of doing it, but it works and I'm using using it on my sumobot.
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Jul 09, 2011 - 02:37 PM
10k+ Postman


Joined: Jul 18, 2005
Posts: 62281
Location: (using avr-gcc in) Finchingfield, Essex, England

Most mega AVRs have 8 mux inputs so why add the additional hardware overhead of an external mux until you run out of 8. Though I agree you are forced to do this for 10 channels on a 5 channel MCU.

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
loti1990
PostPosted: Jun 09, 2012 - 09:43 AM
Newbie


Joined: Nov 26, 2011
Posts: 1


Code:
uint16_t Adc_Read(uint8_t adc_input){
   
   uint8_t low_bit=0;
   uint16_t avrage=0;
   ADMUX=(ADMUX & 0xf0)|adc_input;
   _delay_us(10);
   
for(int i=0;i<31;i++){
ADCSRA|=1<<ADSC);         
while(!(ADCSRA & (1<<ADIF)));   
low_bit=ADCL;
avrage+=(uint16_t)((ADCH<<8)|low_bit);   
    ADCH=0;
    ADCL=0;
   }
   return(uint16_t)(avrage/30);   
}


That functions works excellent !!
 
 View user's profile Send private message  
Reply with quote Back to top
Display posts from previous:     
Jump to:  
All times are GMT + 1 Hour
Post new topic   Reply to topic
View previous topic Printable version Log in to check your private messages View next topic
Powered by PNphpBB2 © 2003-2006 The PNphpBB Group
Credits