; control a small stepper motor with a 12c509 ; This version is controlled through a 38400 Baud ; connection on pin GP3 ; ; Peter Lynch, 15 May 1998 ; pic@beowulf.demon.co.uk ; (this code is NOT certified Year 2000 compliant) LIST P=12c509 include "C:\picde\P12c509.inc" CARRY EQU 0 ; carry bit (0) in STATUS byte ZERO EQU 2 ; zero bit (2) in STATUS byte OPMASK EQU B'11000000' BMASK EQU B'00001000' ; all bits output (except GP3) ; GP3 controls run/stop ; GP5 controls direction MY_ID EQU 'A' ; identifer byte for this device ; (create a sequence if many on same line) SERIAL EQU 3 ; serial input on GP3 DEL_MS EQU 0C ; milliseconds to wait between steps DEL_CNT EQU 0D INDEX EQU 0E ; step index RXBYTE EQU 0F ; store received byte IDENT EQU 10 DIRN EQU 11 ; direction of motion N1 EQU 12 ; msb count of steps N2 EQU 13 ; lsb count of steps R0 EQU 14 ; msd of 5 digit BCD step count R1 EQU 15 R2 EQU 16 ; lsd of BCD step count H_byte EQU 17 ; holds msb of 16 bit binary conversion L_byte EQU 18 ; holds lsb of 16 bit binary conversion H_temp EQU 19 L_temp EQU 1A S0 EQU 1B ; msd of 5 digit step speed S1 EQU 1C S2 EQU 1D S_RATE EQU 1E ORG 3ff DW 0c70 ORG 0 ; start of main code MOVWF OSCCAL MOVLW OPMASK OPTION MOVLW BMASK TRIS GPIO CLRF INDEX ; now go into a loop, output the next bit pattern on ; GP0 - GP4 (GP3 is input only) NEXT BSF GPIO, 5 ; indicate waiting for ident byte CALL RX MOVLW MY_ID SUBWF RXBYTE, W BTFSS STATUS, 2 ; skip if non-zero GOTO NEXT ; must be for another device ... ; get the next byte, which is either a '+' or '-' ; depending on the direction to step the motor BCF GPIO, 5 ; got our ident, proceed CLRF DIRN CALL RX MOVLW '-' ; check the direction byte SUBWF RXBYTE, W BTFSC STATUS, 2 GOTO DIR_NEG MOVLW '+' SUBWF RXBYTE, W ; wasn't -ve, check for +ve BTFSS STATUS, 2 GOTO NEXT ; neither INCF DIRN ; set bit 0 for +ve stepping DIR_NEG ; now get the count of steps to take, this is 5 digits of BCD ; with left-padded zeros. CALL RX MOVF RXBYTE, W ANDLW 0F ; only want the bottom 4 bits MOVWF R0 CALL RX MOVF RXBYTE, W ANDLW 0F MOVWF R1 SWAPF R1, F ; place in top 4 bits (and clear low 4 bits) CALL RX MOVF RXBYTE, W ANDLW 0F ADDWF R1, F ; got bottom 4 bits too CALL RX MOVF RXBYTE, W ANDLW 0F MOVWF R2 SWAPF R2, F CALL RX MOVF RXBYTE, W ANDLW 0F ADDWF R2, F ; get the step rate, this is a ":" followed by 3 digits ; giving the step-rate in mSec per step CALL RX MOVLW ':' ; check for : between step count & step rate SUBWF RXBYTE, W BTFSS STATUS, 2 GOTO NEXT CLRF S0 CLRF S1 CALL RX MOVF RXBYTE, W ANDLW 0F MOVWF S1 CALL RX MOVF RXBYTE, W ANDLW 0F MOVWF S2 SWAPF S2, F CALL RX MOVF RXBYTE, W ANDLW 0F ADDWF S2, F ; get the last byte, it should be a . If not go round again ... CALL RX MOVLW .10 SUBWF RXBYTE, W BTFSS STATUS, 2 GOTO NEXT ; not a ; now convert the BCD into a 16 bit step count and store it in N1, N2 CALL BCDtoB MOVF H_byte, W MOVWF N1 MOVF L_byte, W MOVWF N2 ; do the same with the step time MOVF S0, W ; shuffle the step rate into the MOVWF R0 ; correct regsiters for BCD conversion MOVF S1, W MOVWF R1 MOVF S2, W MOVWF R2 CALL BCDtoB MOVF L_byte, W ; only want values in range 1 - 255 mSec MOVWF S_RATE NX_STEP ; test for the end condition, the step count == 0 MOVF N1, W IORWF N2, W BTFSC STATUS, 2 ; check if both counters are zero GOTO NEXT ; don't step if so ; take a step in the appropriate direction BTFSC DIRN, 0 GOTO CWISE ACWISE INCF INDEX, W GOTO NEW_IDX CWISE DECF INDEX, W NEW_IDX ANDLW .7 MOVWF INDEX ; here W contains the index (either incremented or decremented, depending ; on the direction switch) into the array for the new stepper actuations CALL STEP ; convert the index into a bit pattern MOVWF GPIO CALL DELAY ; now decrement the step count (16 bits) MOVLW 1 SUBWF N2, F BTFSS STATUS, 0 ; carry is 0 if result was -ve DECF N1 ; if so decr. top byte too GOTO NX_STEP ; and back round the loop ; routine to get step index STEP ADDWF PCL, F RETLW B'00000001' RETLW B'00000101' RETLW B'00000100' RETLW B'00000110' RETLW B'00000010' RETLW B'00010010' RETLW B'00010000' RETLW B'00010001' ; routine to delay between steps ; do this in two parts: ; - first part, delay for the first millisecond. ; this will include the time taken to do all the ; work in the main loop, stepping the motor etc. ; - second part, delay for he second and subsequent ; milliseconds DELAY NOP ; padding to get the total NOP ; overhead to a multiple of ; 4 uSec. MOVLW .242 ; additional time to use up ; from first millisecond MOVWF DEL_CNT DEL_0 NOP DECFSZ DEL_CNT, F GOTO DEL_0 ; here the first millisecond is done, do the subsequent ones DECF S_RATE, W ; as we've done the first one MOVWF DEL_MS DEL_1 MOVLW .249 ; 1 millisecond delay MOVWF DEL_CNT DEL_2 NOP DECFSZ DEL_CNT, F GOTO DEL_2 DECFSZ DEL_MS, F GOTO DEL_1 RETURN ; routine to delay a full data bit time. ; at 38400 Baud this is 26 uSec. ; take into account the bit-twiddling ; and routine call overheads DLY_F_BIT NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP RETURN ; routine to receive a character from the serial port ; poll for it at 38400 Baud RX ; wait for the serial line to go high (start of start bit) RX_START BTFSS GPIO, SERIAL GOTO RX_START ; wait a quarter bit time and check that the line is still high ; (guards against some false triggering) NOP NOP NOP NOP NOP BTFSS GPIO, SERIAL GOTO RX ; wait a bit time, then read bit 0 CALL DLY_F_BIT BSF RXBYTE, 0 BTFSC GPIO, SERIAL BCF RXBYTE, 0 ; bit 1 CALL DLY_F_BIT BSF RXBYTE, 1 BTFSC GPIO, SERIAL BCF RXBYTE, 1 ; bit 2 CALL DLY_F_BIT BSF RXBYTE, 2 BTFSC GPIO, SERIAL BCF RXBYTE, 2 ; bit 3 CALL DLY_F_BIT BSF RXBYTE, 3 BTFSC GPIO, SERIAL BCF RXBYTE, 3 ; bit 4 CALL DLY_F_BIT BSF RXBYTE, 4 BTFSC GPIO, SERIAL BCF RXBYTE, 4 ; bit 5 CALL DLY_F_BIT BSF RXBYTE, 5 BTFSC GPIO, SERIAL BCF RXBYTE, 5 ; bit 6 CALL DLY_F_BIT BSF RXBYTE, 6 BTFSC GPIO, SERIAL BCF RXBYTE, 6 ; bit 7 (yay!) CALL DLY_F_BIT BSF RXBYTE, 7 BTFSC GPIO, SERIAL BCF RXBYTE, 7 CALL DLY_F_BIT ; wait for stop bit RX_STOP BTFSC GPIO, SERIAL GOTO RX_STOP ; loop until i/p goes low RETURN ; routine to convert 5 digits of BCD into a 16bit binary number ; from the Microchip Embedded Control Handbook p 2-201 mpy10b andlw 0f addwf L_byte btfsc STATUS, CARRY incf H_byte mpy10a bcf STATUS, CARRY rlf L_byte, w movwf L_temp rlf H_byte, w movwf H_temp ; bcf STATUS, CARRY ; multiply by 2 rlf L_byte rlf H_byte bcf STATUS, CARRY ; multiply by 2 rlf L_byte rlf H_byte bcf STATUS, CARRY ; multiply by 2 rlf L_byte rlf H_byte ; movf L_temp, w addwf L_byte btfsc STATUS, CARRY incf H_byte movf H_temp, w addwf H_byte retlw 0 ; ; BCDtoB clrf H_byte movf R0, w andlw 0F movwf L_byte call mpy10a ; result = 10a + b ; swapf R1, w call mpy10b ; result = 10(10a+b) ; movf R1, w call mpy10b ; result = 10(10(10a+b)+c) ; swapf R2, w call mpy10b ; result = 10(10(10(10a+b)+c)+d) ; movf R2, w andlw 0F addwf L_byte btfsc STATUS, CARRY incf H_byte ; result = 10(10(10(10a+b)+c)+d)+e retlw 0 END