Enabling Atmega 2560 Analog ports ADC0 to ADC15

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

Good day guys.  I would like to ask for your advice on how to enable all the analog ports of Atmega 2560 ADC0 to ADC15.  I found out that MUX5 is in the ADCSRB register and not in the ADCSRA which makes it a little tricky.  How shall I set the configuration?

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

Welcome to AVRFreaks!

there is only one ADC, so you select one channel via the mux and do a conversation, then set up the mux for the next one, rinse and repeat!

 

An Arduino mega is similar, so if you need a way to experiment, that is a good way to get familiar with it and you can find lots of examples to examine.

 

jim

 

 

(Possum Lodge oath) Quando omni flunkus, moritati.

"I thought growing old would take longer"

 

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

ki0bk wrote:

Welcome to AVRFreaks!

there is only one ADC, so you select one channel via the mux and do a conversation, then set up the mux for the next one, rinse and repeat!

 

An Arduino mega is similar, so if you need a way to experiment, that is a good way to get familiar with it and you can find lots of examples to examine.

 

jim

 

Thank you Sir for the hint. Do you have a code that I can refer to?

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

First separate your new mux value  (0-31)  into ADC mux bit 5 and bits 4 - 0.   uint8_t myMUX5 = myADCmux & b00100000;  uint8_t myMUX40 = myADCmux & b00011111;

Then read ADCSRB,  clear bit 5 of the read value, and OR the read value with myMUX5.  Write the updated value back to ADCSRB.

Read ADCSRA, clear bits 4-0, and OR with myMUX40. Write the updated value back to ADCSRA.

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

ryan2019 wrote:
Thank you Sir for the hint. Do you have a code that I can refer to?

google github Arduino core

in github look for core_arduino

then wire analog

you will find the analog read function there

it is much as simonetta said, if channel is >7 set mux5 bit

the AVR ADC is easy to use, but you must set correct clock speed for the conversion, all is in the data sheet.

Search tutorial forum here for example adc code.

 

jim

 

(Possum Lodge oath) Quando omni flunkus, moritati.

"I thought growing old would take longer"

 

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

ki0bk and Simonetta thank you for the hints.

I tried to do the suggestions and I came up with the code below.  However it does not work as expected.

What I am trying to do is to:

1.  Sense analog input at ADC1 and when threshold 2.5V is hit the PB6 activates.

2.  Sense analog input at ADC8 and when threshold 4V is hit the PB5 activates.

 

I separated the functions to read ADC0 to ADC7 and ADC8 to ADC15 using the ADMUX and ADCSRB registers.

However both outputs does not respond to the analog inputs.  And what I found out is analog ADC9 input activates 

both PB6 at 2.5V and PB5 at 4V.  May I ask why it behaves this way?

 

 



#include <avr/io.h>                                            
#define F_CPU 16000000
#include <util/delay.h>


void ADC_init(void)                                           //ADC initialization
{
	ADMUX|=(1<<REFS0);
	ADCSRA|=(1<<ADEN)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);
}

uint16_t ADC_read(uint16_t ch)                                 //ADC read
{
	ch&=0x07;
	ADMUX&=0xF8;                                                //clear old analog channel
	ADMUX|=ch;                                                  //set new analog channel
	ADCSRA|=(1<<ADSC);                                          //Start Single conversion
	while(!(ADCSRA&(1<<ADIF)));                                 //Wait for conversion to complete
	ADCSRA|=(1<<ADIF);
	return (ADC);                                               //10 bit ADC result
}

uint16_t ADC2_read(uint16_t ch2)
{
	ch2&=0x08;
	ADCSRB&=0xF7;
	ADCSRB|=ch2;
	ADCSRA|=(1<<ADSC);                                          //Start Single conversion
	while(!(ADCSRA&(1<<ADIF)));                                 //Wait for conversion to complete
	ADCSRA|=(1<<ADIF);
	return (ADC);
}

int main(void)
{
	
	DDRF=0x00;
	DDRK=0X00;
	DDRB=0xFF;                 
	ADC_init();                     //configure Analog to Digital Converter registers
	
	uint16_t AD_value1;
	uint16_t AD_value2;

	while(1)
	{
		for(int count=0; count<16; count++)			 
		{
			switch(count)
			{

				case 1:										//read analog 1
				AD_value1=ADC_read(1);
				if(AD_value1>=512)							//set threshold to 2.5V
				{
					PORTB|=(1<<6);							//enable Port B pin 6                  
				}
				else
				{
					PORTB&=~(1<<6);							//enable Port B pin 6                    
				}
				break;	
				
				case 8:										//read analog 8
				AD_value2=ADC2_read(8);
				if(AD_value2>=818)							//set threshold to 4V    
				{
					PORTB|=(1<<5);                           //enable Port B pin 5
				}
				else
				{
					PORTB&=~(1<<5);                          //disable Port B pin 5
				}
				break;	
			}
		}		
	}	
}



 

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

ryan2019 wrote:

ch2&=0x08;

This is changing unintended bits and your ref too!

This should be the same as the first ADC read (i.e. 0xF8)

Jim

Sorry false alert!

Actually, this should be similar to the adc read,

ch2 &= 0x07; // mask low 3 bits for channels 8-15

then set mux5 bit in ADCSRB

Jim

 

 

 

(Possum Lodge oath) Quando omni flunkus, moritati.

"I thought growing old would take longer"

 

Last Edited: Mon. Mar 16, 2020 - 03:31 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Lets try this again:

uint16_t ADC_read(uint16_t ch)                                 //ADC read
{
	ch &= 0x07;
	ADCSRB &= ~(1<<MUX5);  //use mux 0-7
	ADMUX  &= 0xF8;                                                //clear old analog channel
	ADMUX  |= ch;                                                  //set new analog channel
	ADCSRA |= (1<<ADSC);                                          //Start Single conversion
	while(ADCSRA & (1<<ADSC));                                 //Wait for conversion to complete

	return (ADC);                                               //10 bit ADC result
}

uint16_t ADC2_read(uint16_t ch2)
{
	ch2 &= 0x07;
	ADCSRB |= (1<<MUX5); //use mux 8-15
	ADCSRB |= ch2;
	ADCSRA |= (1<<ADSC);                                          //Start Single conversion
	while(ADCSRA & (1<<ADSC));                                 //Wait for conversion to complete

	return (ADC);
}

I think that will work better, as it clears mux5 on the low channels, and sets mux5 on the high channels.

 

Jim

 

 

(Possum Lodge oath) Quando omni flunkus, moritati.

"I thought growing old would take longer"

 

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

ki0bk wrote:

Lets try this again:

uint16_t ADC_read(uint16_t ch)                                 //ADC read
{
	ch &= 0x07;
	ADCSRB &= ~(1<<MUX5);  //use mux 0-7
	ADMUX  &= 0xF8;                                                //clear old analog channel
	ADMUX  |= ch;                                                  //set new analog channel
	ADCSRA |= (1<<ADSC);                                          //Start Single conversion
	while(ADCSRA & (1<<ADSC));                                 //Wait for conversion to complete

	return (ADC);                                               //10 bit ADC result
}

uint16_t ADC2_read(uint16_t ch2)
{
	ch2 &= 0x07;
	ADCSRB |= (1<<MUX5); //use mux 8-15
	ADCSRB |= ch2;
	ADCSRA |= (1<<ADSC);                                          //Start Single conversion
	while(ADCSRA & (1<<ADSC));                                 //Wait for conversion to complete

	return (ADC);
}

I think that will work better, as it clears mux5 on the low channels, and sets mux5 on the high channels.

 

Jim

 

 

Thank you for the hint Sir :)

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

Personally I'm not sure I see need the need for two separate functions. Just pass the full channel number into ADC_read() and then make the MUX5 (set/clear) determination from the passed channel number.