基于STM32F407+W5500的freemodbus tcp移植与实现
环境: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移植与实现相关推荐
- 基于STM32和W5500的Modbus TCP通讯
在最近的一个项目中需要实现Modbus TCP通讯,而选用的硬件平台则是STM32F103和W5500,软件平台则选用IAR EWAR6.4来实现. 1.移植前的准备工作 为了实现Modbus ...
- FreeModbus的移植
FreeModbus V1.6 主机使用说明 一.简述 FreeModbus是一款开源的Modbus协议栈,但是只有从机开源,主机源码是需要收费的.同时网上也没有发现比较好的开源的Modbus主机协议 ...
- EC20模组使用MQTT库对接EMQX,基于STM32F407
一.说明 本lib库基于STM32F407编译,其他的cortexM4内核也支持,采用串口和EC20模组通信. 库包括两个文件:ec20_mqtt.h和ec20_mqtt.lib.使用时添加lib文件 ...
- 通讯接口应用笔记3:使用W5500实现Modbus TCP服务器
前面我们设计实现了W5500的驱动程序,也讲解了驱动的使用方式.在最近一次的项目应用中,正好有一个使用W5500实现TCP通讯的需求,所以我们就使用该驱动程序轻松实现.这一篇中我们就来说一说基于我 ...
- 基于Stm32f407 的贪吃蛇小游戏【正点原子-探索者开发板】
基于单片机stm32f407的单机小游戏----贪吃蛇小游戏 1.介绍 这是我花一个星期完成的一个简单地单机贪吃蛇小游戏项目,芯片是stm32f407,项目是基于正点原子-探索者开发板完成的,有需要的 ...
- 基于STM32F407的简易菜单设计+LCD+按键
基于STM32F407的简易多级菜单设计+LCD+按键 实现原理 主要使用 双向链表 结构实现的菜单: 结构体包含7个变量,分别是菜单中功能项的个数,当前菜单标题,菜单中各功能项标题,功能项的类型,然 ...
- STM32F407 + LAN8720A + LWIP 实现TCP服务器
STM32F407 + LAN8720A + LWIP 实现TCP客户端 环境说明: 开发板:某宝买的,STM32F407IG STM32CUBEMX5.6 HAL Lib Version 1.25 ...
- Boost:基于boost::asio的延迟tcp服务器测试程序
Boost:基于boost::asio的延迟tcp服务器测试程序 实现功能 C++实现代码 客户端源码 服务端源码 实现功能 boost::asio模块,基于boost::asio的延迟tcp服务器测 ...
- 轨迹跟踪主要方法_DELMIA教程:基于指令形式的机器人TCP轨迹局部跟踪方法
上一期为大家介绍了基于工具条中的"TCP Trace"命令按钮的全局TCP轨迹跟踪,之所以称之为全局轨迹跟踪,是因为只要命令被打开,机器人运行的全部轨迹都将实现跟踪.既然有全局TC ...
最新文章
- go移植linux内核书名叫啥,Go语言移植Linux内核数据结构hlist
- :link,:visited,:focus,:hover,:active详解
- UVa 11729 - Commando War(贪心算法)
- TechEd2007现场侧记:TechEd的变与不变
- 前端开发——移动端及响应式布局解决办法总结(适配)
- 一个软件网络连接异常_你的电脑运转正常吗?这 10 款系统监控软件能告诉你答案...
- 基于SSM的购物商城系统(含文档)
- 在Kali中使用Ettercap进行ARP欺骗
- 360桌面隐藏应用 android代码,360手机桌面上的隐藏应用怎么设置?
- 谁在管理拼多多:超级大脑和原子化组织
- 带小数的二进制转十进制(C代码)
- python十二星座符号_12种编程语言类比12星座女
- 学单片机之前需要做哪些准备?
- OpenCV竟然可以这样学!成神之路终将不远(六)
- K8s系列之-集群节点规划
- oracle并行查询结果不唯一,Oracle并行查询出错
- We should: Good Good Study, Day Day Up
- 如何高效学习英语?这个方法你一定要知道
- 一个高颜值宝藏开源软件,跨平台终端神器 Tabby
- C语言程序设计—学籍信息管理系统
热门文章
- flag!flag!flag!flag!flag!flag!flag!flag!flag!flag!flag!flag!
- 你听说过箱根驿传么?
- android强制关掉应用,android应用程序强制关闭执行此查询
- halcon相机标定助手_Halcon 学习笔记---单相机标定(2)
- Minecraft钻石矿生成定位器③(版本:1.16和1.17的Java版本)
- java 设计模式之桥接模式,策略模式
- Android QQ技术分享三(QQ换肤之SkinEngine实现)
- ListView具体使用
- glided_sky 镀金的天空 爬虫闯关 js加密1
- 和数集团打造《神念无界:源起山海》,诠释链游领域创新与责任