📄 8051-uart(asm)_2.asm
字号:
;-----------------------------------------------------------------------------
; COPYRIGHT 2001 CYGNAL INTEGRATED PRODUCTS, INC.
;
; FILE NAME : an015_2.ASM
; TARGET MCU : C8051F000
; DESCRIPTION : Example source code for a software UART
;
; IMPLEMENTATION NOTES:
; - uses Timer0 in Mode3 (two 8-bit timers)
; - Timer0 run/overflow is used for RX state machine
; - Timer1 overflow is used for TX state machine
; - 8N1, no Framing error detection
; - uses IE7 as user-level interrupt
; - uses single-byte PC offset for state table implementation
; - uses /INT0 falling as START bit detect (primitive START bit verification)
;
;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
; EQUATES
;-----------------------------------------------------------------------------
$MOD8F000
; SW UART constants
SW_TX_GPIO EQU P0.4 ; SW UART TX GPIO pin (can be any GPIO pin)
SW_RX_GPIO EQU P0.2 ; SW UART RX GPIO pin (must be /INT0)
TIME_COUNT EQU 320 ; = SYSCLK_FREQ / BAUD_RATE (MIN = 128 HD /
; 480 FD)
; Note: 320 is the limit for reliable
; FD operation...
; FOR SYSCLK = 18.432 MHz:
; 115200 = 160
; 57600 = 320
; 38400 = 480
; 19200 = 960
; 9600 = 1920
; 4800 = 3840
; 2400 = 7680
TX_CORR EQU 41 ; (41) Timer preload correction value in
; cycles for TX
RX_CORR EQU 47 ; (47) Timer preload correction value in
; cycles for RX
THALF_CORR EQU 113 ; (113)Timer preload correction value for
; 3/2 RX
TX_BT EQU TIME_COUNT - TX_CORR ; actual 16-bit bit counter cycle value
; TX
RX_BT EQU TIME_COUNT - RX_CORR ; actual 16-bit bit counter cycle value
; RX
THALF_BT EQU TIME_COUNT*3/2 - THALF_CORR ; actual 16-bit 1.5 bit cycle value
; RX
RX_BUFSIZE EQU 16 ; size of RX buffer in chars
;-----------------------------------------------------------------------------
; VARIABLES
;-----------------------------------------------------------------------------
BSEG
org 0h
SRI: DBIT 1 ; SW UART Receive complete flag
STI: DBIT 1 ; SW UART Transmit complete flag
STXBSY: DBIT 1 ; SW UART TX BSY flag
SREN: DBIT 1 ; SW UART RX Enable
SES: DBIT 1 ; SW UART user-Interrup Support Enable
DSEG at 30h
TDR: DS 1 ; SW UART TX data register
RDR: DS 1 ; SW UART RX data register
RXSHIFT: DS 1 ; SW UART RX shift register
SURXST: DS 1 ; SW UART RX state variable
SUTXST: DS 1 ; SW UART TX state variable
BCRHI: DS 1 ; MSB of 16-bit bit timer for SW UART RX
BCTHI: DS 1 ; MSB of 16-bit bit timer for SW UART TX
;test variables
RX_TAIL: DS 1 ; write pointer to RX message buffer
TX_VAL: DS 1 ; value to transmit
;-------------------
; Indirect address space variables
ISEG at 80h
RX_BUF: DS RX_BUFSIZE ; RX message buffer
;-------------------
; STACK
STACK_TOP: DS 1 ; placeholder in symbol table for
; beginning of hardware stack
;-----------------------------------------------------------------------------
; MACRO DEFINITIONS
;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
; RESET AND INTERRUPT VECTOR TABLE
;-----------------------------------------------------------------------------
CSEG
org 00h
ljmp Reset ; RESET initialization vector
org 03h
ljmp INT0_ISR ; Software UART RX START bit detect
org 0bh
ljmp Timer0_ISR ; Software UART RX state machine interrupt
org 1bh
ljmp Timer1_ISR ; Software UART TX state machine interrupt
org 9bh
ljmp IE7_ISR ; user-level Software UART interrupt
;-----------------------------------------------------------------------------
; MAIN PROGRAM CODE
;-----------------------------------------------------------------------------
org 0B3h
Main:
; ajmp PolledRX_PolledTX ; leave one of these lines uncommented
ajmp InterruptRX_InterruptTX ; leave one of these lines uncommented
sjmp $ ; spin forever...
;-----------------------------------------------------------------------------
; MAIN SUBROUTINES
;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
; PolledRX_PolledTX
;-----------------------------------------------------------------------------
; This routine demonstrates polled access to the SW UART.
;
; The transmitter transmits a sequence from $00 to $ff
;
; The receiver receives characters and stores them in a circular buffer.
;
PolledRX_PolledTX:
acall SW_UART_Init ; initialize SW UART (leave in a
; disabled state)
setb SREN ; enable SW UART receiver
clr SES ; disable user-level interrupt
; support
acall SW_UART_Enable ; enable SW UART
; transmit message -- polled mode
jb STXBSY, $ ; wait for SW TX available
; transmit chars $00 to $ff
clr a
TX_LOOP: setb STXBSY ; Claim SW UART Transmitter
mov TDR, a ; write char to transmit data reg
setb ET1 ; initiate SW TX operation
inc a ; set next value to write
jnb STI, $ ; wait for TX complete
clr STI ; clear TX complete indicator
jnz TX_LOOP
TX_LOOP_END:
mov RX_TAIL, #RX_BUF ; init TAIL pointer
; receive message -- polled mode
RX_LOOP: mov r0, RX_TAIL ; indirect address to write character to
jnb SRI, $ ; wait for RX character
clr SRI ; clear RX complete indicator
mov @r0, RDR ; store it
inc RX_TAIL ; advance TAIL pointer
mov a, RX_TAIL ; handle TAIL wrapping
add a, #-(RX_BUF + RX_BUFSIZE)
jnc RX_LOOP
mov RX_TAIL, #RX_BUF ; wrap TAIL
sjmp RX_LOOP ; repeat forever...
;-----------------------------------------------------------------------------
; InterruptRX_InterruptTX
;-----------------------------------------------------------------------------
; This routine demonstrates interrupt access to the SW UART.
;
; The receiver receives characters and stores them in a circular buffer.
; Both the transmit and receive routines are located in the IE7_ISR handler.
;
InterruptRX_InterruptTX:
acall SW_UART_Init ; initialize SW UART (leave in a
; disabled state)
setb SES ; Enable user-level interrupt support
setb SREN ; Enable SW UART receiver
mov RX_TAIL, #RX_BUF ; init TAIL pointer
acall SW_UART_Enable ; enable SW UART
setb STI ; kick-start SW UART transmitter
orl EIE2, #00100000b ; by enabling IE7
orl PRT1IF, #10000000b; and activating IE7
sjmp $
;-----------------------------------------------------------------------------
; INTERRUPT VECTORS
;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
; Reset Interrupt Vector
;
; This routine initializes the device and all peripherals and variables.
; - External oscillator started (sysclk will be switched to external osc.
; once XTLVLD goes high)
; - Watchdog timer is disabled
; - Crossbar and GPIO output modes are defined
; - H/W stack pointer is initialized
; - interrupt priorities and enables are initialized here
; - /INT0
; - Timer0
; - Timer1
Reset:
mov OSCXCN, #01100110b; Enable Crystal osc., divide by 1 mode
; XFCN = '110' for 18.432 MHz crystal
; External oscillator will be selected
; below after XTLVLD has gone high
; indicating that the external osc
; has started and settled (several
; hundred microseconds from now).
mov WDTCN, #0deh ; disable watchdog timer
mov WDTCN, #0adh
; set up Crossbar and Port I/O
mov XBR0, #00000100b ; enable HW UART on P0.0 (TX), P0.1 (RX)
mov XBR1, #10000100b ; enable /INT0 on P0.2; /SYSCLK on P0.3
mov XBR2, #01000000b ; enable crossbar w/ pull-ups enabled
orl PRT0CF, #00011101b; enable P0.0, 0.2, 0.3, and 0.4 as push-pull
; P0.4 is SW UART TX pin
; P0.2 is SW UART RX pin
orl PRT1CF, #01000000b; enable P1.6 (LED on target board) as
; push-pull
mov SP, #STACK_TOP ; init stack pointer to end of allocated RAM
; Wait >1 ms before checking external crystal for stability
clr a
mov r0, a ; Clear r0
djnz r0, $ ; Delay ~380 祍
djnz r0, $ ; Delay ~380 祍
djnz r0, $ ; Delay ~380 祍
OSC_WAIT:
mov a, OSCXCN ; spin here until crystal osc is stable
jnb acc.7, OSC_WAIT
orl OSCICN, #00001000b; Select external osc. as
; system clock source
anl OSCICN, #NOT(00000100b); Disable internal oscillator
orl OSCICN, #10000000b; Enable missing clock detector
; this must be done AFTER
; selecting ext osc as system
; clock source
setb EA ; enable GLOBAL interrupts
ljmp Main
;-----------------------------------------------------------------------------
; Timer0_ISR / INT0_ISR
;
; These interrupts start and drive the SW UART receive state machine
;
SWRX_STATE_TABLE: ; each table entry is 1 byte
DB SWRX_S0 - SWRX_STATE_TABLE ; IDLE / START detect
DB SWRX_S1 - SWRX_STATE_TABLE ; b0
DB SWRX_S2 - SWRX_STATE_TABLE ; b1
DB SWRX_S3 - SWRX_STATE_TABLE ; b2
DB SWRX_S4 - SWRX_STATE_TABLE ; b3
DB SWRX_S5 - SWRX_STATE_TABLE ; b4
DB SWRX_S6 - SWRX_STATE_TABLE ; b5
DB SWRX_S7 - SWRX_STATE_TABLE ; b6
DB SWRX_S8 - SWRX_STATE_TABLE ; b7
DB SWRX_S9 - SWRX_STATE_TABLE ; STOP bit capture
INT0_ISR:
Timer0_ISR:
push PSW ; resource preservation
push acc
mov a, BCRHI ; if BCRHI is non-zero, we need to roll
; through the timer again...
jz SWRX_PROCESS_STATE
dec BCRHI
ajmp Timer0_ISR_EXIT
SWRX_PROCESS_STATE:
push DPH ; resource preservation
push DPL
mov a, SURXST ; read state offset from table
mov DPTR, #SWRX_STATE_TABLE
movc a, @A+DPTR ; 'a' now contains state offset (PC)
jmp @A+DPTR ; execute state
Timer0_ISR_END: ; ALL RX states return here
pop DPL ; resource restoration
pop DPH
Timer0_ISR_EXIT:
pop acc ; resource restoration
pop PSW
reti
;SWRX_S0: RX IDLE state
; At this point, a falling edge has been detected on /INT0.
; We first check to see if the SW UART receiver is enabled. If it is, we check
; once to see if the RX pin is still low (START bit valid). If it is, we set up
; Timer0 to count for 3/2 bit time in order to capture the LSB. Here, we also
; disable /INT0 interrupts.
; - Check for SREN = '1': IF '1':
; - Load TL0 with 3/2 bit time value
; - Start Timer
; - Enable TF0 interrupt
; - Disable /INT0 interrupt
; - INC state variable to S1
; - IF SREN = '0' (SW UART RX disabled)
; - exit gracefully, next state is S0
;
SWRX_S0:
jnb SREN, SWRX_S0_END ; Check to see if SW UART RX is enabled
; if not, exit and remain at IDLE state
jb SW_RX_GPIO, SWRX_S0_END ; check to see if START bit is good
clr EX0 ; disable /INT0
clr TR0 ; Stop Timer0 (low)
clr TF0 ; Clear any pending interrupts
mov BCRHI, #HIGH(THALF_BT) ; set Timer0 (low) + BCRHI for 1.5 bit
mov TL0, #-LOW(THALF_BT) ; times from now (we assume the start
; bit is good)
setb ET0 ; enable Timer0 interrupts
setb TR0 ; Start Timer0L
inc SURXST ; next state is SWRX_S1 (we assume START bit
; is good)
SWRX_S0_END:
ajmp Timer0_ISR_END
;SWRX_S1 thru SWRX_S8: Capture b0..b7
; At this point, we've determined that the START bit is valid, and we're going to
; query RX_GPIO at bit intervals, shifting the results into RXSHIFT.
; - 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 RX_GPIO state into Carry
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -