ADC MUX problem please help

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

Hi chaps

I am trying to write one program (actually part of the code for Light sequencer //previos post) for my atmega8 (1000 000 Hz clock frequency) but after spending hours simulating it in AVRstudio I need your help.

Well, I want to use 3 MUX ADC inputs ADC0,ADC1,ADC1 and then control three PWM otputs.
I wrote a program and simulated it in AVRstudio.
Everything should be fine but in fact microcotroller is not working properly.
When I give signal to ADC0 all diodes switch on and give the light which is not so bright.
It should work in the way that when i provide signal to ADC0 OCR1A increase its value and 1st diode gives light then when I provide ADC1 OCR1B should increase its value and switch on the diode 2 and so on...

Below is my code

#include


int ADC_read(void);

void mode1(void);



int main(void)
{
//setting ADC

ADCSRA|=((1<<ADEN)|(0<<ADPS2)|(1<<ADPS1)|(1<<ADPS0));//enable ADC and switch on dvision factor for 8 which means  250 kHz for ADC clock.
ADMUX|=((0<<REFS1)|(1<<REFS0)|(1<<ADLAR));//AREF, Internal Vref turned off! ADLAR set to one
ADCSRA|=(1<<ADSC); // do a single conversion first takes 25 cycles !!!

 
while(ADCSRA & (1<<ADSC)); //wait till coversion will be done


//setting PWM

DDRB|= ((1<<PIN3)|(1<<PIN2)|(1<<PIN1));setting PWM for output
TCCR1A|= ((0<<WGM11)|(1<<WGM10)|(1<<COM1A1)|(1<<COM1B1)); 
TCCR1B|= (1<<CS11); 
TCCR2|=((0<<WGM21)|(1<<WGM20)|(1<<COM21)|(0<<COM20)|(1<<CS21));

TCNT1=0x00; //wyzerowanie 2 timerow
TCNT2=0x00;

OCR1A=00;
OCR1B=00;
OCR2=00;

DDRD&=((0<<PIND0)&(0<<PIND1));




for(;;)
{

	mode1();
	
		

}

return(0);	
}


void mode1(void) 
{	int pomocnicza;

	ADMUX&=((0<<MUX3)&(0<<MUX2)&(0<<MUX1)&(0<<MUX0)); //Bass connected to Oc1a

    pomocnicza= ADC_read();
	OCR1A= pomocnicza;
	
	
	ADMUX|=((0<<MUX3)|(0<<MUX2)|(0<<MUX1)|(1<<MUX0)); //Mid-Tone podpiety do Oc1b
	pomocnicza= ADC_read();
	OCR1B= pomocnicza;

	ADMUX&=((0<<MUX3)&(0<<MUX2)&(0<<MUX1)&(0<<MUX0));//High-Tone connected Oc2
	ADMUX|=((0<<MUX3)|(0<<MUX2)|(1<<MUX1)|(0<<MUX0));
	pomocnicza= ADC_read();
	OCR2= pomocnicza;
}
int ADC_read(void)
{   

    int ADCr=0;

	ADCSRA|=(1<<ADSC); //do a single conversation
	while(ADCSRA & (1<<ADSC)); 	 //wait till coversion will be done
	
	          
	ADCr=ADCH;
	
	return ADCr; 
}






So my main question and concern is why it is not working as I want ??
Please help me with this tricky chank of code ;)

Thanks in Advance

Adam

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

There are clearly two parts to this program... reading the a/d channels. and controlling the pwm outputs. I humbly suggest that you get these pieces working separately. I always use the serial port for testing. You could have a menu item called 'r' to read the 3 a/ds and display their values. You can test with volume controls.... potentiometers. Use the az sx and dc keys to increment and decremnt the OCR values and see if the pusle width changes. (have a scope?). At some point, you will want to add analog or digital filters to the a/d samples to give some pattern to the lights.

Imagecraft compiler user

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

Yes that`s true I should test values from ADC at first to see if they are correct. Yes I have a scope.
But the worst thing is that I don`t know what can be wrong with the code ?? :roll:

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

I'm confused, what is this line supposed to achieve:

   ADMUX&=((0<<MUX3)&(0<<MUX2)&(0<<MUX1)&(0<<MUX0)); //Bass connected to Oc1a

Firsr 0<<anything is 0 so every element in that is 0 anyway. Then you binary-AND them all together. well 0&0&0&0 is 0. And then you AND the ADMUX register with this. Well ADMUX & 0 or, indeed, "anything & 0" is 0. So wouldn't:

ADMUX = 0;

have been easier??

I have a sneaking suspicion you had something else in mind. Remember that to set just one it in a REG you use:

REG |= (1<<bitname);

and to clear a bit you use:

REG &= ~(1<<bitname);

To set a couple of bits you use:

REG |= ((1<<bitname1) | (1<<bitname2));

and to clear just a couple of bits it's:

REG &= ~((1<<bitname1) | (1<<bitname2));

To the right of the = you would only be using | (an possibly ~) but never &. Also you would never use 0<<, it's always 1<<

Cliff

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

Yeah

What a shame :oops:

I thought that I graduated from being newbie to the next level but I was wrong ;) I was not able to set and clear bit :evil:
Thanks Cliff for great remarks !
By the way you wrote here in this post great short tutorial :D
Now everything works fine !

I can`t belive how i couldn`t notice in AVRstudio that i am clearing whole ADCSRA register :oops:

Good way is to take paper and a pencil and write these bits and see what`s going on :)

Once again thank you very much chaps for the great job you are making on this forum

Adam

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

Why not simplify your code and have ADC_read take the channel that you want to read (and have it return a char since that is what the value can fit in, and why use a temp variable to send it back).

unsigned char ADC_read(unsigned char channel)
{
    ADMUX = (ADMUX & 0xF0) | (channel << MUX0); 
    ADCSRA|=(1<<ADSC);
    while(ADCSRA & (1<<ADSC));
    return ADCH;
}

Regards,
Steve A.

The Board helps those that help themselves.

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

Quote:
Everything should be fine but in fact microcotroller is not working properly.

In the very most cases the controller does what the datasheet says..

Same here...

Klaus
********************************
Look at: www.megausb.de (German)
********************************