winnie 发表于 2009-5-5 17:40:43

PIC单片机模拟异步串行通讯UART

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
    #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


      END                     ;
页: [1]
查看完整版本: PIC单片机模拟异步串行通讯UART