;****************************** StepCon.ASM *********************************** ; ; Function: This program implements a two stepper motor controller. A ; function word is input on the least 4 significant bits of PORTA and the ; 8 bits output on PORTB must be fed into a suitable driver (such as the ; ULN2803A for unipolar steppers or the L293D for bipolar steppers). ; ; The 4 bit function word is broken into two two bit function words, one for ; each motor. See the motor states in the constant section below (the order ; may be changed). ; ; PORTA<4> is an output pin pulsed for each motor step. One can monitor this ; pin and command the motors appropriately. ; ; The excitation table can also be changed; you may also need to change the ; EXCITATION_TABLE_SIZE (eg for half-stepping). ; ; The motor speeds can be adjusted via the the TMR0 prescaler and the TMR0 ; duration; they cannot be individually adjusted. ; ; This program uses the macro suite available from the website: ; http://www3.telus.net/Girard/ ; ; Author: Jean-Louis Girard ; Copyright: This program may be distributed freely, without profit, ; subject to proper acknowledgement. ; ; Date: Aug, 2001 ; ;******************* Global Assembler Directives and Includes ***************** ; LIST p=16F84 #INCLUDE #INCLUDE C:\MYDOCU~1\MYFILE~1\MPLAB\CONTROL.INC #INCLUDE C:\MYDOCU~1\MYFILE~1\MPLAB\SKIP.INC __CONFIG _CP_OFF & _WDT_OFF & _PWRTE_ON & _XT_OSC ; ;********************************* Macros ************************************* ; ASSIGNF MACRO FR1, FR2 movfw FR2 movwf FR1 ENDM ASSIGNL MACRO FR, LITERAL movlw LITERAL movwf FR ENDM SKIP_IF_RIGHT MACRO STATE_VARIABLE, STATE movfw STATE_VARIABLE andlw B'0011' ; mask out left motor state xorlw STATE btfss STATUS, Z ENDM SKIP_IF_LEFT MACRO STATE_VARIABLE, STATE movfw STATE_VARIABLE andlw B'1100' ; mask out right motor state xorlw STATE btfss STATUS, Z ENDM ; ;******************************* Constants ************************************ ; EXCITATION_TABLE_SIZE EQU 4 ; number of excitations in sequence TMR0_CNT_UP EQU D'256'-D'150' ; D'256' - duration (motor speed) ; Motor states RIGHT_FORWARD EQU 0 RIGHT_BACKWARD EQU 1 RIGHT_HOLD EQU 2 RIGHT_IDLE EQU 3 LEFT_FORWARD EQU RIGHT_FORWARD << 2 LEFT_BACKWARD EQU RIGHT_BACKWARD << 2 LEFT_HOLD EQU RIGHT_HOLD << 2 LEFT_IDLE EQU RIGHT_IDLE << 2 ; ;**************************** File Registers ********************************** ; CBLOCK H'C' leftExcitationCntr ; current left motor excitation number rightExcitationCntr ; current right motor excitation number motorState ; 4 bit function word for both motors (PORTA<3:0>) leftExcitation ; excitation for left motor rightExcitation ; excitation for right motor ENDC ; ;****************************** Start Vector ********************************** ; ORG 0 goto Main ; ;***************************** Interrupt Vector ******************************* ; ORG 4 BEGINCOND btfss INTCON, T0IF ; if (TMR0 interrupt) NEXTCOND bsf PORTA, 4 ; { signal motor step on call MotorISR ; call motor interrupt service routine bcf PORTA, 4 ; signal motor step off ASSIGNL TMR0, TMR0_CNT_UP ; reset TMR0 to proper count bcf INTCON, T0IF ; clear TMRO interrupt flag ENDCOND ; } retfie ; return from interrupt ; ;******************************* Subroutines ********************************** ; MotorISR BEGINCOND ; Decide state of right motor SKIP_IF_RIGHT motorState, RIGHT_FORWARD ; if (motorState == FORWARD) NEXTCOND incf rightExcitationCntr, F ; { excitationCntr++ SKIPL rightExcitationCntr, LE, EXCITATION_TABLE_SIZE-1; if (excitationCntr > EXCITATION_TABLE_SIZE-1) clrf rightExcitationCntr ; excitationCntr = 0 movfw rightExcitationCntr ; convert excitationCntr call Excitations ; to excitation sequence movwf rightExcitation ; and save it ; } COND ; else SKIP_IF_RIGHT motorState, RIGHT_BACKWARD ; if (motorState == BACKWARD) NEXTCOND BEGINCOND SKIPL rightExcitationCntr, EQ, 0 ; { if (excitationCntr == 0) NEXTCOND ASSIGNL rightExcitationCntr, EXCITATION_TABLE_SIZE-1; excitationCntr = EXCITATION_TABLE_SIZE-1 COND ; else decf rightExcitationCntr, F ; excitationCntr-- ENDCOND movfw rightExcitationCntr ; convert excitationCntr call Excitations ; to excitation sequence movwf rightExcitation ; and save it ; } COND ; else // HOLD SKIP_IF_RIGHT motorState, RIGHT_HOLD ; if (motorState == HOLD) NEXTCOND ; { // keep current excitation movfw rightExcitationCntr ; convert excitationCntr call Excitations ; to excitation sequence movwf rightExcitation ; and save it ; } COND ; else // IDLE clrf rightExcitation ; // idle excitation ENDCOND ; swapf rightExcitation, F ; move high order excitation nibble ; into low order nibble BEGINCOND ; Decide state of left motor SKIP_IF_LEFT motorState, LEFT_FORWARD ; if (motorState == FORWARD) NEXTCOND incf leftExcitationCntr, F ; { excitationCntr++ SKIPL leftExcitationCntr, LE, EXCITATION_TABLE_SIZE-1 ; if (excitationCntr > EXCITATION_TABLE_SIZE-1) clrf leftExcitationCntr ; excitationCntr = 0 movfw leftExcitationCntr ; convert excitationCntr call Excitations ; to excitation sequence movwf leftExcitation ; and save it ; } COND ; else SKIP_IF_LEFT motorState, LEFT_BACKWARD ; if (motorState == BACKWARD) NEXTCOND BEGINCOND SKIPL leftExcitationCntr, EQ, 0 ; { if (excitationCntr == 0) NEXTCOND ASSIGNL leftExcitationCntr, EXCITATION_TABLE_SIZE-1 ; excitationCntr = EXCITATION_TABLE_SIZE-1 COND ; else decf leftExcitationCntr, F ; excitationCntr-- ENDCOND movfw leftExcitationCntr ; convert excitationCntr call Excitations ; to excitation sequence movwf leftExcitation ; and save it ; } COND ; else // HOLD SKIP_IF_LEFT motorState, LEFT_HOLD ; if (motorState == HOLD) NEXTCOND ; { // keep current excitation movfw leftExcitationCntr ; convert excitationCntr call Excitations ; to excitation sequence movwf leftExcitation ; and save it ; } COND ; else // IDLE clrf leftExcitation ; // idle excitation ; // keep current excitation ENDCOND ; movfw rightExcitation ; PORTB = rightExcitation addwf leftExcitation, W ; + leftExcitation movwf PORTB return ; Excitation table Excitations addwf PCL,F retlw B'11000000' ; excitation sequence # 0 retlw B'01100000' ; " # 1 retlw B'00110000' ; " # 2 retlw B'10010000' ; " # 3 ; ;****************************** Main Program ********************************** ; Main bsf STATUS, RP0 clrf TRISB ASSIGNL TRISA, B'00001111' ASSIGNL OPTION_REG, B'11010101' ; 1:64 TMRO prescaler bcf STATUS, RP0 bcf PORTA, 4 ; clear motor step signal clrf leftExcitationCntr ; leftExcitationCntr = 0 clrf rightExcitationCntr ; rightExcitationCntr = 0 ASSIGNL TMR0, TMR0_CNT_UP ; TMR0 = TMR0_CNT_UP bcf INTCON, T0IF ; enable TMRO interrupts bsf INTCON, T0IE bsf INTCON, GIE LOOP ; continually read PORTA motorState; this loop gets ; interrupted to service the motors whenever needed ASSIGNF motorState, PORTA ENDLOOP END