pIC16f874步进电机程序
list p=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 ]*==--
b main
org 0x04 ; --==*[ INT VECTOR ]*==--
b 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 - setup port B ]*==--
clrf PORTB
bsf STATUS, RP0 ; PIN 4 and 5 as input (photo-interrupter signals)
MOVlw b’00110000’ ; pin 1 has to be an output (direction signal)
MOVwf TRISB ; all other pins are outputs, too (default)
bcf STATUS, RP0
; --==*[ PORTS - setup port C ]*==--
clrf PORTC
bsf STATUS, RP0
MOVlw b’11111011’ ; pin 2 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 d’249’ ; pwm period (calculated with formula)
MOVwf PR2
bcf STATUS, RP0 ; duty cycle = 0
clrf CCPR1L ; CCPR1L is upper 8 (bit: 9...2) bits of duty cycle
MOVlw b’00000101’ ; enable timer2 (bit: 2) and set prescale of 1:4 (bit: 0-1)
MOVwf T2CON ; timer2 is important for pwm operation!
MOVlw b’00001111’ ; select pwm mode for ccp1 module (bit: 0-3)
MOVwf CCP1CON ; and reset lower two bits of duty cycle (bit: 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 b’00100100’ ; enable trasmit (bit: 5) and high speed baud rate (bit: 2)
MOVwf TXSTA
bcf STATUS, RP0
MOVlw b’10010000’ ; 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; avoids infinite loops in sendByte)
; --==*[ TIMER 0 - 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:
b loop
; --==*[ sendByte - ROUTINE ]*==--
sendByte: ; send byte (which is stored in W)
sendByte_l0: ; wait until new data arrived in txreg
btfss PIR1, TXIF ; (inDICated via transmit interrupt flag bit: txif)
b sendByte_l0
sendByte_l1:
MOVwf TXREG ; send new data
return
; --==*[ INTERRUPT HANDLING ROUTINE ]*==--
int_handler:
btfsc RCSTA, OERR ; overflow error occured, handle it
b err_Overflow
btfsc RCSTA, FERR ; framing error occured, handle it
b err_Frame
btfsc PIR1, RCIF ; receive interrupt: rcif
b int_USART_receive
btfsc INTCON, RBIF ; pin interrupt: rbif
b int_RB_change
btfsc INTCON, T0IF ; tmr0 interrupt: t0if
b 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
MOVfw PORTB
MOVwf newb ; newb = PORTB
MOVlw b’00110000’ ; 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 b’00010000’ ; oldb == 01 ?
subwf oldb, W
bz o01
MOVlw b’00100000’ ; oldb == 10 ?
subwf oldb, W
bz o10
b o11 ; else, oldb == 11
o00:
MOVlw b’00010000’ ; newb == 01 ?
subwf newb, W
bnz quit
bsf quad, 7 ; left
b quit
o01:
MOVlw b’00110000’ ; newb == 11 ?
subwf newb, W
bnz quit
bsf quad, 7 ; left
b quit
o10:
clrw ; newb == 00 ?
subwf newb, W
bnz quit
bsf quad, 7 ; left
b quit
o11:
MOVlw b’00100000’ ; newb == 10 ?
subwf newb, W
bnz quit
bsf quad, 7 ; left
quit:
MOVfw PORTB
MOVwf oldb ; oldb = PORTB
MOVfw 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 oscillograph
bsf PORTB, 7 ; signal is on bit 7 of portb
goto mainl
next1:
bcf PORTB, 7
mainl:
MOVwf wtemp2 ; save W
MOVfw tickL ; store ticks in result1
MOVwf result1L
MOVfw tickH
MOVwf result1H
MOVfw 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
MOVfw 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
MOVfw RCREG ; store received byte
clrf RCREG ; it’s a good idea to flush the buffer
clrf RCREG ; after receiving a byte, so it’s
clrf RCREG ; forced that we have a new byte in the buffer in the next step
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
MOVfw wtemp3 ; restore W
retfie
; --==*[ COMMAND EXEC - transmit motor data in debug mode ]*==--
command2:
MOVfw result1H
call sendByte
MOVfw result1L
call sendByte
MOVfw winkelH
call sendByte
MOVfw winkelL
call sendByte
MOVfw 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
MOVfw 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
MOVfw RCREG ; else, 1st byte receive
MOVwf motorL ; store in motorL
b outhere ; and exit
c3_b2:
MOVfw RCREG ; 2nd byte receive
MOVwf motorH ; store in motorH
MOVlw 0xFF ; reset cmdNum to undefined value (0xFF)
MOVwf cmdNum
; reconfigure PWM
MOVfw 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
b turn_left
bsf PORTB, 1 ; turn motor right
b outhere
turn_left:
bcf PORTB, 1 ; turn motor left
outhere:
MOVfw wtemp3 ; restore W
retfie
; --==*[ COMMAND EXEC - transmit motor data ]*==--
command4:
MOVfw result1H ; transmit high byte
call sendByte
MOVfw result1L ; transmit low byte
call sendByte
MOVfw 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 ; reenable continuous reception
MOVfw 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
MOVfw wtemp4 ; restore W
retfie
end
上一篇:pic12C508 DTMF拔号程序
下一篇:pic16f508步进电机程序
推荐阅读最新更新时间:2024-03-16 15:48