# PIC18 USART problem

Ok, my next PIC18 problem...

USART - I can't get it to transmit anything sensible. All I get is random x's and inverted question marks.

I am using the same BAUD settings as I have used many times on PIC16s quite happily. I have tried re-calculating the baud setting from the formula, I have tried different baud rates and different crystal frequencies to give different baud accuracies, but still all I get is the same two wrong characters.

If I change the baud to something completely wrong it puts more random gibberish than just these two characters.

I have tried this on 2 different PIC18s - both my '4455 and my '14K50 - both do exactly the same.

Here's my program:

void main()
{
OpenUSART ( USART_TX_INT_OFF &
USART_RX_INT_OFF &
USART_ASYNCH_MODE &
USART_EIGHT_BIT &
USART_BRGH_HIGH &
USART_CONT_RX, 103);
baudUSART(  BAUD_IDLE_CLK_HIGH &
BAUD_8_BIT_RATE &
BAUD_WAKEUP_OFF &
BAUD_AUTO_OFF);
while(1)
{

WriteUSART('F');
WriteUSART('o');
WriteUSART('o');
WriteUSART(13);
WriteUSART(10);
}
}


The 103 I caclulated from a 16MHz crystal at 9600 baud according to the formula in the data sheet for the PIC.

So what am I missing?

UPDATE

Timing the data stream with a 'scope I have determined that it is infact running at 2400 baud (setting the computer to 2400 baud confirms it).

I have checked and the crystal is oscillating at 16MHz.

The formula for calculating the BAUD is:

$\frac{F_{osc}}{(16*(n+1))}$

where Fosc is the is the oscillator frequency, and n is the number passed to the baud rate generator.

$\frac{16,000,000}{(16*(103+1))} = \frac{16,000,000}{(16 * 104)} = \frac{16,000,000}{1664} = 9615.384615385$

So why is it actually running at 2400 baud???

I know it's not my calculations - the table of bauds in the datasheet quotes 119 for a 9600 baud on an 18.432MHz crystal, so 103 for a 16MHz is perfectly reasonable.

Things I have tried:

• Switch to BRGH=0 - slows the baud down even more
• Switch to 16-bit timer not 8-bit - slows the baud down to a crawl.

• What are the question marks in hex or binary? They may not be a specific character code, but just mean something the terminal cannot display. If they are not all the same character, it may give you more information about what is going on. May 31 '11 at 10:24
• Also, do you have an oscilloscope or logic analyzer? That would be the best way to debug what is going on. You could actually see the bit-timings and data content the chip is outputting. May 31 '11 at 10:25
• From what I can see with my scope the actual data format and content looks ok, but I'm not sure about the timing. May 31 '11 at 10:34
• If you can see the data you're sending on the bus, you're 90% of the way there. As for timing, Measure it! An oscilloscope or logic analyzer makes an excellent precision timer. If it all looks good, time to start looking at the PC end of the affair. May 31 '11 at 10:44
• Note: Are you certain that you don't have a signal inversion somewhere? Is it possible the PIC output is active low, and the computer active-high (or vice versa)? Serial interfaces come in both flavors, and you need to make sure that both ends match. May 31 '11 at 10:45

The problem here is that Microchip sneakily defaulted the CPUDIV to /4 meaning the internal clock of the PIC was running at a quarter of the expected frequency - thus the calculations were all wrong.

It took some time to figure this out, but setting

#pragma config CPUDIV = NOCLKDIV


appears to fixed the problem. Also, because I am using a MAX232 linked to the output I have to invert the signals:

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, 103);


This test program worked OK with an 18F4520:

/Test.c
//Tx RC6 (pin 44)
//Rx RC7 (pin 1)

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

#pragma config OSC = INTIO67, MCLRE = ON

void main (void)
{
char c;

TRISC = 0x80;       // RC6 output, RC7 input

// Internal osc. 8 MHz, PLL 4x
OSCCON |= 0x72;
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, 103);

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

}

• With a little bit of tweaking for the '14k50 (PLL is in config, not register controlled), I get a screen full of 'B' with that program. May 31 '11 at 10:35
• Transmit 'U' continuously and check the bit time with a scope. May 31 '11 at 12:24