目录
1 前言
2 项目环境
2.1 硬件环境
2.2 软件环境
3 硬件连接和方案
3.3 W5500硬件连接
3.4 方案图示
4 例程修改
5 配置连接
5.1 串口打印
5.2 Modbus Master Suite
6 发送数据
7 效果展示并解析
8 总结
1 前言
Modbus是一种串行通信协议,最初为工业自动化领域设计,因其简单、开放、易于实现而成为工业电子设备间通信的事实标准
Modbus 的工作原理围绕着三个核心部分:主站(Master)、从站(Slave) 和 寄存器(Registers)。主站负责向特定从站发送数据请求或写入命令,从站则处理这些命令(读取或修改自身寄存器数据)并向主站返回响应。这种主站轮询、从站响应的同步模式,使其非常适合于工业设备的状态监控和控制。
SMTP (Simple Mail Transfer Protocol) 是一种电子邮件传输协议,基于 TCP/IP,采用客户端-服务器模型和存储转发机制,专用于电子邮件的发送与传输。
SMTP 的工作原理围绕着三个核心部分:发送方 SMTP 客户端、接收方 SMTP 服务器 和 命令/响应机制。发送方客户端连接服务器,通过文本命令(如 MAIL FROM, RCPT TO, DATA)指定发件人、收件人并传输邮件内容;接收方服务器处理命令、验证信息,并将邮件存入目标邮箱或转发。这种基于命令序列的模式,确保了电子邮件在互联网上的可靠传输
W5500io-M 是炜世推出的高性能SPI转以太网模块,具有以下特点:
- 极简设计:集成MAC、PHY、32KB缓存及RJ45网口,通过4线SPI接口直连主控,3.3V供电,紧凑尺寸适配嵌入式场景 。
- 简单易用:用户无需再移植复杂的TCP/IP协议栈到MCU中,可直接基于应用层数据做开发。
- 资料丰富:提供丰富的MCU应用例程和硬件参考设计,可直接参考使用,大大缩短研发时间,硬件兼容W5100Sio-M模组,方便方案开发与迭代。
- 应用广泛:在工业控制、智能电网、充电桩、安防消防、新能源、储能等领域都有广泛应用。
产品链接:商品详情
2 项目环境
2.1 硬件环境
2.2 软件环境
3 硬件连接和方案
3.3 W5500硬件连接
//W5500_SCS—>STM32_GPIOD7/*W5500的片选引脚*/
//W5500_SCLK—>STM32_GPIOB13/*W5500的时钟引脚*/
//W5500_MISO—>STM32_GPIOB14/*W5500的MISO引脚*/
//W5500_MOSI—>STM32_GPIOB15/*W5500的MOSI引脚*/
//W5500_RESET—>STM32_GPIOD8/*W5500的RESET引脚*/
//W5500_INT—>STM32_GPIOD9/*W5500的INT引脚*/
3.4 方案图示
4 例程修改
需要下载Modbus_TCP_Server和SMTP的例程,然后进行修改,例程下载上方软件环境里面提供的有链接,自行下载即可
(1)下载好之后打开Modbus_TCP_Server例程,然后把SMTP例程中的dns.c dns.h和smtp.c smtp.h以及do_dns.c和do_dns.h文件加入到Modbus_TCP_Server例程中去
(2)文件路径进行添加
(3)在user_main.h的第5行添加一路SMTP所需要使用的socket
#ifndef __USER_MAIN_H__
#define __USER_MAIN_H__
#define SOCKET_ID 0
#define SMTP_SOCKET_ID 1
#define ETHERNET_BUF_MAX_SIZE (1024 * 2)
/**
* @brief User Run Program
* @param none
* @return none
*/
void user_run(void);
#endif
(4)打开user_main.c,在while(1)中添加do_smtp函数,并且把SOCKET ID 替换为我们定义的SMTP SOCKET ID
while (1)
{
do_Modbus(SOCKET_ID);
do_smtp(SMTP_SOCKET_ID, ethernet_buf, smtp_server_ip);
}
(5) 我们找到mb.c来修改解析Modbus数据的函数,由于Modbus tcp不需要要crc校验,所以在第3行添加一个长度条件,再在代码里添加一个解析写单个寄存器的else of的函数,添加在21行,里面解析传回的浓度值,如果浓度过高,打印出浓度,此时Avalue已经被赋值。
void mbTCPtoEVB(uint8_t sn)
{
if (MBtcp2evbFrame() != 0 && recv_len >= 12) // Frame received complete
{
if (pucASCIIBufferCur[0] == 0x01) // Check whether the device address is 0x01
{
if ((uint8_t)pucASCIIBufferCur[1] == 0x05) // Write to a single device
{
if ((uint8_t)pucASCIIBufferCur[4] == 0xff)
{
LED_ON();
printf("LED ON\\r\\n");
}
else if ((uint8_t)pucASCIIBufferCur[4] == 0x00)
{
LED_OFF();
printf("LED OFF\\r\\n");
}
send(sn, recv_data, recv_len);
}
else if((uint8_t)pucASCIIBufferCur[1] == 0x06)
{
Avalue = ((uint16_t)pucASCIIBufferCur[4] << 8) | pucASCIIBufferCur[5];
if (Avalue > 30)
{
printf("Alert: Concentration too high%u > 30\\r\\n", Avalue);
}
send(sn, recv_data, recv_len);
}
else if ((uint8_t)pucASCIIBufferCur[1] == 0x01) // Read Write to a single device
{
if (recv_data[recv_len – 1] != 0x01)
{
printf("len error!%x\\r\\n", recv_data[recv_len – 1]);
}
else
{
printf("Read OK!\\r\\n");
send_data[0] = recv_data[0];
send_data[1] = recv_data[1];
send_data[2] = recv_data[2];
send_data[3] = recv_data[3];
send_data[4] = 0x00;
send_data[5] = 0x04;
send_data[6] = 0x01;
send_data[7] = 0x01;
send_data[8] = 0x01;
send_data[9] = ~HAL_GPIO_ReadPin(LED_GPIO_Port, LED_Pin);
send_len = 10;
send(sn, send_data, send_len);
memset(send_data, 0, send_len);
}
}
}
else
{
printf("error code!\\r\\n");
}
}
else
{
printf("address error!\\r\\n");
}
}
(6)把定义的Avalue在mb.h中第11行进行传出
#ifndef _MB_H_
#define _MB_H_
/**
* @brief Parse Modbus TCP instructions and process them accordingly
*
* According to the given sequence number, the Modbus TCP data is converted into an EVB instruction and processed accordingly.
*
* @param sn socket number
*/
extern uint16_t Avalue;
void mbTCPtoEVB(uint8_t sn);
#endif
(7)此时回到while(1)中,加入条件判断,然后再执行发送信息的操作
while (1)
{
do_Modbus(SOCKET_ID);
if(Avalue>30){
do_smtp(SMTP_SOCKET_ID, ethernet_buf, smtp_server_ip);}
}
(8)在stmp.c中修改接收邮件的邮箱以及邮件的主题及内容,在第15行修改接收邮件的邮箱账号,在第7行和第13行可以修改发件邮箱登录地址和发件人邮箱,在第10行修改邮箱登录密码,在第21行和第22行修改邮件的主题和内容。系统中通过126邮箱服务器向指定QQ邮箱发送警报邮件。首先通过HELO命令建立连接,然后使用AUTH LOGIN进行Base64编码的用户名密码认证,接着设置发件人(MAIL FROM)和收件人(RCPT TO地址为232++++16@qq.com),再通过DATA命令传输邮件内容。邮件主题为"Breaking In",正文内容是"Excessive gas concentration",最后以\\r\\n.\\r\\n结束传输。
#define ETHERNET_MAX_BUF_SIZE (1024 * 2)
uint8_t Mail_Send_OK;
char hello[50] = "HELO localhost"; // Identity command
char hello_reply[] = "250 OK"; // Id successfully responded
char AUTH[50] = "AUTH LOGIN"; // Authentication request
char AUTH_reply[] = "334 dXNlcm5hbWU6"; // The authentication request was successfully sent
char name_126[100] = "wiznethk@126.com"; // 126 Login email address
char base64name_126[200]; // 126 base64 encoding of the login mailbox name
char name_reply[] = "334 UGFzc3dvcmQ6"; // The login name was sent successfully
char password_126[50] = "ZPURADLGRUPQLVBK"; // 126 Email login password
char base64password_126[100]; // base64 123 Password for logging in to the mailbox
char password_reply[] = "235 Authentication successful"; // Login successful response
char from[] = "wiznethk@126.com"; // Sender email
char from_reply[] = "250 Mail OK";
char to[] = "232++++16@qq.com"; // Recipient email address
char to_reply[] = "250 Mail OK";·
char data_init[10] = "data"; // Request data transfer
char data_reply[] = "354"; // The request was successfully responded to HEAD
char Cc[] = ""; // Cc to email
char subject[] = "Breaking In"; // subject
char content[] = "Excessive gas concentration"; // text part
char mime_reply[] = "250 Mail OK queued as"; // The email was sent successfully
char mailfrom[50] = "MAIL FROM:<>";
char rcptto[50] = "rcpt to:<>";
char mime[200] = "From:\\r\\n";
char mime1[50] = "To:\\r\\n";
char mime2[50] = "Cc:\\r\\n";
char mime3[50] = "Subject:\\r\\n";
char mime4[50] = "MIME-Version:1.0\\r\\nContent-Type:text/plain\\r\\n\\r\\n";
char mime5[50] = "\\r\\n.\\r\\n";
(9) 在stmp.c的最后,发送成功后会进入一个空循环,会导致在这里出不去,可以把while(1)的空循环去除,然后在里面添加一个延时,当邮件发送成功,代表浓度已经超过标准,如果不加延时,会持续发送警告信息,请根据自己需要添加延时。
case SOCK_CLOSED:
socket(sn, Sn_MR_TCP, anyport++, 0x00);
break;
default:
break;
}
if(Mail_Send_OK)
{
// while(1){
HAL_Delay(20000);
// }
}
}
5 配置连接
5.1 串口打印
5.2 Modbus Master Suite
Modbus Master Suite是用于Modbus协议设备通信交互的工具。它支持多种Modbus协议,能通过串口或网络连接设备,可读写各类寄存器数据,具备功能码测试、数据转换与校验等功能。
(1)首先需要先点击设置,再点击连接设置
(2)选择Modbus TCP/IP连接模式,地址和端口号填写上方串口打印的值,点击确认,就可以连接成功
(3)连接成功后,串口会显示连接的信息
6 发送数据
(1)接下来我们在Modbus Master Suite端点击功能,然后点击写单寄存器
(2)依次填写从机地址、寄存器地址以及将要写入的数值,然后点击发送
(3)此时我们的值设置的小于30,串口并未打印出异常信息
(4)再次进行配置,此时我没们把值增加到32,然后点击发送。
7 效果展示并解析
(1)此时,我们可以看到串口打印出浓度数值,并且显示邮件发送成功
(2)打开邮箱,我们可以看到,收到了气体浓度过高的告警邮件。
(3)再来看一下刚才发的报文,由于这两段报文差别不大,我对浓度为32的进行解析
字节范围(十六进制) |
字段名称 |
字段值(十六进制) |
十进制值 |
含义说明 |
00 20 |
事务标识符(TID) |
00 20 |
32 |
主站自定义的事务 ID(与报文 1 不同,说明是另一个独立请求) |
00 00 |
协议标识符(PID) |
00 00 |
0 |
固定为 0(Modbus 协议标识) |
00 06 |
长度(LEN) |
00 06 |
6 |
后续 PDU 字节数(单元标识符 + 功能码 + 数据 共 6 字节) |
01 |
单元标识符(UID) |
01 |
1 |
目标从站地址(仍为 1 ,与报文 1 操作同一从站) |
06 |
功能码(FC) |
06 |
6 |
写单个保持寄存器(Preset Single Register):修改 1 个保持寄存器的值 |
00 01 |
寄存器地址 |
00 01 |
1 |
要写入的保持寄存器起始地址(与报文 1 相同,操作同一寄存器地址) |
00 20 |
写入值 |
00 20 |
32 |
要写入寄存器的数据(十进制 32 ,16 位无符号整数) |
功能总结:
主站向 从站 ID = 1 的设备,发送指令:将地址为 1 的保持寄存器,写入值 32。
8 总结
本系统通过 STM32 与 W5500 的结合,实现了 Modbus TCP 服务器的轻量化部署,同时通过 SMTP 服务打通了传感器数据与远程告警的链路。方案兼顾工业通信的稳定性与物联网应用的灵活性,可根据实际需求调整传感器阈值、邮件内容及硬件接口,适用于对实时性和可靠性有要求的分布式监测场景。感谢您的观看,如您对本文有不清楚的地方或想了解更多产品信息的,欢迎私信或在评论区留言,我们会及时回复您!
评论前必须登录!
注册