技术热线: 4007-888-234

PIC单片机控制步进电机的方法与实例

更新时间: 2019-03-23
阅读量:1808

十年专注单片机方案开发的方案公司英锐恩,分享PIC单片机控制步进电机的方法与实例。英锐恩现提供服务产品涉及主控芯片:8位单片机、16位单片机、32位单片机及各类运算放大器等。

================================
C Program for Stepper controller
================================

 

/* StepA C Version 0    */
/* Stepper controller   */
/* A. Prewitt           */
/* N4PT                 */
/* Aprewitt@prodigy.net */
/* Jan 9 2000           */
/* CC5X C Compiler      */
/* NO  WDT              */

 

#include <16f84.h>   /* Part of CC5X */

#pragma bit Pulses    = PORTA.4   /* Drives TOCKI a step for each pulse */
#pragma bit HoldIn    = PORTB.3   /* 0= release   1=hold */
#pragma bit StepIn    = PORTB.4   /* 0=NoStep     1=step */
#pragma bit DirIn     = PORTB.5 /* 0=CCW        1=CW  */
#pragma bit ModeLoIn = PORTB.6 /* 00 = 2ph 01 =1/2step 10=wave 11=nil */
#pragma bit ModeHiIn  = PORTB.7

 

#define TwoPhase  0
#define HalfStep  1
#define WaveDrive 2
#define NoPhase   3
#define True      1
#define False     0
#define CW        1
#define CCW       0 

 

char Index ;
char Mode ;
char MotorVal ;

 

bit Dir ;
bit StepDly ;
bit Step  ;

 

#pragma bit  ModeLo = Mode.0
#pragma bit  ModeHi = Mode.1

 

char TwoPhase_Tbl(char i )      /* Two Phase Drive look up table */
{
  skip(i);
  #pragma return[] = 0xc
  #pragma return[] = 0x6
  #pragma return[] = 0x3
  #pragma return[] = 0x9
}

char WaveDrive_Tbl ( char i)  /* Wave Drive Look up Table */
{
  skip(i) ;
  #pragma return[] = 0x8
  #pragma return[] = 0x4
  #pragma return[] = 0x2
  #pragma return[] = 0x1
}

 

char HalfStep_Tbl(char i)     /* Half Step or Micro Step Look up Table */
{
  skip(i) ;
  #pragma return[] = 0x8
  #pragma return[] = 0xc

#pragma return[] = 0x4
  #pragma return[] = 0x6
  #pragma return[] = 0x2
  #pragma return[] = 0x3
  #pragma return[] = 0x1
  #pragma return[] = 0x9
}

 

void main(void)
{

 

INTCON = 0x10 ;    /*  Enable the INTE Interrupt bit Interrupts not Used */
                   /*  The INTF Flag is set on each high to low        */
                   /*   transition of the 555 */
    /*  The motor drive is on for 1 period of the 555 */

 

OPTION = 0x28 ;           /* TOCKI enabled  and Prescaler to WDT */
PORTA  = 0b.00000 ;
TRISA  = 0b.10000 ;       /* RA4 as TMR0 input -- RA0 - RA3 as motor Drives */

PORTB  = 0b.00000000 ;
TRISB  = 0b.11111111 ;    /* all B as inputs */
PORTA = 0 ;
INTF = 0 ;                /* Clear ALL */
Index = 0 ;
TMR0 = 0 ;
Mode = 0 ;
MotorVal = 0 ;
Step = 0 ;
StepDly = 0 ;
Dir = CCW ;

 

do
{

 

if (Dir != DirIn )      /* Adjusts Table index if Direction change */
  {
   if (DirIn == CW )
     {
       Index = Index + 2 ;  /*  Ahead 2 table entries */
       Dir = CW ;
     }
     else
     {
       Index= Index - 2 ;  /* Back 2 table entries */
       Dir = CCW ;
     }
   }
     
if ( INTF )                   /*  True if RB0 High to Low */
  {
 
   Step = StepIn & StepDly ;  /* Cheap debounce of the Step input */
  

 

  if ((Step) || ( TMR0 > 0 ))  /* Either Step or TMR0 Can move motor */
   {

 ModeLo = ModeLoIn;   /* Get Mode selection */
    ModeHi = ModeHiIn ;
    Mode = Mode & 0x03 ;  /* Make sure mode is 0 - 3 */

 

    switch ( Mode)   /* Which mode */
     {
case TwoPhase:
            Index = Index & 0x03 ;      
            MotorVal = TwoPhase_Tbl(Index);
         
break ;
   
case HalfStep:
     Index = Index & 0x07 ;
            MotorVal = HalfStep_Tbl(Index);
 
        break ;

case WaveDrive:
    Index = Index & 0x03 ;
    MotorVal = WaveDrive_Tbl (Index); 
         
        break ;

 


      case NoPhase:
        
        break ;
      }
         PORTA = MotorVal ;    /* Send Table value to Motor */ 
        
         if (Dir == CW )  /* Adjust Table index for Direction */
           Index++ ;
         else
           Index-- ;
        
         if ( TMR0 > 0 )  /* Was it TMR0 ? */
    TMR0-- ;         /* Yep Decrement TMR0 */
  else
           Step = 0 ;    /* No Clear Step */

 

        }
else
        {

 if (!HoldIn )   /* No Motor action just 555 timer */
           PORTA = 0 ;   /* Clear the port is No Hold required */
          else
           PORTA = MotorVal ;  /* HOLD Send last value to keep locked */
        }
        INTF = False ;   /* Clear the INTF flag */
        StepDly = StepIn ;  /* cheap debounce of Step */
   } 

 

}
while(True);    /* Do Forever */
}

ASM Output of Compiler

 


; CC5X Version 3.0E, Copyright (c) B. Knudsen Data
; C compiler for the PICmicro family
; ************   9. Feb 2000  23:27  *************

 

processor  16F84
radix  DEC

 

TMR0        EQU   0x01
OPTION_REG  EQU   0x81
PCL         EQU   0x02
PORTA       EQU   0x05
TRISA       EQU   0x85
PORTB       EQU   0x06
TRISB       EQU   0x86
PCLATH      EQU   0x0A
INTCON      EQU   0x0B
Zero_       EQU   2
RP0         EQU   5
INTF        EQU   1
HoldIn      EQU   3
StepIn      EQU   4
DirIn       EQU   5
ModeLoIn    EQU   6
ModeHiIn    EQU   7
Index       EQU   0x0D
Mode        EQU   0x0E
MotorVal    EQU   0x0F
Dir         EQU   0
StepDly     EQU   1

Step        EQU   2
ModeLo      EQU   0
ModeHi      EQU   1
i           EQU   0x0C
i_2         EQU   0x0C
i_3         EQU   0x0C

 

GOTO main

 

  ; FILE D:\HAM\PIC\MPLAB\MPLAB\STEPPER\STEPA.C
   ;/* StepA C */
   ;/* Stepper controller */
   ;/* A. Prewitt */
   ;/* N4PT   */
   ;/*  Jan 9 2000 */
   ;/* CC5X C Compiler */
   ;
   ;
   ;
   ;#include <16f84.h>
   ;
   ;#pragma bit Pulses    = PORTA.4   /* Drives TOCKI */
   ;#pragma bit HoldIn    = PORTB.3  /* 0= release 1=hold */
   ;#pragma bit StepIn    = PORTB.4  /* 0=NoStep 1=step */
   ;#pragma bit DirIn     = PORTB.5  /* 0=CCW  1=CW  */

;#pragma bit ModeLoIn = PORTB.6 /* 00 = 2ph 01 =1/2step 10=wave 11=nil */
   ;#pragma bit ModeHiIn  = PORTB.7
   ;
   ;#define TwoPhase  0
   ;#define HalfStep  1
   ;#define WaveDrive 2
   ;#define NoPhase   3
   ;#define True      1
   ;#define False     0
   ;#define CW        1
   ;#define CCW       0 
   ;
   ;char Index ;
   ;char Mode ;
   ;char MotorVal ;
   ;

;bit StepDly ;
   ;bit Step  ;
   ;
   ;
   ;#pragma bit  ModeLo = Mode.0
   ;#pragma bit  ModeHi = Mode.1
   ;
   ;
   ;char TwoPhase_Tbl(char i )      /* Two Phase Drive look up table */
   ;{
TwoPhase_Tbl
MOVWF i
   ;  skip(i);
CLRF  PCLATH
MOVF  i,W
ADDWF PCL,1
   ;  #pragma return[] = 0xc
RETLW .12
   ;  #pragma return[] = 0x6
RETLW .6
   ;  #pragma return[] = 0x3
RETLW .3
   ;  #pragma return[] = 0x9
RETLW .9
   ;}
   ;
   ;
   ;char WaveDrive_Tbl ( char i)  /* Wave Drive Look up Table */
   ;{
WaveDrive_Tbl

MOVWF i_2
   ;  skip(i) ;
CLRF  PCLATH
MOVF  i_2,W
ADDWF PCL,1
   ;  #pragma return[] = 0x8
RETLW .8
   ;  #pragma return[] = 0x4
RETLW .4
   ;  #pragma return[] = 0x2
RETLW .2
   ;  #pragma return[] = 0x1
RETLW .1
   ;}
   ;
   ;char HalfStep_Tbl(char i)     /* Half Step or Micro Step Look up Table */
   ;{
HalfStep_Tbl
MOVWF i_3

 ;  skip(i) ;
CLRF  PCLATH
MOVF  i_3,W
ADDWF PCL,1
   ;  #pragma return[] = 0x8
RETLW .8
   ;  #pragma return[] = 0xc
RETLW .12
   ;  #pragma return[] = 0x4
RETLW .4
   ;  #pragma return[] = 0x6
RETLW .6
   ;  #pragma return[] = 0x2
RETLW .2
   ;  #pragma return[] = 0x3
RETLW .3
   ;  #pragma return[] = 0x1
RETLW .1
   ;  #pragma return[] = 0x9
RETLW .9
   ;}
   ;
   ;
   ;
   ;void main(void)
   ;{
main
   ;
   ;
   ;

;INTCON = 0x10 ;           /*  Enable the INTE Interrupt bit Interrupts not Used */
MOVLW .16
MOVWF INTCON
   ;     /*  The INTF Flag is set on high to low transitions of the 555 */
   ;     /*  The motor drive is on for 1 period of the 555 */
   ;
   ;OPTION = 0x28 ;           /* TOCKI  and Prescaler to WDT */
MOVLW .40

BSF   0x03,RP0
MOVWF OPTION_REG
   ;PORTA  = 0b.00000 ;
BCF   0x03,RP0
CLRF  PORTA
   ;TRISA  = 0b.10000 ;       /* RA4 as TMR0 input -- RA0 - RA3 as motor Drives */
MOVLW .16
BSF   0x03,RP0
MOVWF TRISA
   ;PORTB  = 0b.00000000 ;
BCF   0x03,RP0
CLRF  PORTB
   ;TRISB  = 0b.11111111 ;    /* all B as inputs */
MOVLW .255
BSF   0x03,RP0
MOVWF TRISB
   ;PORTA = 0 ;
BCF   0x03,RP0
CLRF  PORTA
   ;INTF = 0 ;                /* Clear ALL */
BCF   0x0B,INTF
   ;Index = 0 ;
CLRF  Index
   ;TMR0 = 0 ;
CLRF  TMR0
   ;Mode = 0 ;
CLRF  Mode

 ;MotorVal = 0 ;
CLRF  MotorVal
   ;Step = 0 ;
BCF   0x10,Step
   ;StepDly = 0 ;
BCF   0x10,StepDly
   ;Dir = CCW ;
BCF   0x10,Dir
   ;
   ;
   ;do
   ;{
   ;
   ; 
   ; if (Dir != DirIn )            /* Adjusts Table index if Direction change */
m001 BTFSC 0x10,Dir
GOTO  m002

BCF   0x03,RP0
BTFSC 0x06,DirIn
GOTO  m003
GOTO  m005
m002 BCF   0x03,RP0
BTFSC 0x06,DirIn
GOTO  m005
   ;  {
   ;   if (DirIn == CW )
m003 BCF   0x03,RP0
BTFSS 0x06,DirIn
GOTO  m004
   ;     {
   ;       Index = Index + 2 ;  /*  Ahead 2 table entries */
MOVLW .2
ADDWF Index,1
   ;       Dir = CW ;
BSF   0x10,Dir
   ;     }
   ;     else
GOTO  m005
   ;     {
   ;       Index= Index - 2 ;  /* Back 2 table entries */
m004 MOVLW .2
SUBWF Index,1
   ;       Dir = CCW ;
BCF   0x10,Dir
   ;     }

   ;   }
   ;     
   ; if ( INTF )                   /*  True if RB0 High to Low */
m005 BTFSS 0x0B,INTF
GOTO  m001
   ;  {
   ; 
   ;   Step = StepIn & StepDly ;  /* Cheap debounce of the Step input */
BSF   0x10,Step
BCF   0x03,RP0
BTFSS 0x06,StepIn
BCF   0x10,Step
BTFSS 0x10,StepDly
BCF   0x10,Step
   ;  
   ;

 ;  if ((Step) || ( TMR0 > 0 ))   /* Either Step or TMR0 Can move motor */
BTFSC 0x10,Step
GOTO  m006
MOVF  TMR0,W
BTFSC 0x03,Zero_
GOTO  m014
   ;   {
   ;
   ;    ModeLo = ModeLoIn;   /* Get Mode selection */
m006 BCF   0x0E,ModeLo
BCF   0x03,RP0
BTFSC 0x06,ModeLoIn
BSF   0x0E,ModeLo
   ;    ModeHi = ModeHiIn ;
BCF   0x0E,ModeHi
BTFSC 0x06,ModeHiIn
BSF   0x0E,ModeHi
   ;    Mode = Mode & 0x03 ;  /* Make sure mode is 0 - 3 */
MOVLW .3
ANDWF Mode,1
   ;
   ;    switch ( Mode)   /* Which mode */
MOVF  Mode,W
BTFSC 0x03,Zero_
GOTO  m007
XORLW .1
BTFSC 0x03,Zero_

GOTO  m008
XORLW .3
BTFSC 0x03,Zero_
GOTO  m009
XORLW .1
BTFSC 0x03,Zero_
GOTO  m010
GOTO  m010
   ;     {
   ; case TwoPhase:
   ;            Index = Index & 0x03 ;      
m007 MOVLW .3
ANDWF Index,1
   ;            MotorVal = TwoPhase_Tbl(Index);
MOVF  Index,W
CALL  TwoPhase_Tbl
MOVWF MotorVal

;         
   ; break ;
GOTO  m010
   ;   
   ; case HalfStep:
   ;     Index = Index & 0x07 ;
m008 MOVLW .7
ANDWF Index,1
   ;            MotorVal = HalfStep_Tbl(Index);
MOVF  Index,W
CALL  HalfStep_Tbl
MOVWF MotorVal
   ; 
   ;        break ;
GOTO  m010
   ;
   ; case WaveDrive:
   ;    Index = Index & 0x03 ;
m009 MOVLW .3
ANDWF Index,1
   ;    MotorVal = WaveDrive_Tbl (Index); 
MOVF  Index,W
CALL  WaveDrive_Tbl
MOVWF MotorVal
   ;         
   ;        break ;
   ;
   ; case NoPhase:
   ;        
   ;        break ;
   ;      }

  ;         PORTA = MotorVal ;    /* Send Table value to Motor */ 
m010 MOVF  MotorVal,W
BCF   0x03,RP0
MOVWF PORTA
   ;        
   ;         if (Dir == CW )  /* Adjust Table indexer for Direction */
BTFSS 0x10,Dir
GOTO  m011
   ;           Index++ ;
INCF  Index,1
   ;         else
GOTO  m012
   ;           Index-- ;

m011 DECF  Index,1
   ;        
   ;         if ( TMR0 > 0 )  /* Was it TMR0 ? */
m012 BCF   0x03,RP0
MOVF  TMR0,W
BTFSC 0x03,Zero_
GOTO  m013
   ;    TMR0-- ;   /* Yep Decrement TMR0 */
DECF  TMR0,1
   ;  else
GOTO  m016
   ;           Step = 0 ;    /* No Clear Step */
m013 BCF   0x10,Step
   ;
   ;        }
   ; else
GOTO  m016
   ;        {
   ;          if (!HoldIn )   /* No Motor action just 555 timer */
m014 BCF   0x03,RP0
BTFSC 0x06,HoldIn
GOTO  m015
   ;           PORTA = 0 ;   /* Clear the port is No Hold required */
CLRF  PORTA
   ;          else
GOTO  m016
   ;           PORTA = MotorVal ;  /* Send last value to keep motor locked */
m015 MOVF  MotorVal,W
BCF   0x03,RP0
MOVWF PORTA
   ;        }

 ;        INTF = False ;   /* Clear the INTF flag */
m016 BCF   0x0B,INTF
   ;        StepDly = StepIn ;  /* Poor mans debounce of Step */
BCF   0x10,StepDly
BCF   0x03,RP0
BTFSC 0x06,StepIn
BSF   0x10,StepDly
   ;   } 
   ;
   ;}
   ;while(True);    /* Do Forever */
GOTO  m001
   ;}

 

END