RS485 Module and STM32

RS485 is one of the most common method of communicating with a device using the modbus protocol. Soon we will start the modbus tutorials, so before that I thought about covering the RS485 itself.

In the tutorial we will see how to interface the RS485 to TTL converter module with STM32. I am going to use the 2 STM32 controllers, F103 and F446, which are connected via these modules, and they will communicate with each other.

Let’s first start by understanding this module.

The RS485 to TTL Converter

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





The Connection

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.

The CubeMX configuration 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 pin PA8 is set as output and I have renamed it to the TX_EN pin.

This is it for the connection, let’s see the code now.



Some Insight into the Code

As I mentioned earlier, I want the MCUs to communicate with each other. We will program the F103 to start this communication, and every message sent by the F103, the F446 will send a response to that message.

Below is 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.
  • 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.


Below is 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.

Check out the Video Below










Info

You can help with the development by DONATING
To download the code, click DOWNLOAD button and view the Ad. The project will download after the Ad is finished.

2 Comments. Leave new

  • 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??

    Reply
    • 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”

      Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

Fill out this field
Fill out this field
Please enter a valid email address.

keyboard_arrow_up

Adblocker detected! Please consider reading this notice.

We've detected that you are using AdBlock Plus or some other adblocking software which is preventing the page from fully loading.

We don't have any banner, Flash, animation, obnoxious sound, or popup ad. We do not implement these annoying types of ads!

We need money to operate the site, and almost all of it comes from our online advertising.

Please add controllerstech.com to your ad blocking whitelist or disable your adblocking software.

×