| Author |
Message |
|
|
Posted: Jun 04, 2011 - 02:20 PM |
|

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 |
|
|
| |
|
|
|
|
|
Posted: Jun 04, 2011 - 02:23 PM |
|


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. |
_________________
|
| |
|
|
|
|
|
Posted: Jun 04, 2011 - 02:48 PM |
|

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 |
|
|
| |
|
|
|
|
|
Posted: Jun 04, 2011 - 05:06 PM |
|

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.
|
| |
|
|
|
|
|
Posted: Jun 04, 2011 - 07:11 PM |
|

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... |
|
|
| |
|
|
|
|
|
Posted: Jun 04, 2011 - 08:43 PM |
|

Joined: Aug 07, 2007
Posts: 1474
Location: Czech
|
|
|
|
|
|
|
Posted: Jun 04, 2011 - 08:58 PM |
|

Joined: Aug 07, 2007
Posts: 1474
Location: Czech
|
|
|
|
|
|
|
Posted: Jun 27, 2011 - 10:19 AM |
|

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.  |
|
|
| |
|
|
|
|
|
Posted: Jun 27, 2011 - 10:41 AM |
|


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;
|
_________________
|
| |
|
|
|
|
|
Posted: Jun 27, 2011 - 11:11 AM |
|

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
|
| |
|
|
|
|
|
Posted: Jun 27, 2011 - 07:35 PM |
|

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 |
|
|
| |
|
|
|
|
|
Posted: Jun 27, 2011 - 07:41 PM |
|


Joined: Jul 18, 2005
Posts: 62281
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
|
Quote:
I start debuging
Simulator or real hardware debugging? |
_________________
|
| |
|
|
|
|
|
Posted: Jun 27, 2011 - 07:46 PM |
|

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. |
|
|
| |
|
|
|
|
|
Posted: Jun 27, 2011 - 07:59 PM |
|


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? |
_________________
|
| |
|
|
|
|
|
Posted: Jun 27, 2011 - 10:43 PM |
|

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
|
| |
|
|
|
|
|
Posted: Jun 29, 2011 - 02:27 PM |
|

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  |
|
|
| |
|
|
|
|
|
Posted: Jun 29, 2011 - 02:29 PM |
|


Joined: Jul 18, 2005
Posts: 62281
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
| Your code makes no sense whatsoever?!? |
_________________
|
| |
|
|
|
|
|
Posted: Jun 29, 2011 - 02:37 PM |
|

Joined: Dec 28, 2008
Posts: 47
Location: Italy
|
|
|
Quote:
Your code makes no sense whatsoever?!?
...Ok I give it up... |
|
|
| |
|
|
|
|
|
Posted: Jun 29, 2011 - 03:14 PM |
|

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. |
|
|
| |
|
|
|
|
|
Posted: Jun 29, 2011 - 04:05 PM |
|


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. |
|
|
| |
|
|
|
|
|
Posted: Jun 29, 2011 - 04:36 PM |
|


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
|
_________________
|
| |
|
|
|
|
|
Posted: Jun 30, 2011 - 05:27 AM |
|

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 ) ? |
_________________ 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
|
| |
|
|
|
|
|
Posted: Jun 30, 2011 - 08:59 AM |
|

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. |
|
|
| |
|
|
|
|
|
Posted: Jun 30, 2011 - 09:38 PM |
|

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. |
|
|
| |
|
|
|
|
|
Posted: Jun 30, 2011 - 10:24 PM |
|

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
|
| |
|
|
|
|
|
Posted: Jul 01, 2011 - 07:35 AM |
|

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.
|
| |
|
|
|
|
|
Posted: Jul 08, 2011 - 06:04 PM |
|

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 |
|
|
| |
|
|
|
|
|
Posted: Jul 08, 2011 - 06:14 PM |
|


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?!? |
_________________
|
| |
|
|
|
|
|
Posted: Jul 08, 2011 - 06:39 PM |
|

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...) |
|
|
| |
|
|
|
|
|
Posted: Jul 08, 2011 - 06:41 PM |
|

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. |
|
|
| |
|
|
|
|
|
Posted: Jul 09, 2011 - 03:23 AM |
|

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. |
|
|
| |
|
|
|
|
|
Posted: Jul 09, 2011 - 11:14 AM |
|

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. |
|
|
| |
|
|
|
|
|
Posted: Jul 09, 2011 - 02:37 PM |
|


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. |
_________________
|
| |
|
|
|
|
|
Posted: Jun 09, 2012 - 09:43 AM |
|

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 !! |
|
|
| |
|
|
|
|
|