📄 motor.asm
字号:
; - Homepage: http://www.xraw.de -
list p=16f874
include <p16f874.inc>
; --==*[ 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -