Reputation: 33
I am trying to read data from a meter using a RS485 to TTL Converter to an STM32f407VG. My device slave ID is 121, the baudrate is 9600. I want to read holdingRegisters
and InputRegisters
.
I am trying this FreeMODBUS RTU port for STM32 HAL library .
I have connected my DI
pin to PA_2(Tx)
, R0
pin to PA_3(Rx)
, DE&RE
pin to GND
. But I am not getting any data.
This is my code:
#include "stm32f4xx_hal.h"
#include "cmsis_os.h"
#include "mb.h"
#include "mbport.h"
#define REG_INPUT_START 30005
#define REG_INPUT_NREGS 8
static USHORT usRegInputStart = REG_INPUT_START;
static USHORT usRegInputBuf[REG_INPUT_NREGS];
void ModbusRTUTask(void const * argument)
{
/* ABCDEF */
usRegInputBuf[0] = 11;
usRegInputBuf[1] = 22;
usRegInputBuf[2] = 33;
usRegInputBuf[3] = 44;
usRegInputBuf[4] = 55;
usRegInputBuf[5] = 66;
usRegInputBuf[6] = 77;
usRegInputBuf[7] = 88;
eMBErrorCode eStatus = eMBInit( MB_RTU, 121, 3, 9600, MB_PAR_NONE );
eStatus = eMBEnable();
while(1) {
eMBPoll();
}
}
eMBErrorCode
eMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs )
{
eMBErrorCode eStatus = MB_ENOERR;
int iRegIndex;
if( ( usAddress >= REG_INPUT_START )
&& ( usAddress + usNRegs <= REG_INPUT_START + REG_INPUT_NREGS ) )
{
iRegIndex = ( int )( usAddress - usRegInputStart );
while( usNRegs > 0 )
{
*pucRegBuffer++ =
( unsigned char )( usRegInputBuf[iRegIndex] >> 8 );
*pucRegBuffer++ =
( unsigned char )( usRegInputBuf[iRegIndex] & 0xFF );
iRegIndex++;
usNRegs--;
}
HAL_GPIO_TogglePin(LD4_GPIO_Port, LD4_Pin);
}
else
{
HAL_GPIO_TogglePin(LD5_GPIO_Port, LD5_Pin);
eStatus = MB_ENOREG;
}
return eStatus;
}
eMBErrorCode
eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs,
eMBRegisterMode eMode )
{
return MB_ENOREG;
}
eMBErrorCode
eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNCoils,
eMBRegisterMode eMode )
{
return MB_ENOREG;
}
eMBErrorCode
eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT
usNDiscrete)
{
return MB_ENOREG;
}
Why these variables ?
usRegInputBuf[0] = 11;
usRegInputBuf[1] = 22;
usRegInputBuf[2] = 33;
usRegInputBuf[3] = 44;
usRegInputBuf[4] = 55;
usRegInputBuf[5] = 66;
usRegInputBuf[6] = 77;
usRegInputBuf[7] = 88;
What changes do I need to make?
Upvotes: 2
Views: 14051
Reputation: 165
@kamilcuk is close, but on all RS485 transceivers, the DE is active high and the RE is active low. Tying DE and RE low will create a universal receiver that cannot send.
The simplest "half-duplex" RS485 is to connect RE and DE to a single GPIO pin. Drive this signal HIGH (GPIO_PIN_SET in HAL lingo) to transmit and set the signal LOW (GPIO_PIN_RESET in HAL lingo) to receive.
If you have RE and DE attached to different GPIO pins, that's okay, just set them to the same value at the same time. I use a couple of macros to do this, so I don't have to always think about the logic.
Then just name the pins accordingly in the CubeMX editor.
// RS485_DE Data Enable, Active High
// RS485_RE Receive En, Active Low
#define ENABLE_TRANSMIT() do { \
/* Disable Receiver */ \
HAL_GPIO_WritePin(RS485_RE_GPIO_Port, RS485_RE_Pin, GPIO_PIN_SET); \
/* Enable Transmitter */ \
HAL_GPIO_WritePin(RS485_DE_GPIO_Port, RS485_DE_Pin, GPIO_PIN_SET); \
} while(0)
#define ENABLE_RECEIVE() do { \
/* Enable Receiver */ \
HAL_GPIO_WritePin(RS485_RE_GPIO_Port, RS485_RE_Pin, GPIO_PIN_RESET); \
/* Disable Transmitter */ \
HAL_GPIO_WritePin(RS485_DE_GPIO_Port, RS485_DE_Pin, GPIO_PIN_RESET); \
} while(0)
Upvotes: 1
Reputation: 141000
DE&RE pin to GND
DE and RE pins are used to enable and disable input and output from the converted. You should:
Before sending each character through rs485, you need to set DE=1, RE=0, then write the character, then change back to receive mode and then receive the data.
Inspect the datasheet of the transceiver very carefully. If you use, ex. MAX485 (but really, their're all the same usuallly), you see at page 7:
More about three state logic can be found ex. on wiki.
With RE set to GND the gates will never open, so you will have always high impedance on RO pin and never receive any data. Other way round, you will never send any data, because DE will be low, and I believe you need to send smth to the meter before it starts transmitting.
You should connect uart TX to DI, uart RX to RO. In your case and if the converter inverts one of the RE/DE pins (usually RE is inverted, as above) you can connect both to the same pin.
Upvotes: 3
Reputation: 16
The Github code is messy, i would suggest you to follow the UART communication procedure mentioned here
Upvotes: 0