[Digi-Key Follow me Issue 4] Summary submission post: Getting started with W5500-EVB-Pico
[Copy link]
This post was last edited by MioChan on 2024-2-12 19:04
Follow Me The fourth issue of the board is W5500-EVB-Pico , which is used in the same way as the Raspberry Pi Pico board, except that it has an additional RJ45 network port.
The devices I chose are W5500-EVB-Pico and Arduino R4 WIFI, because I feel that the recommended screen is too cost-effective. It happens that R4 also has a dot matrix LED, which can be used with W5500-EVB-Pico as a small screen. I set up an API server on Arduino that accepts Post requests so that Pico can send the content to be displayed to the dot matrix screen of R4 through network requests. Both boards use Arduino IDE to write and upload programs. Please see the attachment for the source code, and only some key fragments are posted in the text.
Getting started tasks: build the development environment, BLINK, drive the LCD display to display (if there is no serial port HelloWorld)
The environment is very simple to set up. You only need to download the corresponding firmware from the official website, then drag it into the USB flash drive displayed on the PC in the board burning mode, and then select the corresponding board in Arduino to upload the program.
First, you need to build an API server on the Arduino R4 development board to accept the string of Post requests from other devices, and then scroll it on the onboard dot matrix LED. The core code is mainly to implement the API server and text scrolling display.
void checkForNewClient() { //建立API服务器
WiFiClient client = server.available();
if (client) {
Serial.println("New client");//判断是否有设备发送请求
// Read the first line of the request
String firstLine = client.readStringUntil('\n'); //解析请求
// Check if this is a POST request
if (firstLine.startsWith("POST")) {
// Read the headers and find the Content-Length
int contentLength = -1;
while (client.connected()) {
String line = client.readStringUntil('\n');
if (line.startsWith("Content-Length:")) {
contentLength = line.substring(15).toInt();
}
// Check if the end of headers is reached (empty line)
if (line == "\r") {
break;
}
}
// Read the request body
if (contentLength > 0) {
String requestBody = client.readStringUntil('\n');
// Parse JSON from the request body
DynamicJsonDocument doc(1024);
deserializeJson(doc, requestBody);
String content = doc["content"];
if (content != "") {
Serial.println("Received content: " + content);
receivedContent = " "+content+" "; // Update the received string
} else {
Serial.println("No content received");
}
}
}
// Send response to the client
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/plain");
client.println("Connection: close");
client.println();
client.println("Response sent");
client.stop();
Serial.println("Client disconnected");
}
}
void displayScrollingText(String text) { //实现LED点阵上的滚动显示
matrix.beginDraw();
matrix.stroke(0xFFFFFFFF);
matrix.textScrollSpeed(50);
matrix.textFont(Font_5x7);
matrix.beginText(0, 1, 0xFFFFFF);
matrix.println(text);
matrix.endText(SCROLL_LEFT);
matrix.endDraw();
}
Next is the part of the main control board W5500. The task requires BLINK and output Hello World. Because we need to send a Post request to the dot matrix LED of R4 to display text, this step has completed the initialization of the network function of the main control board W5500. The code is as follows:
#include <SPI.h>
#include <Ethernet.h>
//初始化和网络配置部分
EthernetClient client;
IPAddress server(192, 168, XX, XX); // 设置Arduino R4的 IP 地址
uint16_t serverPort = 80;
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
unsigned long lastTime = 0;
const unsigned long interval = 15000; // 15秒间隔
void setup() {
Serial.begin(9600);
delay(4000);
Serial.println("Hello World");//串口输出Hello World
pinMode(LED_BUILTIN, OUTPUT);
delay(100);
digitalWrite(LED_BUILTIN, HIGH);
if (Ethernet.begin(mac) == 0) { //DHCP配网
Serial.println("Failed to configure Ethernet ");
while (true);
}
delay(1000);
lastTime = millis();
}
//Blink和发送文字Post请求
void loop() {
if (millis() - lastTime >= interval) {
digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level)
delay(1000); // wait for a second
digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW
delay(1000); // wait for a second
sendPostRequest();
lastTime = millis();
}
}
void sendPostRequest(String content ) {
if (client.connect(server, serverPort)) {
Serial.println("Connected to server");
client.println("POST / HTTP/1.1");
client.println("Host: 192.168.50.18");
client.println("Content-Type: application/json");
client.println("Connection: close");
client.print("Content-Length: ");
client.println(23);
client.println();
if( content != "")
client.println("{\"content\":\""+content+"\"}");
else
client.println("{\"content\":\"Hello from W5500\"}");
} else {
Serial.println("Connection failed");
}
while (client.available()) {
char c = client.read();
Serial.write(c);
}
if (!client.connected()) {
Serial.println();
Serial.println("Disconnecting from server...");
client.stop();
}
}
Basic Task 1: Complete the initialization of the main control board W5500 (static IP configuration), and be able to ping it using a LAN computer. At the same time, W5500 can ping Internet sites; use packet capture software (Wireshark, Sniffer, etc.) to capture the ping message of the local PC, display and analyze it.
In the basic task 1, because our onboard is supposed to communicate with the R4 development board, the network configuration has been completed in the previous task. Since the question requires a static IP, it can be achieved by using Ethernet.begin(mac, staticIP, myDns, gateway, subnet);. The LAN computer can successfully ping Pico
From the Wireshark screenshot, we can see a series of ICMP ping requests. The source address of each request is 192.168.50.76 and the destination address is 192.168.50.200. The length of each ICMP message is 74 bytes.
These requests are sent continuously, and the sequence number (seq) increases one by one, indicating that ping requests are sent continuously from one device to another. The increasing sequence number can help the sender track the matching of responses and requests. ICMP echo requests are used to detect the status of network connections. These requests can determine whether there is a valid network connection between two IP addresses.
You can also ping the homepage of EEWorld
Basic Task 2: The main control board establishes a TCPIP or UDP server, and the LAN PC uses a TCPIP or UDP client to connect and send data. After the main control board receives the data, it sends it to the LCD screen for display (if not, it will be displayed through the serial port print); the interactive message is captured by the packet capture software, displayed and analyzed. (Choose one of TCP and UDP, or operate both)
The establishment of TCPIP server in Task 2 is actually completed in the Getting Started Task, because the communication between Pico and R4 development board is through TCP protocol. We only need to change the IP of R4 development board to the IP of PC.
The Wireshark screenshot shows a series of TCP packets. These packets are transmitted between the source IP address 192.168.50.200 and the destination IP address 192.168.50.76. We can see different TCP flags, including SYN, ACK, and PSH, which are common flags in the TCP three-way handshake and data transmission process.
SYN (Synchronization Sequence Number): Used in the handshake process when establishing a connection. We can see the SYN packet at the beginning of the handshake and the corresponding SYN-ACK reply.
ACK (Acknowledgement): Confirm receipt of the other party's packet. Almost all TCP packets have the ACK flag set.
PSH (Push): prompts the receiving end to push this data to the application immediately instead of waiting for the buffer to fill up.
Data packets from source port 49154 to destination port 80 usually indicate that the client is trying to access the Web service on the server. Port 80 is the standard port for HTTP services. Judging from the length of the data packets, some contain a small amount of data (for example, packets with a length of 2 or 15 bytes), which may contain control information or the transmission of a small amount of data.
This TCP communication mode is a typical interaction between a client and a server, involving connection establishment, data transmission, and final connection termination. Through the analysis of these data packets, the status of the TCP connection, the order and integrity of data transmission, and the performance issues of the connection can be checked.
In the Wireshark packet capture screenshot, we can see two UDP packets. The first packet (number 88) is sent from port 8888 of the source IP address 192.168.50.76 to port 8888 of the destination IP address 192.168.50.200. The length of this packet is 56 bytes, of which the UDP payload data length is 14 bytes. The second packet (number 100) is sent from port 8888 of 192.168.50.200 back to port 8888 of 192.168.50.76, with a length of 60 bytes and a payload data length of 12 bytes.
This indicates that the two devices are communicating using the UDP protocol, with port 8888 used to send and receive data. Since UDP is a connectionless protocol, these messages show the sending of data and possible responses, but there is no guarantee that the data will be delivered. UDP is often used for applications that require fast transmission, such as video streaming or online gaming, rather than error-free data transmission.
Advanced task: synchronize time from NTP server (pay attention to the parsing of data exchange format), obtain time and send it to display screen (serial port) for display.
In the advanced task, you can complete it by making some changes to the sample program. The following is the specific effect. It can be seen that pico can normally obtain Beijing time and output it on the serial port and R4 dot matrix.
Ultimate Mission (Choose One)
■ Ultimate Task 2: Use external storage to build a simple FTP file server that can upload and download files normally.
The ultimate task: Because the logistics in my hometown stopped during the Chinese New Year, and there was no ready-made SD card module, I wanted to do task 1, but found that it was very troublesome to call the Digi-Key API. It must be https and there are various verification problems. I happened to see a site that can use the Pico onboard external memory to implement FTP, so I copied the homework directly. This is done with MicroPython.
import socket
import network
import uos
import gc
from time import localtime
from machine import Pin,SPI
import time
def w5x00_init():
#spi init
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)#network active
nic.ifconfig(('192.168.50.200','255.255.255.0','192.168.50.1','192.168.50.1'))#Set static network address information
while not nic.isconnected():
time.sleep(1)
print(nic.regs())#Print register information
#Print network address information
print("IP Address:",nic.ifconfig()[0])
print("Subnet Mask:",nic.ifconfig()[1])
print("Gateway:",nic.ifconfig()[2])
print("DNS:",nic.ifconfig()[3])
return nic
month_name = ["", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
def send_list_data(path, dataclient, full):
try: # whether path is a directory name
for fname in uos.listdir(path):
dataclient.sendall(make_description(path, fname, full))
except: # path may be a file name or pattern
pattern = path.split("/")[-1]
path = path[:-(len(pattern) + 1)]
if path == "": path = "/"
for fname in uos.listdir(path):
if fncmp(fname, pattern) == True:
dataclient.sendall(make_description(path, fname, full))
def make_description(path, fname, full):
if full:
stat = uos.stat(get_absolute_path(path,fname))
file_permissions = "drwxr-xr-x" if (stat[0] & 0o170000 == 0o040000) else "-rw-r--r--"
file_size = stat[6]
tm = localtime(stat[7])
if tm[0] != localtime()[0]:
description = "{} 1 owner group {:>10} {} {:2} {:>5} {}\r\n".format(
file_permissions, file_size, month_name[tm[1]], tm[2], tm[0], fname)
else:
description = "{} 1 owner group {:>10} {} {:2} {:02}:{:02} {}\r\n".format(
file_permissions, file_size, month_name[tm[1]], tm[2], tm[3], tm[4], fname)
else:
description = fname + "\r\n"
return description
def send_file_data(path, dataclient):
with open(path, "r") as file:
chunk = file.read(512)
while len(chunk) > 0:
dataclient.sendall(chunk)
chunk = file.read(512)
def save_file_data(path, dataclient, mode):
with open(path, mode) as file:
chunk = dataclient.read(512)
while len(chunk) > 0:
file.write(chunk)
chunk = dataclient.read(512)
def get_absolute_path(cwd, payload):
# Just a few special cases "..", "." and ""
# If payload start's with /, set cwd to /
# and consider the remainder a relative path
if payload.startswith('/'):
cwd = "/"
for token in payload.split("/"):
if token == '..':
if cwd != '/':
cwd = '/'.join(cwd.split('/')[:-1])
if cwd == '':
cwd = '/'
elif token != '.' and token != '':
if cwd == '/':
cwd += token
else:
cwd = cwd + '/' + token
return cwd
# compare fname against pattern. Pattern may contain
# wildcards ? and *.
def fncmp(fname, pattern):
pi = 0
si = 0
while pi < len(pattern) and si < len(fname):
if (fname[si] == pattern[pi]) or (pattern[pi] == '?'):
si += 1
pi += 1
else:
if pattern[pi] == '*': # recurse
if (pi + 1) == len(pattern):
return True
while si < len(fname):
if fncmp(fname[si:], pattern[pi+1:]) == True:
return True
else:
si += 1
return False
else:
return False
if pi == len(pattern.rstrip("*")) and si == len(fname):
return True
else:
return False
def ftpserver():
DATA_PORT = 13333
ftpsocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
datasocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
ftpsocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
datasocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
ftpsocket.bind(socket.getaddrinfo("0.0.0.0", 21)[0][4])
datasocket.bind(socket.getaddrinfo("0.0.0.0", DATA_PORT)[0][4])
ftpsocket.listen(1)
datasocket.listen(1)
datasocket.settimeout(10)
msg_250_OK = '250 OK\r\n'
msg_550_fail = '550 Failed\r\n'
try:
dataclient = None
fromname = None
while True:
cl, remote_addr = ftpsocket.accept()
cl.settimeout(300)
cwd = '/'
try:
# print("FTP connection from:", remote_addr)
cl.sendall("220 Hello, this is the ESP8266.\r\n")
while True:
gc.collect()
data = cl.readline().decode("utf-8").rstrip("\r\n")
if len(data) <= 0:
print("Client disappeared")
break
command = data.split(" ")[0].upper()
payload = data[len(command):].lstrip()
path = get_absolute_path(cwd, payload)
print("Command={}, Payload={}, Path={}".format(command, payload, path))
if command == "USER":
cl.sendall("230 Logged in.\r\n")
elif command == "SYST":
cl.sendall("215 UNIX Type: L8\r\n")
elif command == "NOOP":
cl.sendall("200 OK\r\n")
elif command == "FEAT":
cl.sendall("211 no-features\r\n")
elif command == "PWD":
cl.sendall('257 "{}"\r\n'.format(cwd))
elif command == "CWD":
try:
files = uos.listdir(path)
cwd = path
cl.sendall(msg_250_OK)
except:
cl.sendall(msg_550_fail)
elif command == "CDUP":
cwd = get_absolute_path(cwd, "..")
cl.sendall(msg_250_OK)
elif command == "TYPE":
# probably should switch between binary and not
cl.sendall('200 Transfer mode set\r\n')
elif command == "SIZE":
try:
size = uos.stat(path)[6]
cl.sendall('213 {}\r\n'.format(size))
except:
cl.sendall(msg_550_fail)
elif command == "QUIT":
cl.sendall('221 Bye.\r\n')
break
elif command == "PASV":
addr = nic.ifconfig()[0]
cl.sendall('227 Entering Passive Mode ({},{},{}).\r\n'.format(
addr.replace('.',','), DATA_PORT>>8, DATA_PORT%256))
dataclient, data_addr = datasocket.accept()
# print("FTP Data connection from:", data_addr)
elif command == "LIST" or command == "NLST":
if not payload.startswith("-"):
place = path
else:
place = cwd
try:
send_list_data(place, dataclient, command == "LIST" or payload == "-l")
cl.sendall("150 Here comes the directory listing.\r\n")
cl.sendall("226 Listed.\r\n")
except:
cl.sendall(msg_550_fail)
if dataclient is not None:
dataclient.close()
dataclient = None
elif command == "RETR":
try:
send_file_data(path, dataclient)
cl.sendall("150 Opening data connection.\r\n")
cl.sendall("226 Transfer complete.\r\n")
except:
cl.sendall(msg_550_fail)
if dataclient is not None:
dataclient.close()
dataclient = None
elif command == "STOR":
try:
cl.sendall("150 Ok to send data.\r\n")
save_file_data(path, dataclient, "w")
cl.sendall("226 Transfer complete.\r\n")
except:
cl.sendall(msg_550_fail)
if dataclient is not None:
dataclient.close()
dataclient = None
elif command == "APPE":
try:
cl.sendall("150 Ok to send data.\r\n")
save_file_data(path, dataclient, "a")
cl.sendall("226 Transfer complete.\r\n")
except:
cl.sendall(msg_550_fail)
if dataclient is not None:
dataclient.close()
dataclient = None
elif command == "DELE":
try:
uos.remove(path)
cl.sendall(msg_250_OK)
except:
cl.sendall(msg_550_fail)
elif command == "RMD":
try:
uos.rmdir(path)
cl.sendall(msg_250_OK)
except:
cl.sendall(msg_550_fail)
elif command == "MKD":
try:
uos.mkdir(path)
cl.sendall(msg_250_OK)
except:
cl.sendall(msg_550_fail)
elif command == "RNFR":
fromname = path
cl.sendall("350 Rename from\r\n")
elif command == "RNTO":
if fromname is not None:
try:
uos.rename(fromname, path)
cl.sendall(msg_250_OK)
except:
cl.sendall(msg_550_fail)
else:
cl.sendall(msg_550_fail)
fromname = None
else:
cl.sendall("502 Unsupported command.\r\n")
# print("Unsupported command {} with payload {}".format(command, payload))
except Exception as err:
print(err)
finally:
cl.close()
cl = None
finally:
datasocket.close()
ftpsocket.close()
if dataclient is not None:
dataclient.close()
nic = w5x00_init()
ftpserver()
Source code: https://download.eeworld.com.cn/detail/eew_nkXjf8/631128
|