NerdKits - electronics education for a digital generation

You are not logged in. [log in]

NEW: Learning electronics? Ask your questions on the new Electronics Questions & Answers site hosted by CircuitLab.

Microcontroller Programming » 4-wire stepper motor and ADC speed control

December 04, 2011
by rkohl44
rkohl44's Avatar

First things first: thanks to all the prolific and incredibly helpful members here. Usually I'm able to search and find what I'm doing wrong through others' similar problems. This time I'm at a loss and need help. I'm not an engineer, but a tinkering hobbyist with rudimentary (at best) skills in the programming and electrical worlds.

The project: stepper motor control with variable speed control. I salvaged a 4-wire stepper motor out of a dead printer and have successfully gotten it to run clockwise and counterclockwise through an L293 H-bridge. At first, I hard coded a delay between steps like this:

    uint8_t delay_CW;
    delay_CW = 3;

    // step 1       
    PORTB |= (1<<PB4);  // step 1 on        
    PORTB &= ~(1<<PB4); // step 1 off

A delay of 3 ms resulted in fast, smooth rotation, over 80 RPM. A delay of 2 ms resulted in 135 RPM. A delay of 1 ms was too fast and the motor didn't spin at all.

Of course, I want to vary the speed dynamically. I used the temp sensor code to set a delay from reading the potentiometer (and writing the speed to the LCD). This works fine if the speed is set BEFORE the stepping loop begins. The problem comes in when I put the call to getspeed() INSIDE the stepping loop. It takes too much time to do the adc_read() and the motor skips and jitters.

So the question is: how do I check for a change in the potentiometer while keeping the motor control loop flowing? Can I do this using the adc, or is this always going to take too much time (therefore causing step skips). I suppose I could hard code several delay values and use a simple pushbutton (or the dipswitch) to set speeds.

Thanks for any thoughts and suggestions.

December 05, 2011
by JimFrederickson
JimFrederickson's Avatar

If you want to 'check for a change in the potentiometer while keeping the motor control loop flowing' a few changes are necessary.

1 - Create some uint16 variables to hold some amount of the last ADC Results, as well as a uint16 to hold the average of those results. (I would recommend between 3-5...)

2 - Change your 'Motor Control Loop' so that you check to see if there are 'ADC results'.

If 'ADC Results' = TRUE - Drop oldest 'ADC Result'. Store the new result Average the results (If you want to) Apply any 'rules/limits' that would suite your needs to the average Store that 'ADC Average of the Results' Start a new ADC Conversion

Then run your 'Motor Control Loop' from the 'ADC Average of the Results'.

(Even if you don't use an 'Average' you can just use the 'Last Result'.) (What I mean by 'rules/limits' is filtering out bad values, or making sure the values are within a defined range of limits'.)
That's it...

Probably right now you are starting an ADC Conversion and then waiting in a while loop for it to complete. So now, during the time you are waiting, your motor is not being controlled, and 'stutters'.

If instead you 'check to see if the ADC conversion has completed', instead of 'waiting for the ADC conversion to complete', you can do other more useful things while the ADC is churning away. (Such as continuing on with your 'Motor Control Loop' until there is a new ADC Result.)

Does that make sense?

What would, if you wanted to get fancier, work better would be to use Interrupts.

Setup a timer for an interrupt interval. Using a timer you can have a lot of other options at that point.

 1 - 'Run the Motor Control Loop' in the interrupt routine

 2 - 'Run the ADC' in the interrupt routine

 3 - 'Run both the Motor Control Loop and the ADC in the interrupt routine

 4 - 'Create a time base' that is controlled in the interrupt routine and then use 
     that 'time base' in how you control the rest of your code.

(Although, I am thinking that you may not quite be ready for and interrupt routine right now.)

(There also is an ADC specific interrupt that you could utilize was well, and you can set the ADC to auto-trigger too.)

For now though, just changing your way of thinking a little so that 'every single thing that needs to be done doesn't have to get done each pass through your loop' will get you over your current issue.

December 22, 2011
by rkohl44
rkohl44's Avatar

Thanks, JimFrederickson, for your reply. Yes, that's exactly what I was doing: waiting in a while loop for the adc to complete. I'm on the right track now and am kinda sorta controlling the speed with the pot.

December 24, 2011
by BobaMosfet
BobaMosfet's Avatar

What are the four wires for? 2 pairs for stepping, or is one of the leads from a rotary encoder?


Post a Reply

Please log in to post a reply.

Did you know that Morse code is a compact way to transmit human-readable text over binary channels? Learn more...