ADC stepper motor control

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

I hope someone can help me. I'm totally new to this,(and probably too old to be starting) but I wan't to eventually control 3 stepper motors with potentiometers using an ATmega8.
I've managed to get one working:

/* Program is supposed to read voltage on C0 and produce a number from 0-255 and, depending on the value the stepper motor turns (anti)clockwise and proportionally varies speed)*/
#include
#include
#include

int main (void)
{
ADMUX=0x60; //Sets reference vcc and left adjusts the reading
ADCSRA=0xEB;//Turns on EDEN, ADSC, ADATE and devides the clock rate by 8
sei(); // Enable Global Interrupts
DDRD = 0xF0;
while(1)
{
}
}
ISR(ADC_vect)
{
while(ADCH>135)
{
int time;
time=(1000/(ADCH-100)); // should give 6.6 to 33 ms delay
PORTD = 0b10000000;
_delay_ms(time);
PORTD = 0b11000000;
_delay_ms(time);
etc. (I know there's better ways to do this but I'm still trying out different patterns)
}
while (ADCH<120)
{
int time;
time=(5+(ADCH/5)); // should give a 5-35 ms delay
PORTD = 0b00010000;
_delay_ms(time);
PORTD = 0b00100000;
etc.
} // between 120 and 135 nothing
}

I've hunted around all the forums etc. and spent many hours trying to figure out appropriate interrupt routines, but totally failed to get any sign of multi channel ADC reading.

I've seen the recent stepper motor project posting. It looks fantastic, but too far up the learning curve for me.

Guidance on the next step appreciated please. There has to be a better answer than replicating the existing set up three times.

Dave

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

I'd do it all without any interrupts. Just read the first pot, figure out how many steps to take, go do that, then do the next pot, then the next. When you arent fiddling with a pot everything just sits there. If you turn 1 and 2 at the same time, 2 just sits there till one gets to where its going. So you just need 2 subroutines... rea an a/d channel. which is in the datashett, and 'take a step' which is just increment or decrement the index into a table of output pattern to the stepper outputs mod 4. For example, the 4 patterns might be 0101, 0110, 1010, 1001 then back to 0101.

Imagecraft compiler user

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

Thanks Bob,

I started by using steps and buttons, but I'm trying to align a camera via the image feed and having more flexibility on velocity seemed like a good idea. I'll have another think about it and get back to the books.

Thanks for the suggestion.

Dave

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

How many degrees on the video is a step? You dont want to pan more than about 4 pixels per frame... is a frame 30 degrees wide in 640 pixels?

Imagecraft compiler user

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

I'm planning to do x,y,z, not rotation. It's for a macro application at about 1x. The z is a bit of a luxury, but I'm thinking of a gearing for fine focus, which will need to end up at no more than 2 micron per step.

I've done a bit more reading and I think I realise now I would have to introduce a timing interrupt to do it the way I was thinking (not ready for that). An alternative might be to use one pot one routine as above and use hardware switches to select which motor. A bit of a cop-out but maybe a prudent one.

I'll have to find an easier test project to work up the multichannel reading.

Dave

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

Steppers are used in milling machine x,y tables a lot. I've used the little bitty MicroMo steppers with gearheads and encoders. So you want to drive x and y simultaneously, to move shortest distance to a target? If the steppers can take a step every 2ms, you just need a loop that steps x one step to decrease x error, steps y one step to decrease y error, and goes out for a smoke for the rest of two milliseconds.

Imagecraft compiler user

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

Sorry, I don't understand the relevance of the 2ms step time. Could you explain?

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

Just playing here...

1. Moved the calculations from the ISR to main(), where they belong.
2. Made an array representing something close to the proper stepper motor code.
3. Made all variables "unsigned char ".
4. Set code up so that the stepper motor changes direction, based on ADCH value.

I haven't a clue what you are doing. I just interpreted what I thought your code was trying to accomplish and revised it accordingly.

If I'm completely wrong, just ignore my efforts.

But please learn how to use the " CODE " tag and indenting, as it makes posted code much easier to read and understand.

/* Program is supposed to read voltage on C0 and produce a number from 0-255 and, depending on the value the stepper motor turns (anti)clockwise and proportionally varies speed)*/ 
#include  
#include  
#include  

// For bi-polar operation, using two full H-Bridge drivers.
//* unsigned char StepCode[] {
                          0b00000000,
                          0b10000000,
                          0b01000000,
                          0b11000000
}; */

// For uni-polar operation, using four common emitter driver transistors.
unsigned char StepCode[] {
                          0b10100000,
                          0b01100000,
                          0b01010000,
                          0b10010000
};

unsigned StepIndex = 0;
unsigned char Time;

int main (void) { 
ADMUX=0x60; //Sets reference VCC and left adjusts the reading 
ADCSRA=0xEB;//Turns on EDEN, ADSC, ADATE and divides the clock rate by 8 
sei(); // Enable Global Interrupts 
DDRD = 0xF0;
 
while (1) {
      // should give 6.6 to 33 ms delay 
      time = 1000 / (ADCH - 100);

      //
      // between 120 and 135 there is no movement... 
      //
 
      // should give a 5-35 ms delay 
      time = 5 + (ADCH / 5);
}

ISR (ADC_vect) {
    if (ADCH < 120) PORTD = StepCode[StepIndex++]; 

    if (ADCH > 135) PORTD = StepCode[StepIndex--]; 
    
    _delay_ms(time); // While it might be acceptable in this application, I don't think delays are proper
                        within an ISR.  You might consider converting this ISR to a hardware timer
                        ISR function and use it to establish the stepper motor velocity.

    if ((StepIndex < 0) || (StepIndex > 3))
       StepIndex = 0;
   
}

You can avoid reality, for a while.  But you can't avoid the consequences of reality! - C.W. Livingston

Last Edited: Sat. Apr 12, 2008 - 04:11 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks Carl,

Points noted, I'll try better in future.

That's really helpful, it simplifies some code examples I've been struggling to understand. I'll crank up the aging grey matter and give it a go.

Cheers,

Dave

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

Two ms per step is a guesstimate of how fast you can take steps. 500 per sec. If the motor is 1.8 deg per step (before the gearhead) thats 200 steps per rev, so thats about 2.5 rev per sec. Of course if you want a 100:1 gearhead in front of that, you trade off speed for resolution. There are current mode stepper drives that hit the coil real hard and they seem to be able to do 1000s of steps per sec, but I havent been able to get a good idea of how they do it. I just speed it up till it poops out, then slow it back down a little.

Imagecraft compiler user

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

Hi Carl,

I've given it a try, but with the time calculations in main() I'm getting no time modulation. Just nothing or a high pitched hum depending on the pot setting.

Where do you set the step interval? Or is is possible with that code structure to put in a pot driven variable speed?

Sorry to try your patience.

Dave

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

bobgardner wrote:
Two ms per step is a guesstimate of how fast you can take steps

Sorry, I was being dumb. I'm doing the workup with some ancient 9 degree can motors which seem to max out at 5ms, but planned to buy some 1.8 once I'd sorted out the control.

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

typo wrote:
Hi Carl,

I've given it a try, but with the time calculations in main() I'm getting no time modulation. Just nothing or a high pitched hum depending on the pot setting.

Where do you set the step interval? Or is is possible with that code structure to put in a pot driven variable speed?

Sorry to try your patience.

Dave


Do you have an Oscilloscope, so that you can look at the outputs?

If not, use really long delays and LEDs to visually look at the output pattern.

The fact that you say "I'm getting no time modulation. Just nothing or a high pitched hum depending on the pot setting. " from the stepper motor means that some pattern of output is occurring.

I'm not sure if you have the shaft of the POT attached to the stepper motor shaft, or not. If you do, use that POT for stepper motor position. Use a second "Hand-Turned " POT on a second A/D channel for velocity to drive one of the controllers hardware timers that establishes velocity.

You could then use a third POT & A/D channel to set position, comparing values between the POT connected to the stepper motor shaft and the third "Hand-Turned "POT, stopping the stepper motor when the two are withing a few counts of each other.

But it all really depends on what you are actually trying to accomplish.

And as far as trying my patience... You are making an effort to work out your problems by doing the required "Hands-On " learning. It's the individuals that just want the code handed to them that try my (our) patience. So, it's all about helping you and suggesting things that you might not have thought about. We suggest ideas to you. You in turn, experiment and learn from our suggestions.

So please be patient with us, as we prod you into stretching your knowledge...

You might also want to re-post your commented code, so we can see and understand what you've currently got...

You can avoid reality, for a while.  But you can't avoid the consequences of reality! - C.W. Livingston

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

Quote:
If not, use really long delays and LEDs to visually look at the output pattern.

Taking out the equations from main and just putting time=100 makes no difference to the nothing or hum status and trying it before the _delay_ms results in nothing. Perhaps the _delay_ms doesn't work in the IRS as you suggested.

Sadly, SHE who must be obeyed tells me I've timed out. I'll get back to this when I've erned some more brownie points.(do you have those in the US?)

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

typo wrote:

Sadly, SHE who must be obeyed tells me I've timed out. I'll get back to this when I've earned some more brownie points.(do you have those in the US?)

What, the "She-gender BOSS " or the "Brownie Points ?"
Yes! She is definitely the "BOSS ", wearing the pants in this household.

And "Brownie Points " are accumulated daily by telling her that she is a "Sweetheart " - each and every day...

You can avoid reality, for a while.  But you can't avoid the consequences of reality! - C.W. Livingston

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

i used the ST LL9942 stepper motor driver....pretty nice chip!

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

Well thanks to Carl I can report some progress.
It now turns one way at low voltage and the other way at high at a fixed speed.

* Program is supposed to read voltage on C0 and produce a number from 0-255 and, depending on the value the stepper motor turns (anti)clockwise and proportionally varies speed)*/ 
#include  
#include  
#include  
#define F_CPU 1000000UL



// For uni-polar operation, using four common emitter driver transistors. 
unsigned char StepCode[] ={0b10000000, 0b11000000, 0b01000000, 0b01100000, 0b00100000, 0b001100000, 0b00010000,0b10010000
}; 
unsigned char StepCode2[] ={0b00010000, 0b00110000, 0b00100000, 0b01100000, 0b01000000, 0b11000000, 0b10000000, 0b10010000
};

unsigned StepIndex = 0; 
unsigned char time =2; 

int main (void) { 
ADMUX=0x60; //Sets reference VCC and left adjusts the reading 
ADCSRA=0b11101011;//Turns on EDEN, ADSC, ADATE and divides the clock rate by 8 
sei(); // Enable Global Interrupts 
DDRD = 0xF0; 
  
while (1) { 
/*    while (ADCH > 135)
	  {
      time = (1000 / (ADCH - 100)); 
	  }
      while (ADCH < 120)
	  {
      time = (5 + (ADCH / 5)); 
	  
	  }		*/
	}
}
ISR (ADC_vect) { 
    if (ADCH < 120) PORTD = StepCode[StepIndex++]; 
	_delay_ms(time);		
    if (ADCH > 135) PORTD = StepCode2[StepIndex++];
    _delay_ms(time); 

    if ((StepIndex < 1) || (StepIndex > 7)) 
        StepIndex = 0; 
   
}

I'm simply using one pot.

When I'm trying to do is to get the speed proportional to the voltage in each direction. For all it's faults the code at the top did that. However I don't seem to put the commented out equations anywhere. Any Ideas?

Then, I want to control different motors with different pots. I was originally trying to do that with the proportonal speed control. I'll give it a try without.

Sorry Carl I just couldn't get this line to work:

    if (ADCH > 135) PORTD = StepCode[StepIndex--]; 
    

Hence the StepCode2.

The sequence works because I wired it that way.

And no, I don't have an Oscilliscope, I've only had a multimeter about 3 weeks.

Thanks again for your help.

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

typo wrote:
Sorry Carl I just couldn't get this line to work:

    if (ADCH > 135) PORTD = StepCode[StepIndex--];

If the ADCH value is larger the 135, PORTD gets assigned the value in the StepCode array, pointed to by the StepIndex position pointer.

After the transfer of data from the StepCode array to PORTD is finished, the StepIndex pointer is decremented by 1, point to the next value in the StepCode array that will be used.

You can avoid reality, for a while.  But you can't avoid the consequences of reality! - C.W. Livingston

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

If you fill out your location in your profile, all the freaks will know which continent you live on, and if some are close by, might even come over and help you fix something that is broke, or break something that is fixed.

Imagecraft compiler user

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

bobgardner wrote:
...and if some are close by, might even come over and help you fix something that is broke, or break something that is fixed.

Now that's what I'm talking about! I especially like it when the smoke comes out and there is some form of Kaboom ! Kaput, Kaboom! Are they related?

"If it ain't broke, I'll figure out how to break it!!! " :wink:

You can avoid reality, for a while.  But you can't avoid the consequences of reality! - C.W. Livingston

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

So far I think there are more freaks per city in Cincinatti than anywhere else on earth. Who wants to make a table of freaks per city, freaks per country and freaks per continent? Oz might have most freaks per continent. I bet its freaks per country is exactly the same! I suppose freaks per planet would be a one liner at this point.

Imagecraft compiler user

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

Thanks for the code. A double caffein fix on order.