# PIC18F + MAX232 USART Bizarreness

Okay, I've been struggling with this for weeks, and it's blowing my mind. I have been working with PICs for a long time, and I'm very confused as to why I can't make my USART work.

First off, a few questions for people that don't want to read through this post but might be able to help:

• How do I invert the signals to use with the MAX232 chip?
• Should TX and RX be set to outputs, inputs, or output for RX and input for TX? The datasheet says one, examples say another.
• Do I need to use the PLL?
• What are the USART_ADDEN_OFF and BAUD_IDLE_RX_PIN_STATE_HIGH flags for, and why aren't they in the C18 documentation?

For everyone else, here is the long story:

The setup: PIC18F46K20 <--> MAX232 <--> PC

RC7 is RX, and RC6 is TX.

Terminal software is just a Python interpreter:

port = serial.Serial("COM6", 2400, timeout=5)
port.write("abcd")
etc...

• If I connect the T1in and R1out pins of the MAX232 together, then serial-loopback works perfectly from my PC, so I know that the MAX232 board is okay.
• I moved the PIC off of it's board, and it's sitting on a breadboard for debugging. The only things plugged into it are power, ground, and TX & RX.

I have tried an incredible different number of code variations - none are doing the trick. Here are some of the things I have tried:

This is basically taken entirely from this post: PIC18 USART problem

Note the use of a PLL and the HS setting for BRGH, and that the TX pin is set to input, and only RX is set to output, contrary to the datasheet.

#include <p18cxxx.h>
#include <usart.h>

void main(void)
{
char c = 'a';

TRISC = 0x80;
// Internal osc. 8 MHz, PLL 4x
OSCCON |= 0xE2;
OSCTUNEbits.PLLEN = 1;

// wait until IOFS = 1 (osc. stable)
while (!OSCCONbits.IOFS)
;

/*
* Open the USART configured as
* 8N1, 2400 baud, in polled mode
*/
OpenUSART (USART_TX_INT_OFF &
USART_RX_INT_OFF &
USART_ASYNCH_MODE &
USART_EIGHT_BIT &
USART_CONT_RX &
USART_BRGH_HIGH, 207);

while (1)
{
putcUSART(c);
c = getcUSART();
Nop();
}

}


Anyway, I feel silly that I can't make a silly USART work, but I'm completely stumped. What am I missing? What am I doing that's stupid? Someone please help!

Addition I'm exhausted - posting this last thing before I go to bed and try more tomorrow.

This returns a constant stream of gibberish, even if I'm not writing anything to the USART from the PC:

#include <p18cxxx.h>
#include <usart.h>

void main(void)
{
char test = 'a';
TRISC = 0xFF;
OSCCON |= 0b11100010;
OSCTUNEbits.PLLEN = 1;

while (!OSCCONbits.IOFS);

baudUSART(BAUD_IDLE_CLK_LOW &
BAUD_AUTO_OFF &
BAUD_8_BIT_RATE &
BAUD_IDLE_RX_PIN_STATE_HIGH);

OpenUSART (USART_TX_INT_OFF &
USART_RX_INT_OFF &
USART_ASYNCH_MODE &
USART_EIGHT_BIT &
USART_CONT_RX &
USART_BRGH_HIGH, 207);
while (1)
{
WriteUSART(test);
while(!DataRdyUSART());
Nop();
}
}


UPDATE

Okay, now my TX pin is at a constant 0.00 Volts. It's almost like it is tied directly to ground (it very well may be at this point, I don't know). I have tried switching out PICs, making it constantly transmit, making it do nothing, changing configuration bits... nothing seems to help. The RX pin sits high (which is correct, because it isn't receiving anything), but the TX pin sits flat at 0V - whether it's supposed to be transmitting or not.

Here is my current code:

#include <p18cxxx.h>
#include <usart.h>

void main(void)
{
char test = 't';
TRISCbits.RC7 = 1;
TRISCbits.RC6 = 0;
OSCCON = 0b11100010;
OSCTUNEbits.PLLEN = 0;

while (!OSCCONbits.IOFS);

baudUSART(BAUD_IDLE_CLK_LOW &
BAUD_AUTO_OFF &
BAUD_8_BIT_RATE &
BAUD_IDLE_RX_PIN_STATE_HIGH &
BAUD_IDLE_TX_PIN_STATE_HIGH);

OpenUSART (USART_TX_INT_OFF &
USART_RX_INT_OFF &
USART_ASYNCH_MODE &
USART_EIGHT_BIT &
USART_CONT_RX &
USART_BRGH_HIGH, 207);
while (1) {
//       WriteUSART(test);
//      while(!DataRdyUSART());
Nop();
}
}


What on Earth did I do to make it do that? Note that I also rebuilt my old code (an example from above, that was previously just spitting out gibberish) - and now the voltage is 0.0V with that hex file as well. Also, the MAX232 loopback still works correctly. Huh?

• What terminal software are you using? How is it set up? Also, have you checked the PICs Rx/Tx with a scope, and/or confirmed continuity between all lines with a multimeter? – Oli Glaser Sep 27 '11 at 5:29
• I added a note to the top about my terminal setup (all Python). I have not yet checked with a scope because I don't have one handy - may travel somewhere tomorrow where there is one. I have, however, confirmed voltages with a multimeter. – bhilburn Sep 27 '11 at 5:36
• Added an update to the end of my post, if you have any ideas :-/ – bhilburn Sep 28 '11 at 6:26

Okay, for anyone that ever encounters something like this in the future:

The issue was that there was leakage from the power trace into the serial trace, such that a 60Hz wave was appearing on the SPI line, which obviously would mess things up.

I know the likelihood of this same fix applying to other people is small, but maybe it will at least give you some ideas!

• Break it up into sections.

• Where possible eliminate complexity that may be getting in the way of the basic working low level connection.

• Try to test one thing at a time and change one thing at a time.

You can check for N things that may happen as a result of one change but this risks masking what is causing what.

Changes would ideally only target a single area in their effect).

THEN:

TX pin must be set to output.

If you are using an RS232 IC (which inverts) then TX idle level at PIC must be high.

If you want to see if PIC clock and coms connections are working as expected you could use a bit bashed TX routine (many around) to send characters to the PC. If you can't get any data showing this way then your connection is suspect in some way. If you do get any trace of data at the PC you can alter things until it works and then know what your PIC should do via UART

TX low level functionality can be confirmed by measuring voltage with a voltmeter.

• If idle = logic 1 = high = 5V (say) and you send in a tight loop
and send null (\$00)

• then voltage will fall to a low % of 5V.
eg if you can send with NO delay between characters *(depends on buffering etc) then you'd be sending:
start = 0, 8 x low, 1 x stop= 5V so you'd see 1/10 x 5V = 0.5V DC.

If you have a delay between characters the voltage will rise accordingly.

Without a scope - If you send tx characters into the PC in a loop you should see voltage change when you send and you should see voltage at RS232 output also change but with opposite polarity.

RS232 output to PC should be idle low and then be changed in the oppoeite way to the test above.

• Thanks so much for the tips! I took your advice and set the TX pin to output. Also, I started checking the voltages, and somehow now have a TX pin that sits at a constant 0.0V (this was not happening before) - check the end of my post for the update showing my current code. Thoughts? – bhilburn Sep 28 '11 at 6:27