在这个智能硬件和物联网时代,MicroPython和树莓派PICO正以其独特的优势引领着嵌入式开发的新潮流。MicroPython作为一种精简优化的Python 3语言,为微控制器和嵌入式设备提供了高效开发和简易调试的
当我们结合WIZnet W5100S/W5500网络模块,MicroPython和树莓派PICO的开发潜力被进一步放大。这两款模块都内置了TCP/IP协议栈,使得在嵌入式设备上实现网络连接变得更加容易。无论是进行数据传输、远程控制,还是构建物联网应用,它们都提供了强大的支持。
本章我们将以WIZnet W5100S为例,以MicroPython的开发方式进行Modbus TCP通信示例
Modbus TCP是一种基于TCP/IP协议的应用层协议,它是Modbus协议的扩展。Modbus协议是一种串行通信协议,最初由Modicon公司在1979年开发,用于工业自动化控制系统中设备之间的通信。Modbus TCP则是将Modbus协议转换为基于以太网的TCP/IP协议,以支持更广泛的设备和系统集成。
Modbus TCP的数据帧可分为两部分:MBAP+PDU。MBAP为报文头,长度为7字节。PDU由功能码+数据组成。功能码为1字节,数据长度不定,由具体功能决定。
根据对象的不同,modbus的功能码有:0x01 读线圈,0x05 写单个线圈,0x0F 写多个线圈,0x02 读离散量输入,0x04 读输入寄存器,0x03 读保持寄存器,0x06 写单个保持寄存器,0x10 写多个保持寄存器。
WIZnet 主流硬件协议栈以太网芯片参数对比
Model | Embedded Core | Host I/F | TX/RX Buffer | HW Socket | Network Performance |
---|---|---|---|---|---|
W5100S | TCP/IPv4, MAC & PHY | 8bit BUS, SPI | 16KB | 4 | Max 25Mbps |
W6100 | TCP/IPv4/IPv6, MAC & PHY | 8bit BUS, Fast SPI | 32KB | 8 | Max 25Mbps |
W5500 | TCP/IPv4, MAC & PHY | Fast SPI | 32KB | 8 | Max 15Mbps |
相较于软件协议栈,WIZnet的硬件协议栈以太网芯片有以下优点:
软件:
硬件:
我们直接打开modbus_tcp_server.py文件。
第一步:可以看到在w5x00_init()函数中,进行了SPI的初始化。以及将spi相关引脚和复位引脚注册到库中,后续则是激活网络,并使用DHCP配置网络地址信息,当DHCP失败时,则配置静态网络地址信息。当未配置成功时,会打印出网络地址相关寄存器的信息,可以帮助我们更好的排查问题。
第二步:在modbus_run()函数中,会打开一个TCP服务器,然后等待接收到数据(即Modbus 指令)。
第三步:对Modbus指令进行核对,然后解析并作出相应的操作以及回复。
from usocket import socket
from machine import Pin,SPI
import network
import time
local_ip = ''
local_port = 5000
led = Pin(25, Pin.OUT)
"""
W5x00 chip initialization.
param: None
returns: None
"""
def w5x00_init():
global local_ip
spi=SPI(0,2_000_000, mosi=Pin(19),miso=Pin(16),sck=Pin(18))
nic = network.WIZNET5K(spi,Pin(17),Pin(20)) #spi,cs,reset pin
nic.active(True)
try:
#DHCP
print("\r\nConfiguring DHCP")
nic.ifconfig('dhcp')
except:
#None DHCP
print("\r\nDHCP fails, use static configuration")
nic.ifconfig(('192.168.1.20','255.255.255.0','192.168.1.1','8.8.8.8'))#Set static network address information
#Print network address information
print("IP :",nic.ifconfig()[0])
print("Subnet Mask:",nic.ifconfig()[1])
print("Gateway :",nic.ifconfig()[2])
print("DNS :",nic.ifconfig()[3],"\r\n")
local_ip = nic.ifconfig()[0]
#If there is no network connection, the register address information is printed
while not nic.isconnected():
time.sleep(1)
print(nic.regs())
"""
Modbus packet parsing.
param1: receive data
param2: connecting object
returns: None
"""
def modbus_parsing(data,conn):
senddata = bytearray(128)
if data[2] != 0x00 and data[3] != 0x00:
print("protocol error")
else:
if data[6] == 0x01:
if data[7] == 0x01:
if int(data[8])+int(data[9]) == 0 and int(data[10])+int(data[11])==1:
print("Read OK!")
senddata[0] = data[0]
senddata[1] = data[1]
senddata[2] = data[2]
senddata[3] = data[3]
senddata[4] = 0x00
senddata[5] = 0x04
senddata[6] = 0x01
senddata[7] = 0x01
senddata[8] = 0x01
senddata[9] = led.value()
conn.send(senddata)
else:
print("address error!")
elif data[7] == 0x05:
if int(data[8])+int(data[9]) == 0:
if data[10] == 0xFF:
print("LED ON!")
led.value(1)
elif data[10] == 0x00:
print("LED OFF!")
led.value(0)
else:
print("value error!")
conn.send(data)
else:
print("address error!")
else:
print("The function code is not processed!")
else:
print("slave address error!")
"""
Start the Modbus TCP server.
param: None
returns: None
"""
def modbus_run():
global local_ip
global local_port
s = socket()
s.bind((local_ip, local_port)) #Source IP Address
s.listen(0)
print("remote ip:",local_ip,",port:",local_port)
conn, addr = s.accept()
print("type",type(conn))
print("Connected:", conn, "address:", addr[0])
while True:
data = conn.recv(2048)
if data != 'NULL':
modbus_parsing(data,conn)
def main():
print("WIZnet chip Modbus TCP example")
w5x00_init()
modbus_run()
if __name__ == "__main__":
main()
要测试以太网示例,必须将开发环境配置为使用Raspberry Pi Pico。
第一步:将程序复制到Thonny中,然后选择环境为Raspberry Pi Pico,最后点击运行。
第二步:在Modbus Poll上进行连接,地址为开发板的地址,端口号为5000。
第三步:在Modbus Poll上下发指令控制LED,并读取LED灯状态。
注意:因为MicroPython的print函数是启用了stdout缓冲的,所以有时候并不会第一时间打印出内容。
WIZnet官网
本章例程链接
想了解更多,评论留言哦!