用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 #include <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 ;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 #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 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 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 next 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 from 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 ; ;======================================= ;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
|