STM32F4接口与RS485
STM32F4 interface with RS485
我正在尝试使用 RS485 到 TTL 转换器从仪表读取数据到 STM32f407VG。我的设备slave ID是121,波特率是9600。我想读取holdingRegisters
和InputRegisters
。
我正在尝试这个 FreeMODBUS RTU port for STM32 HAL library 。
我已将 DI
引脚连接到 PA_2(Tx)
,R0
引脚连接到 PA_3(Rx)
,DE&RE
引脚连接到 GND
。但是我没有得到任何数据。
这是我的代码:
#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;
}
为什么会有这些变量?
usRegInputBuf[0] = 11;
usRegInputBuf[1] = 22;
usRegInputBuf[2] = 33;
usRegInputBuf[3] = 44;
usRegInputBuf[4] = 55;
usRegInputBuf[5] = 66;
usRegInputBuf[6] = 77;
usRegInputBuf[7] = 88;
我需要做哪些改变?
Github代码比较乱,建议按照UART通信步骤here
- 首先使用串行终端检查您是否能够使用 UART 与 stm32f4x 板进行通信。
- 使用 modbus 通信协议来实现您的寄存器读取逻辑。
DE&RE pin to GND
DE 和 RE 引脚用于启用和禁用转换后的输入和输出。你应该:
- 发送时设置DE=1,RE=0
- 接收时设置DE=0,RE=1
- (extra) 在不使用设备时设置DE=0和RE=0(这取决于收发器,但通常都设置为低可以节省很多能量)
在通过rs485发送每个字符之前,需要设置DE=1,RE=0,然后写入字符,然后改回接收模式,然后接收数据。
仔细检查收发器的数据表。如果你使用,例如。 MAX485(但实际上,它们通常都是一样的),您在第 7 页看到:
有关三态逻辑的更多信息,请参见 ex。在 wiki.
将 RE 设置为 GND 时,门将永远不会打开,因此您将始终处于高阻抗状态
在 RO 引脚上,从不接收任何数据。反过来,你永远不会发送任何数据,因为 DE 会很低,我相信你需要在开始传输之前向仪表发送 smth。
串口TX接DI,串口RX接RO。在您的情况下,如果转换器反转 RE/DE 引脚之一(通常 RE 反转,如上所述),您可以将两者连接到同一引脚。
@kamilcuk 很接近,但是在所有的RS485收发器上,DE是高电平有效,RE是低电平有效。将 DE 和 RE 拉低将创建一个无法发送的通用接收器。
最简单的"half-duplex"RS485就是将RE和DE连接到一个GPIO引脚上。将此信号驱动为高电平(HAL 术语中的GPIO_PIN_SET)以发送并将信号设置为低电平(HAL 术语中的GPIO_PIN_RESET)以接收。
如果你将RE和DE连接到不同的GPIO引脚,没关系,只需同时将它们设置为相同的值即可。我使用了几个宏来执行此操作,因此我不必总是考虑逻辑。
然后在 CubeMX 编辑器中相应地命名引脚。
// 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)
我正在尝试使用 RS485 到 TTL 转换器从仪表读取数据到 STM32f407VG。我的设备slave ID是121,波特率是9600。我想读取holdingRegisters
和InputRegisters
。
我正在尝试这个 FreeMODBUS RTU port for STM32 HAL library 。
我已将 DI
引脚连接到 PA_2(Tx)
,R0
引脚连接到 PA_3(Rx)
,DE&RE
引脚连接到 GND
。但是我没有得到任何数据。
这是我的代码:
#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;
}
为什么会有这些变量?
usRegInputBuf[0] = 11;
usRegInputBuf[1] = 22;
usRegInputBuf[2] = 33;
usRegInputBuf[3] = 44;
usRegInputBuf[4] = 55;
usRegInputBuf[5] = 66;
usRegInputBuf[6] = 77;
usRegInputBuf[7] = 88;
我需要做哪些改变?
Github代码比较乱,建议按照UART通信步骤here
- 首先使用串行终端检查您是否能够使用 UART 与 stm32f4x 板进行通信。
- 使用 modbus 通信协议来实现您的寄存器读取逻辑。
DE&RE pin to GND
DE 和 RE 引脚用于启用和禁用转换后的输入和输出。你应该:
- 发送时设置DE=1,RE=0
- 接收时设置DE=0,RE=1
- (extra) 在不使用设备时设置DE=0和RE=0(这取决于收发器,但通常都设置为低可以节省很多能量)
在通过rs485发送每个字符之前,需要设置DE=1,RE=0,然后写入字符,然后改回接收模式,然后接收数据。
仔细检查收发器的数据表。如果你使用,例如。 MAX485(但实际上,它们通常都是一样的),您在第 7 页看到:
有关三态逻辑的更多信息,请参见 ex。在 wiki.
将 RE 设置为 GND 时,门将永远不会打开,因此您将始终处于高阻抗状态 在 RO 引脚上,从不接收任何数据。反过来,你永远不会发送任何数据,因为 DE 会很低,我相信你需要在开始传输之前向仪表发送 smth。
串口TX接DI,串口RX接RO。在您的情况下,如果转换器反转 RE/DE 引脚之一(通常 RE 反转,如上所述),您可以将两者连接到同一引脚。
@kamilcuk 很接近,但是在所有的RS485收发器上,DE是高电平有效,RE是低电平有效。将 DE 和 RE 拉低将创建一个无法发送的通用接收器。
最简单的"half-duplex"RS485就是将RE和DE连接到一个GPIO引脚上。将此信号驱动为高电平(HAL 术语中的GPIO_PIN_SET)以发送并将信号设置为低电平(HAL 术语中的GPIO_PIN_RESET)以接收。
如果你将RE和DE连接到不同的GPIO引脚,没关系,只需同时将它们设置为相同的值即可。我使用了几个宏来执行此操作,因此我不必总是考虑逻辑。
然后在 CubeMX 编辑器中相应地命名引脚。
// 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)