|
|
|
|
12. One Bit at a Time 339 |
|
|
|
|
|
movlw |
K |
; |
1˜ |
; K is the delay const |
BAUD_LOOP addlw |
-1 |
; |
K˜ |
; Decrement |
btfss |
STATUS,Z ; |
((K-1)+2)˜ ; until zero |
goto |
BAUD_LOOP; |
2(K-1)˜ |
|
|
|
|
|
|
which gives a total of 4K cycles delay, where each cycle is 4/XTAL microseconds. This can be increased by padding with nop instructions, each adding K cycles to the total.
|
For any given baud rate we require |
106 |
|
microseconds for a |
1 |
bit |
|
2×BAUD |
2 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
period delay; so to evaluate the value of K we need to calculate the total |
|
number N of 4/XTAL cycles. |
|
|
|
|
|
|
|
4 |
|
|
|
|
|
106 |
|
|
|
|
|
|
|
N × XTAL = |
2 |
× |
BAUD |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
N |
= |
|
106 × XTAL |
|
|
|
|
|
|
|
|
|
8 |
× |
BAUD |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
In the macro of Program 12.10 N has been defined accordingly. To determine the constant to be loaded into W at the beginning of the loop this value is divided by the total delay cycles in the loop. For example, if XTAL is greater than 12 MHz then the five extra nop instructions bring the total delay to nine cycles, hence the initial constant K is N/9. Actually the value of K is can be reduced by around 2% to compensate for the instructions outside the macro; hence the use of 980,000 in Program 12.10 in the definition of N rather than 1,000,000 (106).
Notice the use of the local directive to qualify a label inside a macro; in this case BAUD_LOOP. This ensures that when the macro is used several times, the assembler will not object to the same named label appearing more than once in the one program.
With our delay macro in situ, the basic input/output subroutines of Program 12.11 are similar to our bit banging SPI subroutines. The PUTCHAR subroutine simply brings the TX pin low for two Baud_delay periods and then toggles the pin eight times mirroring the data in DATA_OUT least-significant bit first – the opposite order to SPI/I2C. Finally TX is held high for the same period to give the Stop/Idle condition.
The input GETCHAR counterpart is more complex. After an Idle state a low-going voltage at pin RX will be treated as a Start bit. However, if the data stream is subsequentially sampled at intervals of one bit period (two evocations of Baud_delay) then as this is just at the transition point of the transmitter, any drift in the two clock rates may cause errors. To avoid this, a half bit period is evoked and then the state of RX checked to ensure that the Start bit is still present. If it is, then subsequent samples are taken at two Baud_delay periods, which is approximately at the bit center point. Better noise rejection could be obtained by sampling at a
340 The Quintessential PIC Microcontroller
Program 12.11 Asynchronous formatted input and output subroutines.
;*************************************************************
;* FUNCTION: Transmits one 8-bit byte in asynchronous format *
;* FUNCTION: Baud rate can be 1200 - 9600 for XTAL 1 -- 20MHz*
; * |
RESOURCE: |
Macro |
Baud_delay giving a |
0.5 |
bit delay; COUNT |
* |
; |
* |
ENTRY |
: |
8-bit |
datum |
in DATA_OUT, XTAL |
& BAUD predefined * |
; |
* |
EXIT |
: |
Contents of |
DATA_OUT 00h, |
byte TXed |
* |
; *************************************************************
PUTCHAR |
movlw |
8 |
; Eight data bits |
|
movwf |
COUNT |
|
|
bcf |
PORTA,TX |
; Start bit |
|
Baud_delay |
; 2x0.5 bit delay |
|
Baud_delay |
|
; Now shift out data, LSB first |
|
PUTCHAR_LOOP rrf |
DATA_OUT,f |
; Rotate right into Carry |
|
btfss |
STATUS,C |
; Test Carry bit |
|
goto |
ITS_A_0 |
; IF 0 THEN output a 0 |
|
bsf |
PORTA,TX |
; ELSE output a 1 |
|
goto |
PUTCHAR_NEXT |
; and continue |
ITS_A_0 |
bcf |
PORTA,TX |
; Output a 0 |
PUTCHAR_NEXT |
Baud_delay |
; One-bit duration |
|
|
Baud_delay |
|
|
decfsz |
COUNT,f |
; Repeat eight times |
|
goto |
PUTCHAR_LOOP |
|
|
bsf |
PORTA,TX |
; Stop bit |
Baud_delay
Baud_delay return
; *************************************************************
; * FUNCTION: |
Receives one 8-bit byte in asynchronous format |
* |
; * FUNCTION: |
Baud rate can be 1200 - 9600 for XTAL 1 -- 20MHz* |
; * RESOURCE: |
Macro BAUD_DELAY giving a 0.5 bit delay; COUNT |
* |
; * ENTRY |
: |
XTAL & BAUD predefined |
* |
; * EXIT |
: |
DATA_IN holds the received byte. |
* |
; * EXIT |
: |
Err is 00 if no Framing error ELSE -1 |
* |
; *************************************************************
GETCHAR |
movlw |
8 |
; Eight data bits |
|
movwf |
COUNT |
|
|
clrf |
ERR |
; Zero Error byte |
GETCHAR_START |
btfsc |
PORTA,RX |
; Poll for 0 |
|
|
goto |
GETCHAR_START |
|
|
Baud_delay |
; Hang around for 0.5 bit time |
|
btfsc |
PORTA,RX |
; Check; is it still low? |
|
goto |
GETCHAR_START |
|
|
Baud_delay |
; IF yes THEN hang around |
|
Baud_delay |
|
GETCHAR_LOOP bcf |
STATUS,C |
; Clear Carry |
|
rrf |
DATA_IN,f |
; Shift 0 into datum |
|
btfsc |
PORTA,RX |
; Check; is input high? |
|
bsf |
DATA_IN,7 |
; IF yes THEN set bit in datum |
|
Baud_delay |
|
|
Baud_delay |
|
|
decfsz |
COUNT,f |
; Do eight times |
|
goto |
GETCHAR_LOOP |
|
|
btfss |
PORTA,RX |
; Look for a Stop bit (High) |
|
decf |
ERR,f |
; IF low THEN signal an error |
|
return |
|
|
|
|
|
|
12. One Bit at a Time 341
higher rate and then taking a majority decision regarding the logic state of the incoming voltage.
After the eight data bits have been shifted into DATA_IN, the Stop bit is checked for 1. If Stop is 0 then a Framing error has occurred. This is signalled by returning a value of −1 in ERR. Other more elaborate schemes may return a variety of error types. For example, where parity is used then a Parity error can be returned.
As an example, if we wish to transmit the three characters PIC then the following code fragment would implement our task. For convenience the assembler allows the programmer to represent ASCII codes in delimited single quotes to represent their ASCII equivalent, as described on page 223.
movlw |
’P’ |
; ASCII for P is 50h |
movwf |
DATA_OUT |
; Put in store |
call |
PUTCHAR |
; Send it out |
movlw |
’I’ |
; ASCII for I is 49h |
movwf |
DATA_OUT |
; Put in store |
call |
PUTCHAR |
; Send it out |
movlw |
’C’ |
; ASCII for C is 43h |
movwf |
DATA_OUT |
; Put in store |
call |
PUTCHAR |
; Send it out |
|
|
|
Handling serial communications this way is only really satisfactory for very simple situations. For example, if the RX pin is not continually monitored a transmission can be missed or synchronization lost. Also it is di cult to implement a full-duplex link. In addition the procedure is software intensive with most of the processing power being wasted in delay loops. The situation can be improved somewhat by using an internal timer to generate the baud delay and by using interrupt-driven techniques. However, the majority of 28+pin PICs have an integral communications port to automatically deal with asynchronous transmission.
One of the first applications of the then new LSI fabrication techniques in the late 1960s, was the implementation of a dedicated hardware asynchronous serial port known as the Universal Asynchronous Receiver Transmitter. The UART12 was already in production by the time microprocessors were developed. Most PCs, even in the 1970s, had a serial port implemented by a UART, as do current systems. As well as dealing with shifting, error checking and interrupt handling, most UARTs also have an integral baud-rate generator which can be set up in software to give the correct bit frequency.
Figure 12.19 shows a simplified model of the basic PIC USART – Universal Synchronous-Asynchronous Receiver Transmitter as the port has a synchronous mode (SYNC = 1) which will not be discussed here. The core of the USART is the Transmit and Receive registers and their
12Sometimes known as the Asynchronous Communication Interface Adapter or ACIA.
342 The Quintessential PIC Microcontroller
Serial Port
Baud Rate Generator
SPBRG File 99h
X f/4
Fosc/64(X+1) 0
TranSmit STAtus
7 |
|
Transmit 6 |
X |
|
data length |
|
|
|
|
TX9 |
(R/W 0) |
|
(R/W 0) |
Serial 7 |
|
ReCeive 6 |
|
|
Port |
|
data length |
ENable |
|
|
SPEN |
|
RX9 |
(R/W 0) |
|
(R/W 0) |
|
|
|
Clock |
|
Transmit |
shift |
register |
Serial |
data |
out |
RC6/TX |
|
|
|
|
|
|
|
|
|
|
|
|
|
TranSmit |
data |
REGister |
File 19h |
|
|
|
|
|
|
|
TXREG |
|
|
|
|
|
|
|
|
Receive |
shift |
register |
|
Serial |
data |
in |
RC7/RX |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ReCeive |
data |
REGister |
File 1Ah |
|
|
|
|
|
|
|
RCREG |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
h
|
and |
control register |
|
|
|
|
|
|
|
|
|
|
File 0C PIR1
|
Transmit 5 |
4 |
3 |
Baud Rate2 |
TRansMiT 1 |
|
TX Data 0 |
|
|
|
|
|
|
ENable |
0 |
---- |
Generator |
|
shift reg |
|
|
bit 9 |
File 98h |
4
|
|
|
|
High speed |
empty |
|
|
|
bufferTX
|
empty TXIF 0)(R/W
|
|
|
|
|
|
|
|
TXSTA |
|
|
|
|
|
|
|
|
|
TXEN |
SYNC |
|
BRGH |
|
TRMT |
|
|
TX9D |
|
|
|
|
|
|
|
|
|
|
(R/W |
0) |
(R/W 0) |
(R 0) |
(R/W 0) |
|
(R 1) |
|
(R/W 0) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5
|
Empty RCIF 0)(R/W
|
|
5 |
4 |
3 |
Framing |
2 |
Overflow |
1 |
|
RX Data |
0 |
|
bufferRX
|
|
|
Continuous |
|
|
|
|
|
|
|
|
X |
|
Receive |
---- |
ERRor |
|
ERRor |
|
|
bit 9 |
File 18h |
|
|
|
ENable |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
RCSTA |
|
|
|
|
CREN |
|
FERR |
|
OERR |
|
|
RX9D |
|
|
|
|
|
|
|
|
|
|
|
|
(R/W |
0) |
(R/W 0) |
(R 0) |
(R 0) |
|
(R 0) |
|
|
(R X) |
|
|
|
|
ReCeive STAtus and control register
Fig. 12.19 The PIC USART configured for asynchronous communication.
associated bu ers and Status registers. To enable the overall USART the
Serial Port ENable (SPEN) bit in the ReCeive STAtus register (RCSTA[7]) at File 18h must be set.
Transmission
The transmitter logic is enabled when the TranSmit ENable (TXEN) bit in the TranSmit STAtus register (TXSTA[5]) at File 98h is set. To send a character the datum must be moved to the TranSmit data REGister (TXREG) at File 19h, whence it will be transferred to the Transmit shift register and shifted out of pin TX, which is shared with RC6. If a 9- bit format is required the TX9 bit in TXSTA[6] must be set to 1 and the ninth bit placed in bit 0 of the same register before moving the lower eight bits into TXREG. If the Transmit shift register is not empty; that is it is in the process of shifting out a previous datum, then the new datum will remain in the TXREG bu er register awaiting the completion of transmission before being transferred.
Bit 1 of the TranSmit STAtus register reflects the state of the Transmit shift register whilst the TranSmit Interrupt Flag (TXIF) in bit 4 of the Peripheral Interrupt Register 1 (PIR1) is automatically set when the TXREG bu er is empty and ready for reloading. If an interrupt on TX bu er is empty is required, the corresponding TXIE mask bit in the Peripheral
12. One Bit at a Time 343
Enable Register 1 (PIE1[4]) must be set – see Fig. 14.10 on page 408. TXIF is automatically cleared whenever a datum is written into the TXREG.
Reception
Once a Start bit is detected at pin RX then the succeeding eight or nine bits are shifted into the 2-deep ReCeive data REGister (RCREG) at File 1Ah pipeline irrespective of what is going on at the transmitter section. If a 9-bit receive protocol has been selected with RX9 set to 1 in RCSTA[6] then the ninth bit can be read in the RX9D bit of the same status register.
When a datum has been received, it is automatically stored in the top RCREG bu er whence it moves to the lower bu er, provided that no datum is still waiting to be read. ReCeiver Interrupt Flag (RCIF) is automatically set whenever a datum is waiting for collection and this can be used to generate an interrupt if the RCIE mask bit is set; as well as the GIE and PEIE global masks. RCIF is cleared whenever a datum is read. If a datum is waiting in the top bu er, then RCIF is immediately set again showing that there is another datum ready for collection.
If a third character has been received and the 2-deep receive pipeline is full then the Overflow ERRor (OERR) bit at RCSTA[1] will be set and this newly received datum will be lost. The RCREG can still be read twice to retrieve the two bu ered bytes. However, to clear OERR the receive logic must be reset by clearing the Continuous Receive ENable (CREN) bit in RCSTA[4] and then setting it again.
The Framing ERRor (FERR) bit in RCSTA[2] will be updated by reading the RCREG on the next received datum. Both FERR and any ninth received bit are double bu ered in the same way as the received data and so should be read/checked first before the main datum is read as this will empty the pipeline and therefore change these auxiliary bits.
Serial Port Baud-Rate Generator, SPBRG
This is basically a programmable 8-bit counter followed by a switchable frequency ÷4 flip flop chain which can be set up to give the appropriate sampling and shifting rates for the desired baud rate, based on the PIC’s crystal frequency XTAL giving:
|
Baud rate |
XTAL |
|
64×(X+1) |
|
|
|
Baud rate |
XTAL |
|
16×(X+1) |
|
|
where X is an 8-bit datum written into SPBRG at File 99h who’s value
is XTAL×106 − 1. For example, if we require a baud rate of 4800 on a
64×BAUD
20 MHz device, then a value X = 64 will give a baud rate of 4808, an error of +0.161%. At 20 MHz the maximum baud rate is 312,500 whilst the lowest rate is 1221. A baud rate of 1.25 Mbaud is obtainable at 20 MHz in the high-speed mode with SPBRG = 1, but Microchip do not advise this