I've had correspondence where people are unsure of the code that performs the "USART" serialisation. Constructors want to make changes to the serial data rate. They have applications monitor remotely, using simple FSK radio transmission. Dropping the speed from 19200 bps down to 2400 makes the modulation fit in to the pass band of an audio receiver.
In the design I'm not using a discrete USART Universal Synchronous Asynchronous Receiver Transmitter chip. I'm not using a PIC (16F628/20) that could do this for me. I actually chose to use timing delays.
I specified a crystal frequency of 2.4576 MHz. This gives an instruction delay of 1.627 us. To delay one bit period at 19200 bps, 52.08 us, the PIC needs to execute 32 instructions. But where are the instructions?
Here's the serialisation source:
Why does the delay subroutine bitdly16 only have 16 NOP's? Shouldn't there be 32?
No, the rest of the delay is in the decision logic and in actually setting the port I/O to a one or zero.
I'll unravel the first part of the code, documenting the instruction set cycle count from the time the start bit begins.
The I/O pin is at the logic 1 from the last call to send a character. The last call would have left the pin in logic state 1, the stop bit value. We start by sending a logic 0 for the initial transition of the stop bit, then set the I/O pin back to a 1 for a contrived data bit 0.
call OutZero ; start bit
// this calls:
| bcf PORTA, RS232_BIT; 1
// Pin is now at logic 0
goto bitdly16 // 2
| nop ; trim!
nop // 22
decfsz RS232_COUNT, f ; // 23
goto SendBit ; 2 // 25
rrf RS232_DATA, f ; // 26
btfss STATUS, C ; // 28
goto SendZero ;
nop // 29
call OutOne ; send 1 // 31
// this calls:
bsf PORTA, RS232_BIT // 32
// Pin is now at logic 1
I could carry on and pick out the delays for each data bit, and finally the 2 stop bits.
I haven't tried this, but....
For 2400 bps bit period we need a delay of 416.66 us. That's 256 instruction cycles in place of 32. We could insert extra NOP instructions at label bitdly16. Adding 224 NOP's would do the trick.
A more elegant solution is to set up a loop counter as below:
movlw .73 //
73 = 224/ 3
movwf MY_COUNT // 2
DECFSZ MY_COUNT,f // 3 (6, 9..... 222)
goto L1 // 5 (8, 11.....224)
NOP // and carry on with existing code...
Back to the Schematics page