用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
listp=16F83;define processor
#include
__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
cblock0x0c;GPR start from 0x0c
w_temp;W context saving during interrupt
status_temp;STATUS context saving during interrupt
pclath_temp;PCLATH 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
#defineRX_PINPORTA,2;assign RX pin
#defineTX_PINPORTA,3;assign TX pin
#defineTXENUSART_F,0;USART transmit enable
#defineTXBUSYUSART_F,1;USRAT transmit is in progress
#defineRXBFUSART_F,2;USART receive buff full
#defineRXBUSYUSART_F,3;USART receive is in progress
#defineRX_ERRUSART_F,4;USART receive error
#defineTX_ERRUSART_F,5;USART transmit error
;===============================
;define constant
#defineOSC_FREQ.4000;oscillator frequency in KHz
#defineBAUDRATE.2400
#define TMR0CONST.118;256-OSC_FREQ*1000/4/(BAUDRATE*3) + 2
;===============================
;for my personal style
#defineskp0btfsc
#defineskp1btfss
;**********************************************************************
ORG0x000
clrwdt
gotoMAIN; go to beginning of program
;=======================================
;Interrupt service routine
ORG0x004; interrupt vector location
movwfw_temp; save off current W register contents
movfSTATUS,w; move status register into W register
bankselstatus_temp
movwfstatus_temp; save off contents of STATUS register
movfPCLATH,w
movwfpclath_temp; save off contents of PCLATH
bankselINTCON;select bank
skp0INTCON,T0IF;test for TMR0 interrupt
gototmr0IntStart;do TMR0 ISR
;here test for any other interrupt source
gotoint_end
tmr0IntStart;TIMER0 interrupt service
bcfINTCON,T0IF;clear T0IF
;====== start of RX =======
movlwhigh($)
movwfPCLATH;set PCLATH before PCL change
movfRX_STA,w;get the state value for RX
andlw0x03;for safeguard purpose
addwfPCL,f;switch to STATE
gotorxStartChk;check for START bit
gotorxReceiveBit;receive DATA bit
gotorxIdle;wait for idle
gotorxEnd;do nothing
rxStartChk;check for START bit
skp0RX_PIN;test RX pin for START bit
gotorxEnd;not found
;start bit found. do following
movlw.8
movwfRX_bcnt;count for 8 bits incoming data
movlw.4
movwfRX_SLICE;wait 4 time-slice for 1st data bit
movlw.1
movwfRX_STA;switch to STATE 1 for 1st data bit sampling
gotorxEnd
rxReceiveBit;receive DATA bit
decfszRX_SLICE,f;wait of bit timing
gotorxEnd
;time to sample incoming data bit
rrfRX_BUFF,f;right shift for new bit space
bcfRX_BUFF,7;pre-set to 0
skp0RX_PIN;incoming data bit test
bsfRX_BUFF,7;set if data bit = 1
movlw.3;3 slice for data bit timing
movwfRX_SLICE;bit timing for next data bit
decfszRX_bcnt,f;see if 8-bit completed
gotorxEnd
;bit receive completed, do follwoing
movlw.2
movwfRX_STA;set to STATE 2 for idle waiting
bsfRXBF;set receive buffer full
movfRX_BUFF,w;display data on PORTB
movwfPORTB
gotorxEnd
rxIdle;wait for idle
skp0RX_PIN;try to find STOP bit
clrfRX_STA;back to STATE 0 for next byte
gotorxEnd
;====== End of RX =========
rxEnd
;====== start of TX =======
;do TX, if transmit is engaged
skp1TXEN;skip if TXEN set, do TX
gototmr0IntEnd;not in transmit mode
movfTX_SLICE,f;see if in bit-timing delay
skpnz;
gototxDo;bit-timing completed
decfszTX_SLICE,f;keep bit-timing delay
gototxEnd
txDo
;Transmit STATE-MACHINE control
movlwhigh($)
movwfPCLATH;set PCLATH before PCL change
movfTX_STA,w;get current state
andlw0x03;make sure in range
addwfPCL,f;switch to TX STATE
gototxStartBit;send START bit
gototxDatBit;send DATA bit
gototxStop;send STOP bit
gototxIdle;set transtim IDLE
txStartBit;TX_STA=0, send START bit here
bsfTXBUSY;set TX busy flag
movlw.8
movwfTX_bcnt;count for 8 bit transmitting
bcfTX_PIN;start bit
movlw.3
movwfTX_SLICE;set bit timing
movlw.1
movwfTX_STA;set transmit STATE-MACHINE
gototxEnd
txDatBit;TX_STA=1, send DATA bit here
;time for next bit sending
rrfTX_BUFF,f;rotate bit to C
skpnc;test C
goto 3
bcfTX_PIN;0 out
goto 2
bsfTX_PIN;1 out
movlw.3
movwfTX_SLICE;wait 3 time-slices
decfszTX_bcnt,f
gototxEnd;8 bit serial not end
movlw.2
movwfTX_STA;set transmit STATE-MACHINE
gototxEnd
txStop;TX_STA=2, send STOP bit here
bsfTX_PIN;send STOP bit
movlw.3
movwfTX_SLICE;set bit timing
movlw.3
movwfTX_STA;set transmit STATE-MACHINE
gototxEnd
txIdle;TX_STA=3, reset transmission to IDLE
bcfTXBUSY;not busy
bcfTXEN;not in transmission
clrfTX_STA;reset transmit STATE-MACHINE
gototxEnd
;====== End of TX =========
txEnd
;add more TMR0 related code here
tmr0IntEnd
movlwTMR0CONST
addwfTMR0,f
gotoint_end
int_end
bankselpclath_temp
movfpclath_temp,w; retieve copy of PCLATH register
movwfPCLATH
movfstatus_temp,w; retrieve copy of STATUS register
movwfSTATUS; restore pre-isr STATUS register contents
swapfw_temp,f
swapfw_temp,w; restore pre-isr W register contents
retfie; return from interrupt
;=======================================
;Code wriiten for test purpose
MAIN
bankselTRISA;select respective bank
movlwb'00000100';RA2-input, RA3-output
movwfTRISA
clrfTRISB
movlwb'10001000';TMR0 in timer mode
movwfOPTION_REG
clrfSTATUS;make sure in bank 0
callUSART_INIT
movlwTMR0CONST
movwfTMR0
movlw0xff
movwfPORTB
bsfINTCON,T0IE
bsfINTCON,GIE
LOOP;test code
skp1RXBF;wait for data received
goto$-1
bcfRXBF;clear data flag
movfRX_BUFF,w
movwfTX_BUFF;send back received data
bsfTXEN
skp0TXEN;wait for transmit completion
goto$-1
gotoLOOP;
;=======================================
;Initializtion of software USART
USART_INIT
clrfUSART_F;clear all flag bit
clrfRX_STA;reset STATE MACHINE
clrfTX_STA
bsfTX_PIN;TX is in Idle
return