RS485 Communication using STM32
Learn how to interface the RS485 module (MAX485) with STM32 using UART. This tutorial covers UART communication, DE/RE pin control, and sending data between STM32 boards with clear code examples. The project is available for download at the end of the post.

Recommended Resources:
The RS485 communication is performed using the UART peripheral of STM32. I have already covered a series on the UART peripheral and you must check out the related tutorials before continuing here.
In this tutorial, we will demonstrate how to interface the RS485 to TTL converter module with an STM32 microcontroller. Two STM32 boards—specifically the STM32F103 and STM32F446—will be used for this setup. These boards will communicate with each other through the RS485 modules, showcasing a practical implementation of half-duplex serial communication.
VIDEO TUTORIAL
You can check the video to see the complete explanation and working of this project.
Check out the Video Below
Introducing The RS485 to TTL Converter
An RS485 to TTL converter is a communication interface module that allows microcontrollers, like STM32, to communicate over long distances using the RS485 protocol. It converts the differential RS485 signals into standard TTL-level serial data, which can be read by UART peripherals on microcontrollers. RS485 is known for its robustness, noise immunity, and ability to support multiple devices on the same bus, making this converter ideal for industrial and embedded systems applications.
These modules often use the MAX485 transceiver chip, which supports half-duplex communication and is capable of driving long cable lengths with high reliability.
Important Features of RS485 to TTL Converter:
- Differential Signaling for Long-Distance Communication: It uses differential signal transmission, which reduces noise and allows data to be transmitted over distances of up to 1200 meters.
- Multi-Device Bus Support: RS485 supports up to 32 devices on the same communication line, enabling multi-node communication in a single network.
- Wide Voltage Compatibility: Operates on a 5V power supply and provides TTL-level output compatible with 3.3V or 5V microcontrollers.
- Driver/Receiver Enable Pins (DE/RE): The DE and RE pins allow precise control of data direction, essential for implementing half-duplex communication between devices.
The signal level used during the RS485 communication method typically ranges from -7V to +12V. The microcontroller pins are generally not designed to handle these levels. This is why these signals needs to be converted to low voltages, for eg ±3V. The module have the MAX485 chip on it, which does most of the job of conversion.
The pinout of the module is shown below
On the left side of the module, the RO pin connects to the RX pin of the UART, and the DI pin connects to the TX pin.
The RE and DE Pins are responsible for setting the module in Receiver or Transmitter mode.
- When the RE pin is LOW and DE pin is LOW, the Module is set in the Receiver mode.
- When the DE pin is HIGH and RE pin is HIGH, the Module is set in the Transmitter mode.
The Pin A and the Pin B are the output pins which carries the transmission signal.
Let’s take an example where we provide the data, 0x95 (10010101) to the module. If the Module is powered with 5V, the output on pins A and B will be as shown below
- Since A is the non-inverting pin, it’s output will be in sync to the input. It varies between 0 to +5V
- B is the inverting pin, so the output is inverted and varies between -5V to 0
- When the second module receives these as inputs, it decode the data based on the voltage differences.
- If the voltage difference is maximum, the bit is 1, and if the difference is 0 the bit is 0
- This data is then converted to lower voltages (0 to 3V) to suit the MCU requirement
WIRING DIAGRAM
Below is the connection diagram of the module with the STM32F103C8 controller. The connection will remain same with the F446 also, so I am just showing one of them here.
As shown above, The RO pin is connected to the PA10 (UART1 RX) and DI pin is connected to the PA9 (UART1 TX).
The RE and DE are connected together with the pin PA8, which we have set as the output in the MCU.
CubeMX CONFIGURATION
The UART configuration in the CubeMX is shown below
The UART1 is configured to it’s default setup with the baud rate of 115200 and 8-N-1. Also I have enabled the interrupt to receive the data from the second controller.
The Pins used for this project are shown below.
The pin PA8 is set as output and I have renamed it to the TX_EN pin.
THE CODE
As previously mentioned, the goal is to establish communication between the two microcontrollers. The STM32F103 will initiate the communication by transmitting a message, and upon receiving this message, the STM32F446 will respond accordingly. This setup demonstrates a simple request-response mechanism using RS485.
The code for the F103
uint8_t TxData[16];
uint8_t RxData[16];
int indx = 0;
int main ()
{
HAL_UARTEx_ReceiveToIdle_IT(&huart1, RxData, 16);
while (1)
{
sprintf(TxData, "F103 %d", indx++);
sendData (TxData);
HAL_Delay(1000);
}
}
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
HAL_UARTEx_ReceiveToIdle_IT(&huart1, RxData, 16);
}
- Here in the main function we will first set the UART to receive the data.
- The function
ReceiveToIdle_IT
will receive the incoming data and store in the RxData buffer, until the Idle line is detected. - Once the RX pin is idle for some time, it will trigger the interrupt, which will eventually call the
RxEventCallbak
. - Inside this callback we will simply enable the receive to idle interrupt. This is because the HAL disables the interrupt after each call, so we need to enable it again after each time the interrupt is triggered.
- The function
- In the while loop we will update the string we want to send, with the incremented value of the indx variable.
- And we will keep sending this updated string every 1 second.
The sendData function used above is shown below
void sendData (uint8_t *data)
{
// Pull DE high to enable TX operation
HAL_GPIO_WritePin(TX_EN_GPIO_Port, TX_EN_Pin, GPIO_PIN_SET);
HAL_UART_Transmit(&huart1, data, strlen (data) , 1000);
// Pull RE Low to enable RX operation
HAL_GPIO_WritePin(TX_EN_GPIO_Port, TX_EN_Pin, GPIO_PIN_RESET);
}
- Before transmitting the data we need to put the RS485 module in the transmitter mode.
- To do this we have to pull the DE (Driver enable) pin as HIGH.
- Then we will send the data using the
HAL_UART_Transmit
Function. - Once the data is transmitted, we will enable the receiver mode by pulling the RE (Receive Enable) Pin LOW.
Remember that DE and RE are connected to the same pin (PA8, TX_EN), so we can use the same pin to set the module in transmitter or receiver mode.
Since the time of the incoming data is unknown, the module is always kept in the receive mode. Just before we want to send the data, we put it in the transmitter mode, and then put it back to receive mode again.
The transmitted data will be received by the F446 and it will send a response.
The code for the F446
Once the F446 receives the data, the RxEventCallback will be called, and we will write our code inside it.
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
RxData[0] = 'F';
RxData[1] = '4';
RxData[2] = '4';
RxData[3] = '6';
sendData(RxData);
HAL_UARTEx_ReceiveToIdle_IT(&huart1, RxData, 64);
// memset (RxData, '\0',64);
}
Here we will replace the first 4 bytes (‘F’ ‘1’ ‘0’ ‘3’) with the ‘F’ ‘4’ ‘4’ ‘6’ and send the data back to the first controller.
This is just a response and this way we would get an idea that the data is coming from the F446 itself.
The rest of the code is similar to that we saw for the F103.
RESULT
Below are the images of the TxData and RxData buffers of the F103 controller.
As you can see the data transmitted and data received by the F103 are pretty much the same except the first few bytes.
So we transmitted “F103 46” from the F103 controller. This was received by the F446 and it changes the first few bytes and transmitted “F446 46” back to the F103 controller.
PROJECT DOWNLOAD
Info
You can help with the development by DONATING Below.
To download the project, click the DOWNLOAD button.
You May Also Like
🙏 Support Us by Disabling Adblock
We rely on ad revenue to keep Controllerstech free and regularly updated. If you enjoy the content and find it helpful, please consider whitelisting our website in your ad blocker.
We promise to keep ads minimal and non-intrusive.
Thank you for your support! 💙
Hello,
I am facing a issue that I could not receive proper data or continious data at both end.
Check for the baud rate. If the garbage data is received, it is because of the baud rate. Also make sure the clock configuration is correct as per your MCU.
I don’t understand what you mean continuous data is not being received.
Hi, I’m using STM32H750VB, I can’t find the instruction “HAL_UARTEx-ReceiveToIdle_IT()” in this family and I have error in my code.
Can I use “HAL_UART_Receive_IT()” instead of it??
It is available across all STM32 families. Make sure you have enabled the uart in the cubeMX. Also check if you are writing the function properly. It is not “HAL_UARTEx-ReceiveToIdle_IT()”, but “HAL_UARTEx_ReceiveToIdle_IT”