I have a PIC16 for which I have the (asynchronous) UART transmit working just fine, but the UART receive producing invalid results.
For example, a
gets interpreted as O
, b
gets interpreted as '
, and c
gets as N
.
Here is my receive function:
char UART_read(void) {
while(!PIR1bits.RCIF) {}
return RCREG;
}
My hypothesis is that the UART polarity is wrong for the receiver, so that in particular the start/stop bits get messed up. I have set the SCKP
bit (see page 302) to invert the data on the TX/CK pin but I cannot find an equivalent for the RX/DT pin.
What could be the cause of the UART receive not working? How can I invert the data on the RX/DT pin?
Best Answer
EDIT: This answer has been modified to reflect the comment by the question asker and points out that he is quite right in his diagnosis of the problem, which isn't terribly useful information. The only useful piece of information in the section is the fact that there is no receive invert bit... But perhaps it will help future people diagnose their own UART problems
So let's take a look
a maps to O which means 01100001 maps to 01001111
b maps to ' which means 01100010 maps to 00100111
Let's assume that there's an implicit 1 before each of those and an implicit 0 after (start and stop bits). The RX module receives a continuous low signal, then the stop bit is sent as a high, which will be eaten as an idle signal, then the initial 0 will be consumed as a stop bit. Then the remaining bits will be inverted,
Looks like you nailed the diagnosis, unfortunately there is no similar "invert signal" configuration bit in the receiver on the PIC. Though it's not hard to put an inverter on the receive path, which is incidentally what I would recommend doing!
As Olin noted, standard rs-232 signals are from +3V to +15V for a logical '1' and -3V to -15V for a logical '0'. The PIC is designed to operated at "TTL" levels, which means "transistor-transistor logic". The idea is that the PIC is designed to talk to other things which are physically close (i.e. on the same board) and thus the extra transmission distance and noise rejection provided by the full rs-232 levels are not needed for "standard" operation. It's not practical to be able to completely internally generate the positive/negative voltages needed for rs-232 operation completely internally on the PIC, so "normal" rs-232 communication was never really an option.
Since TTL levels are not the standard but instead a derivative of the standard (same protocol for timing, start and stop bits, parity, but different voltages), you don't buy a consumer "rs-232 adapter" for your computer unless it adheres to the standard. They do make TTL-level rs-232 adapters and they're very popular on hobbyist websites! Check out Adafruit's cable or the Sparkfun FTDI breakout. I find that in general, if it goes to a DB9 connector, it's probably a rs-232 level adapter.