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: 2024/8/15 00:36,
owner: eugene-ksf-,
3.131.38.22:LOG IN
|
©2024 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://ecomorder.com/Techref/member/eugene-ksf-/index.htm"> Member Homepage for eugene-ksf-</A> |
Did you find what you needed? |