Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

Stepping a Motor with the A3979

Status
Not open for further replies.

drkidd22

Member
I've been working on a project for a little while now and I'm at the step of programming my microchip to control the rotation of a NEMA 17 stepper motor using the Allegro Controller A3979.

So far the motor works fine after getting help for members of this forum specially phalanx. I opened this new thread to keep it separated from the other ones I have, but for anyone looking around and getting started soon or in a couple of years from now the other thread is Microchip and A3979

Now my problems are with programming. I'm familiar with C and have done it before and can do some simple stuff, but I'm having issue trying to get the motor, A3979 controller, to accomplish what I want to do.

Basically is just to control the Step pin with the microchip to signal the motor to step certain amount of time. I've never used stepper motors before. I have the stepper set to Sixteenth Step micro stepping and want to know if anyone can help me clear this out or correct me if I'm wrong.

1.My motor has a step angle of 1.8 degrees (Full Step, Correct?).
2.Since I'm at Sixteenth Step does this mean that it will then be stepping @ (1.8/16) = 0.1125 degrees/step?
3.That means I got 3200 steps per/rev, correct?
4.Ok now I want to turn the motor 90 degrees, this means that I have to step (90/.1125) = 800 times to turn the motor 90 degrees?

If some one can please let me know if I have all the above correct I'll appreciate. I've tried stepping the motor from 200-800 times, but maybe my code is not working or I'm doing some thing wrong.

This is the function I been trying to use:

step45Degrees
{
int i;
for(i = 0; i < 400; i++) //Step for 400 times for 45degrees
ena = 0; //enable the A3979 to start stepping
dir = 1; //set direction of stepper motor
step = 1; //step the motor logic high
_delay_us(100)
step = 0; //go logic low.
}

I've tried calling the above function from inside and outside the while loop, but I get odd behavior from the motor. It either doesn't start, tries to start or it continuously turn. The minimun step pulse width of A3979 is 1us, so I'm well above that.
 

Attachments

  • N1728S87.pdf
    859.9 KB · Views: 240
  • StepperControlPCB.pdf
    86.6 KB · Views: 192
You don't say what voltage your using to drive the motor, Vbb1 and Vbb2 on the driver. Minimum from the data sheet is 8V, more(depending on the motor load) is better, up to 35V. Without enough motor voltage you will not get good movement.
 
You left the important brackets off your for() loop! I have added the brackets below. I also added a while(1) loop at the end to keep the PIC stopped (as it will repeat all its code without that). And please use CODE tags when posting code (as I did below) to make it neat! :)

Code:
step45Degrees
{
  int i;
  for(i = 0; i < 400; i++) //Step for 400 times for 45degrees
  {
    ena = 0; //enable the A3979 to start stepping
    dir = 1; //set direction of stepper motor
    _delay_us(100)
    step = 1; //step the motor logic high
    _delay_us(100)
    step = 0; //go logic low.
  }
}
while(1);    // just END here
 
thanks for your reply, sorry about the code tags, just forgot. So far the motor turns as commanded and for the amount of steps expected, but I have a bigger problem. I'm using a PIR sensor from parallax, when it detects motion it goes logic high which is the pirsens input. The issue is that the sensor remains on as long as it detects movement so the motor keeps sniping past the expected amount of steps.

What I'm trying to do is even if the pirsens is high the motor should only turn whatever the amount of steps it is commanded and then stop wait a while (maybe 2 secs for next signal) I've tried differents setups but can;t figure it out. below is the code as I have it now, hope someone understand what im trying to say.

Code:
#define FCY 8000000UL

#include <P24FJ64GB002.h>
#include <libpic30.h> 
 
_CONFIG1( FWDTEN_OFF  & ICS_PGx1 & GWRP_OFF & GCP_OFF & GWRP_OFF & JTAGEN_OFF) 
_CONFIG2( POSCMOD_NONE  &   I2C1SEL_PRI & IOL1WAY_ON & OSCIOFNC_ON & FCKSM_CSDCMD  & FNOSC_FRC & PLL96MHZ_OFF & IESO_OFF)
_CONFIG3(SOSCSEL_IO)
//Fast Internal RC (FRC) Oscillator 8MHz Clock Source

//Function Prototypes
void step45Degrees (void);

//Defines
#define                   sleep                    LATAbits.LATA0
#define                   ena                       LATAbits.LATA1
#define                   pirsens                PORTAbits.RA2
#define                   rst                        LATAbits.LATA3
#define                   sr                          LATAbits.LATA4
#define                   step                      LATBbits.LATB4
#define                   ms1                      LATBbits.LATB7
#define                   ms2                      LATBbits.LATB8
#define                   dir                        LATBbits.LATB15
 
main ()
{
   AD1PCFG = 0xFFFF;          //All pins are digital

    //Output Ports
    TRISAbits.TRISA0 =   0;      //Set sleep port as output
    TRISAbits.TRISA1 =   0;      //Set ena port as output
    TRISAbits.TRISA3 =   0;      //Set rst port as output
    TRISAbits.TRISA4 =   0;      //Set sr port as output
    TRISBbits.TRISB4 =   0;      //Set step port as output
    TRISBbits.TRISB7 =   0;      //Set ms1 port as output
    TRISBbits.TRISB8 =   0;      //Set ms2 port as output
    TRISBbits.TRISB15 = 0;      //Set dir port as output
 
    //Input Ports
    TRISAbits.TRISA2 = 1;      //Set pirsens port as input

    //Output ports initial states
    sleep = 1; 
    ena = 1;    
    rst = 1;     
    sr = 0;       
    step = 0;   
    ms1 = 0;   
    ms2 = 1;   
    
        while (1)
{
  if (pirsens == 1)
{
   step45Degrees ();
}
else
    ena = 1; //dissable the stepper motor
}

}//endMain

void step45Degrees (void)
{
  int i;
  for(i = 0; i < 400; i++) //Step for 400 times for 45degrees
  {
    ena = 0; //enable the A3979 to start stepping
    dir = 1; //set direction of stepper motor
 
__delay_us(100);
    step = 1; //step the motor logic high
    __delay_us(100);
    step = 0; //go logic low.
  }
}
 
Last edited:
The usual way when you have 2 positions to move between is to use a flag, that's a global variable that knows which position the machine is in.

So you could add a flag called motor_pos;
0 means the motor is at the left position
1 means the motor is at the right position

In your code below I added the global variable motor_pos, then initialised it to 0, then after the motor has moved 45' the variable is set to 1. This means the motor can only move once. It should be fairly obvious you can use the motor_pos flag to get the motor to move back and forth as needed.

If you need more sophisticated motor movement, you can use a value for motor_pos that tells what STEP the motor is at. Then you can make a function called move_motor() that will move the motor to any desired position, right or left.
Code:
#define FCY 8000000UL
 
#include <P24FJ64GB002.h>
#include <libpic30.h> 
 
_CONFIG1( FWDTEN_OFF  & ICS_PGx1 & GWRP_OFF & GCP_OFF & GWRP_OFF & JTAGEN_OFF) 
_CONFIG2( POSCMOD_NONE  &   I2C1SEL_PRI & IOL1WAY_ON & OSCIOFNC_ON & FCKSM_CSDCMD  & FNOSC_FRC & PLL96MHZ_OFF & IESO_OFF)
_CONFIG3(SOSCSEL_IO)
//Fast Internal RC (FRC) Oscillator 8MHz Clock Source
 
//Function Prototypes
void step45Degrees (void);
 
//Defines
#define                   sleep                    LATAbits.LATA0
#define                   ena                       LATAbits.LATA1
#define                   pirsens                PORTAbits.RA2
#define                   rst                        LATAbits.LATA3
#define                   sr                          LATAbits.LATA4
#define                   step                      LATBbits.LATB4
#define                   ms1                      LATBbits.LATB7
#define                   ms2                      LATBbits.LATB8
#define                   dir                        LATBbits.LATB15
 
unsigned char motor_pos;    // gloabl var, records motor position

main ()
{
    AD1PCFG = 0xFFFF;          //All pins are digital
 
    //Output Ports
    TRISAbits.TRISA0 =   0;      //Set sleep port as output
    TRISAbits.TRISA1 =   0;      //Set ena port as output
    TRISAbits.TRISA3 =   0;      //Set rst port as output
    TRISAbits.TRISA4 =   0;      //Set sr port as output
    TRISBbits.TRISB4 =   0;      //Set step port as output
    TRISBbits.TRISB7 =   0;      //Set ms1 port as output
    TRISBbits.TRISB8 =   0;      //Set ms2 port as output
    TRISBbits.TRISB15 = 0;      //Set dir port as output
 
    //Input Ports
    TRISAbits.TRISA2 = 1;      //Set pirsens port as input
 
    //Output ports initial states
    sleep = 1; 
    ena = 1;    
    rst = 1;     
    sr = 0;       
    step = 0;   
    ms1 = 0;   
    ms2 = 1;   
    motor_pos = 0;  // start with motor at left


  while (1)
  {
    if (pirsens == 1 && motor_pos == 0)
    {
      step45Degrees ();
      motor_pos = 1;     // record that motor has moved!
    }
    else
      ena = 1; //dissable the stepper motor
  }
 
}//endMain
 
void step45Degrees (void)
{
  int i;
  for(i = 0; i < 400; i++) //Step for 400 times for 45degrees
  {
    ena = 0; //enable the A3979 to start stepping
    dir = 1; //set direction of stepper motor
 
__delay_us(100);
    step = 1; //step the motor logic high
    __delay_us(100);
    step = 0; //go logic low.
  }
}
 
Thanks, I will give that a try today.
But I think I might have some error in calculating the actual steps required to move the motor 45 degrees.
 
I wouldn't be surprised if you are losing steps because you aren't accelerating the motor. With 2 100us delays, you are running at 5000steps/sec. Due to the mass of the rotor and a few other factors, you can't instantaneously start or stop the motor. You need a ramp up/ramp down profile for your step speed otherwise you run the risk of stalling the motor and open loop counting of steps will not give you an accurate motor position.
 
As a quick test, change your code so it only runs at 100 steps/sec and see if it stops where you expect it to.
 
Status
Not open for further replies.

New Articles From Microcontroller Tips

Back
Top