PIC单片机模拟异步串行通讯UART
用TMR0实现定时查询。任何带中断的PIC上都可以实现。可用此法扩展多个串口。
;|--------------------------------------------------------------|
;| Implement duplex USART base on normal I/O pin |
;| Using TIMER0 interrupt for bit timing |
;| Tested on PIC16F83 running at 4MHz |
;| Written by Paul Zhang, Microchip Tech Inc |
;| 6 Aug, 2000 |
;| All rights reserved |
;|--------------------------------------------------------------|
errorlevel -302 ;no bank warning
errorlevel -301 ;no default file warning
list p=16F83 ;define processor
#i nclude <p16F83.inc> ;
__CONFIG _CP_OFF & _WDT_OFF & _PWRTE_ON & _XT_OSC
;code protect = OFF
;watchdog = OFF
;power-up delay timer = ON
;oscillator mode = XT
;===============================
;define RAM variables
cblock 0x0c ;GPR start from 0x0c
w_temp
;W context saving during interrupt
status_temp ;STATUS context saving during interrupt
pclath_temp CLATH context saving during interrupt
USART_F ;containing flags for USART
RX_BUFF ;USART received data buffer
TX_BUFF ;USART transmitting data buffer
RX_SLICE ;RX bit-timing control
TX_SLICE ;TX bit-timing control
RX_bcnt ;RX received bit counting
TX_bcnt ;TX transmitting bit counting
RX_STA ;RX STATE-MACHINE controller
TX_STA ;TX STATE-MACHINE controller
endc
;===============================
;pre-definition for readability
#define RX_PIN PORTA,2 ;assign RX pin
#define TX_PIN PORTA,3 ;assign TX pin
#define TXEN USART_F,0 ;USART transmit enable
#define TXBUSY USART_F,1 ;USRAT transmit is in progress
#define RXBF USART_F,2 ;USART receive buff full
#define RXBUSY USART_F,3 ;USART receive is in progress
#define RX_ERR USART_F,4 ;USART receive error
#define TX_ERR USART_F,5 ;USART transmit error
;===============================
;define constant
#define OSC_FREQ .4000 ;oscillator frequency in KHz
#define BAUDRATE .2400
#define TMR0CONST .118 ;256-OSC_FREQ*1000/4/(BAUDRATE*3) + 2
;===============================
;for my personal style
#define skp0 btfsc
#define skp1 btfss
;**********************************************************************
ORG 0x000
clrwdt
goto MAIN ; go to beginning of program
;=======================================
;Interrupt service routine
ORG 0x004 ; interrupt vector location
movwf w_temp ; save off current W register contents
movf STATUS,w ; move status register into W register
banksel status_temp
movwf status_temp ; save off contents of STATUS register
movf PCLATH,w
movwf pclath_temp ; save off contents of PCLATH
banksel INTCON ;select bank
skp0 INTCON,T0IF ;test for TMR0 interrupt
goto tmr0IntStart ;do TMR0 ISR
;here test for any other interrupt source
goto int_end
tmr0IntStart ;TIMER0 interrupt service
&
nbsp; bcf INTCON,T0IF ;clear T0IF
;====== start of RX =======
movlw high($)
movwf PCLATH ;set PCLATH before PCL change
movf RX_STA,w ;get the state value for RX
andlw 0x03 ;for safeguard purpose
addwf PCL,f ;switch to STATE
goto rxStartChk ;check for START bit
goto rxReceiveBit ;receive DATA bit
goto rxIdle ;wait for idle
goto rxEnd ;do nothing
rxStartChk ;check for START bit
skp0 RX_PIN ;test RX pin for START bit
goto rxEnd ;not found
;start bit found. do following
movlw .8
movwf RX_bcnt ;count for 8 bits incoming data
movlw .4
movwf RX_SLICE ;wait 4 time-slice for 1st data bit
movlw .1
movwf RX_STA ;switch to STATE 1 for 1st data bit sampling
&n
bsp; goto rxEnd
rxReceiveBit ;receive DATA bit
decfsz RX_SLICE,f ;wait of bit timing
goto rxEnd
;time to sample incoming data bit
rrf RX_BUFF,f ;right shift for new bit space
bcf RX_BUFF,7 ;pre-set to 0
skp0 RX_PIN ;incoming data bit test
bsf RX_BUFF,7 ;set if data bit = 1
movlw .3 ;3 slice for data bit timing
movwf RX_SLICE ;bit timing for next data bit
decfsz RX_bcnt,f ;see if 8-bit completed
goto rxEnd
;bit receive completed, do follwoing
movlw .2
movwf RX_STA ;set to STATE 2 for idle waiting
bsf RXBF ;set receive buffer full
movf RX_BUFF,w ;display data on PORTB
movwf PORTB
goto rxEnd
rxIdle ;wait for idle
skp0 RX_PIN ;try to find STOP bit
clrf RX_STA ;back to STATE 0 for nex
t byte
goto rxEnd
;====== End of RX =========
rxEnd
;====== start of TX =======
;do TX, if transmit is engaged
skp1 TXEN ;skip if TXEN set, do TX
goto tmr0IntEnd ;not in transmit mode
movf TX_SLICE,f ;see if in bit-timing delay
skpnz ;
goto txDo ;bit-timing completed
decfsz TX_SLICE,f ;keep bit-timing delay
goto txEnd
txDo
;Transmit STATE-MACHINE control
movlw high($)
movwf PCLATH ;set PCLATH before PCL change
movf TX_STA,w ;get current state
andlw 0x03 ;make sure in range
addwf PCL,f ;switch to TX STATE
goto txStartBit ;send START bit
goto txDatBit ;send DATA bit
goto txStop ;send STOP bit
goto txIdle ;set transtim IDLE
txStartBit ;TX_STA=0, send START bit here
bsf TXBUSY ;set TX busy flag
movlw .8
movwf TX_bcnt ;count for 8 bit transmitting
bcf TX_PIN ;start bit
movlw .3
movwf TX_SLICE ;set bit timing
movlw .1
movwf TX_STA ;set transmit STATE-MACHINE
goto txEnd
txDatBit ;TX_STA=1, send DATA bit here
;time for next bit sending
rrf TX_BUFF,f ;rotate bit to C
skpnc ;test C
goto $+3
bcf TX_PIN ;0 out
goto $+2
bsf TX_PIN ;1 out
movlw .3
movwf TX_SLICE ;wait 3 time-slices
decfsz TX_bcnt,f
goto txEnd ;8 bit serial not end
movlw .2
movwf TX_STA ;set transmit STATE-MACHINE
goto txEnd
txStop ;TX_STA=2, send STOP bit here
bsf TX_PIN ;send STOP bit
movlw .3
movwf TX_SLICE ;set bit timing
movlw .3
movwf TX_STA ;set transmit STATE-MACHINE
goto txEnd
txIdle ;TX_STA=3, reset transmission to IDLE
bcf TXBUSY ;not busy
bcf TXEN ;not in transmission
clrf TX_STA ;reset transmit STATE-MACHINE
goto txEnd
;====== End of TX =========
txEnd
;add more TMR0 related code here
tmr0IntEnd
movlw TMR0CONST
addwf TMR0,f
goto int_end
int_end
banksel pclath_temp
movf pclath_temp,w ; retieve copy of PCLATH register
movwf PCLATH
movf status_temp,w ; retrieve copy of STATUS register
movwf STATUS ; restore pre-isr STATUS register contents
swapf w_temp,f
swapf w_temp,w ; restore pre-isr W register contents
retfie ; return fr
om interrupt
;=======================================
;Code wriiten for test purpose
MAIN
banksel TRISA ;select respective bank
movlw b'00000100' ;RA2-input, RA3-output
movwf TRISA
clrf TRISB
movlw b'10001000' ;TMR0 in timer mode
movwf OPTION_REG
clrf STATUS ;make sure in bank 0
call USART_INIT
movlw TMR0CONST
movwf TMR0
movlw 0xff
movwf PORTB
bsf INTCON,T0IE
bsf INTCON,GIE
LOOP ;test code
skp1 RXBF ;wait for data received
goto $-1
bcf RXBF ;clear data flag
movf RX_BUFF,w
movwf TX_BUFF ;send back received data
bsf TXEN
skp0 TXEN ;wait for transmit completion
goto $-1
goto LOOP &nb
sp;;
;=======================================
;Initializtion of software USART
USART_INIT
clrf USART_F ;clear all flag bit
clrf RX_STA ;reset STATE MACHINE
clrf TX_STA
bsf TX_PIN ;TX is in Idle
return