Separate Interrupt Handling using ADC

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

Hello,

How do I handle separate Interrupt for ADC0 and ADC1(my output is different for both inputs)?

Thanks,
Nilesh

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

You can't, there is only one ADC (and therefore only one ADC interrupt). You need to check in the ADC handler what channel is currently set and act accordingly.

Regards,
Steve A.

The Board helps those that help themselves.

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

Hello,

Thanks for your reply Koshchi.

as someone suggested me.

ISR(ADC_vect) 
{ 
   if (ADMUX & (1<<MUX0)) 
   { 
      // Code for channel 1 (well, odd numbers) 
   } 
   else 
   { 
       // Code for channel 0 (even) 
   } 
} 

But its not working.

- Nilesh

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

How do you define "not working"? How do you know it is not working?

Jim

 

Until Black Lives Matter, we do not have "All Lives Matter"!

 

 

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

And where is the rest of the code that sets the channels in the first place?

Regards,
Steve A.

The Board helps those that help themselves.

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

Yes "someone" suggested that in the ADC-tutorial :wink:. But I wasn't in the mood of pulling information out of you, therefore no response from me. But, as said, we need to know more.

- How do you set up the ADC?
- How/when/where do you change channel?
- Do you enable global interrupts?
- Do you disable them?

Maybe you could post a small test program that shows your problem?

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

Hello Jim,

Thank you for your reply.

Quote:
How do you define "not working"? How do you know it is not working?
I have made changes according suggested code, compile the code and write atmega8 and test on circuit but not worked here below my code according to suggested code.

Hello Koshchi,

Quote:
And where is the rest of the code that sets the channels in the first place?
Here below I'm pasting my code please look at that and let me know if anything missing.

Hello snigelen,

Quote:
Yes "someone" suggested that in the ADC-tutorial
Yes snigelen suggested me the code in ADC Tutorial :)

Here below my reply.

- How do you set up the ADC? >>I am not sure but is it like?

 ADMUX =| (1 << MUX0) | (1 << MUX1) //ADC0 and ADC1

I have tried with above code too but not worked.
- How/when/where do you change channel? >>How>Using Joystick,When>When I wants to reverse or forward motor, Where>ADC0 Pin 23, ADC1 Pin 24 (atmega8)
- Do you enable global interrupts? >>Yes Here below I'm pasting my code
- Do you disable them? >>No

My code

#include  
#include  

int main (void) 
{ 
   DDRB |= (1 << 0); // Set motor1 as output 
   DDRB |= (1 << 1); // Set motor1 as output 
   DDRB |= (1 << 2); // Set motor2 as output 
   DDRB |= (1 << 3); // Set motor2 as output

   ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); // Set ADC prescaler to 128 - 125KHz sample rate @ 16MHz 

   ADMUX |= (1 << REFS0); // Set ADC reference to AVCC 
   ADMUX |= (1 << ADLAR); // Left adjust ADC result to allow easy 8 bit reading 

   // No MUX values needed to be changed to use ADC0 

   ADCSRA |= (1 << ADFR);  // Set ADC to Free-Running Mode 
   ADCSRA |= (1 << ADEN);  // Enable ADC 

   ADCSRA |= (1 << ADIE);  // Enable ADC Interrupt 
   sei();   // Enable Global Interrupts 

   ADCSRA |= (1 << ADSC);  // Start A2D Conversions 

   for(;;)  // Loop Forever 
   { 
   } 
} 
ISR(ADC_vect) 
{ 
   if(ADMUX & (1<<MUX0))   //Joystick X    
    { 
   if(ADCH < 100) 
   { 
    PORTB |= (1 << 0);       // motor1 forward 
    PORTB &= ~(1 << 1);      // motor1 forward 
    } 
   else if(ADCH > 150) 
   { 
    PORTB |= (1 << 1);       // motor1 reverse 
    PORTB &= ~(1 << 0);      // motor1 reverse 
    } 
   else
      { 
    PORTB &= ~(1 << 0); //m1 stop(Joy center position) 
    PORTB &= ~(1 << 1); //m1 stop(Joy center position) 
    } 
   }                         //end of coding for ADC0 
    
   else if(ADMUX & (1<<MUX1)) //Joystick Y 
   { 
   if(ADCH < 100) 
   { 
    PORTB |= (1 << 2);       // motor2 forward 
    PORTB &= ~(1 << 3);      // motor2 forward 
    } 
   else if(ADCH > 150) 
   { 
    PORTB |= (1 << 3);       // motor2 reverse 
    PORTB &= ~(1 << 2);      // motor2 reverse 
   } 
   else 
   { 
    PORTB &= ~(1 << 3); //m2 stop(Joy center position) 
    PORTB &= ~(1 << 2); //m2 stop(Joy center position) 
    } 
   }                         //end of coding for ADC1 
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
ADCSRA |= (1 << ADFR); // Set ADC to Free-Running Mode
Free running, interrupts and multiple channels don't mix well. By the time the interrupt happens, the next conversion has already started, so your channel is one off. There is no real advantage to use free-running mode with interrupt or multiple channels. Just use single conversion and start the next conversion in the interrupt. Besides, your code as written never changes the channel anyways. You set channel 0, but only read the result if the channel is 1 or 2 (which means you never really read ADCH at all).

Also, you would be reading the result multiple times in the same interrupt. It is possible that the value has changed between reads. Read it once at the beginning, set the next channel, start the next conversion, then act on the result.

Regards,
Steve A.

The Board helps those that help themselves.

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

Thanks Steve,

Quote:
Read it once at the beginning, set the next channel, start the next conversion, then act on the result.
Is it possible for you to give me any code example.

Regards,
Nilesh

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

Preempting Steve:

void port_init(void) {
   DDRB |= (1 << 0); // Set motor1 as output 
   DDRB |= (1 << 1); // Set motor1 as output 
   DDRB |= (1 << 2); // Set motor2 as output 
   DDRB |= (1 << 3); // Set motor2 as output 
}

void ADC_init(void) {
   ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); // Set ADC prescaler to 128 - 125KHz sample rate @ 16MHz 
   ADMUX |= (1 << REFS0); // Set ADC reference to AVCC 
   ADMUX |= (1 << ADLAR); // Left adjust ADC result to allow easy 8 bit reading 
   // No MUX values needed to be changed to use ADC0 
   ADCSRA |= (1 << ADEN);  // Enable ADC 
   ADCSRA |= (1 << ADIE);  // Enable ADC Interrupt 
}

int main(void) {
   port_init();
   ADC_init();
   sei();
   // select channel 1
   ADMUX |= (1<<MUX0);
   // trigger very first interrupt to get started
   ADCSRA |= (1<<ADSC);
   while(1) {
   }
}

ISR(ADC_vect) 
{ 
   // channel 1
   if(ADMUX & (1<<MUX0))   //Joystick X    
    { 
   if(ADCH < 100) 
   { 
    PORTB |= (1 << 0);       // motor1 forward 
    PORTB &= ~(1 << 1);      // motor1 forward 
    } 
   else if(ADCH > 150) 
   { 
    PORTB |= (1 << 1);       // motor1 reverse 
    PORTB &= ~(1 << 0);      // motor1 reverse 
    } 
   else 
      { 
    PORTB &= ~(1 << 0); //m1 stop(Joy center position) 
    PORTB &= ~(1 << 1); //m1 stop(Joy center position) 
    } 
   }                         //end of coding for ADC0 
   // channel 2 
   else if(ADMUX & (1<<MUX1)) //Joystick Y 
   { 
   if(ADCH < 100) 
   { 
    PORTB |= (1 << 2);       // motor2 forward 
    PORTB &= ~(1 << 3);      // motor2 forward 
    } 
   else if(ADCH > 150) 
   { 
    PORTB |= (1 << 3);       // motor2 reverse 
    PORTB &= ~(1 << 2);      // motor2 reverse 
   } 
   else 
   { 
    PORTB &= ~(1 << 3); //m2 stop(Joy center position) 
    PORTB &= ~(1 << 2); //m2 stop(Joy center position) 
    } 
   }                         
   // now setup next channel
   if (ADMUX & (1<<MUX0)) {
     // channel 1 current so switch to 2
     ADMUX &= 0x7F; // clear current channel
     ADMUX |= (1<<MUX1);
   }
   else {
     // channel 2 current so switch to 1
     ADMUX &= 0x7F; // clear current channel
     ADMUX |= (1<<MUX0);
   }
   // and start conversion leading to next interrupt
   ADCSRA |= (1<<ADSC);
}

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

Quote:
Is it possible for you to give me any code example.

Assuming the ADC is set to single conversion (and to correct Cliff's code to give the proper order :) ):

ISR(ADC_vect)
{
    uint8_t adcValue = ADCH;
    if (ADMUX & (1<<MUX0)) //If MUX0 is set, we must have been on channel 1
    {
        ADMUX &= ~(1<<MUX0); // Clear MUX0 to get channel 0
    }
    else
    {
        ADMUX |= (1<<MUX0); // Set MUX0 to get channel 1
    }
    ADCSRA |= (1<<ADSC);

    // Use adcValue here
}

Regards,
Steve A.

The Board helps those that help themselves.

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

Hello Cliff and Steve,

Thanks a lot for your help. :)

I'm not able to check your above code as my PC Crashed

I'm sure that it will work for sure. will post my results here once my PC up for other newbie's who also following this post.

Thanks,
Nilesh

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

Quote:

Quote:
Is it possible for you to give me any code example.

Search the forums for "round robin lee", all words.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

void port_init(void) { 
   DDRB |= (1 << 0); // Set motor1 as output 
   DDRB |= (1 << 1); // Set motor1 as output 
   DDRB |= (1 << 2); // Set motor2 as output 
   DDRB |= (1 << 3); // Set motor2 as output 
} 

void ADC_init(void) { 
   ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); // Set ADC prescaler to 128 - 125KHz sample rate @ 16MHz 
   ADMUX |= (1 << REFS0); // Set ADC reference to AVCC 
   ADMUX |= (1 << ADLAR); // Left adjust ADC result to allow easy 8 bit reading 
   // No MUX values needed to be changed to use ADC0 
   ADCSRA |= (1 << ADEN);  // Enable ADC 
   ADCSRA |= (1 << ADIE);  // Enable ADC Interrupt 
} 

int main(void) { 
   port_init(); 
   ADC_init(); 
   sei(); 
  //  select channel 1 
  ADMUX |= (1<<MUX0); 
   // trigger very first interrupt to get started 
   ADCSRA |= (1<<ADSC); 
   while(1) { 
   } 
} 

ISR(ADC_vect) 
{ 
            uint8_t adcValue = ADCH;
       if(ADMUX & (1<<MUX0)) 
            {
	        ADMUX &= ~(1<<MUX0);
            }
           else 
            {
            ADMUX |= (1<<MUX0); 
			//ADCSRA |= (1<<ADSC);  
            }   
            ADCSRA |= (1<<ADSC); 
            // ***Use adcValue here***
	      if((adcValue < 100) && (ADMUX & (1<<MUX0)))
    		{ 
    		PORTB |= (1 << 0);       // motor1 forward 
    		PORTB &= ~(1 << 1);      // motor1 forward 
    		} 
   		  else if((adcValue > 150) && (ADMUX & (1<<MUX0)))
    		{ 
    		PORTB |= (1 << 1);       // motor1 reverse 
    		PORTB &= ~(1 << 0);      // motor1 reverse 
            } 
   		  else if(((adcValue < 150) && (adcValue > 100)) && (ADMUX & (1<<MUX0)))
    		{ 
    		PORTB &= ~(1 << 0); //m1 stop(Joy center position) 
    		PORTB &= ~(1 << 1); //m1 stop(Joy center position)
			//ADMUX &= ~(1<<MUX0);
			ADCSRA |= (1<<ADSC); 
			}
			
//////////////////////////////////////////////////////////////
       if (ADMUX & (1<<MUX1)) 
            {
	        ADMUX &= ~(1<<MUX1); 
            }
           else 
            { 
            ADMUX |= (1<<MUX1); 
            //ADCSRA |= (1<<ADSC); 
			}
		    ADCSRA |= (1<<ADSC);  
   		    //Use adcValue here 
	       if((adcValue < 100) && (ADMUX & (1<<MUX1)))
    		{ 
    		PORTB |= (1 << 2);       // motor1 forward 
    		PORTB &= ~(1 << 3);      // motor1 forward 
    		} 
   		   else if((adcValue > 150) && (ADMUX & (1<<MUX1)))
    		{ 
    		PORTB |= (1 << 3);       // motor1 reverse 
    		PORTB &= ~(1 << 2);      // motor1 reverse 
            } 
   		   else if(((adcValue < 150) && (adcValue > 100)) && (ADMUX & (1<<MUX1)))  
    		{ 
    		PORTB &= ~(1 << 2); //m1 stop(Joy center position) 
    		PORTB &= ~(1 << 3); //m1 stop(Joy center position)
			//ADMUX &= ~(1<<MUX1);
			ADCSRA |= (1<<ADSC);  
			} 
}

above code works fine on ADC1 and ADC2, now I've decided to use separate atmega8 for each channel above code gives me constant speed how do I control speed?

Nilesh

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

If you don't want the next conversion to start in the ISR, then don't start the next conversion in the ISR. Start the conversion whenever you want. Only you could know when it is convenient for you to do so.

Regards,
Steve A.

The Board helps those that help themselves.

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

Quote:

Only you could know when it is convenient for you to do so.

Though a typical technique is to run a timer interrupt a little (or possibly a lot) slower than the AVR conversion speed and simply set ADSC in the compare/overflow interrupt for the timer. For greatest control/accuracy run the timer in CTC mode and vary the timing with the OCRx register. (the one that sets TOP in CTC mode)

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

Generally, I do continuous conversions of all used channels, starting the next conversion in the ADC ISR after grabbing the result of the previous conversion.

I'd rarely do any of the app code in the ADC ISR.

The end result is that whenever the mainline wants to "close the app loop", there is a recent (within about the past millisecond) conversion result on all the channels available for use. (There are certain apps that might require a different approach, but joystick response certainly ain't one of them.)

In the main loop you can re-calculate and respond every few milliseconds (say).

Lee

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

Last Edited: Sun. Aug 8, 2010 - 07:26 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Lee,

I was possibly a little biased - the application at the back of my mind was sound sampling in fact- running an 8kHz timer and storing/triggering a sample on each "tick". In general I agree you might as well go as fast as the 15kHz conversion rate allows and just keep your samples "up to date" (perhaps with averaging if actually required at a lower rate).

Cliff

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

Quote:

if((adcValue < 100) && (ADMUX & (1<<MUX1)))
{
PORTB |= (1 << 2); // motor1 forward
PORTB &= ~(1 << 3); // motor1 forward
}
else if((adcValue > 150) && (ADMUX & (1<<MUX1)))
{
PORTB |= (1 << 3); // motor1 reverse
PORTB &= ~(1 << 2); // motor1 reverse
}


I don't know much about this type of motor driving--is it typically "active low"?

If not (and "active low" on these types of outputs doesn't make much sense to me, or the motor(s) could run away when the AVR is in reset), then the sequences above are scary for an H-bridge or similar--the "new" command is 'made' before the previous is 'broken'.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

Hello Cliff,

Quote:
the application at the back of my mind was sound sampling in fact- running an 8kHz timer and storing/triggering a sample on each "tick". In general I agree you might as well go as fast as the 15kHz conversion rate allows and just keep your samples "up to date"
Any Example as I don't know how to interface ADC and Timer.

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

Well roughly:

main() {
  setup timer for CTC
  set OCR to set compare interrupt frequency
  configure ADC
  while(1);
}

ISR(timer_compare) {
  ADCSRA |= (1<<ADSC);
}

ISR(ADC) {
  use result in 'ADC' registers
}

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

Hello Cliff,

Thanks for your prompt reply.

Nilesh

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

Hello Cliff,

Please see below code, as per your instruction. as I don't know the OCR1A value, please help me in this.

#include  
#include  

int main (void) 
{ 
   
   DDRB |= (1 << 0); // Set LED1 as output 
   DDRB |= (1 << 1); // Set LED2 as output 
   
   TCCR1B |= (1 << WGM12); // Configure timer 1 for CTC mode
   
   TIMSK |= (1 << OCIE1A); // Enable CTC interrupt 
   
   OCR1A = ????? (I don't know this value)
   TCCR1B |= (1 << CS10); // Set up timer 
   
    ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); // Set ADC prescaler to 128 - 125KHz sample rate @ 16MHz 

   ADMUX |= (1 << REFS0); // Set ADC reference to AVCC 
   ADMUX |= (1 << ADLAR); // Left adjust ADC result to allow easy 8 bit reading 

   // No MUX values needed to be changed to use ADC0 

   ADCSRA |= (1 << ADFR);  // Set ADC to Free-Running Mode 
   ADCSRA |= (1 << ADEN);  // Enable ADC 

   ADCSRA |= (1 << ADIE);  // Enable ADC Interrupt 
   sei();   // Enable Global Interrupts 
   
   for (;;)  
   { 
   } 
}
ISR(TIMER1_COMPA_vect) 
{ 
ADCSRA |= (1 << ADSC); 
}
ISR(ADC_vect)
{
   if(ADCH < 100) 
    { 
    PORTB |= (1 << 0);       // motor forward 
    PORTB &= ~(1 << 1);      // motor forward 
    } 
   else if(ADCH > 150) 
    { 
    PORTB |= (1 << 1);       // motor reverse 
    PORTB &= ~(1 << 0);      // motor reverse 
    } 
   else 
    { 
    PORTB &= ~(1 << 0); //m1 stop(Joy center position) 
    PORTB &= ~(1 << 1); //m1 stop(Joy center position) 
    } 
}

Nilesh

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

To calculate OCR1A Google for "avrcalc" (there's a strong chance it links back here ;-))

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

Yes and I have downloaded the AvrCalc, there is OCR1AH and OCR1AL, means OCR1A= OCR1AH+OCR1AL?, the software asking about Pre Scale TCCRxx and Needed Timer detail, its look like very helpful tool but I don't know how to use this tool and get the OCCR1A value from it as I have set 20MHz in crystal, 8 in pre scale and 100 in Needed Timer it gives me OCR1AL value: 0x7d, OCR1AH: 0x00 and Actual Timer ISR: 50.00 uSec I have ticked OCx Toggled

Also please look at the above code as per your code that I'm on right track or not.

Thanks,
Nilesh

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

Well you use the droplist to pick the chip frequency. You then put your desired frequency or period into the "needed timer" box" and blob one of ms, us or Hz. Finally you play with the prescaler drop list until it shows beneath it the exact period (or as close as possible to what you want). You then program the timer using the CSnn bits to program the prescaler you came up with and you combine OCRAH/L as a 16bit vaue (for a 16 bit timer) that you put into OCRxx. If using CTC subtract 1 from this value.

That's it.

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

Hello Cliff,

Quote:
until it shows beneath it the exact period
you mean until it show the TCNT0 value? How to combine OCR1AH and OCR1AL like this below?
tmp_ocr = OCR1AH+OCR1AL;
tmp_ocr = tmp_ocr-1; //using CTC so -1

Nilesh

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

With below code I'm able to change motor direction but still it gives me constant speed with joystick, I want speed control with Joystick.

#include  
#include 

int main (void) 
{ 
    
   DDRB |= (1 << 0); //Set LED1 as output 
   DDRB |= (1 << 1); //Set LED2 as output

   TCNT0 = 0xf1;
   TCNT1L = 0xf1;
   TCNT1H = 0xff;
    
   TCCR1B |= (1 << WGM12); //Configure timer 1 for CTC mode 
    
   TIMSK |= (1 << OCIE1A); //Enable CTC interrupt 
    
   OCR1A = 14; // Prescale 64

   TCCR1B |= (1 << CS10) | (1 << CS11); //Set up timer for Prescale 64
    
   ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); // Set ADC prescaler to 128 - 125KHz sample rate @ 16MHz 

   ADMUX |= (1 << REFS0); //Set ADC reference to AVCC 
   ADMUX |= (1 << ADLAR); //Left adjust ADC result to allow easy 8 bit reading 

   // No MUX values needed to be changed to use ADC0 

   ADCSRA |= (1 << ADFR);  //Set ADC to Free-Running Mode 
   ADCSRA |= (1 << ADEN);  //Enable ADC 

   ADCSRA |= (1 << ADIE);  //Enable ADC Interrupt 
   sei();   //Enable Global Interrupts 
    
   for (;;)  
   { 
   } 
} 
ISR(TIMER1_COMPA_vect) 
{ 
ADCSRA |= (1 << ADSC); 
} 
ISR(ADC_vect) 
{ 
   if(ADCH < 100) 
    { 
    PORTB |= (1 << 0);       //motor forward 
    PORTB &= ~(1 << 1);      //motor forward 
    } 
   else if(ADCH > 150) 
    { 
    PORTB |= (1 << 1);       //motor reverse 
    PORTB &= ~(1 << 0);      //motor reverse 
    } 
   else 
    { 
    PORTB &= ~(1 << 0); //m1 stop(Joy center position) 
    PORTB &= ~(1 << 1); //m1 stop(Joy center position) 
    } 
}

Nilesh

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

Quote:

you mean until it show the TCNT0 value?

No I'm talking about the value I have circled below. In this I've set F_CPU to 3.6864MHz and asked for a 13ms period. The program is telling me that with no prescaler and an OCR of 0xBB33 (0xBB32 for CTC) what I'll actually get is 13.000054253699ms - keep changing prescaler until that gets as close as possible to the desired 13ms (in fact it's with no prescaling that this is as close as you can get)...

Attachment(s): 

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

Thanks for the detailed info Cliff, I'm trying to achieve 13 mSec and update my code according.

Nilesh

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

Hello Cliff,

I achieved the exact 13mSec at 4 Mhz Crystal, OCR:0xcb20 =(52000 in decimal and we uses CTC so 52000-1=51999?) and above result with no prescaler option

so as per above I have to use 4 MHz External crystal? as I'm already using 20MHz crystal.

Nilesh

Attachment(s): 

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

It seems very coincidental that I just picked the value 13ms completely at random simply to illustrate the use of avrcalc and you are now saying that it's 13ms you want to use too - what made you choose 13ms?

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

Quote:
It seems very coincidental that I just picked the value 13ms completely at random simply to illustrate the use of avrcalc and you are now saying that it's 13ms you want to use too - what made you choose 13ms?
:)Yes I strongly believe in thought frequency transmitted :) (telepathy)and it happens most time when we think in same wave length As I thought as it will not gonna that that much faster if some one moving joystick so value may be between 10-20 mSec. I don't know I'm right or wrong, I'm checking the results in my code now.

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

Quote:
:)Yes I strongly believe in thought frequency transmitted Smile (telepathy)and it happens most time when we think in same wave length
Work a bit more on this part and you will get our answers faster.
You need to keep F_CPU at the right freq(20MHz) and change prescalers to get as close as possible to 13mS.

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

:)
Again same think

I have changed F_CPU at 20 MHz and without prescale I got exact 10 mSec. at OCR:43104

(without prescale means I need not to set TCCR1B |= (1 << CS10), right?

oh! lately noticed that it posted by Lennart :) Hello Lennart

Nilesh

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

Quote:
Work a bit more on this part and you will get our answers faster.
You need to keep F_CPU at the right freq(20MHz) and change prescalers to get as close as possible to 13mS.
I've changed my code as per 20MHz and got exact 13mSec at prescaler 8, here below my code but still got constant speed
#include  
#include 

int main (void) 
{ 
  	DDRB |= (1 << 0); //Set LED1 as output 
	DDRB |= (1 << 1); //Set LED2 as output

	//TCNT0 = 0xf1;
	TCNT1L = 0x0c;
	TCNT1H = 0x81;

	TCCR1B |= (1 << WGM12); //Configure timer 1 for CTC mode 

	TIMSK |= (1 << OCIE1A); //Enable CTC interrupt 

	OCR1A = 62589; // Prescale 64

	TCCR1B |= (1 << CS10) ; //Set up timer for Prescale 64

	ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); // Set ADC prescaler to 128 - 125KHz sample rate @ 16MHz 

	ADMUX |= (1 << REFS0); //Set ADC reference to AVCC 
	ADMUX |= (1 << ADLAR); //Left adjust ADC result to allow easy 8 bit reading 

	// No MUX values needed to be changed to use ADC0 

	ADCSRA |= (1 << ADFR);  //Set ADC to Free-Running Mode 
	ADCSRA |= (1 << ADEN);  //Enable ADC 

	ADCSRA |= (1 << ADIE);  //Enable ADC Interrupt 
	sei();   //Enable Global Interrupts 

	for (;;)  
	{ 
	} 
} 

//Timer
ISR(TIMER1_COMPA_vect) 
{ 
	ADCSRA |= (1 << ADSC); 
} 

//ADC
ISR(ADC_vect) 
{ 
	if(ADCH < 100) 
	{ 
	PORTB |= (1 << 0);       //motor forward 
	PORTB &= ~(1 << 1);      //motor forward 
	} 
	else if(ADCH > 150) 
	{ 
	PORTB |= (1 << 1);       //motor reverse 
	PORTB &= ~(1 << 0);      //motor reverse 
	} 
	else 
	{ 
	PORTB &= ~(1 << 0); //m1 stop(Joy center position) 
	PORTB &= ~(1 << 1); //m1 stop(Joy center position) 
	} 
}

Nilesh

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

What do you mean "constant speed"? It appears you code does fwd/back/stop. How does your code intend to vary motor speed?

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

Quote:
oh! lately noticed that it posted by Lennart Smile Hello Lennart

Hello Nilesh
On this forum we're all connected to the collective unconscious mind, so the answers might come from anywhere on the globe.

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

Hello Lee,

Quote:
What do you mean "constant speed"? It appears you code does fwd/back/stop. How does your code intend to vary motor speed?
when I move joystick in A direction motor runs forward and when I move joystick in B direction motor runs reverse but speed not increasing (slow to maximum related to center), I want speed increasing on joystick move and maximum on joystick maximum position related to center I also want to manage this center portion (stop position(decrease forward working portion or decrease reverse working portion)) using potentiometer but it will do later on

I'am doing this first time and not sure about the above code will work or not

Nilesh

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

Quote:

I want speed increasing on joystick move

But there's nothing in your program that would deliver that?You just have a simple on/off gate dependent on some ADCH boundary value.

To vary a (DC) motor speed you vary the voltage to the motor. The AVR cannot do that exactly (it needs DAC to achieve that - only Xmega has this) but it can "fake" it by using PWM. This picture (actually talking about LED brightness but could just as easily be motor speed) gives an idea how this is achieved:

By outputting a square wave where the "time on" varies you can effectively vary the applied voltage. If the signal is only on for 1/5th of the time and it's a 5V signal then it sort of acts as if only 1V was applied and so on.

Most AVRs have a number of hardware PWM output channels and there's been TONS of prior threads here about motor control using PWM (but don't get confused by any that mention "BLDC" - the BL means Brushless and these are actually controlled by three phased coils and is far more advanced than where you are now!)

Cliff

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

Hello Cliff,

Any good PWM tutorial link? as Dean's yet not complete.

Regards,
Nilesh

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

Maybe have a look here at application notes for different motor types.
http://www.atmel.com/dyn/product...

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

Thanks Lennart,

it suggets me ATmega32M1 and ATAVRMC320 for BLDC, mine is simple geared dc motor up to 24 volts max, I am using H Bridge 5206

Regards,
Nilesh

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

As I said before - ignore anything that mentions "BLDC" that is far more complex than you require here.

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

Quote:
As I said before - ignore anything that mentions "BLDC" that is far more complex than you require here.
Yes Sir I have already ignored and only looking for simple dc motor control examples and tuts.

Regards,
Nilesh

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

Hello Cliff,

Any pseudo code for my project or any pwm example?

Regards,
Nilesh

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

A "Search" in Tutorials forum revealed this.
https://www.avrfreaks.net/index.p...
That ought to be enough to get you started.
Connect a LED instead of the motor while testing.
A scope is very useful to detect what waveform is produced and how your input values alter that waveform.

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

Hello Lennart,

Thanks for your reply.

I'm using joystick to start motor, reverse or forward so its external interrupt and I want to use ADC to detect that it pressed reverse or forward or in middle position, but don't know how can I use togather PWM and ADC.

Regards,
Nilesh

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

Quote:

how can I use togather PWM and ADC

Well write the two separately and get them working. For the PWM just have a slow loop that varies the output over time and see if you can make the LED brighter/dimmer or the motor slower/faster.

Separately develop the stuff to make ADC readings and use some form of output (LEDs, UART, LCD, whatever) to show the readings. Vary the joystick position and make sure you get different readings.

Only when both modules are proven and working should you then worry about connecting the output of the ADC to control the duty cycle of the PWM.

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

Hello Cliff,

Which PWM mode you suggest, I want linear speed increasing or decreasing.

Regards,
Nilesh

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

For a motor just go for the simplest possible - that would mean "Fast PWM".

You then have a choice about the frequency which is determined by the "TOP" value. For a motor you want a PWM frequency above audio range (or the motor can "chirp"/"sing"). Something like the TOP=0xFF (8bit) mode or just doing PWM on an 8bit timer is probably the best idea.

With a timer set to no-prescale and running the AVR on 8MHz (say) the timer will overflow every 256 * 0.125us = 32us and 1/32us is 31.25kHz which is well out of human audio range.