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 <p16F84a.inc>
;=======================================================================================
; Copyright (c) 2000 by Robert V Ammerman (-Remove-rammerman-Remove- at TakeThisOuTadelphia.net 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
curr_input
; 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.
full
; 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
work
new_wait_start
new_ignore1
; Save area for interrupts
int_w_save
int_status_save
ENDC
;==============================================================================
; 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
endm
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
retfie
;===============================================================================
; Mainline code
start:
; 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
forever:
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
rcv_#v(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
return
ferr_#v(chan):
bcf frame_err,chan
bcf rcv_ready,chan
; deal with framing error condition
movlw 0x80
movwf rsr_chan+chan
return
oerr_#v(chan)
bcf overrun_err,chan
bcf rcv_ready,chan
; deal with overrun condition
movlw 0x80
movwf rsr_chan+chan
return
endm
rcvchan 0
rcvchan 1
rcvchan 2
rcvchan 3
rcvchan 4
rcvchan 5
rcvchan 6
rcvchan 7
end
See:
| file: /Techref/microchip/16F84-rs232-8ch-ba.htm, 12KB, , updated: 2008/3/18 22:48, local time: 2025/10/26 14:56,
owner: RVA-RAm-R00a,
216.73.216.22,10-3-83-201:LOG IN
|
| ©2025 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? <A HREF="http://www.piclist.com/Techref/microchip/16F84-rs232-8ch-ba.htm"> PIC Specific RS232 routine</A> |
| Did you find what you needed? |
|
o List host: MIT, Site host massmind.org, Top posters @none found - Page Editors: James Newton, David Cary, and YOU! * Roman Black of Black Robotics donates from sales of Linistep stepper controller kits. * Ashley Roll of Digital Nemesis donates from sales of RCL-1 RS232 to TTL converters. * Monthly Subscribers: Gregg Rew. on-going support is MOST appreciated! * Contributors: Richard Seriani, Sr. |
|
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! |
.