
| 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/31 16:01, 
owner: eugene-ksf-, 
 
216.73.216.219,10-1-97-123: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.ecomorder.com/techref/member/eugene-ksf-/index.htm"> Member Homepage for eugene-ksf-</A> | 
| Did you find what you needed? From: "/member/eugene-ksf-/index.htm" |