please dont rip this site

PIC Specific RS232 routine

by Bob Ammerman

This progam allows a 16F84A at 20MHz to simultaneously receive 8 full 9600 communication links. The transmit side of the UART is _not_ implemented.

Note that the code has been tested under simulation, but not in actual hardware.

        list    p=16F84a,f=INHX32
        #include <>

; Copyright (c) 2000 by Robert V Ammerman (rammermanSPAM at as of Jun 2003)
; This code may be used for any legal purpose, commerical or not. I only ask that you
; let me know if you use it and that you leave this copyright notice unchanged in 
; your source code.
; Also, you understand that I have no liability if this code doesn't work as expected.
; Software UAR(no T) code developed by and used with the permission of:
;       Robert V Ammerman
;       RAm Systems
;       (contract development of high performance, high function, low-level software)
; This code is a sample UAR(no T) that receives 8 channels at 9600 baud on a 20Mhz 16F84A
; (or other midrange PIC).
; This code has been tested until simulation only, not on real hardware. Use at your own
; risk!
; The program works by handling timer interrupts at 3x the nominal bit rate and running a 
; state machine for each channel to acquire the data. 
; The interrupts are at the rate of:
;       20000000/4/174 == 28735.63 Hz.
; The 'perfect' rate would be 9600*3 == 28800 Hz.
; The bit rate error is thus about 0.22 percent.
; The first trick behind this code is the way the state machines are run: instead of
; handling each channel one at a time the program uses 'vertical arithmetic' to 
; process all eight channels together.
; The second trick is the way that the program works thru processing the eight
; input bits on the channels, accumulating them into the 'receiver shift register'
; variables, and determining when a byte has been completely received. This is done 
; using only 3 instructions per channel.
; Using these two tricks results in code that uses only 76 instructions per interrupt, 
; including context save and restore, but not interrupt latency. Since interrupts 
; are generated every 174 instructions this leaves about 54 percent of the CPU available 
; for 'task level' code.
; One important thing to note: since this code does _not_ double buffer the receiver, 
; task level code must process a received byte within 4/3 of a bit time (approximately 
; 390 task level instructions), otherwise the overrun flag will be set for that channel.

    CBLOCK      0x0C

; The state visible to task-level code for the UART receivers

    rsr_chan:8    ; Receiver shift registers for channels 0..7
        rcv_ready         ; Bitmap of channels with bytes ready
        frame_err         ; Bitmap of channels with framing error
        overrun_err       ; Bitmap of channels with overrun error

; The current inputs from the 8 serial ports


; The following bitmapped variable is used to track when a UART shift 
; register is full and thus we have to check for the stop bit at the 
; next sample time.
; The following bitmapped variables maintain the state data for each of the 
; channels. Note that each channel will always have exactly 1 one bit set
; in these variables to indicate what state that channel is in.

        wait_start              ; Channel is waiting for start bit
        confirm_start           ; Channel is verifying that it is really in start bit
        ignore1                 ; Channel is waiting for sample time
        ignore2                 ; Channel is waiting for sample time
        sample                  ; Channel is sampling the input state
        stop_exp                ; Channel is expecting the stop bit

; Temps used in computing the new state



; Save area for interrupts



; Main entry point

    goto        start

; Interrupt handler

    org         0x04

; context save

    movwf       int_w_save       
    swapf       STATUS,W
    movwf       int_status_save

; Clear the timer interrupt and adjust the timer to correct its period

    bcf         INTCON,T0IF

; We want a period of 174 instructions, which is 1/3 of a bit time
; So we have to add 256-174 to the counter. 
; But the counter delays updating by 2 cycles.
; So we really add 256-174+2 to get the
; desired period.

    movlw       D'256'-D'174'+D'2'
    addwf       TMR0,F

; Get the input and prepare to process it

    comf        PORTB,W         ; Get current input state 
    movwf       curr_input      ; Save a copy
    movwf       work
; Process all the inputs.

; Note that we only shift in bits for channels that are in the 'sample'
; state.

rcv_chan macro n

; The next instruction does two things:
;       1: It puts 'receive shift register full' status, if any, 
;       for the previous channel into the high bit of 'work'.
;       2: It puts the input data bit for the current channel into
;               carry.
    rrf         work,F 

; See if this channel is ready to sample

    btfsc       sample,n      ; Do we need a new bit?

; If this channel is ready to sample, the following instruction will be 
; executed to perform two functions:
;       1: It puts the input data bit into the receiver shift register.
;       2: It puts the 'receive shift register full' status into carry.

    rrf         rsr_chan+n,F    ; Yes, move it in

        rcv_chan 0
        rcv_chan 1
        rcv_chan 2
        rcv_chan 3
        rcv_chan 4
        rcv_chan 5
        rcv_chan 6
        rcv_chan 7

; At this point 'work' contains the 'receive shift register full' bits for
; channels 0..6 (in bits 1..7) and carry has the bit for channel 7.

        rrf     work,W  ; Bring in channel 7's 
                        ;'receive shift register full' bit

; Note that the bits in WREG that correspond to channels that were not
; sampled on this cycle are garbage. Zero them out and then turn on the 
; full bits for the sampled channels that we just filled.

    andwf       sample,W        ; (can only include chans with new bits)
    iorwf       full,F          ; Turn on full bits for sampled channels

; compute the new state variables based on the old state and the 
; 'curr_input' and 'full' vectors

; Note: a stop bit is a 1, a start bit is a 0

; Here are the transitions of the state machine:
;       stop_exp                -> wait_start
;                                   *set rcv_ready bits
;                                   *set frame_err bits

;       wait_start              -> INPUT==1 -> wait_start
;                                  INPUT==0 -> confirm_start

;       confirm_start           -> INPUT==1 -> wait_start 
;                                  INPUT==0 -> ignore1

;       ignore1                 -> ignore2

;       ignore2                 -> FULL==0 -> sample
;                                  FULL==1 -> stop_exp
;                                       *clear full bits

;       sample                  -> ignore1
;                                       *set overrun error bits
;                                       *store data bits
;                                       *set full bits

; Turning this around into math to compute the new values of the state
; bit vectors and 'full', 'rcv_ready', 'overrun_err' and 'frame_err' vectors 
; based on the old state bit vectors and the 'input' and 'full' vectors
; we get: 
;   NOTE: These comments are written assuming all the assignments happen
;       simultaneously:
;       confirm_start   <- (wait_start & ~input) 
;       ignore1         <- (confirm_start & ~input) | sample
;       ignore2         <- ignore1
;       sample          <- (ignore2 & ~full)
;       stop_exp        <- (ignore2 & full)
;       full            <- full & ~ignore2
;       wait_start      <- stop_exp 
;                        | (wait_start & input)
;                        | (confirm_start & input)
;       rcv_ready       <- rcv_ready | stop_exp
;       frame_err       <- frame_err | (stop_exp & ~input)
;       overrun_err     <- overrun_err | (sample & rcv_ready)

; new_wait_start = ((wait_start | confirm_start) & input) | stop_exp

        movf    wait_start,W
        iorwf   confirm_start,W
        andwf   curr_input,W
        iorwf   stop_exp,W
        movwf   new_wait_start

; new_ignore1 = (confirm_start & ~input) | sample

        comf    curr_input,W
        andwf   confirm_start,W
        iorwf   sample,W
        movwf   new_ignore1

; overrun_err |= sample & rcv_ready

        movf    sample,W
        andwf   rcv_ready,W
        iorwf   overrun_err,F

; sample = ignore2 & ~full

        comf    full,W
        andwf   ignore2,W
        movwf   sample

; rcv_ready |= stop_exp

        movf    stop_exp,W
        iorwf   rcv_ready,F

; frame_err |= stop_exp & ~input

        comf    curr_input,W
        andwf   stop_exp,W
        iorwf   frame_err,F

; stop_exp = ignore2 & full

        movf    ignore2,W
        andwf   full,W
        movwf   stop_exp

; full = full & ~ignore2
        comf    ignore2,W
        andwf   full,F

; ignore2 = ignore1

        movf    ignore1,W
        movwf   ignore2

; confirm_start = wait_start & ~input

        comf    curr_input,W
        andwf   wait_start,W
        movwf   confirm_start

; wait_start = new_wait_start

        movf    new_wait_start,W
        movwf   wait_start

; ignore1 = new_ignore1
        movf    new_ignore1,W
        movwf   ignore1

; Context restore

        swapf   int_status_save,W
        movwf   STATUS
        swapf   int_w_save,F
        swapf   int_w_save,W


; Mainline code


; initialize all the UART status values

        movlw   0x80
        movwf   rsr_chan+0
        movwf   rsr_chan+1
        movwf   rsr_chan+2
        movwf   rsr_chan+3
        movwf   rsr_chan+4
        movwf   rsr_chan+5
        movwf   rsr_chan+6
        movwf   rsr_chan+7

        clrf    rcv_ready
        clrf    frame_err

        clrf    full

        movlw   0xFF
        movwf   wait_start

        clrf    confirm_start
        clrf    ignore1
        clrf    ignore2
        clrf    sample
        clrf    stop_exp

        bsf     STATUS,RP0
        bcf     OPTION_REG-0x80,T0CS
        bcf     STATUS,RP0

        bsf     INTCON,T0IE
        bsf     INTCON,GIE

    btfsc   rcv_ready,0
    call    rcv_0
    btfsc   rcv_ready,1
    call    rcv_1
    btfsc   rcv_ready,2
    call    rcv_2
    btfsc   rcv_ready,3
    call    rcv_3
    btfsc   rcv_ready,4
    call    rcv_4
    btfsc   rcv_ready,5
    call    rcv_5
    btfsc   rcv_ready,6
    call    rcv_6
    btfsc   rcv_ready,7
    call    rcv_7
    goto    forever

rcvchan macro   chan

    btfsc   frame_err,chan
    goto    ferr_#v(chan)
    btfsc   overrun_err,chan
    goto    oerr_#v(chan)
    movf    rsr_chan+chan,W
     ; do something with the byte in W
    bcf     rcv_ready,chan
    movlw   0x80
    movwf   rsr_chan+chan
    bcf     frame_err,chan
    bcf     rcv_ready,chan
     ; deal with framing error condition
    movlw   0x80
    movwf   rsr_chan+chan
    bcf     overrun_err,chan
    bcf     rcv_ready,chan
     ; deal with overrun condition
    movlw   0x80
    movwf   rsr_chan+chan

    rcvchan 0
    rcvchan 1
    rcvchan 2
    rcvchan 3
    rcvchan 4
    rcvchan 5
    rcvchan 6
    rcvchan 7



file: /Techref/microchip/16F84-rs232-8ch-ba.htm, 12KB, , updated: 2008/3/18 22:48, local time: 2017/10/18 11:14, owner: RVA-RAm-R00a,

 ©2017 These pages are served without commercial sponsorship. (No popup ads, etc...).Bandwidth abuse increases hosting cost forcing sponsorship or shutdown. This server aggressively defends against automated copying for any reason including offline viewing, duplication, etc... Please respect this requirement and DO NOT RIP THIS SITE. Questions?
Please DO link to this page! Digg it! / MAKE! / 

<A HREF=""> PIC Specific RS232 routine</A>

After you find an appropriate page, you are invited to your to this massmind site! (posts will be visible only to you before review) Just type in the box and press the Post button. (HTML welcomed, but not the <A tag: Instead, use the link box to link to another page. A tutorial is available Members can login to post directly, become page editors, and be credited for their posts.

Link? Put it here: 
if you want a response, please enter your email address: 
Attn spammers: All posts are reviewed before being made visible to anyone other than the poster.
Did you find what you needed?

Quick, and RELIABLE! RCL-1 RS232 Level Converter in a DB9 backshell only $15.00
Ashley Roll has put together a really nice little unit here. Leave off the MAX232 and keep these handy for the few times you need true RS232!

Welcome to!