📄 8051-uart(asm)_2.asm
字号:
; - Right shift Carry into RXSHIFT
; - set up timer to capture the next bit
; - enable timer
; - advance state variable
;
SWRX_S1:
SWRX_S2:
SWRX_S3:
SWRX_S4:
SWRX_S5:
SWRX_S6:
SWRX_S7:
SWRX_S8:
clr TR0 ; Stop Timer0 (low)
clr TF0 ; Clear any pending interrupts
mov BCRHI, #HIGH(RX_BT); load bit time value into 16-bit virtual
; counter
mov TL0, #-LOW(RX_BT)
setb TR0 ; START RX bit timer
mov C, SW_RX_GPIO ; Move RX state into Carry prior to rshift
mov a, RXSHIFT
rrc a ; right shift Carry into shift register
mov RXSHIFT, a ; re-store
inc SURXST ; advance state variable
SWRX_S2_END:
ajmp Timer0_ISR_END
;SWRX_S9: Capture STOP bit
; At this point, we've shifted all the data bits into RXSHIFT, and we're ready to
; sample the STOP bit. Here, we indicate that we've received a character, and reset
; the state machine back to IDLE. In this implementation, we don't actually capture
; the STOP bit; we assume it's good. Here's where we would add support for Framing
; Error detection.
; - If BCRHI is non-zero, then we need to spin through the timer again
; - DEC BCRHI
; - let timer roll over on its own
; - leave state as is
; - If BCRHI is zero:
; - stop timer
; - Move RXSHIFT into RDR
; - Set SRI
; - Disable timer interrupt
; - Enable /INT0 interrupt
; - Reset state variable to IDLE
; - Check to see if User-level interrupt support is enabled (EIS): If so:
; - Enable IE7
; - Toggle P1.7 to activate IE7
;
SWRX_S9:
clr TR0 ; Stop Timer0L
mov RDR, RXSHIFT ; move data from shift reg to data reg
setb SRI ; set SW UART SRI bit to indicate RX complete
clr ET0 ; Disable Timer0L interrupt
clr IE0 ; Disable pending /INT0 interrupts
setb EX0 ; Enable /INT0 interrupt
mov SURXST, #00 ; reset RX state to IDLE
jnb SES, SWRX_S9_END ; check to see if user-level interrupt
; support is enabled
orl EIE2, #00100000b ; enable IE7; leave priority alone
orl PRT1IF, #10000000b; activate IE7
SWRX_S9_END:
ajmp Timer0_ISR_END
;-----------------------------------------------------------------------------
; Timer1_ISR (note that this is actually called by the upper-half of Timer0
; which is operating in Mode 3)
;
; This interrupt drives the SW UART transmit state machine
;
SWTX_STATE_TABLE: ; each table entry is 1 byte; 11 entries
; total
DB SWTX_S0 - SWTX_STATE_TABLE ; START bit
DB SWTX_S1 - SWTX_STATE_TABLE ; b0
DB SWTX_S2 - SWTX_STATE_TABLE ; b1
DB SWTX_S3 - SWTX_STATE_TABLE ; b2
DB SWTX_S4 - SWTX_STATE_TABLE ; b3
DB SWTX_S5 - SWTX_STATE_TABLE ; b4
DB SWTX_S6 - SWTX_STATE_TABLE ; b5
DB SWTX_S7 - SWTX_STATE_TABLE ; b6
DB SWTX_S8 - SWTX_STATE_TABLE ; b7
DB SWTX_S9 - SWTX_STATE_TABLE ; STOP bit onset edge
DB SWTX_S10 - SWTX_STATE_TABLE ; STOP bit terminus
Timer1_ISR:
push PSW ; resource preservation
push acc
mov a, BCTHI ; if BCTHI is non-zero, we need to roll
; through the timer again...
jz SWTX_PROCESS_STATE
dec BCTHI
ajmp Timer1_ISR_EXIT
SWTX_PROCESS_STATE:
push DPH ; resource preservation
push DPL
mov a, SUTXST ; read state offset from table
mov DPTR, #SWTX_STATE_TABLE
movc a, @A+DPTR ; acc now contains state offset
jmp @A+DPTR ; execute State x
Timer1_ISR_END: ; ALL TX states return here
pop DPL ; resource restoration
pop DPH
Timer1_ISR_EXIT:
pop acc ; resource restoration
pop PSW
reti
;SWTX_S0: TX START bit state
; At this point, user code has placed the char to be transmitted in TDR and has
; called the Timer1 interrupt handler explicitly by setting TF1.
; - Clear STI
; - Drop TX_GPIO (START bit onset edge)
; - Configure TH0, BCTHI for next bit time, which will be the LSB
; - Enable TH0
; - Set next state to SWTX_S1
;
SWTX_S0:
mov BCTHI, #HIGH(TX_BT); load bit time value into 16-bit virtual
; counter
mov TH0, #-LOW(TX_BT)
clr SW_TX_GPIO ; START bit onset edge
clr TF1 ; clear any pending interrupts
inc SUTXST ; next state is SWTX_S1
SWTX_S0_END:
ajmp Timer1_ISR_END
;SWTX_S1 thru SWTX_S9: TX b0..b7 and STOP bit
; At this point, we start shifting the character in TDR out the TX_GPIO pin, bit
; by bit, one bit per state transition. We shift in an extra '1' at the MSB which
; becomes the STOP bit.
; - If BCTHI is non-zero, then we need to spin through the timer again
; - DEC BCTHI
; - let timer roll over on its own
; - leave state as is
; - If BCTHI is zero:
; - stop timer
; - set up timer for next bit
; - right-shift TDR
; - enable timer
; - output bit
; - advance state variable
;
SWTX_S1:
SWTX_S2:
SWTX_S3:
SWTX_S4:
SWTX_S5:
SWTX_S6:
SWTX_S7:
SWTX_S8:
SWTX_S9:
mov BCTHI, #HIGH(TX_BT); load bit time value into 16-bit virtual
; counter
mov TH0, #-LOW(TX_BT)
mov a, TDR ; right shift next bit to transmit into Carry
setb C ; shift STOP bit into MSB
rrc a
mov TDR, a ; re-store value
mov SW_TX_GPIO, C ; output bit on GPIO pin
clr TF1 ; clear any pending interrupts
inc SUTXST ; advance to next state
SWTX_S1_END:
ajmp Timer1_ISR_END
;SWTX_S10 STOP bit complete / reset to IDLE
; At this point, we've shifted the STOP bit out, and we're ready to reset the state
; machine and indicate transmit complete, including initiating a user-level interrupt
; if it's enabled.
; - If BCTHI is non-zero, then we need to spin through the timer again
; - DEC BCTHI
; - let timer roll over on its own
; - leave state as is
; - If BCTHI is zero:
; - stop timer
; - set STI
; - clear STXBSY
; - check for IE7 support, and activate if enabled
; - set state variable to S0
;
SWTX_S10:
clr ET1 ; Disable Timer1 interrupts
setb TF1 ; Force a pending Timer1 interrupt. This
; allows the Enable Timer1 interrupt
; operation to immediately trigger a
; transmit operation
mov SUTXST, #00h ; reset state variable to IDLE state
setb STI ; Set STI to indicate transmit complete
clr STXBSY ; Clear TXBSY to indicate transmitter
; available
jnb SES, SWTX_S10_END ; activate user-level interrupt IE7 if
; enabled
orl EIE2, #00100000b ; enable IE7; leave priority alone
orl PRT1IF, #10000000b; activate IE7
SWTX_S10_END:
ajmp Timer1_ISR_END
;-----------------------------------------------------------------------------
; IE7_ISR
;
; This is the user-level interrupt handler for the SW UART. Note: this code
; MUST check both SRI and TRI, and if both are set, it must handle one case, and
; retrigger IE7 for the other case (or handle it in the same call) if that case
; is interrupt handled. This is not required, for example, if the RX case is
; handled in the interrupt and the TX case is polled.
;
; Note, if the TX case is polled, STI should not be cleared here.
;
; In this example, if SRI is set, indicating that a character was received by
; the SW UART, that received character is stored in a circular buffer (RX_BUF).
; If STI is set, indicating transmit complete, the character stored in TX_VAL
; is transmitted (and post incremented).
;
;
IE7_ISR:
push PSW
push acc
anl PRT1IF, #NOT(10000000b); clear IE7
jbc SRI, SW_RX_HANDLE ; handle receive first, since
; it's the most sensitive to
; latency
jbc STI, SW_TX_HANDLE ; handle TX case
IE7_ISR_END:
pop acc
pop PSW
reti ; all IE7_ISR routines return here...
SW_RX_HANDLE:
push ar0 ; resource preservation
mov r0, RX_TAIL ; point r0 to location to store
mov @r0, RDR ; read value into buffer
inc RX_TAIL ; update the TAIL pointer
mov a, RX_TAIL ; wrap pointer if necessary
add a, #-(RX_BUF+RX_BUFSIZE)
jnc SW_RX_HANDLE_END
mov RX_TAIL, #RX_BUF ; wrap the pointer
SW_RX_HANDLE_END:
jnb STI, NO_TX_PENDING; if TX interrupt is pending,
orl PRT1IF, #10000000b; activate it (IE7)
NO_TX_PENDING:
pop ar0
ajmp IE7_ISR_END
SW_TX_HANDLE:
setb STXBSY ; Claim SW UART Transmitter
mov TDR, TX_VAL ; load byte to trasmit into TDR
setb ET1 ; start SW UART transmitter
inc TX_VAL ; next byte to store
SW_TX_HANDLE_END:
jnb SRI, NO_RX_PENDING; if RX interrupt is pending,
orl PRT1IF, #10000000b; activate it (IE7)
NO_RX_PENDING:
ajmp IE7_ISR_END ; exit
;-----------------------------------------------------------------------------
; SUBROUTINES
;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
; SW UART SUBROUTINES (non-user code)
;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
; SW_UART_Init
;
; Init:
; - /INT0 is falling-edge triggered
; - Timer0 in Mode 3, (2) 8-bit timers, interrupt handlers for TL0, TH0 (TF0, TF1)
; timers initially disabled...
; - RX/TX State machines and state variables
; - SW UART TX state machine and RX state machine operate at HIGH priority
SW_UART_Init:
; Init /INT0
clr EX0 ; disable /INT0 interrupts
setb IT0 ; /INT0 is falling-edge triggered
clr IE0 ; forcibly clear /INT0 interrupt flag
setb PX0 ; /INT0 is HIGH priority interrupt
; Init Timer0
clr ET0 ; disable Timer0 interrupts
clr ET1 ; disable Timer1 interrupts
clr TR0 ; Timer0 off
clr TR1 ; Timer1 off
clr TF0 ; forcibly clear interrupt flags
clr TF1
orl TMOD, #00000011b ; Timer0 in Mode 3 (2) 8-bit timers
anl TMOD, #NOT(00001100b); GATE0=0; C/T0 = 0
orl CKCON, #00001000b ; Timer0 uses system clock as time base
setb PT0 ; Timer0 interrupt is HIGH priority
setb PT1 ; Timer1 interrupt is HIGH priority
; User-level interrupt (IE7) is initialized explicitly by the state
; machines
; Init State Machines and Variables
clr a ; Init state machines
mov SURXST, a ; RX state variable
mov SUTXST, a ; TX state variable
mov BCRHI, a ; RX bit timer MSB
mov BCTHI, a ; TX bit timer MSB
clr SES ; Disable user-level interrupt support
clr SREN ; Disable SW UART receiver
clr TXBSY ; clear TXBSY indicator
clr SRI ; clear RX complete indicator
clr STI ; clear TX complete indicator
ret
;-----------------------------------------------------------------------------
; SW_UART_Enable
;
; The SW_UART is enabled by enabling the interrupt handlers that move the transmit
; and receive state machines from their IDLE states to their corresponding next
; states. /INT0 transitions the RX state machine from IDLE to START. Timer1,
; which is called explicitly by the user code (setb TF1), transitions the
; transmit state machine from IDLE/START to TX_LSB.
;
; The user-level interrupt (IE7) is enabled in the state machines themselves
; after polling EIS (external interrupt support).
;
SW_UART_Enable:
clr IE0 ; clear pending /INT0 interrupts
setb TF1 ; Force a pending Timer1 interrupt
setb EX0 ; enable /INT0 interrupts
clr ET1 ; keep Timer1 interrupts disabled
setb TR1 ; Enable Timer1
ret
;-----------------------------------------------------------------------------
; SW_UART_Disable
;
; The SW UART is disabled by disabling all of its state machine interrupts,
; including the user-level interrupt (IE7), if the status register indicates that
; it's enabled.
SW_UART_Disable:
clr EX0 ; disable /INT0 interrupts
clr ET0 ; disable Timer0 interrupts
clr ET1 ; disable Timer1 interrupts
jnb SES, SW_UART_Dis_End; check to see if IE7 use is enabled
anl EIE2, #NOT(00100000b); disable IE7 interrupts
SW_UART_Dis_End:
ret
;-----------------------------------------------------------------------------
; End of file.
END
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -