0

I want to work with two analog sensors connected to ATmega16. The first one is the temperature sensor (LM35), connected to PA0. The LED should be ON when the temperature goes high. The second one is the photo-resistor and it's connected to PA1. I want to turn the LED ON when the lighting is low. I was looking for a solution all over the internet, but couldn't find something similar to my situation. They all just say one thing- you can't read two analog sensors at the same time.

I have this code that works just for one sensor:

#define F_CPU 1600000UL
#include <avr/io.h>

void ADC_Init() {
    DDRA = 0x0;
    ADCSRA = 0x87;
    ADMUX = 0x40;
}

uint16_t ADC_Read(uint8_t channel) {
    ADMUX = (ADMUX & 0xF0) | (channel & 0x0F);
    ADCSRA |= (1 << ADSC);
    while (ADCSRA & (1 << ADSC)) ;
    return ADC;
}

int main(void) {
    ADC_Init();
    DDRB = 0xFF;
    while (1) {
        uint8_t value;
        value = ADC_Read(0);
        if (value > 70) {
            PORTB |= (1<<0);
        } else {
            PORTB &= ~(1<<0);
        }
    }
}

Can you somehow help me to modify this code, give me advice on how can I do it, or some example?

4
  • What happens when you change ADC_Read(0) to ADC_Read(1)?
    – devnull
    Apr 18, 2022 at 17:44
  • 1
    @devnull it works just for one sensor at a time. If I go with ADC_Read(1), it will work for the second sensor. I tried to adjust it using a switch loop, the first case ADC_Read(0), the second one ADC_Read(1), but it won't work.
    – cerouno
    Apr 18, 2022 at 17:57
  • Good. Since the MCU can't do any two things programmatically at the same time, you can read from channel 0 to one variable, read from channel 1 to another variable, than decide what to do with the LED(s) accordingly to the two values. You may also edit your question to show this second code you mentioned, since your test indicates that the hardware/ADC part is already working for the two sensors.
    – devnull
    Apr 18, 2022 at 18:00
  • 1
    I reformatted the code for legibility and, while doing so, I took the liberty to add the closing brace that was missing from ADC_Init(). Apr 18, 2022 at 18:24

1 Answer 1

0

I just skimmed over the ATmega16 datasheet, so perhaps take this answer with a grain of salt.

It is technically true that you cannot read two ADC channels at the same time because there is only one ADC and you must multiplex the various channel inputs to that one ADC. You can, most likely, change the ADC source at runtime to switch between the different channels.

Take a look at the ADMUX register description in the datasheet

Right now, you set the mux once during the init() function and then never change it. In your new code, you will have to change the value in the register at runtime (in addition to any other configuration/housekeeping that is required) which should happen in your main loop()

High level description:

int main()
{
    system_init();
    
    while (1)
    {
        set ADMUX to read from PA0
        read ADC

        set ADMUX to read from PA1
        read ADC

        do stuff
    }

}
3
  • I understand what you mean, but if I do it in the main loop it won't run infinitely, and the channel will be changed only once. How can I constantly change between those two sensors?
    – cerouno
    Apr 19, 2022 at 9:47
  • @cerouno If you put the above code in your while (1) loop it will run indefinitely. I will edit the pseudocode above to show this. Apr 19, 2022 at 17:06
  • If you read the datasheet carefully, you will find the fact, that you should throw out the first reading after the input switch operation.
    – gbg
    Jan 14 at 20:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.