Problem interfacing RS485

Discussion in 'Embedded Systems and Microcontrollers' started by aamirali, Aug 4, 2014.

  1. aamirali

    Thread Starter Member

    Feb 2, 2012
    I have interfaced two MCU with RS-485 using SN65HVD72.

    1. If on startup, I define one as receiver fro entire code & other as transmiiter then I am able to communicate

    2. But if I do, send master address, let slave ack & then transmit or receive data depending upon situation, codes does not work.

    I have written master code as:

    Code ( (Unknown Language)):
    1. main()
    2. {
    3.     uint8_t ready = 0;
    4.     while(0 == ready)
    5.     {
    6.         RX_DISABLE_TX_ENABLE();
    7.         send_uart(0x01);   /* slave will send ack after this */
    8.         RX_ENABLE_TX_DISABLE();
    10.         WAIT_1_SEC();  or (receive_uart());
    12.         if(0x02 == receive_uart)
    13.         {
    14.             ready = 1;
    15.             //slave ack
    16.         }
    18.     }
    21.     while(1)
    22.     {
    23.         //send_data();
    24.     }
    26. }

    Slave code:

    Code ( (Unknown Language)):
    1. main()
    2. {
    3.     uint8_t ready = 0;
    4.     RX_ENABLE_TX_DISABLE();
    5.     while(0 == ready)
    6.     {
    7.         if(receive_data() == 0x01)
    8.         {
    9.             RX_DISABLE_TX_ENABLE();
    10.             uart_send(0x02);
    11.             ready = 1;
    12.         }      
    13.     }
    14.     RX_ENABLE_TX_DISABLE();
    16.     while(1)
    17.     {
    18.         //receive_data();
    19.     }
    21. }
  2. MrChips


    Oct 2, 2009
    When you have two independent processes waiting for each other you can end up with a lock-out situation where they both wait forever.

    You are best to use interrupts on the received signal.
    The master should have a time-out in case the slave never responds.
  3. JohnInTX


    Jun 26, 2012
    What MrChips said PLUS:

    Consider what happens when you do send_uart(0x01). Its likely that the compiler writes the data to the uart TX register and returns. BUT! The data still has to be shifted out. That takes time. At 9600 baud it takes roughly 1ms to shift out the 8 bit data plus start and stop bits. But your code turns the transmitter off right after loading the transmitter register. That means that the RS485 transmitter is turned off BEFORE the character is transmitted. That doesn't work.

    That's a partial solution. You also have to monitor the transmitter to know when the character has been shifted out then immediately switch the RS485 to receive for the response.

    In the PIC world, this can be done by buffering the transmit data and monitoring TXSTA.TRMT (shift register empty i.e. character is sent), interrupting on that and changing to receive.

    I use interrupt driven buffers for RX and TX. The RX logic is simple enough.. when a character is received, the processor is interrupted, the character is read from RXBUF and buffered in a FIFO which the main program reads. TX is the same with the addition of interrupt enable control. When you have characters to send (TX FIFO not empty) you write them to the UART TX register until its full then enable interrupt on TRMT. On each TRMT interrupt, inspect the contents of the TX FIFO, if not empty, write the next character. When you get a TRMT interrupt and there is nothing left in the FIFO to send, switch to receive and let the RX interrupt take over.

    This of course implies some protocol i.e. a rule set that defines how communications are implemented. Its a MUST for half duplex RS-485 i.e. every processor has to know when to listen and when to send.

    I would discourage you from using ad-hoc transmission and delays to wait for receive etc. As you have seen, there are problems. While implementing an interrupt driven transmitter and receiver may seem difficult at first, its way better to just get on with it and do it right. I've never seen any delay-based stuff that works without a lot of trouble. You are seeing this now.

    I have done a lot of RS-485 using several different protocols and would not consider any other implementation than interrupt driven RX/TX FIFO buffers that work autonomously from the main code i.e. to transmit, make the message and dump it into the TX FIFO. Start a timer. If the receive FIFO doesn't get something in return by a certain time take remedial measures (error, re-send etc).

    My .02 - good luck.
  4. MrChips


    Oct 2, 2009
    John makes a good point. I did not scrutinize your code.
    When checking the transmitter status there is a difference between TBE (transmitter buffer empty) and TC (transmission complete). Since you need to control the RS-485 transceiver I would naturally assume that you are making sure that the character has been transmitted before disabling the transmitter.