Seizing immense
If we take an arbitrary clock frequency and an arbitrary baud rate, the transmitter routine would still look similar to one of the examples given above. The only differences would be specific delays. It is reasonable to let compiler calculate these delays and place them in the routine body. Now our challenge is to write a macro that would produce transmitter routine for any specified baud rate at any specific clock frequency. What would be input for this macro? Clock frequency, baud rate, number of bits, port, pin, and space level (0 or 1). Since all applications in PIC work on the same clock J, we may pass it to our macro via a global constant or a definition. Other parameters may not be considered as global. For example, there may be a need of two transmitter routines sending via different ports with different speeds (such as main communication channel (slow) and debug output channel (fast)). Considering this, the first line of macro may look like:
RS_bodySEND macro speed, bits, port, pin, spacelvl
Next what we have to do is calculating instruction cycles per bit (CBP) and alignment. CBP is simply clock divided by speed (with fractional part ignored). To calculate alignment we will code a loop that accumulates and compares required bit lengths to the length achieved with CBP. If difference is greater than 0.5 IC, an alignment bit is set.
RS_calcCONST macro speed, bits
local cycles, align
local i, c
cycles = CLOCK / (speed / .25) ; ((CLOCK / 4) / speed ) * 100
RS_CYCLESPERBIT set cycles / .100
i = 0
c = 0
align = 0
while( i <= bits ) ; bit alignment for all bits + stop bit
c = c + RS_CYCLESPERBIT
i++
if( (i * cycles) - (c * .100) >= .50 )
align = align | (1 << (i-1) ) ; set alignment bit
c++
endif
endw
RS_BITALIGNMENT set align
endm
Now we have to decide which template routine to use: looped or linear. RS_CYCLESPERBIT gives as a guidance: 10 and more may be achieved with the looped, lesser – only with the linear. As a result, the main macro is ready:
RS_bodySEND macro speed, bits, port, pin, spacelvl
RS_calcCONST speed, bits
RS_#v(speed)SEND
movwf RS_DATA ; put data to rotation buffer
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 ; sending stop bit
else
bsf port, pin ; sending stop bit
endif
endm
RS_DELAY0WC
addlw | -.1 | ; 4 | |
skpz | ; 5 | ||
goto | RS_DELAY0WC | ; 6 | |
return | ; 7 |
Post a Comment