1
\$\begingroup\$

I'm trying to figure out why my serial communication is not working. The design is to use the UART of a PIC18F26J50 over a RS485 link. Here is the relevant part of the schematic.

schematic of RS485 link

Other relevant info:

  • RS485_RX is connected to RC7/RX1
  • RS485_TX is connected to RC6/TX1
  • RS485_DE is connected to RA2

Source code:

#define BAUD_2400       0
#define BAUD_9600       1
#define BAUD_19200      2
#define BAUD_38400      3
#define BAUD_57600      4
#define BAUD_115200     5

#define PARITY_NONE     0
#define PARITY_ODD      1
#define PARITY_EVEN     2

#define UART_READ       0
#define UART_WRITE      1

PRIVATE UINT32 speed_[] = {2400, 9600, 19200, 38400, 57600, 115200};

/*----------------------------------------------------------------------------*/

PRIVATE UINT16_VAL getBrgValue_( const UINT8 baud )
{
    UINT16_VAL value = 0;

    value.Val = (UINT16)((CLOCK/(4*speed_[baud])) - 1);

    return value;
}

/*----------------------------------------------------------------------------*/
PRIVATE VOID uartEnableWrite_( VOID )
{   
    PORTAbits.RA2 = UART_WRITE;    
}

/*----------------------------------------------------------------------------*/
PRIVATE VOID uartEnableRead_( VOID )
{
    PORTAbits.RA2 = UART_READ;
}

/*----------------------------------------------------------------------------*/

VOID uartInit( VOID )
{
#if 1
    UINT16_VAL brgValue;    

    RCSTA1 = 0x00;
    TXSTA1 = 0x00;
    BAUDCON1 = 0x00;    

    brgValue = getBrgValue_(BAUD_57600);

    SPBRGH1 = brgValue.byte.HB;
    SPBRG1 = brgValue.byte.LB;

    TXSTA1bits.BRGH = 1;
    BAUDCON1bits.BRG16 = 1;

    TXSTA1bits.TXEN = 1;
    RCSTA1bits.CREN = 1;
    RCSTA1bits.SPEN = 1;

    // enables rs485 transceiver direction control
    TRISAbits.TRISA2 = 0;

#else    
#endif
}

/*----------------------------------------------------------------------------*/

INT8 uartSend( UINT8* buffer, const UINT32 bufferSize )
{
#if 1
    uartEnableWrite_();

    while (!TXSTA1bits.TRMT);
    TXREG1 = *buffer;

#else
#endif
}

The test could not be simpler:

VOID doUartTxTest( VOID )
{
    UINT8 b = 0x55;

    (VOID)uartSend(&b, sizeof(b));    
}

/*----------------------------------------------------------------------------*/

VOID main( VOID )
{    
    ANCON0 = 0xFF;              // AN0 to AN7  are Digital I/O
    ANCON1 = 0x1F;              // AN8 to AN12 are Digital I/O

    uartInit();

    while( 1 )
    {
        doUartTxTest();
        delay1s();
    }    
}

Now, this is what I'm getting in RealTerm: RealTerm Capture

I expect RealTerm to get 0x55 several times. Can anyone, please, help?

\$\endgroup\$
4
\$\begingroup\$

E0 is very typical of a baud-rate mismatch, in which the transmitter is sending at 1/6 the speed that the receiver is expecting. In your case, 9600 bps vs. 57600 bps.

You see, when you transmit 55, the actual bit sequence is ...1110101010101111..., where the initial ones are the "idle" line, the first zero is the "start" bit and the next 8 bits are the data, LSB first. The next bit after that is the "stop" bit (always a 1) and then more idle bits.

But if the receiver is operating at 6× the rate, it samples each bit six times, so it sees:

    start    stop
      |   E0   |
...111000000111111000000111111000...
                  |   E0    |
                start     stop

Each 1→0 transistion is seen as a start bit, the next 8 bits are interpreted as E0 followed by a stop bit, and then two idle bits.

So the answer is, your transmitter is not running at the speed you think it is. Let me guess — when you run your code, you see the E0 appearing in batches of 5 at a time, right?


I once wrote a microcontroller application that used this exact technique to "auto-baud". On power-up it set the UART to the highest available speed, and then looked at the first character received to try to measure the actual width of the "start" bit and then jump directly to the correct baud rate. Obviously, E0 was one of the patterns I was looking for.

It works as long as the first character received has a one in the LSB. Since most people hit <CR> as their first key, it worked like a charm!

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.