ON 20030528@8:12:37 AM at page: http://piclist.com/techref/member/eugene-ksf-/index.htm eugene-ksf- replace Pages: /techref/microchip/rs232.htm PIC Specific RS232 IO ON 20030528@8:28:50 AM at page: http://piclist.com/techref/member/eugene-ksf-/index.htm eugene-ksf- removed post 37769.3420949074 |Delete ' /techref/microchip/rs232.htm PIC Specific RS232 IO' ON 20030528@8:39:17 AM at page: http://piclist.com/techref/member/eugene-ksf-/index.htm eugene-ksf- Says http://piclist.com/techref/member/eugene-ksf-/highspeedserial.html Yet another software implementation of RS-232 routines: any baud rate at any clock frequency (up to F/10); CTS/RTS flow control.
Maximum speed achived @ 4 Mhz is 230400.
ON 20030528@8:41:08 AM at page: http://piclist.com/techref/member/eugene-ksf-/index.htm eugene-ksf- removed post 37769.3606134259 |Delete ' Says:
Yet another software implementation of RS-232 routines: any baud rate at any clock frequency (up to F/10); CTS/RTS flow control.
Maximum speed achived @ 4 Mhz is 230400.
' ON 20030528@8:43:38 AM at page: http://piclist.com/techref/member/eugene-ksf-/index.htm eugene-ksf- See also: /techref/member/eugene-ksf-/highspeedserial.html Yet another software implementation of RS-232 routines: any baud rate at any clock frequency (up to F/10); CTS/RTS flow control.
Maximum speed achived @ 4 Mhz is 230400.
ON 20030528@8:44:37 AM at page: http://piclist.com/techref/member/eugene-ksf-/index.htm eugene-ksf- Replied to post 37769.3636342593 |Insert '?' at: '' refers to
/techref/member/eugene-ksf-/highspeedserial.html Yet another software implementation of RS-232 routines: any baud rate at any clock frequency (up to F/10); CTS/RTS flow control.
Maximum speed achived @ 4 Mhz is 230400.
ON 20030528@8:45:50 AM at page: http://piclist.com/techref/member/eugene-ksf-/index.htm eugene-ksf- edited the page. Difference: http://piclist.com/techref/diff.asp?url=H:\techref\member\eugene-ksf-\index.htm&version=11 ON 20030528@8:48:31 AM at page: http://piclist.com/techref/member/eugene-ksf-/index.htm eugene-ksf- Code: 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
ON 20030528@8:50:08 AM at page: http://piclist.com/techref/member/eugene-ksf-/index.htm eugene-ksf- 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