目录
1、选择STM32F407ZET7芯片创建工程,首先配置RCC、SYS和时钟,配置界面如下(根据自己情况配置就好)
2、配置ETH,参数默认即可,配置界面如下(我的的引脚有调整,是根据实际电路调整的,大家根据自己情况调整即可)
5、到此CubeMX就配置完成可以生成代码了(根据自己用的软件改一下设置即可)
①在工程文件目录下新建一个 FreeModbus_TCP 文件夹,将需要的文件都移植到该文件夹下
②打开 freemodbus-v1.6 文件夹,点击 modbus 文件夹,将modbus 文件夹中的全部文件移植到新建的 FreeModbus_TCP 文件夹中
③将freemodbus-v1.6\demo\STR71XTCP中的 port 文件,移植到新建的 FreeModbus_TCP 文件夹中
④新建的 FreeModbus_TCP 文件夹内容移植最终结果如下:下面的两个文件目前还没有!!
①打开modbus poll 在connection选connect连接或按F3
②点击"Setup"→“Read/Write Definition…”,或者按快捷键F8设置从机地址,功能码,起始地址,寄存器数量等信息
前言
本次实验以 STM32F407ZET7 芯片为MCU,使用 8MHz 外部时钟源。以太网PHY层芯片为 LAN8720A,移植FreeModbus实现ModbusTCP网口通信,做客户端(从机)实现网口TCP-Modbus通信。
另:本人首次使用,也是结合网上多个大佬的经验做的,有不足的地方请大家指正,内容比较详细,对像我一样的新手比较友好,如果觉得过细可跳着看!!!
一、STM32Cubemx配置
1、选择STM32F407ZET7芯片创建工程,首先配置RCC、SYS和时钟,配置界面如下(根据自己情况配置就好)
2、配置ETH,参数默认即可,配置界面如下(我的的引脚有调整,是根据实际电路调整的,大家根据自己情况调整即可)
我配置了一个GPIO_Output作为复位引脚,(低电平复位、默认为高电平)
3、配LWIP,我使用的静态IP,配置界面如下
选LAN8742就可以
4、配置串口,有需要的话方便看数据,配置界面如下
5、到此CubeMX就配置完成可以生成代码了(根据自己用的软件改一下设置即可)
二、修改程序、移植FreeModbus源码
1、先复位一下芯片(不写也没啥问题)
到目前为止,已经初始化完成了,在cmd中可以ping通!!!!!!
到此之前的例程:有需要的自己下载幺,不需要积分的!!!
(设备IP为:192.168.1.10 电脑IP为:192.168.1.200 子网掩码:255.255.255.0 默认网关:192.168.1.1 注意:复位引脚我默认放在了低电平(一直复位状态),根据自己需要将复位引脚电平拉高或者配置一下Cubemx默认放在高电平即可)
2.FreeModbus源码下载
下载链接放在下面了,自己下载就可以了!
FreeModbus源码下载链接https://www.embedded-experts.at/en/freemodbus-downloads/
3.移植FreeModbus源码
①在工程文件目录下新建一个 FreeModbus_TCP 文件夹,将需要的文件都移植到该文件夹下
②打开 freemodbus-v1.6 文件夹,点击 modbus 文件夹,将modbus 文件夹中的全部文件移植到新建的 FreeModbus_TCP 文件夹中
③将freemodbus-v1.6\demo\STR71XTCP中的 port 文件,移植到新建的 FreeModbus_TCP 文件夹中
④新建的 FreeModbus_TCP 文件夹内容移植最终结果如下:下面的两个文件目前还没有!!
⑤导入到工程中
将FreeModbus_TCP 文件夹中的文件导入
选择FreeModbus_TCP 文件夹中的mb.c文件
选择FreeModbus_TCP 文件夹中的 functions 文件夹、 port 文件夹、tcp 文件夹的全部.c文件
结果如下图所示(目前最后一个文件还没有!)
⑥点击魔法棒,选择 C/C++,添加文件路径
三、编辑程序
①
②
③找不到这个文件在哪的可以在mb.c的头文件中跳转打开!!后面找不到的也一样!
④修改 portevent.c将以下程序,替换原来的程序
/* ----------------------- Modbus includes ----------------------------------*/
#include "mb.h"
#include "mbport.h"
/* ----------------------- Variables ----------------------------------------*/
static eMBEventType eQueuedEvent;
static BOOL xEventInQueue;
/* ----------------------- Start implementation -----------------------------*/
BOOL
xMBPortEventInit( void )
{
xEventInQueue = FALSE;
return TRUE;
}
BOOL
xMBPortEventPost( eMBEventType eEvent )
{
xEventInQueue = TRUE;
eQueuedEvent = eEvent;
return TRUE;
}
BOOL
xMBPortEventGet( eMBEventType * eEvent )
{
BOOL xEventHappened = FALSE;
if( xEventInQueue )
{
*eEvent = eQueuedEvent;
xEventInQueue = FALSE;
xEventHappened = TRUE;
}
return xEventHappened;
}
⑤添加 #include “string.h” 和 #define NETCONN_COPY 0x01
⑥新建User_modbus_TCP.c文件
#include <stdio.h>
#include <string.h>
#include "User_modbus_TCP.h"
#include "mb.h"
#include "mbutils.h"
void ModbusTCPInit(void)
{
eMBTCPInit(MODBUS_TCP_PORT);
eMBEnable();
}
void ModbusTCPDeInit(void)
{
eMBDisable();
eMBClose();
}
void ModbusTCPMain(void)
{
if (MB_ENOERR != eMBPoll())
{
ModbusTCPDeInit();
ModbusTCPInit();
}
}
//线圈
#define REG_Coils_START 1
#define REG_Coils_SIZE 10
uint8_t Coils_Data[REG_Coils_SIZE] = {1,1,0,1,0,0,1,1,1,0};
/**
* @brief: 读线圈---01,写线圈---05
*
* @param pucRegBuffer 缓存指针
* @param usAddress 起始地址
* @param usNCoils 线圈数量
* @param eMode 读写模式
* @return eMBErrorCode 错误码
*/
eMBErrorCode eMBRegCoilsCB(UCHAR *pucRegBuffer, USHORT usAddress, USHORT usNCoils, eMBRegisterMode eMode)
{
uint16_t i = 0,byteOffset=0,bitOffset=0,RegIndex = usAddress - REG_Coils_START-1;
if ((usAddress >= REG_Coils_START)&&(usAddress + usNCoils <= REG_Coils_START + REG_Coils_SIZE+1))
{
if (MB_REG_READ == eMode)
{
for(i=0;i<usNCoils;i++)
{
byteOffset = i / 8;
bitOffset = i % 8;
xMBUtilSetBits(&pucRegBuffer[byteOffset], bitOffset, 1, Coils_Data[RegIndex+i]);
}
}
else
{
for(i=0;i<usNCoils;i++)
{
byteOffset = i / 8;
bitOffset = i % 8;
Coils_Data[RegIndex+i]=xMBUtilGetBits(&pucRegBuffer[byteOffset], bitOffset, 1);
}
}
}
else
{
return MB_ENOREG;
}
return MB_ENOERR;
}
//离散寄存器
#define REG_DISCRETE_START 10
#define REG_DISCRETE_SIZE 20
uint8_t Discrete_Data[REG_DISCRETE_SIZE] = {1,1,0,1,0,0,1,1,1,0,1,0,0,1};
/**
* @brief:读离散寄存器---02
*
* @param pucRegBuffer 缓存指针
* @param usAddress 起始地址
* @param usNDiscrete 寄存器个数
* @return eMBErrorCode 返回错误码
*/
eMBErrorCode eMBRegDiscreteCB(UCHAR *pucRegBuffer, USHORT usAddress, USHORT usNDiscrete)
{
uint16_t i = 0,byteOffset=0,bitOffset=0,RegIndex = usAddress - REG_DISCRETE_START-1;
if ((usAddress >= REG_DISCRETE_START)&&(usAddress + usNDiscrete <= REG_DISCRETE_START + REG_DISCRETE_SIZE+1))
{
for(i=0;i<usNDiscrete;i++)
{
byteOffset = i / 8;
bitOffset = i % 8;
xMBUtilSetBits(&pucRegBuffer[byteOffset], bitOffset, 1, Discrete_Data[RegIndex+i]);
}
}
else
{
return MB_ENOREG;
}
return MB_ENOERR;
}
//保持寄存器
#define REG_HOLDING_REGISTER_START 10
#define REG_HOLDING_REGISTER_SIZE 30
uint16_t Holding_Data[REG_HOLDING_REGISTER_SIZE] =
{0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x10,0x11,0x12};
/**
* @brief: 读保持寄存器---03,写保持寄存器---06
*
* @param pucRegBuffer 缓存指针
* @param usAddress 起始地址
* @param usNRegs 寄存器个数
* @param eMode 读写模式
* @return eMBErrorCode 返回错误码
*/
eMBErrorCode eMBRegHoldingCB(UCHAR *pucRegBuffer, USHORT usAddress, USHORT usNRegs, eMBRegisterMode eMode)
{
uint16_t i = 0,RegIndex = usAddress - REG_HOLDING_REGISTER_START-1;
if ((usAddress >= REG_HOLDING_REGISTER_START )&&(usAddress + usNRegs <= REG_HOLDING_REGISTER_START + REG_HOLDING_REGISTER_SIZE+1))
{
if (MB_REG_READ == eMode)//读
{
for(i=0;i<usNRegs;i++)
{
pucRegBuffer[i*2] = (UCHAR)(Holding_Data[RegIndex+i]>>8);
pucRegBuffer[i*2+1] = (UCHAR)Holding_Data[RegIndex+i];
}
}
else//写
{
for(i=0;i<usNRegs;i++)
{
Holding_Data[RegIndex+i]=(pucRegBuffer[i*2]<<8)|(pucRegBuffer[i*2+1]);
}
}
}
else
{
return MB_ENOREG;
}
return MB_ENOERR;
}
//输入寄存器
#define REG_INPUT_REGISTER_START 1
#define REG_INPUT_REGISTER_SIZE 20
uint16_t Input_Data[REG_DISCRETE_SIZE] =
{100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119};
/**
* @brief: 读输入寄存器---04
*
* @param pucRegBuffer 缓存指针
* @param usAddress 起始地址
* @param usNRegs 寄存器个数
* @return eMBErrorCode 返回错误码
*/
eMBErrorCode eMBRegInputCB(UCHAR *pucRegBuffer, USHORT usAddress, USHORT usNRegs)
{
uint16_t i = 0,RegIndex = usAddress - REG_INPUT_REGISTER_START-1;
if ((usAddress >= REG_INPUT_REGISTER_START)&&(usAddress + usNRegs <= REG_INPUT_REGISTER_START + REG_INPUT_REGISTER_SIZE+1))
{
for(i=0;i<usNRegs;i++)
{
pucRegBuffer[i*2] = (UCHAR)(Input_Data[RegIndex+i]>>8);
pucRegBuffer[i*2+1] = (UCHAR)Input_Data[RegIndex+i];
}
}
else
{
return MB_ENOREG;
}
return MB_ENOERR;
}
⑦新建User_modbus_TCP.h文件
#ifndef __User_modbbus_TCP_H__
#define __User_modbbus_TCP_H__
#include "main.h"
#define MODBUS_TCP_PORT 0 //0代表默认即为502,也可以自己设
extern void ModbusTCPInit(void);
extern void ModbusTCPMain(void);
#endif
⑧主程序中
⑨printf重定向(必须要有,不然会卡主,目前不知道原因,有知道的可以在评论区解释一下!)
#include <stdio.h>
int fputc(int ch, FILE *f)
{
HAL_UART_Transmit(&huart3, (uint8_t *)&ch, 1, 0xffff);
return ch;
}
到这里程序就移植完成了!!!
四、测试
①打开modbus poll 在connection选connect连接或按F3
端口号在User_modbus_TCP.h定义,0为默认即为502,也可以按照自己需求修改
②点击"Setup"→“Read/Write Definition…”,或者按快捷键F8设置从机地址,功能码,起始地址,寄存器数量等信息
③测试结果
其他同理!!
功能代码表放在下面了!
五、工程文件
按需自取幺!
STM32F407ZET7+ETH+LWIP移植modbusTCP测试通过(带软件和freemodbusv1.6包)https://download.youkuaiyun.com/download/qq_33288274/88747061F407ZET7-ETH+LWIP+freemodbus+FreeRTOS+SPI+DMA
https://download.youkuaiyun.com/download/qq_33288274/88791756
ps:积分不够的可以留下邮箱,我看到的了可以私发