| Name: | Mr. |
| Web Site: | |
replace Pages:
See also:
Bit timing errors
| Clock/Rate | 4 MHz | 10 MHz |
| 57600 | 2.7% | 1.0% |
| 115200 | 5.1% | 2.3% |
| 230400 | 8.8% | 4.1% |
| 460800 | 23% | 8.3% |
| 921600 | - | 16% |
Code:
http://piclist.com/techref/member/eugene-ksf-/rs.asm+TITLE "Example on using RS_bodySEND, RS_bodyRECEIVE macros" ;------------------------------------------------------------ ; Copyright: Eugene M. Hutorny © 2003,eugene@ksf.kiev.ua ; Revision: V0.01 ; Date: Feb 25, 2003 ; Assembler: MPASM version 3.20.07 ;------------------------------------------------------------ ; Example on using RS_bodySEND, RS_bodyRECEIVE macros ;------------------------------------------------------------ include "p16f84a.inc" include "rs.inc" #define CLOCK .4000000 #define RX PORTB,0 ; RX Pin, RB0, input #define TX PORTB,1 ; TX Pin, RB1, output #define CTS PORTB,2 ; CTS pin, RB2, output #define RTS PORTB,6 ; RTS pin, RB6, input #define RS_BITCOUNT .8 #define RS_BUFFSIZE .16 UDATA TMP_WREG res 1 ; temporary storage for WREG TMP_STATUS res 1 ; - " - STATUS RS_DATA res 1 ; file register used in RS RS_COUNT res 1 ; bit counter RS_ALIGN res 1 ; alignment bits RS_COUNTER res 1 ; recieved/echoed counter RS_BUFFER res RS_BUFFSIZE ; data buffer nope macro ; nop 2 cycles long goto $+1 endm RS CODE RS_SEND RS_bodySEND .115200, RS_BITCOUNT, TX, 0 return ;--------------------------------------------------------------------------- RS_READBUFF ; READ incoming data to buffer bcf INTCON, INTF bsf INTCON, INTE bsf INTCON, GIE bcf CTS ; transmission shall begin clrf TMR0 ; clear timer bcf INTCON, T0IF ; clear timer expiration flag rx clrwdt btfsc RTS ; is RTS kept SPACE goto suspend ; no, suspend reception tstf RS_COUNTER ; test is something received skpnz goto rx ; if no bytes yet received, just wait btfsc INTCON, T0IF ; if timer expired goto suspend ; suspend reception tstf RS_COUNTER ; test RS_COUNTER skpnz ; if( RS_COUNTER > 0) goto rx ; continue reception suspend bsf CTS ; request suspending reception clrf TMR0 ; clear timer ; relaxation period after last byte recived xr clrwdt movlw RS_BUFFSIZE - 1 subwf RS_COUNTER, W ; RS_COUNTER - (RS_BUFFSIZE - 1) skpnc ; if( RS_COUNTER - (RS_BUFFSIZE - 1) > 0) goto readdone btfsc RTS ; wait if space is kept SPACE goto readdone btfss TMR0, 2 ; time out = 4 timer ticks (1024 IC) ~ 1 ms, good for fast PC's goto xr readdone bcf INTCON, GIE bcf INTCON, INTE ; disable INT interrupt return RS_INTERRUPT ; interrupt on RX entry movwf TMP_WREG ; 6: save W swapf STATUS, W ; 7: load STATUS movwf TMP_STATUS ; 8: save STATUS bsf CTS ; 9: request suspending reception RS_bodyRECEIVE .115200, RS_BITCOUNT, RX, 0, INDF, .9, -.3 clrf TMR0 ; 75: clear timer incf FSR, F ; 76: forward buffer pointer incf RS_COUNTER, F ; 77: count this byte swapf TMP_STATUS, W ; 78: movwf STATUS ; 79: restore STATUS swapf TMP_WREG, F ; 80: swapf TMP_WREG, W ; 81: restore W bcf INTCON, INTF ; 82: interrupt handled retfie ; 83: leave routine - 2 cycles of one stop bit left RS_delays END
http://piclist.com/techref/member/eugene-ksf-/rs.inc
SUBTITLE "RS-232 Definitions"
;
;------------------------------------------------------------
; File Name : RS.inc
;------------------------------------------------------------
; Copyright: Eugene M. Hutorny © 2003, eugene@ksf.kiev.ua
; Revision: V0.01
; Date: Feb 25, 2003d
; Assembler: MPASM version 3.20.07
;------------------------------------------------------------
;
;------------------------------------------------------------
; This file contains macro that expands to RS procedures
; Usage:
; 1. Define CLOCK, CTS', RTS'
; 2. include into your ASM file
; 3. Define RAM locations RS_DATA, RS_ALIGN, RS_COUNT
; 4. Place RS_body macro in your code
; 5. Place RS_delays in your code
; Requires definitions of:
; CLOCK, CTS', RTS'
; Requires visibility of RAM locations:
; RS_DATA, RS_ALIGN", RS_COUNT"
; Note' Only if CTS/RTS control turned on by RS_OPTION_CTSRTS
; Note" For low speed only (bit longer 10 cycles)
;------------------------------------------------------------
; RS_232 options
#define RTS_SPACE_LEVEL 0
#define CTS_SPACE_LEVEL 0
; Hardware flow control is implemented in software on PC
; Doc on 16550 UART (PC16550D.pdf by NS) says:
; CTS, Clear to Send, Pin 36: When low, this indicates that
; the MODEM or data set is ready to exchange data. The CTS
; signal is a MODEM status input whose conditions can be
; tested by the CPU reading bit 4 (CTS) of the MODEM Status
; Register. Bit 4 is the complement of the CTS signal. Bit 0
; (DCTS) of the MODEM Status Register indicates whether
; the CTS input has changed state since the previous reading
; of the MODEM Status Register.
; CTS has no effect on the Transmitter.
; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
;------------------------------------------------------------
;
; This macro calculates RS constants for transmitter or reciver
; at specified speed and number of bits
; requires CLOCK to be defined (in hertz)
RS_calcCONST macro speed, bits, rcv
local cycles, align, half
local i, c
cycles = CLOCK / (speed / .25) ; ((CLOCK / 4) / speed ) * 100
half = CLOCK / (.2 * speed / .25)
RS_CYCLESPERBIT set cycles / .100
RS_HALFCYCLE set half / .100
i = 0
c = RS_HALFCYCLE * rcv
align = 0
while( i <= bits ) ; bit alignment for all bits + stop bit
c = c + RS_CYCLESPERBIT
i++
if( (i * cycles + (half - .25) * rcv) - (c * .100) >= .50 )
align = align | (1 << (i-1) )
c++
endif
endw
RS_BITALIGNMENT set align
endm
;------------------------------------------------------------
; This macro generates code for the specified delay (in cycles)
; valid values are 0-1028, gurantied precision - 1 cycle
; delays 0-3 are generated inline, 4-8 - call RS_DELAY(N)IC
; 9 and higher - call RS_DELAY(0-3)WC, WREG is loaded with delay counter
; requires instatiation of RS_delays
RS_delay macro cycles
local c
if( cycles < 0 )
error "Negative delay requested"
else
if( cycles == 0 )
else
if( cycles == .1 )
nop
else
if( cycles == .2)
nope
else
if( cycles == .3)
nope
nop
else
if( cycles <= .8)
call RS_DELAY#v(cycles)IC
RS_DELAYNEEDED set RS_DELAYNEEDED | (1 << cycles)
else
c = (cycles / .4) - .1
if( c > .255 )
error "Too long delay requested"
endif
movlw #v(c)
c = cycles & .3
RS_DELAYNEEDED set RS_DELAYNEEDED | (0x8000 >> c)
call RS_DELAY#v(c)WC
endif
endif
endif
endif
endif
endif
endm
;------------------------------------------------------------
; This macro instantiates delay routines, used in code,
; generated by RS_delay
RS_delays macro
if( RS_DELAYNEEDED & 0xF000 )
if (RS_DELAYNEEDED & 0x1000 )
RS_DELAY3WC ; 0x1000
nop
endif
if (RS_DELAYNEEDED & 0x3000 )
RS_DELAY2WC ; 0x2000
nop
endif
if (RS_DELAYNEEDED & 0x7000 )
RS_DELAY1WC ; 0x4000
nop
endif
RS_DELAY0WC ; 0x8000
addlw -.1 ; 2
skpz ; 3
goto RS_DELAY0WC ; 4
return ;
endif
local i, d
i = .8
d = 0
while( i >= .4 )
if( RS_DELAYNEEDED & (1 << i))
RS_DELAY#v(i)IC
d = .1
endif
d = d && (i > .4 )
i--
if( d )
if( RS_DELAYNEEDED & (1 << i))
nop
else
i--
if( i >= .4)
nope
else
nop
endif
endif
endif
endw
if( RS_DELAYNEEDED & 0x1FF )
return
endif
endm
; This procedure uses port driving method suggested by Regulus Berdin
; http://www.piclist.com/techref/microchip/rs232at500kbps.htm
; this macro generates code for short bit length: 2 - 9 cycles
; Code length:
; maximum = 8 + 4*bits; (RS_CYCLESPERBIT = 5)
; minimum = 5 + 2*bits; (RS_CYCLESPERBIT = 2)
; average = 6 + 3*bits
RS_bodySEND2_9 macro speed, bits, port, pin, spacelvl
TX_SPACE_LEVEL equ spacelvl
local i, d
rrf RS_DATA, W ; prepare data for output:
xorwf RS_DATA, F ; '1' in RS_DATA means toggle port
movlw (1 << pin) ; load port-toggling mask
if( spacelvl )
bsf port, pin ; 0: sending start bit
else
bcf port, pin ; 0: sending start bit
endif
if ( RS_BITALIGNMENT & 1 )
RS_delay (RS_CYCLESPERBIT - .1)
else
RS_delay (RS_CYCLESPERBIT - .2)
endif
i = 0
while( i < bits )
if( i == 0 )
skpnc ; 1: first bit is already in C
else
btfsc RS_DATA,#v(i-.1); 1: test data
endif
xorwf port, F ; 2: send bit
i++
if( i == bits )
d = .1 ; last bit delay
else
d = .0
endif
if ( RS_BITALIGNMENT & (1 << i) )
RS_delay (RS_CYCLESPERBIT - .1 + #v(d))
else
RS_delay (RS_CYCLESPERBIT - .2 + #v(d))
endif
endw
endm
; this macro generates code for long bit length: 10 and more cycles
RS_bodySEND10_H macro speed, bits, port, pin, spacelvl
local looplen, startlen
clrc ; C will be rolled in
if( spacelvl )
bsf port, pin ; 0: sending start bit
else
bcf port, pin ; 0: sending start bit
endif
rlf RS_DATA, W ; 1: prepare data for output:
xorwf RS_DATA, F ; 2: '1' in RS_DATA means toggle port
movlw bits ; 3: load bit count
movwf RS_COUNT ; 4: into counter
if ( (RS_BITALIGNMENT >> .1) == 0 || RS_CYCLESPERBIT > .450 )
looplen = .7 ; alignment not required, loop is 7 cycles long
startlen = .8
else
movlw RS_BITALIGNMENT >> .1 ; 5: load alignment bits, not including start bit
movwf RS_ALIGN ; 6: load to alignment rotation file
looplen = .10 ; alignment required, loop is 10 cycles long
startlen = .10
endif
RS_delay (RS_CYCLESPERBIT - startlen + (RS_BITALIGNMENT & .1)) ; 7: the start bit aligned here
RS_#v(speed)BIT
movlw (1 << pin) ; 7: load port-toggling mask
rrf RS_DATA, F ; 8: put data bit into C
skpnc ; 9: test data bit
xorwf port, F ; 10: send bit
if ( looplen == .10 )
rrf RS_ALIGN, F ; 1: rotate align bits
skpnc ; 2: align if indicated
nope ; 3: this instruction alings the cycle
endif
RS_delay (RS_CYCLESPERBIT - looplen); 4/5: loop is 10 (7) cycle long
decfsz RS_COUNT,F ; 4/5:
goto RS_#v(speed)BIT ; 5/6:
RS_delay .4 ; 6
endm
RS_bodyRECEIVE2_9 macro speed, bits, port, pin, spacelvl, file, expire, delay
local i, c
i = 0
c = RS_CYCLESPERBIT + RS_HALFCYCLE + (RS_BITALIGNMENT & 1) - expire
if( c >= 0 )
RS_delay c
endif
while( i < bits )
if( c >= 0 )
if( spacelvl )
btfss port, pin ; 1: test data on port, pin
else
btfsc port, pin ; 1: test data on port, pin
endif
bsf file, #v(i) ; 2: set data bit
i++
if( i < bits ) ; no delay for the last bit
if ( RS_BITALIGNMENT & (1 << i) )
RS_delay (RS_CYCLESPERBIT - .1)
else
RS_delay (RS_CYCLESPERBIT - .2)
endif
endif
else
messg Too many cycles expired (#v(expire)), can not read bit #v(i) in RS_RECEIVE#v(speed)
i++
c = c + RS_CYCLESPERBIT
if ( RS_BITALIGNMENT & (1 << i) )
c++
endif
if( c >= 0 )
RS_delay c
endif
endif
endw ; exits one cycle after last bit middle
RS_delay RS_HALFCYCLE + delay - .1
endm
RS_bodyRECEIVE12_H macro speed, bits, port, pin, spacelvl, file, expire, delay
local i, c, looplen, startlen
if ( (RS_BITALIGNMENT >> .1) == 0 || RS_CYCLESPERBIT > .450 )
looplen = .9
startlen = .4
else
looplen = .12
startlen = .6
endif
i = 0
c = RS_CYCLESPERBIT + RS_HALFCYCLE + (RS_BITALIGNMENT & 1) - expire - startlen
if( c >= 0 )
RS_delay c ; expiring start bit and half of first bit
c = .0
movlw bits ; 1: load bit count
movwf RS_COUNT ; 2: into counter
else
c = c + .2
messg Too many cycles expired (#v(expire)) for RECIEVE#v(speed). "RS_COUNT" not loaded
endif
if ( looplen == .10 )
if( c >= .0 )
RS_delay c
c = .0
movlw RS_BITALIGNMENT >> 1 ; 3: load alignment bits, not including start bit
movwf RS_ALIGN ; 4: into alignment rotation file
else
messg Too many cycles expired (#v(expire)) for RS_RECIEVE#v(speed). "RS_ALIGN" not loaded
c = c + .2
endif
endif
if( c < 0 )
error Too many cycles expired (#v(expire)) for RS_RECIEVE#v(speed).
else
RS_delay c
endif
RS_#v(speed)_BIT ; data reading loop
clrc ; 1:
if( spacelvl )
btfss port, pin ; 2: test data
else
btfsc port, pin ; 2: test data
endif
setc ; 3: set data bit in C
rrf file, F ; 4: roll-in the databit from C into RS_DATA
decf RS_COUNT,F ; 5:
skpnz ; 6:
goto RS_#v(speed)_STOP ;7
if( looplen == .10 )
rrf RS_ALIGN, F ; 8: rotate align bits
skpnc ; 9: align if indicated
nope ; 10: this instruction alings the cycle
endif
RS_delay (RS_CYCLESPERBIT - looplen); loop is 12 cycles long
goto RS_#v(speed)_BIT; 11:
RS_#v(speed)_STOP ; exits 7 cycles after last bit middle
c=.7
if(bits < .8) ; if there were less than 8 bits,
i=.8
clrc
while(i>bits)
rrf file, F ; fill most significant bits with zeros
i--
c++
endw
endif
RS_delay RS_HALFCYCLE + delay - c
endm
RS_DELAYNEEDED set 0
; RS_bodyRECEIVE generates RS_RECEIVE routine body
; speed - baud rate (57600, 115200, etc.)
; bits - data bits (5..8)
; port - input port (PORTA, PORTB, etc)
; pin - RX pin on the port (0..7)
; spacelvl - Port level (0..1) driven by SPACE (+V) on the interface line
; file - file register where data is placed
; expire - number of IC expired since start bit rasing edge
; delay - number of IC to expire after stop bit is estimated (negative allowed)
RS_bodyRECEIVE macro speed, bits, port, pin, spacelvl, file, expire, delay
RS_calcCONST speed, bits, 1
if(RS_CYCLESPERBIT + RS_HALFCYCLE < .4)
error Baud rate #v(speed) is to high for frequency #v(CLOCK)
endif
if( (RS_CYCLESPERBIT < .12) || (RS_CYCLESPERBIT < .24 && RS_CYCLESPERBIT + RS_HALFCYCLE - expire < .6) )
RS_bodyRECEIVE2_9 speed, bits, port, pin, spacelvl, file, expire, delay
else
RS_bodyRECEIVE12_H speed, bits, port, pin, spacelvl, file, expire, delay
endif
endm
; RS_bodySEND generates RS_SEND routine
; speed - baud rate (57600, 115200, etc.)
; bits - data bits (5..8)
; port - output port (PORTA, PORTB, etc)
; pin - TX pin on the port (0..7)
; spacelvl - Port level (0..1) that drives SPACE (+V) on the interface line
RS_bodySEND macro speed, bits, port, pin, spacelvl
RS_calcCONST speed, bits, 0
movwf RS_DATA ; put data to rotation buffer
if(RS_CYCLESPERBIT < .3)
error Baud rate #v(speed) is to high for frequency #v(CLOCK)
endif
if(RS_CYCLESPERBIT < .10)
RS_bodySEND2_9 speed, bits, port, pin, spacelvl
else
RS_bodySEND10_H speed, bits, port, pin, spacelvl
endif
if( spacelvl )
bcf port, pin ; 2: sending stop bit
else
bsf port, pin ; 2: sending stop bit
endif
endm
;-------------------------------------------------------------
; RS RTS/CTS physical primitives
; CTS, RTS must be defined externally
; CTS_SPACE_LEVEL (0..1) defines logicla SPACE level for CTS
; RTS_SPACE_LEVEL (0..1) defines logicla SPACE level for RTS
#ifdef CTS_SPACE_LEVEL
CTS_setMARK macro
if( CTS_SPACE_LEVEL )
bcf CTS
else
bsf CTS
endif
endm
CTS_setSPACE macro
if( CTS_SPACE_LEVEL )
bsf CTS
else
bcf CTS
endif
endm
#else ; empty macro in CTS is not used
CTS_setMARK macro
endm
CTS_setSPACE macro
endm
#endif
#ifdef RTS_SPACE_LEVEL
RTS_skpMARK macro
if( RTS_SPACE_LEVEL )
btfsc RTS ; skip if RTS is high
else
btfss RTS ; skip if RTS is high
endif
endm
RTS_skpSPACE macro
if( RTS_SPACE_LEVEL )
btfss RTS ; skip if RTS is low
else
btfsc RTS ; skip if RTS is low
endif
endm
#endif
+
| file: /Techref/member/eugene-ksf-/index.htm, 18KB, , updated: 2003/9/27 04:58, local time: 2025/10/26 18:41,
owner: eugene-ksf-,
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/member/eugene-ksf-/index.htm"> Member Homepage for eugene-ksf-</A> |
| Did you find what you needed? |