PIC16F874 Stepper Motor Program
List = 16F874
Include
;--==*[CONSTANTS]*==--
#define COMMAND_2 'B'
#define COMMAND_3 'C'
#define COMMAND_4 'D'
;--==*[VARIABLES]*==--
cmdNum equ 0x20 ; command number. 0xFF for invalid command
recByte equ 0x21 ; received byte
motorL equ 0x22 ; motor data - low byte
motorH equ 0x23 ; motor data - high byte
byteCnt equ 0x24 ; internal counter for byte counting during reception
tickL equ 0x25 ; ticks: low byte
tickH equ 0x26 ; ticks: high byte
result1L equ 0x27 ; result: this one is needed for storage of ticks
result1H equ 0x28
winkelL equ 0x29 ; winkel: tick counter without overflow check etc.
winkelH equ 0x30
Quad equ 0x31 ; quadrature signal, for direction storage
Oldb equ 0x32 ; old value of PORTB
Newb equ 0x33 ; new value of PORTB
Tmr0o0 equ 0x34 ; TMR0 overflow counter 0
Tmr0o1 equ 0x35 ; TMR0 overflow counter 1
Wtemp1 equ 0x60 ; storage for the W register (RBIF)
Wtemp2 equ 0x61 ; storage for the W register (CCP2IF)
Wtemp3 equ 0x62 ; storage for the W register (RCIF)
Wtemp4 equ 0x63 ; storage for the W register (USART error routines)
Org 0x00 ; --==*[RESET VECTOR]*==--
Bra main
Org 0x04 ; --==*[INTERRUPT VECTOR]*==--
Bra int_handler
Org 0x05 ; --==*[MAIN PROGRAM]*==--
Main:
;--==*[VARIABLES - INITIALIZE]*==--
movlw 0xFF
movwf cmdNum
clrf motorL
clrf motorH
clrf tickL
clrf tickH
clrf result1L
clrf result1H
clrf winkelL
clrf winkelH
clrf Quad
clrf Oldb
clrf Newb
clrf Tmr0o0
clrf Tmr0o1
;--==*[PORTS - SET PORT B]*==--
clrf PORTB
bsf STATUS, RP0 ; PIN4 and 5 as input (photo interrupter signals)
movlw 0x30 ; pin1 has to be an output (direction signal)
movwf TRISB ; all other pins are outputs, too (default)
bcf STATUS, RP0
;--==*[PORTS - SET PORT C]*==--
clrf PORTC
bsf STATUS, RP0
movlw 0xFB ; pin2 as output (PWM signal)
movwf TRISC ; pins 6 and 7 have to be inputs (default)
bcf STATUS, RP0 ; all other pins are inputs, too (default)
;--==*[CCP1 - SETUP PWM MODULE]*==--
bsf STATUS, RP0
movlw 0xF9 ; PWM period (calculated with formula)
movwf PR2
bcf STATUS, RP0 ; duty cycle = 0
clrf CCPR1L ; CCPR1L is upper 8 bits (bits 9...2) of duty cycle
movlw 0x05 ; enable timer2 (bit:2) and set prescale of 1:4 (bit:0-1)
movwf T2CON ; timer2 is important for PWM operation!
movlw 0x0F ; select PWM mode for CCP1 module (bits 0-3)
movwf CCP1CON ; and reset lower two bits of duty cycle (bits 4-5)
;--==*[USART - SETUP]*==--
bsf STATUS, RP0
movlw 0x40 ; configure baud generator register (calculated with formula)
movwf SPBRG ; with: 9600 baud, no parity, 8 data bits, no handshake
movlw 0x24 ; enable transmit (bit:5) and high speed baud rate (bit:2)
movwf TXSTA
bcf STATUS, RP0
movlw 0x90 ; enable serial port (bit:7) and continuous reception (bit:4)
movwf RCSTA
clrw ; W = 0
movwf RCREG ; reset UART receiver and FIFO
movwf RCREG ; so we can avoid receive/framing/overrun errors at the beginning
movwf RCREG
movwf TXREG ; just in case: the TXIF flag is now valid (=1; avoid infinite loops in sendByte)
;--==*[TIMER0 - SETUP]*==--
bsf STATUS, RP0 ; this is tricky; prescaler has to be assigned to the WDT,
; in case you want to achieve 1:1 prescale
bcf OPTION_REG, PS0 ; first, set prescaler to 1:2
bcf OPTION_REG, PS1
bcf OPTION_REG, PS2
bsf OPTION_REG, PSA ; then, assign prescaler to WDT; now we have a 1:1 prescale for timer0:-)
bcf OPTION_REG, T0SE
bcf OPTION_REG, T0CS
bcf STATUS, RP0
;--==*[INTERRUPTS - SETUP]*==--
bsf STATUS, RP0
clrf PIE1
bsf PIE1, RCIE ; enable "receive byte" interrupt
bcf STATUS, RP0
clrf INTCON ; reset all interrupt flags
bsf INTCON, RBIE ; enable "interrupt on change" interrupt
bsf INTCON, T0IE ; enable "timer0 overflow" interrupt
bsf INTCON, PEIE ; enable peripheral interrupts
bsf INTCON, GIE ; enable global interrupts
;--==*[MAIN LOOP]*==--
Loop:
Bra Loop
;--==*[SEND BYTE ROUTINE]*==--
sendByte: ; send byte (which is stored in W)
sendByte_l0: ; wait until new data arrives in TXREG
btfss PIR1, TXIF ; (indicated via transmit interrupt flag bit: TXIF)
goto sendByte_l0
sendByte_l1:
movwf TXREG ; send new data
return
;--==*[INTERRUPT HANDLING ROUTINE]*==--
int_handler:
btfsc RCSTA, OERR ; overflow error occurred, handle it
goto err_Overflow
btfsc RCSTA, FERR ; framing error occurred, handle it
goto err_Frame
btfsc PIR1, RCIF ; receive interrupt: RCIF
goto int_USART_receive
btfsc INTCON, RBIF ; pin interrupt: RBIF
goto int_RB_change
btfsc INTCON, T0IF ; TMR0 interrupt: T0IF
goto int_timer0_reset
retfie
int_RB_change:
incf tickL, 1 ; increment ticks (low byte)
btfsc STATUS, Z
incf tickH, 1 ; increment ticks on overflow (high byte)
incf winkelL, 1 ; same as tick, but will not be reset (eichungswert)
btfsc STATUS, Z
incf winkelH, 1
movwf Wtemp1 ; save W
movwf PORTB
movwf newb ; newb = PORTB
movlw 0x30 ; and mask
andwf Oldb, 1 ; reset all bits except 4 and 5
andwf newb, 1 ; reset all bits except 4 and 5
clrf Quad ; reset quad value
clrw ; oldb == 00?
subwf Oldb, W
bz O00
movlw 0x10 ; oldb == 01?
subwf Oldb, W
bz O01
movlw 0x20 ; oldb == 10?
subwf Oldb, W
bz O10
goto O11 ; else, oldb == 11
O00:
movlw 0x10 ; newb == 01?
subwf newb, W
bnz quit
bsf Quad, 7 ; left
goto quit
O01:
movlw 0x30 ; newb == 11?
subwf newb, W
bnz quit
bsf Quad, 7 ; left
goto quit
O10:
clrw ; newb == 00?
subwf newb, W
bnz quit
bsf Quad, 7 ; left
goto quit
O11:
movlw 0x20 ; newb == 10?
subwf newb, W
bnz quit
bsf Quad, 7 ; left
quit:
movwf PORTB
movwf Oldb ; oldb = PORTB
movwf Wtemp1 ; restore W
bcf INTCON, RBIF ; reset interrupt (important)
retfie
int_timer0_reset:
btfsc Tmr0o0, 7 ; wait 128 overflows
goto a1
incf Tmr0o0, 1
goto a0
a1:
btfsc Tmr0o1, 6 ; wait 64 overflows
goto a4
incf Tmr0o1, 1
goto a0
a4:
btfsc PORTB, 7 ; a short hack, so we can measure the impulses
goto next1 ; of timer0 with an oscilloscope
bsf PORTB, 7 ; signal is on bit 7 of port B
goto mainl
next1:
bcf PORTB, 7
mainl:
movwf Wtemp2 ; save W
movf tickL ; store ticks in result1
movwf result1L
movf tickH
movwf result1H
movf Quad ; and blend the direction bit on MSB of result1
iorwf result1H, 1
clrf tickH ; clear tick counter
clrf tickL
clrf Tmr0o0 ; clear timer0 overflow counters
clrf Tmr0o1
movf Wtemp2 ; restore W
a0:
bcf INTCON, T0IF ; reset interrupt (important)
retfie
int_USART_receive:
movwf Wtemp3 ; save W
movlw COMMAND_3 ; command3 active?
subwf cmdNum, W
bz getData_command3 ; yes, handle it
movf RCREG ; store received byte
clrf RCREG ; it's a good idea to flush the buffer
clrf RCREG ; after receiving a byte, so it's forced that we have a new byte in the buffer in the next step
clrf RCREG
movwf recByte
movlw COMMAND_2 ; execute command2?
subwf recByte, W
bz command2 ; yes, do it
movlw COMMAND_3 ; execute command3?
subwf recByte, W
bz command3 ; yes, do it
movlw COMMAND_4 ; execute command4?
subwf recByte, W
bz command4 ; yes, do it
commandUnknown: ; else, received byte is unknown
bsf PORTB, 0 ; show error on LEDs
movwf Wtemp3 ; restore W
retfie
;--==*[COMMAND EXEC - transmit motor data in debug mode]*==--
command2:
movf result1H
call sendByte
movf result1L
call sendByte
movf winkelH
call sendByte
movf winkelL
call sendByte
movwf Wtemp3 ; restore W
retfie
;--==*[COMMAND INIT - setup for receive motor data (part 1/2)]*==--
command3: ; command3
movlw COMMAND_3
movwf cmdNum ; cmdNum contains now the current command value
movlw .2
movwf byteCnt ; we want exactly 2 bytes from the PC
movwf Wtemp3 ; restore W
retfie
;--==*[COMMAND EXEC - receive motor data (part 2/2)]*==--
getData_command3:
decf byteCnt, 1 ; handle byte counter
bz c3_b2 ; if byte counter is 0 then it is the 2nd byte
movf RCREG ; else, 1st byte receive
movwf motorL ; store in motorL
goto outHere ; and exit
c3_b2:
movf RCREG ; 2nd byte receive
movwf motorH ; store in motorH
movlw 0xFF ; reset cmdNum to undefined value (0xFF)
movwf cmdNum
; reconfigure PWM
movf motorH
movwf CCPR1L ; store high byte (8; bits 9-2)
bcf CCP1CON, CCP1Y
btfsc motorL, 0 ; store low byte (2; bits 0)
bsf CCP1CON, CCP1Y
bcf CCP1CON, CCP1X
btfsc motorL, 1 ; store low byte (2; bits 1)
bsf CCP1CON, CCP1X
btfss motorL, 2 ; motorL<2> bit is significant for motor direction
goto turn_left
bsf PORTB, 1 ; turn motor right
goto outHere
turn_left:
bcf PORTB, 1 ; turn motor left
outHere:
movwf Wtemp3 ; restore W
retfie
;--==*[COMMAND EXEC - transmit motor data]*==--
command4:
movf result1H ; transmit high byte
call sendByte
movf result1L ; transmit low byte
call sendByte
movwf Wtemp3 ; restore W
retfie
;--==*[ERROR HANDLING - for the serial communication]*==--
err_Overflow: ; handle overflow error
movwf Wtemp4 ; save W
bsf PORTB, 7 ; show error on LEDs (10)
bcf PORTB, 6
bcf RCSTA, CREN ; disable continuous reception
movf RCREG, W ; flush receive FIFO buffer (3 bytes deep)
movf RCREG, W
movf RCREG, W
bsf RCSTA, CREN ; re-enable continuous reception
movwf Wtemp4 ; restore W
retfie
err_Frame: ; handle frame error
movwf Wtemp4 ; save W
bcf PORTB, 7 ; show error on LEDs (01)
bsf PORTB, 6
movf RCREG, W ; flush receive FIFO buffer (3 bytes deep)
movf RCREG, W
movf RCREG, W
movwf Wtemp4 ; restore W
retfie
End
Thyristor module is one of the most commonly used semiconductor devices because of its small size, simple structure and strong function.This device has been widely applied in various kinds of electronic equipment and electronic products, used as a rectifier, inverter, frequency, voltage regulator, contactless control of motor speed, motor excitation, non-contact switch and the power control, etc.
Thyristor Module,High Current Thyristor Module,Air Cooling Thyristor Module,Standard Voltage Thyristor Module
YANGZHOU POSITIONING TECH CO., LTD. , https://www.yzpst.com