我尝试使用定时器中断在 pic 18F452 上实现软件UART——尽管我是微控制器的初学者——但我无法让计时工作。我使用 MPLAB asm 进行编译,使用 PICkit 2 进行编程。
LIST P=18F452
include <P18F452.inc>
CONFIG WDT=OFF, LVP=OFF, OSC=HS, CP0=OFF
variable cyclesPerBaud=1 ; 1 cycle(s) per baud
variable cyclesInt=0xFFFF ; counter in 16 bit timer
variable freq = 20000000 ; clock frequency 20Mhz
variable baud = 9600 ; baud rate
variable cyclesMain=33 ; cycles in Main program branch (intr->checkBitCounter->startStopBit->transfer)
variable cyclesIdle=16 ; cycles in Idle branch (intr->Idle)
variable offset = (freq/(4*baud))/(cyclesPerBaud)
variable initOffset = cyclesInt - offset
variable durrOffset = cyclesInt - offset + cyclesMain
variable hurrOffset = cyclesInt - offset + cyclesIdle
cblock 0x20
char ; character to send
bitCounter ; bits left to send
startStopBit ; checks to send start of stop bit
buffer ; buffer where char is rotated
cycle ; the current cycle in cyclesPerBaud starting high
endc
org 0000h
goto main
org 0008h
goto intr
main
bcf OSCCON, SCS ; use primary clock
bsf RCON, IPEN ; enable priority levels
; interrupt config:
bsf INTCON, GIEH ; enable high priority interrupts
bcf INTCON, GIEL ; disable low priority interrupts
bsf INTCON, TMR0IE; enable TMR0 interrupts
bcf INTCON, INT0IE; dis. ext. interrupts
bcf INTCON, RBIE ; dis. rb port change int.
bcf INTCON, TMR0IF; clear the TMR0 intr. flag bit
bcf INTCON, INT0IF;
bcf INTCON, RBIF ;
bsf INTCON2, TMR0IP; set TMR0 high priority
; timer 0 config:
bcf T0CON, TMR0ON ; temp. disable timer
bcf T0CON, T08BIT ; 16 bit counter
bcf T0CON, T0CS ; T0CKI pin input as source
bcf T0CON, T0SE ; switch on falling edge
bsf T0CON, PSA ; disable prescaler
bcf T0CON, T0PS2 ; doesn't really matter
bcf T0CON, T0PS1 ; -||-
bcf T0CON, T0PS0 ; -||-
; init output registers and variables
clrf TRISD
clrf LATD
movlw 0xFF
movwf PORTD ; our output port set to high (serial 0 - but not sure about that)
movlw b'01111111' ; symbol to send
movwf char
movlw cyclesPerBaud
movwf cycle ; unused
clrf bitCounter ; zeros
clrf startStopBit ; zeros
clrf buffer ; zeros
; eof init
movlw LOW initOffset ; dunno why but HIGH has to be reversed with LOW
movwf TMR0H
movlw HIGH initOffset
movwf TMR0L
bsf T0CON, TMR0ON ; turn on timer
loop
goto loop ; waiting for the interrupt
intr ; main branch: 8 cycles
btfss INTCON, TMR0IF
retfie
bcf T0CON, TMR0ON
; had to comment this section out - didn't want to work with it - dunno why
; decf cycle, F
; btfss STATUS, Z
; goto idle
; movlw cyclesPerBaud
; movwf cycle
checkBitCounter ; all branches until 'tmr_ret': 16 cycles
movf bitCounter, F
btfss STATUS, Z
goto rotateBuffer
;startStopBit
movf startStopBit, F
btfss STATUS, Z
goto stopCopy
movlw 0x8
movwf bitCounter
movf char, W
movwf buffer
rlncf buffer, F
movlw 0x00
transfer
movwf PORTD
decf bitCounter, F
btfsc STATUS, Z
incf startStopBit, F
tmr_ret ; 5 cycles (+8 from intr = 13 cycles)
movlw LOW durrOffset ; dunno why but HIGH has to be reversed with LOW
movwf TMR0H
movlw HIGH durrOffset
movwf TMR0L
bsf T0CON, TMR0ON
retfie
stopCopy
clrf startStopBit
movlw 0xFF
nop
goto transfer
rotateBuffer
rrncf buffer, F
movf buffer, W
nop
nop
nop
nop
goto transfer
idle ; 5 cycles (+7 from intr = 12 cycles)
movlw LOW hurrOffset ; dunno why but HIGH has to be reversed with LOW
movwf TMR0H
movlw HIGH hurrOffset
movwf TMR0L
bsf T0CON, TMR0ON
retfie
end
所以我想知道我做错了什么?我的意思是图片正在发送东西PORTD
,0
正如它应该发送的那样,但它不是它应该发送的数据。当我发送的内容达到峰值时(使用Realterm
),发送的字节是11011111
or 10111111
,有时11111111
而不是01111111
。
我猜我错过了一些关于时间的东西,但不确定是什么?
此外,自从我开始在代码中使用“变量”后,我注意到我必须将具有 HIGH 的时序偏移的下部和具有 LOW 的高字节复制到 TMR0H:L 寄存器中——有人知道它为什么这样工作吗?也许我混淆了这些寄存器的重要性:我以前使用它们,好像 TMR0H 寄存器将保存 2 字节计数器的更重要的 8 位 - 对吗?
无论如何,我会很感激任何帮助。谢谢,酒鬼