环境:STM32CUBEMX6.6.1  MDK532 freemodbus1.6


首先是创建能驱动W5500的工程

主要用到硬件为SPI UART

SPI速度建议不要太快,SPI1可以设置到40M,但是没必要这么快。

导出工程

添加fputc重定义


找到W5500官方例子

参考例程WIZnet W5500/W5300-官方代理商

freemodbus tcp需要用到的是TCP server例子

将Ethernet文件夹拷入刚才建好的工程

添加C文件,添加头文件路径

我这里同时用到了HTTP SERVER,没用到可以不加

驱动主要修改是在w5500.conf

添加reset控制引脚,cs控制引脚

还有SPI发送函数

uint8_t SPI_SendByte(uint8_t byte)
{uint8_t rxbyte=0;uint8_t SPITimeout =200;while(__HAL_SPI_GET_FLAG(&hspi1,SPI_FLAG_TXE)==RESET){if((SPITimeout--)==0)HAL_SPI_ErrorCallback(&hspi1);return 0;}HAL_SPI_TransmitReceive(&hspi1,&byte,&rxbyte,1,100);return rxbyte;
}

将例子中定时器初始化和中断屏蔽掉,没有用到动态IP分配就不需要定时器中断

然后主函数参考例子,添加函数do_tcp_server();

照葫芦画瓢就行

然后下载固件,连上自己的电脑或者路由器,这里要保证在同一个网段,就是IP地址前面三个数是一样才行,电脑IP可以用ipconfig查看

直连电脑就看上面的地址,我这里没连上,显示的断开

如果连的路由器,就看下面这个,设置W5500的IP为192.168.8.x

可以从串口1看到W5500初始化是否完成,初始化正确的话会正常显示MAC和IP为你设置的值

然后随便找一个TCP测试工具,我这里用的是sscom,输入IP和端口,测试一下官方的回环例子即可。


移植freemodbus

GitHub - cwalter-at/freemodbus: BSD licensed MODBUS RTU/ASCII and TCP slave

下载最新软件包,提取出这些文件,新建一个目录freemodbus

修改porttcp.c里的这几个函数,添加各类接口,添加poll处理流程

BOOL
xMBTCPPortInit( USHORT usTCPPort )
{BOOL bOkay = FALSE;switch(getSn_SR(SOCK_TCPS))                             // 获取socket的状态{case SOCK_CLOSED:                                     // socket处于关闭状态socket(SOCK_TCPS ,Sn_MR_TCP,local_port,Sn_MR_ND);   // 打开socketbreak;     case SOCK_INIT:                                       // socket已初始化状态listen(SOCK_TCPS);                                  // socket建立监听break;}bOkay = TRUE;return bOkay;
}
BOOL
xMBTCPPortGetRequest( UCHAR ** ppucMBTCPFrame, USHORT * usTCPLength )
{*ppucMBTCPFrame = &aucTCPBuf[0];*usTCPLength = usTCPBufLen;/* Reset the buffer. */usTCPBufLen = 0;return TRUE;
}
BOOL
xMBTCPPortSendResponse(const UCHAR * pucMBTCPFrame, USHORT usTCPLength )
{send(SOCK_TCPS,(UCHAR*)pucMBTCPFrame,usTCPLength);                         // 向Client发送数据//send_tcp_socket_data(SOCK_TCP_PORT,(UCHAR*)pucMBTCPFrame,usTCPLength);  return TRUE;
}
BOOL
xMBPortTCPPool( void )
{  switch(getSn_SR(SOCK_TCPS))                             // 获取socket的状态{case SOCK_CLOSED:                                     // socket处于关闭状态socket(SOCK_TCPS ,Sn_MR_TCP,local_port,Sn_MR_ND);   // 打开socketbreak;     case SOCK_INIT:                                       // socket已初始化状态listen(SOCK_TCPS);                                  // socket建立监听break;case SOCK_ESTABLISHED:                                // socket处于连接建立状态if(getSn_IR(SOCK_TCPS) & Sn_IR_CON){setSn_IR(SOCK_TCPS, Sn_IR_CON);                   // 清除接收中断标志位}usTCPBufLen=getSn_RX_RSR(SOCK_TCPS);                        // 定义len为已接收数据的长度if(usTCPBufLen>0){recv(SOCK_TCPS,aucTCPBuf,usTCPBufLen);                         // 接收来自Client的数据
//        aucTCPBuf[len]=0x00;                                   // 添加字符串结束符
//        printf("%s\r\n",aucTCPBuf);
//        send(SOCK_TCPS,aucTCPBuf,len);                         // 向Client发送数据( void )xMBPortEventPost( EV_FRAME_RECEIVED );           //发送已接收到新数据到Modbus-TCP状态机}break;case SOCK_CLOSE_WAIT:                                 // socket处于等待关闭状态disconnect(SOCK_TCPS);                              // 断开当前TCP连接close(SOCK_TCPS);                                   // 关闭当前所使用socketbreak;}return TRUE;
}

然后新建一个modbus_tcp.c文件,加入一些协议实现,就是那些什么线圈,什么保持寄存器,什么输入寄存器之类的, 02 04 06 01这些个东西。

#include "modbus_tcp.h"
#include "mb.h"//输入寄存器内容
uint16_t usRegInputBuf[REG_INPUT_NREGS] = {0x0};
//保持寄存器内容
uint16_t usRegHoldingBuf[REG_HOLDING_NREGS] = {0x0};
//线圈状态
uint8_t ucRegCoilsBuf[REG_COILS_SIZE] = {0x00};
//离散寄存器内容
uint8_t ucRegDiscreteBuf[REG_DISCRETE_SIZE]; //= {0x01,0x01,0x00,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x01}; /****************************************************************************
* 名   称:eMBRegInputCB
* 功    能:读取输入寄存器,对应功能码是 04 eMBFuncReadInputRegister
* 入口参数:pucRegBuffer: 数据缓存区,用于响应主机
*                       usAddress: 寄存器地址
*                       usNRegs: 要读取的寄存器个数
* 出口参数:
* 注   意:上位机发来的 帧格式是: SlaveAddr(1 Byte)+FuncCode(1 Byte)
*                               +StartAddrHiByte(1 Byte)+StartAddrLoByte(1 Byte)
*                               +LenAddrHiByte(1 Byte)+LenAddrLoByte(1 Byte)+
*                               +CRCAddrHiByte(1 Byte)+CRCAddrLoByte(1 Byte)
*                           3 区
****************************************************************************/
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 - REG_INPUT_START );while( usNRegs > 0 ){*pucRegBuffer++ = ( UCHAR )( usRegInputBuf[iRegIndex] >> 8 );*pucRegBuffer++ = ( UCHAR )( usRegInputBuf[iRegIndex] & 0xFF );iRegIndex++;usNRegs--;}}else{eStatus = MB_ENOREG;}return eStatus;
}/****************************************************************************
* 名   称:eMBRegHoldingCB
* 功    能:对应功能码有:06 写保持寄存器 eMBFuncWriteHoldingRegister
*                                                   16 写多个保持寄存器 eMBFuncWriteMultipleHoldingRegister
*                                                   03 读保持寄存器 eMBFuncReadHoldingRegister
*                                                   23 读写多个保持寄存器 eMBFuncReadWriteMultipleHoldingRegister
* 入口参数:pucRegBuffer: 数据缓存区,用于响应主机
*                       usAddress: 寄存器地址
*                       usNRegs: 要读写的寄存器个数
*                       eMode: 功能码
* 出口参数:
* 注   意:4 区
****************************************************************************/
eMBErrorCode
eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs, eMBRegisterMode eMode )
{eMBErrorCode    eStatus = MB_ENOERR;int             iRegIndex;if((usAddress >= REG_HOLDING_START)&&\((usAddress+usNRegs) <= (REG_HOLDING_START + REG_HOLDING_NREGS))){iRegIndex = (int)(usAddress - REG_HOLDING_START);switch(eMode){                                       case MB_REG_READ://读 MB_REG_READ = 0while(usNRegs > 0){*pucRegBuffer++ = (u8)(usRegHoldingBuf[iRegIndex] >> 8);            *pucRegBuffer++ = (u8)(usRegHoldingBuf[iRegIndex] & 0xFF); iRegIndex++;usNRegs--;                 }                            break;case MB_REG_WRITE://写 MB_REG_WRITE = 0while(usNRegs > 0){         usRegHoldingBuf[iRegIndex] = *pucRegBuffer++ << 8;usRegHoldingBuf[iRegIndex] |= *pucRegBuffer++;iRegIndex++;usNRegs--;}break;                }}else//错误{eStatus = MB_ENOREG;}   return eStatus;
}/****************************************************************************
* 名   称:eMBRegCoilsCB
* 功    能:对应功能码有:01 读线圈 eMBFuncReadCoils
*                         05 写线圈 eMBFuncWriteCoil
*                         15 写多个线圈 eMBFuncWriteMultipleCoils
* 入口参数:pucRegBuffer: 数据缓存区,用于响应主机
*                       usAddress: 线圈地址
*                       usNCoils: 要读写的线圈个数
*                       eMode: 功能码
* 出口参数:
* 注   意:如继电器
*                       0 区
****************************************************************************/
eMBErrorCode
eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNCoils, eMBRegisterMode eMode )
{eMBErrorCode    eStatus = MB_ENOERR;int             iRegIndex;u8 i;USHORT readNumber=usNCoils;USHORT coilValue=0x0000;if((usAddress >= REG_COILS_START)&&\((usAddress+usNCoils) <= (REG_COILS_START + REG_COILS_SIZE))){iRegIndex = (int)(usAddress + usNCoils-REG_COILS_START);switch(eMode){                                       case MB_REG_READ://读 MB_REG_READ = 0for(i=0;i<usNCoils;i++){readNumber--;iRegIndex--;coilValue|=ucRegCoilsBuf[iRegIndex]<<readNumber;}if(usNCoils<=8){* pucRegBuffer=coilValue;}else{* pucRegBuffer++ = (coilValue)&0x00ff;* pucRegBuffer++ = (coilValue>>8)&0x00ff;}break;                            case MB_REG_WRITE://写 MB_REG_WRITE = 1while(usNCoils > 0){         //            usRegHoldingBuf[iRegIndex] = *pucRegBuffer++ << 8;//           usRegHoldingBuf[iRegIndex] |= *pucRegBuffer++;iRegIndex++;usNCoils--;}break;}}else//错误{eStatus = MB_ENOREG;}  return eStatus;
}
/****************************************************************************
* 名   称:eMBRegDiscreteCB
* 功    能:读取离散寄存器,对应功能码有:02 读离散寄存器 eMBFuncReadDiscreteInputs
* 入口参数:pucRegBuffer: 数据缓存区,用于响应主机
*                       usAddress: 寄存器地址
*                       usNDiscrete: 要读取的寄存器个数
* 出口参数:
* 注   意:1 区
****************************************************************************/
eMBErrorCode
eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete )
{eMBErrorCode    eStatus = MB_ENOERR;int             iRegIndex;u8 i;USHORT readNumber=usNDiscrete;USHORT coilValue=0x0000;iRegIndex = (int)(usAddress + usNDiscrete-REG_DISCRETE_START);if((usAddress >= REG_DISCRETE_START)&&\((usAddress+usNDiscrete) <= (REG_DISCRETE_START + REG_DISCRETE_SIZE))){for(i=0;i<usNDiscrete;i++){readNumber--;iRegIndex--;coilValue|=ucRegDiscreteBuf[iRegIndex]<<readNumber;}if(usNDiscrete<=8){* pucRegBuffer=coilValue;}else{* pucRegBuffer++ = (coilValue)&0x00ff;* pucRegBuffer++ = (coilValue>>8)&0x00ff;}}else{eStatus = MB_ENOREG;}return eStatus;
}

随便塞点数据

主函数里添加

eMBPoll();

替换原来的

do_tcp_server();

然后烧写,找一个MODBUS tcp测试软件,我这里用的是Qmodbus

设置好IP PORT  function  点send

结果如下

基于STM32F407+W5500的freemodbus tcp移植与实现相关推荐

  1. 基于STM32和W5500的Modbus TCP通讯

     在最近的一个项目中需要实现Modbus TCP通讯,而选用的硬件平台则是STM32F103和W5500,软件平台则选用IAR EWAR6.4来实现. 1.移植前的准备工作 为了实现Modbus ...

  2. FreeModbus的移植

    FreeModbus V1.6 主机使用说明 一.简述 FreeModbus是一款开源的Modbus协议栈,但是只有从机开源,主机源码是需要收费的.同时网上也没有发现比较好的开源的Modbus主机协议 ...

  3. EC20模组使用MQTT库对接EMQX,基于STM32F407

    一.说明 本lib库基于STM32F407编译,其他的cortexM4内核也支持,采用串口和EC20模组通信. 库包括两个文件:ec20_mqtt.h和ec20_mqtt.lib.使用时添加lib文件 ...

  4. 通讯接口应用笔记3:使用W5500实现Modbus TCP服务器

      前面我们设计实现了W5500的驱动程序,也讲解了驱动的使用方式.在最近一次的项目应用中,正好有一个使用W5500实现TCP通讯的需求,所以我们就使用该驱动程序轻松实现.这一篇中我们就来说一说基于我 ...

  5. 基于Stm32f407 的贪吃蛇小游戏【正点原子-探索者开发板】

    基于单片机stm32f407的单机小游戏----贪吃蛇小游戏 1.介绍 这是我花一个星期完成的一个简单地单机贪吃蛇小游戏项目,芯片是stm32f407,项目是基于正点原子-探索者开发板完成的,有需要的 ...

  6. 基于STM32F407的简易菜单设计+LCD+按键

    基于STM32F407的简易多级菜单设计+LCD+按键 实现原理 主要使用 双向链表 结构实现的菜单: 结构体包含7个变量,分别是菜单中功能项的个数,当前菜单标题,菜单中各功能项标题,功能项的类型,然 ...

  7. STM32F407 + LAN8720A + LWIP 实现TCP服务器

    STM32F407 + LAN8720A + LWIP 实现TCP客户端 环境说明: 开发板:某宝买的,STM32F407IG STM32CUBEMX5.6 HAL Lib Version 1.25 ...

  8. Boost:基于boost::asio的延迟tcp服务器测试程序

    Boost:基于boost::asio的延迟tcp服务器测试程序 实现功能 C++实现代码 客户端源码 服务端源码 实现功能 boost::asio模块,基于boost::asio的延迟tcp服务器测 ...

  9. 轨迹跟踪主要方法_DELMIA教程:基于指令形式的机器人TCP轨迹局部跟踪方法

    上一期为大家介绍了基于工具条中的"TCP Trace"命令按钮的全局TCP轨迹跟踪,之所以称之为全局轨迹跟踪,是因为只要命令被打开,机器人运行的全部轨迹都将实现跟踪.既然有全局TC ...

最新文章

  1. go移植linux内核书名叫啥,Go语言移植Linux内核数据结构hlist
  2. :link,:visited,:focus,:hover,:active详解
  3. UVa 11729 - Commando War(贪心算法)
  4. TechEd2007现场侧记:TechEd的变与不变
  5. 前端开发——移动端及响应式布局解决办法总结(适配)
  6. 一个软件网络连接异常_你的电脑运转正常吗?这 10 款系统监控软件能告诉你答案...
  7. 基于SSM的购物商城系统(含文档)
  8. 在Kali中使用Ettercap进行ARP欺骗
  9. 360桌面隐藏应用 android代码,360手机桌面上的隐藏应用怎么设置?
  10. 谁在管理拼多多:超级大脑和原子化组织
  11. 带小数的二进制转十进制(C代码)
  12. python十二星座符号_12种编程语言类比12星座女
  13. 学单片机之前需要做哪些准备?
  14. OpenCV竟然可以这样学!成神之路终将不远(六)
  15. K8s系列之-集群节点规划
  16. oracle并行查询结果不唯一,Oracle并行查询出错
  17. We should: Good Good Study, Day Day Up
  18. 如何高效学习英语?这个方法你一定要知道
  19. 一个高颜值宝藏开源软件,跨平台终端神器 Tabby
  20. C语言程序设计—学籍信息管理系统

热门文章

  1. flag!flag!flag!flag!flag!flag!flag!flag!flag!flag!flag!flag!
  2. 你听说过箱根驿传么?
  3. android强制关掉应用,android应用程序强制关闭执行此查询
  4. halcon相机标定助手_Halcon 学习笔记---单相机标定(2)
  5. Minecraft钻石矿生成定位器③(版本:1.16和1.17的Java版本)
  6. java 设计模式之桥接模式,策略模式
  7. Android QQ技术分享三(QQ换肤之SkinEngine实现)
  8. ListView具体使用
  9. glided_sky 镀金的天空 爬虫闯关 js加密1
  10. 和数集团打造《神念无界:源起山海》,诠释链游领域创新与责任