Program over RS485 insted of RS232

Thread Starter

Kittu20

Joined Oct 12, 2022
431
Hello Everyone

I can write a UART program that works over an RS232 interface. I'm not experienced with RS485, but I have a doubt. If I change the interface from RS232 to RS485, would I also need to modify the program or same program would work on RS485?

This is the UART program that I have copied from my old thread.

C:
/*
* File:   main.c
* Author: kittu
* Created on 14 September, 2023, 8:35 AM
*PIC18F45K80
*/

#include <xc.h>
#include <stdio.h>
#include"config.h"


void initializeOscillator(void);
void initializeEUSART1(void);

/*****
*   NOTE:    This function configures the oscillator settings for the microcontroller.
*            It sets the IRCF bits to 110 for HF-INTOSC/2 (8 MHz, default).
*****/
void initializeOscillator(void)
{
    OSCCON  = 0x60;     // Set IRCF bits to 110 for HF-INTOSC/2 (8 MHz, default)
    OSCCON2 = 0x00;
    OSCTUNE = 0x00;
    REFOCON = 0x00;
}


void initializePort() {
    // Set LATx registers to initial states (all low)
    LATA = 0x00;
    LATB = 0x00;
    LATC = 0x00;
    LATD = 0x00;
    LATE = 0x00;


    // Set TRISx registers to configure pins as outputs (all output)
    TRISA = 0x00; 
    TRISB = 0x00;     // RB0 is RED, RB1 is YELLOW and RB2 is GREEN LED
    TRISC = 0x80;     // RC7 is TX and RC6 TX
    TRISD = 0x00; 
    TRISE = 0x00; 

    // Additional configuration for unused peripherals
    ANCON0 = 0x00;     // Set all analog pins to digital mode
    ANCON1 = 0x00;     // Set all analog pins to digital mode
    CM1CON = 0x00;     // Turn off Comparator 1
    CM2CON = 0x00;     // Turn off Comparator 2
    ADCON0 = 0x00;     // Disable A/D conversion
    ADCON1 = 0x00;     // Disable A/D conversion
    ADCON2 = 0x00;     // Disable A/D conversion
}

/*****
*
*   NOTE:    This function configures the EUSART1 settings for communication.
*
*****/
void initializeUART1() {

    // Configure BAUDCON1 register
    // Bit 7: ABDOVF = 0 (Auto-Baud Acquisition Rollover Status bit - Cleared in software)
    // Bit 6: RCIDL = 0 (Receive Operation Idle Status bit - Receive operation is active)
    // Bit 5: RXDTP = 0 (Received Data Polarity Select bit - Receive data is not inverted)
    // Bit 4: TXCKP = 0 (Clock and Data Polarity Select bit - Idle state for transmit is high level)
    // Bit 3: BRG16 = 1 (16-Bit Baud Rate Register Enable bit - 16-bit Baud Rate Generator)
    // Bit 2: Unimplemented: Read as ?0? (Reserved, read as '0')
    // Bit 1: WUE = 0 (Wake-up Enable bit - RX pin is not monitored or rising edge is detected)
    // Bit 0: ABDEN = 0 (Auto-Baud Detect Enable bit - Baud rate measurement is disabled or completed)

    BAUDCON1 = 0b00001000; // Set BRG16 bit to 1 (16-Bit Baud Rate Register Enable)

    // Calculate and set SPBRG1 for a baud rate of approximately 9600 at 8 MHz
    SPBRG1 = 207;
    SPBRGH1 = 0;


    // TXSTA1 register configuration
    // Bit 7: CSRC = 0 (Clock Source Select bit - Don't care in Asynchronous mode)
    // Bit 6: TX9 = 0 (8-bit transmission)
    // Bit 5: TXEN = 1 (Transmit is enabled)
    // Bit 4: SYNC = 0 (Asynchronous mode)
    // Bit 3: SENDB = 0
    // Bit 2: BRGH = 1 (High-speed baud rate)
    // Bit 1: TRMT = 1 (TSR is empty initially)

    TXSTA1 = 0b00100100; // Configure TXSTA1 register


    // RCSTA1 register configuration
    // Bit 7: SPEN = 1 (Serial Port Enable bit - Serial port is enabled)
    // Bit 6: RX9 = 0 (8-bit reception)
    // Bit 5: SREN = 0 (Single Receive Enable bit - Don't care in Asynchronous mode)
    // Bit 4: CREN = 1 (Continuous Receive Enable bit - Enables receiver)
    // Bit 3: ADDEN = 0 (Address Detect Enable bit - Don't care in Asynchronous mode)
    // Bit 2: FERR = 0 (Framing Error bit - No framing error)
    // Bit 1: OERR = 0 (Overrun Error bit - No overrun error)

     RCSTA1 = 0b10010000; // Configure RCSTA1 register

}


void hardwareInitialize() {

    // Initialize the oscillator
    initializeOscillator();

    // Initialize Port Pins
    initializePort();

    // Initialize Uart1
    initializeUART1();

}

/*****
*
*   NOTE:    This function waits until the transmitter buffer is empty (TXIF is set)
*            and then sends the character by placing it in the TXREG1 register.
*
*****/
void UARTWrite(char Character)
{
    // Wait until the transmitter buffer is empty (TXIF is set)
    while (TXIF == 0);

    // Send the character by placing it in the TXREG1 register
    TXREG1 = Character;
}


/*****
*
*   NOTE:    This function waits until the receiver buffer is full (RCIF is set)
*            and then reads the received character from the RCREG1 register.
*
*****/
char UARTRead(void)
{
    // Wait until the receiver buffer is full (RCIF is set)
    while (RCIF == 0);

    // Read the received character from the RCREG1 register
    return RCREG1;
}

/*****
*
*  main - Main program function
*
*****/
void main(void)
{
    // Initialize hardware
    hardwareInitialize();

    // Delay for 5 seconds
    __delay_ms(5000);

    while (1)
    {
        // Define a character to send
        char Character = 'U';
        char ReceivedChar;
    
        ReceivedChar = UARTRead();         // Read a command from UART
  
        UARTWrite(ReceivedChar);           // Send the command back

        // Delay for 5 seconds before the next transmission
        __delay_ms(5000);
    }
}
Thanks in advance for your suggestions
 
Last edited:

Ian0

Joined Aug 7, 2020
9,503
That depends.. .
RS232 sends information only one way down a piece of wire.
If that's all you want from RS485, then no change to the software.
But RS485 can be bi-directional, but if you want to do that, you'll need to add things like collision detection/avoidance.
 

Papabravo

Joined Feb 24, 2006
21,003
If your RS-485 interface is a 4-wire interface so that you can transmit and receive simultaneously then it is possible, but some small tweaks will be required. If the interface is a 2-wire interface so that simultaneous receive and transmit is not possible then you will have to do a major overhaul to handle half-duplex communications. This will not be a trivial undertaking.
 

nsaspook

Joined Aug 27, 2009
12,796
Here is the link for RS485 converter https://www.electronicscomp.com/max...JAfahaM5UiSDggxORqEegLc2A_moWdBBoCi_kQAvD_BwE

I'd appreciate any suggestions you can provide regarding this RS485
A simple half-duplex model that will require software GPIO bit-banging for DE send/receive switching and maybe for RE if you want to software select echo.

My normal testing interface module is this one.

1698445424564.png
1698445404299.png

or this one.
1698445623451.png
https://www.mouser.com/datasheet/2/638/BB_485CON_1921ds20210512232541-2821418.pdf
1698461851435.png

https://forum.allaboutcircuits.com/...c-controlled-battery-array.32879/post-1483807
1698445721565.png

C:
#if HAVE_DECL_TIOCSRS485 || HAVE_DECL_TIOCM_RTS
#include <sys/ioctl.h>
#define FAST_RTS_DELAY 5000
#endif
// ...
#if HAVE_DECL_TIOCM_RTS
    modbus_rtu_t *ctx_rtu = ctx->backend_data;
    if (ctx_rtu->rts != MODBUS_RTU_RTS_NONE) {
        ssize_t size;
        if (ctx->debug) {
            fprintf(stderr, "Sending request using RTS signal\n");
        }
        _modbus_rtu_ioctl_rts(ctx->s, ctx_rtu->rts == MODBUS_RTU_RTS_UP);
        usleep(FAST_RTS_DELAY);
        size = write(ctx->s, req, req_length);
        usleep(ctx_rtu->onebyte_time * req_length + FAST_RTS_DELAY);
        _modbus_rtu_ioctl_rts(ctx->s, ctx_rtu->rts != MODBUS_RTU_RTS_UP);
        return size;
    } else {
#endif

#if HAVE_DECL_TIOCM_RTS
static void _modbus_rtu_ioctl_rts(int fd, int on)
{
    //int flags;
    int RTS_flag;

    RTS_flag = TIOCM_RTS;
    if (on) {
        ioctl(fd,TIOCMBIS,&RTS_flag);//Set RTS pin
    } else {
        ioctl(fd,TIOCMBIC,&RTS_flag);//Clear RTS pin
    }
}
#endif
Some Linux C code that uses the RS485 half-duplex switching mode API (RTS pin for DE)
 
Last edited:

Thread Starter

Kittu20

Joined Oct 12, 2022
431
My understanding is that full duplex means we can transmit and receive bytes at the same time. RS232 module operates in full duplex mode, but with programming, we can't send and receive bytes simultaneously. Half duplex means we can either send or receive one byte at a time, and RS485 operates in half duplex mode.
 

nsaspook

Joined Aug 27, 2009
12,796
My understanding is that full duplex means we can transmit and receive bytes at the same time. RS232 module operates in full duplex mode, but with programming, we can't send and receive bytes simultaneously. Half duplex means we can either send or receive one byte at a time, and RS485 operates in half duplex mode.
RS485 standards only specify the electrical requirements. It can be full-duplex for a point-to-point solution or half-duplex for a more common multi-drop solution.
1698462819644.png
 

nsaspook

Joined Aug 27, 2009
12,796
A PIC18 Q84 example circuit and section of software for half-duplex operation.
1698463704097.png
The RS485 tranceiver IC3 has DE and RE_ (notice the active low for the receiver enable vs active high for the transmit enable) connected for single line half-duplex control from a GPIO pin.
1698464003289.png
DERE pin 36 RC2 on the controller.

The software has a couple of routines that can use that DERE signal for TX or RX mode of operation.
C:
// switch RS transceiver to transmit mode and wait if not tx

static void half_dup_tx(const bool delay) {
    if (DERE_GetValue()) {
        return;
    }
    DERE_SetHigh(); // enable modbus transmitter

    if (delay) {
        delay_ms(DUPL_DELAY); // busy waits
    }
}

// switch RS transceiver to receive mode and wait if not rx

static void half_dup_rx(const bool delay) {
    if (!DERE_GetValue()) {
        return;
    }
    if (delay) {
        delay_ms(DUPL_DELAY); // busy waits
    }
    DERE_SetLow(); // enable modbus receiver
}
 

Thread Starter

Kittu20

Joined Oct 12, 2022
431
RS485 standards only specify the electrical requirements. It can be full-duplex for a point-to-point solution or half-duplex for a more common multi-drop solution.
I've reviewed your code, but I don't fully understand it. My program currently can send and receive bytes over RS232.

What changes are required if I want to do the same over an RS-485 interface, which is a 4-wire interface?
 

Thread Starter

Kittu20

Joined Oct 12, 2022
431
If you implement a 4-wire RS-485 interface between two systems then the original RS-232 UART program should work.
Thanks for the confirmation. My general understanding was that RS-485 communication is no different from serial UART communication.
 
Top