十年专注单片机方案开发的方案公司英锐恩,分享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