- 2024-10-07
-
发表了主题帖:
【Follow me第二季第2期】任务提交:智能家居-环境监测
本帖最后由 太阳上的骑士 于 2024-10-7 21:19 编辑
一、项目视频
[localvideo]3b5db9e50f032066e61df62f28e1622a[/localvideo]
EE大学堂视频链接:
https://training.eeworld.com.cn/course/68689
二、任务实现
2.1 物料清单
这次的物料主要是Arduino UNO R4 WiFi开发板和SHT40温湿度传感器扩展板。
2.2.1 入门任务:搭建环境并开启第一步Blink
Arduino IDE下载地址:https://www.arduino.cc/en/software
下载页面选择适合自己操作系统的软件版本,我的是Windows 11,下载的是Windows版。下载后安装Arduino IDE软件并打开,在boards manager搜索UNO R4安装开发板对应的包。至此Arduino UNO R4 WiFi的软件开发环境搭建完成。
下面实现LED Blink,硬件如下:
软件流程图如下:
软件如下:
// the setup function runs once when you press reset or power the board
void setup() {
// initialize digital pin LED_BUILTIN as an output.
pinMode(LED_BUILTIN, OUTPUT);
}
// the loop function runs over and over again forever
void loop() {
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
}
电脑连接开发板,Arduino IDE选择开发板进行连接,编译下载,运行效果如下:
2.2.2 入门任务:串口打印Hello EEWorld!
Arduino UNO R4 WiFi开发板串口使用需要先对串口进行初始化设置,初始化完成后就可以通过串口和外界通信。
软件流程图如下:
代码如下:
void setup() {
// start serial port at 9600 bps and wait for port to open:
Serial.begin(115200);
}
void loop() {
Serial.println("Hello EEWorld!"); // send an initial string
delay(300);
}
编译下载,打开Arduino IDE的Serial Monitor,运行效果如下:
2.3.1 基础任务:驱动12x8点阵LED
Arduino UNO R4 WiFi内置12x8整列LED。硬件如下:
控制LED矩阵灯需要创建帧,然后将帧加载到缓冲区。
要使用LED矩阵库,需要包含#include "Arduino_LED_Matrix.h",
该库提供两种控制方式,一种是创建二维数组,这种方式每个LED需要占用一个字节的内存,内存占用较多。还有一种方式是用3个32bit数据总共96bit数据来控制LED,每个LED占用1bit。
下面代码使所有灯一起闪烁。
软件流程图如下:
软件如下:
#include "Arduino_LED_Matrix.h"
ArduinoLEDMatrix matrix;
void setup() {
Serial.begin(115200);
matrix.begin();
}
const uint32_t lighton[] = {
0,
0,
0
};
const uint32_t lightoff[] = {
0xffffffff,
0xffffffff,
0xffffffff
};
void loop(){
matrix.loadFrame(lighton);
delay(500);
matrix.loadFrame(lightoff);
delay(500);
}
运行效果如下:
也可以安装ArduinoGraphics来打印字符。
软件如下:
// To use ArduinoGraphics APIs, please include BEFORE Arduino_LED_Matrix
#include "ArduinoGraphics.h"
#include "Arduino_LED_Matrix.h"
ArduinoLEDMatrix matrix;
void setup() {
Serial.begin(115200);
matrix.begin();
matrix.beginDraw();
matrix.stroke(0xFFFFFFFF);
delay(2000);
}
void loop() {
// Make it scroll!
matrix.beginDraw();
matrix.stroke(0xFFFFFFFF);
matrix.textScrollSpeed(50);
// add the text
const char text[] = " I Love China!";
matrix.textFont(Font_5x7);
matrix.beginText(0, 1, 0xFFFFFF);
matrix.println(text);
matrix.endText(SCROLL_LEFT);
matrix.endDraw();
}
运行效果如下:
Arduino还提供LED Matrix tool制作动画功能,网页所见即所得,首先给开发板烧录LivePreview例程,再在
https://ledmatrix-editor.arduino.cc/?_gl=1*1ils84i*_gcl_au*MTU0NDk3MDEuMTcyNzcwNjE2NA..*FPAU*MTU0NDk3MDEuMTcyNzcwNjE2NA..*_ga*MTU3MjI3MjE4OC4xNzI3NzA2MTYy*_ga_NEXN8H46L5*MTcyNzc2OTIxNS4zLjEuMTcyNzc3MDQwMC4wLjAuMzc5NzEwMjkw*_fplc*ZzNEYlAwVDc2T3M2cXpUQ3BIZENicFhaOFVoTjZhN3hRTTJVaWVYUXZGaEFZMzB1QzRPcFUwc0N2U3k3bnZ6OUlsOHNsQnJBeXdlNWhsd2xicVpTV2VjSEZ6NGNuYW8lMkJPeEh6VGJkRFRySGdyd0dMb3RIM2V2bllEZWJacEElM0QlM0Q.
里绘制动画页面,连接开发板显示,如果有出现位置对应不对的情况需要更新开发板固件后就能正常显示。
代码如下:
#include "Arduino_LED_Matrix.h" // Include the LED_Matrix library
ArduinoLEDMatrix matrix; // Create an instance of the ArduinoLEDMatrix class
void setup() {
Serial.begin(115200); // Initialize serial communication at a baud rate of 115200
matrix.begin(); // Initialize the LED matrix
}
// Define an array to hold pixel data for a single frame (4 pixels)
uint32_t frame[] = {
0, 0, 0, 0xFFFF
};
void loop() {
// Check if there are at least 12 bytes available in the serial buffer
if(Serial.available() >= 12){
// Read 4 bytes from the serial buffer and compose them into a 32-bit value for each element in the frame
frame[0] = Serial.read() | Serial.read() << 8 | Serial.read() << 16 | Serial.read() << 24;
frame[1] = Serial.read() | Serial.read() << 8 | Serial.read() << 16 | Serial.read() << 24;
frame[2] = Serial.read() | Serial.read() << 8 | Serial.read() << 16 | Serial.read() << 24;
// Load and display the received frame data on the LED matrix
matrix.loadFrame(frame);
}
}
运行效果如下:
2.3.2 基础任务:用DAC生成正弦波
软件如下:
#include "analogWave.h" // Include the library for analog waveform generation
analogWave wave(DAC); // Create an instance of the analogWave class, using the DAC pin
int freq = 100; // in hertz, change accordingly
void setup() {
Serial.begin(115200); // Initialize serial communication at a baud rate of 115200
wave.amplitude(0.1);
wave.sine(freq); // Generate a sine wave with the initial frequency
}
void loop() {
}
流程图如下:
运行效果如下:
2.3.3 基础任务:用OPAMP放大DAC信号
开发板内置运算放大器,官方给出了电压放大的使用方式,硬件连接为:
放大公式为:
Av = Amplified Voltage (V)
R1 = Resistor connected to Ground (Ω)
R2 = Feedback resistor (Ω)
由于手上没有烙铁工具和洞洞板,所以找了一个开发板上的两个电阻来做:
放大倍数为11倍,放大电压低于4.7V,不会损坏硬件。
软件如下:
#include "analogWave.h" // Include the library for analog waveform generation
#include <OPAMP.h>
analogWave wave(DAC); // Create an instance of the analogWave class, using the DAC pin
int freq = 100; // in hertz, change accordingly
void setup() {
Serial.begin(115200); // Initialize serial communication at a baud rate of 115200
wave.amplitude(0.1);
wave.sine(freq); // Generate a sine wave with the initial frequency
if (!OPAMP.begin(OPAMP_SPEED_HIGHSPEED)) {
Serial.println("Failed to start OPAMP!");
}
}
void loop() {
}
流程图如下:
运行效果如下:
2.3.4 基础任务:用ADC采集并且打印数据到串口等其他接口可上传到上位机显示曲线
串口上位机选择SerialChart,方便观察ADC采样数据。
SerialChart设置如下:
[_setup_]
port=COM11
baudrate=115200
width=1000
height=201
background_color = white
grid_h_origin = 100
grid_h_step = 10
grid_h_color = #EEE
grid_h_origin_color = #CCC
grid_v_origin = 0
grid_v_step = 10
grid_v_color = #EEE
grid_v_origin_color = transparent
[_default_]
min=-20
max=18000
[ch1]
color = green
软件如下:
#include "analogWave.h" // Include the library for analog waveform generation
analogWave wave(DAC); // Create an instance of the analogWave class, using the DAC pin
int sensorPin = A1; // select the input pin for the potentiometer
int sensorValue = 0; // variable to store the value coming from the sensor
void setup() {
// declare the ledPin as an OUTPUT:
Serial.begin(115200); // Initialize serial communication at a baud rate of 115200
wave.sine(10); // Generate a sine wave with the initial frequency
analogReadResolution(14); //change to 14-bit resolution
}
void loop() {
// read the value from the sensor:
sensorValue = analogRead(sensorPin);
Serial.println(sensorValue);
delay(10); // Delay for one second before repeating
}
流程图如下:
运行效果如下:
2.4 进阶任务:通过Wi-Fi,利用MQTT协议接入到开源的智能家居平台HA(HomeAssistant)
虚拟机安装Ubuntu,Ubuntu下安装docker,docker拉取Home Assistant镜像和EMQX镜像。
环境搭建好以后开发板一直连不上EMQX,但是Ping能Ping通,尝试了两天后怀疑是虚拟机的问题,所以后面使用Windows 11来实现。
Win11安装docker
测试两个容器运行正常
搭建环境好以后测试,开发板还是连不上EMQX,然后使用MQTTX来模拟连接,还是连接不上,怀疑是HOST IP设置问题,尝试172.17.0.3不行,后又尝试localhost使用MQTTX能连接上,172.28.112.1使用MQTTX能连上,但是使用开发板使用172.28.112.1还是连不上。最终找到HOST IP需要设置为电脑网卡IP:192.168.31.7。
代码参考https://www.hackster.io/virgilvox/mqtt-with-the-arduino-uno-r4-wifi-and-emqx-2639f9,唯一遇到的问题是开发板连上WiFi后需要延时再连接MQTT,否则会报错。
软件如下:
#include "WiFiS3.h"
#include <ArduinoMqttClient.h>
char ssid[] = "***"; // your network SSID (name)
char pass[] = "***"; // your network password
char mqtt_user[] = "test";
char mqtt_pass[] = "test";
WiFiClient wifiClient;
MqttClient mqttClient(wifiClient);
const char broker[] = "192.168.31.7"; //IP address of the EMQX broker.
int port = 1883;
const char subscribe_topic[] = "UNO/arduino/myButtonA/cmd_t";
const char publish_topic[] = "UNO/arduino/myButtonA/cmd_t";
void setup() {
// Create serial connection and wait for it to become available.
Serial.begin(115200);
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, LOW );
while (!Serial) {
;
}
// Connect to WiFi
Serial.print("Attempting to connect to WPA SSID: ");
Serial.println(ssid);
while (WiFi.begin(ssid, pass) != WL_CONNECTED) {
// failed, retry
Serial.print(".");
delay(5000);
}
Serial.println("You're connected to the network");
Serial.println();
delay(2000);
// You can provide a username and password for authentication
mqttClient.setUsernamePassword(mqtt_user, mqtt_pass);
Serial.print("Attempting to connect to the MQTT broker.");
if (!mqttClient.connect(broker, port)) {
Serial.print("MQTT connection failed! Error code = ");
Serial.println(mqttClient.connectError());
while (1);
}
Serial.println("You're connected to the MQTT broker!");
Serial.print("Subscribing to topic: ");
Serial.println(subscribe_topic);
// subscribe to a topic
mqttClient.subscribe(subscribe_topic);
// topics can be unsubscribed using:
// mqttClient.unsubscribe(topic);
Serial.print("Waiting for messages on topic: ");
Serial.println(subscribe_topic);
}
void loop() {
static bool state = false;
int messageSize = mqttClient.parseMessage();
if (messageSize) {
// use the Stream interface to print the contents
while (mqttClient.available()) {
Serial.print((char)mqttClient.read());
}
Serial.println();
state = ~state;
if(state)
digitalWrite(LED_BUILTIN, HIGH );
else
digitalWrite(LED_BUILTIN, LOW );
}
// send message, the Print interface can be used to set the message contents
// delay(1000);
// mqttClient.beginMessage(publish_topic);
// mqttClient.print(random(1000));
// mqttClient.endMessage();
}
流程图如下:
运行效果如下:
2.5 扩展任务:通过外部SHT40温湿度传感器,上传温湿度到HA,通过HA面板显示数据
安装SHT40库:
配置文件添加信息:
- unique_id: SHT40
name: "SHT40_Template"
state_topic: "UNO/arduino/sht40/template"
unit_of_measurement: "℃"
value_template: "{{ value }}"
软件如下:
#include "WiFiS3.h"
#include <ArduinoMqttClient.h>
#include "DFRobot_SHT40.h"
DFRobot_SHT40 SHT40(SHT40_AD1B_IIC_ADDR);
uint32_t id = 0;
float temperature, humidity;
char ssid[] = "***"; // your network SSID (name)
char pass[] = "***"; // your network password
char mqtt_user[] = "test";
char mqtt_pass[] = "test";
WiFiClient wifiClient;
MqttClient mqttClient(wifiClient);
const char broker[] = "192.168.31.7"; //IP address of the EMQX broker.
int port = 1883;
const char subscribe_topic[] = "UNO/arduino/sht40/template";
const char publish_topic[] = "UNO/arduino/sht40/template";
void setup() {
// Create serial connection and wait for it to become available.
Serial.begin(115200);
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, LOW );
SHT40.begin();
while((id = SHT40.getDeviceID()) == 0){
Serial.println("ID retrieval error, please check whether the device is connected correctly!!!");
delay(1000);
}
while (!Serial) {
;
}
// Connect to WiFi
Serial.print("Attempting to connect to WPA SSID: ");
Serial.println(ssid);
while (WiFi.begin(ssid, pass) != WL_CONNECTED) {
// failed, retry
Serial.print(".");
delay(5000);
}
Serial.println("You're connected to the network");
Serial.println();
delay(2000);
// You can provide a username and password for authentication
mqttClient.setUsernamePassword(mqtt_user, mqtt_pass);
Serial.print("Attempting to connect to the MQTT broker.");
if (!mqttClient.connect(broker, port)) {
Serial.print("MQTT connection failed! Error code = ");
Serial.println(mqttClient.connectError());
while (1);
}
Serial.println("You're connected to the MQTT broker!");
Serial.print("Subscribing to topic: ");
Serial.println(subscribe_topic);
// subscribe to a topic
mqttClient.subscribe(subscribe_topic);
// topics can be unsubscribed using:
// mqttClient.unsubscribe(topic);
Serial.print("Waiting for messages on topic: ");
Serial.println(subscribe_topic);
}
// void update_sensor(int value){
// StaticJsonDocument<200> doc;
// int a = value*100/1024;
// open_window(a);
// doc["light"] = a;
// String payload;
// serializeJson(doc, payload);
// mqttClient.beginMessage("homeassistant/sensor/light");
// mqttClient.print(payload.c_str());
// mqttClient.print("\0");
// mqttClient.endMessage();
// }
unsigned long previousMillis = 0;
void loop() {
static bool state = false;
unsigned long currentMillis = millis();
int messageSize = mqttClient.parseMessage();
if (messageSize) {
// use the Stream interface to print the contents
while (mqttClient.available()) {
Serial.print((char)mqttClient.read());
}
Serial.println();
state = ~state;
if(state)
digitalWrite(LED_BUILTIN, HIGH );
else
digitalWrite(LED_BUILTIN, LOW );
}
if (currentMillis - previousMillis >= 1000)
{
previousMillis = currentMillis;
temperature = SHT40.getTemperature(/*mode = */PRECISION_HIGH);
humidity = SHT40.getHumidity(/*mode = */PRECISION_HIGH);
Serial.print("Temperature :"); Serial.print(temperature); Serial.println(" C");
Serial.print("Humidity :"); Serial.print(humidity); Serial.println(" %RH");
mqttClient.beginMessage("UNO/arduino/sht40/template");
mqttClient.print(temperature);
mqttClient.print("\0");
mqttClient.endMessage();
}
// int time = 0;
// temperature = SHT40.getTemperature(/*mode = */PRECISION_HIGH);
// humidity = SHT40.getHumidity(/*mode = */PRECISION_HIGH);
// Serial.print("Temperature :"); Serial.print(temperature); Serial.println(" C");
// Serial.print("Humidity :"); Serial.print(humidity); Serial.println(" %RH");
// delay(1000);
}
流程图如下:
运行效果如下:
2.6 心得体会
很感谢EEWORLD和得捷举办这次活动,让我有机会实际使用Docker和MQTT,这些都是以前有听过但没实际尝试过,期待在以后的生产环境中运用这些工具。
三、可编译下载的代码
源代码在EEWORLD论坛下载中心链接:
https://download.eeworld.com.cn/detail/%E5%A4%AA%E9%98%B3%E4%B8%8A%E7%9A%84%E9%AA%91%E5%A3%AB/634554
-
上传了资料:
Follow me第二季第2期可编译运行的代码
-
上传了资料:
【Follow me第二季第2期】任务提交:智能家居-环境监测源代码
-
加入了学习《Follow me第四期短视频》,观看 Follow me第四期短视频
- 2024-10-06
-
加入了学习《【Follow me第二季第2期】Arduino UNO R4 WiF》,观看 【Follow me第二季第2期】Arduino UNO R4 WiF
- 2024-09-29
-
加入了学习《Digi-Key: Follow Me 系列(2) 直播回放》,观看 Adafruit ESP32-S3 TFT Feather开发板使用入门
- 2024-08-28
-
回复了主题帖:
>>征集 | 使用 MCU,哪些问题最令你头大?
使用 MCU,最大的痛点是价格和配置之间的平衡很费时间,每次为了找满足功能要求又价格最低的芯片费很多时间,并且还需要花时间去验证选型MCU。再一个痛点是不同厂家的MCU开发模式不一样,需要适应不同MCU开发方式。
- 2024-07-15
-
回复了主题帖:
(已结束)1个掉了按键焊盘的瑞萨RA8D1板卡,能修的网友来拿
这个好修,看原理图可以知道这个按键是P008,从您那个图能看到只是掉了一个焊盘,如果不是离MCU IO较近的焊盘就不影响按键功能,直接焊上就行,不需要怎么修。
如果运气不好,掉的焊盘是连接MCU IO近的焊盘,问题也不大。从板子正反面能看出,和按键配和的电阻和ESD防护器件不在一面,说明他们通过过孔连接,只需要找到那个过孔把过孔表面的阻焊挂掉,飞一根漆包线连接过孔和按键剩下的那个焊盘也能解决问题。
这个我这能修,设备都齐全~
修好后也能分享几篇测评报告。
- 2024-07-10
-
加入了学习《DigiKey 应用说:蓝牙5.4 新特性解读及实例演示》,观看 蓝牙5.4 新特性解读及实例演示
- 2024-03-01
-
加入了学习《【得捷电子Follow me第2期】任务合集(可选任务:24颗流水灯)》,观看 【得捷电子Follow me第2期】任务合集(可选任务:24颗流水灯动画)(修改)
-
加入了学习《【得捷电子Follow me第2期】任务合集(可选任务:24颗流水灯)》,观看 【得捷电子Follow me第2期】任务合集(可选任务:24颗流水灯)(修改)
- 2024-02-21
-
回复了主题帖:
【得捷Follow me第4期】项目总结
吾妻思萌 发表于 2024-2-21 06:34
gpio口设置问题?
应该是固件使用了这个I/O,我看论坛有用W5500那个接口能驱动屏幕,但W5500和屏幕项目都要用,只能二选一了
- 2024-02-20
-
回复了主题帖:
【得捷Follow me第4期】项目总结
wangerxian 发表于 2024-2-20 17:36
这一整套学习下来,感觉以后都可以开发一个不错的项目了。
没用MicroPython直接驱动屏幕挺遗憾的,主要是时间太紧了,后面有时间再试试开发板直接驱动屏幕~
-
回复了主题帖:
【得捷Follow me第4期】项目总结
bitter 发表于 2024-2-20 21:05
根据此链接用W5500-EVB-Pico开发板使用CircuitPython一直没有驱动起来此屏幕,报GP10已经使用了的错误,网 ...
试显示屏驱动的时候开发板是烧录的CircuitPython的固件,估计此CircuitPython固件把GP10用作了其它外设,因为对CircuitPython不是很了解,试了一天没解决,最后换Due开发板来驱动屏幕了。
-
发表了主题帖:
【得捷Follow me第4期】项目总结
很高兴能参加得捷电子Follow me第4期活动,这次活动我使用MicroPython进行开发,相关的软件和源代码附在最后。
一、入门任务
1、固件下载
首先去MicroPython官网下载W5500-EVB-Pico开发板固件,固件下载网址如下:
https://micropython.org/download/W5500_EVB_PICO/
可以看到有很多版本固件可供使用,这里我选择v1.22.1版本。
2、IDE下载安装
W5500-EVB-Pico开发板MicroPython Getting Started网址如下:
https://github.com/Wiznet/RP2040-HAT-MicroPython/blob/main/Ethernet%20Example%20Getting%20Started%20%5BMicropython%5D.md
根据此开发板Getting Started的推荐,开发IDE选择Thonny,Thonny同时支持Windows、Mac和Linux,因为我用的是Windows系统,所以我下载thonny-4.1.4.exe (21 MB)版本。
Thonny下载网址如下:
https://thonny.org/
Thonny安装完成后会有和技术不相关的东西,可以按照此链接操作对此进行屏蔽,链接如下:
https://zhuanlan.zhihu.com/p/643865344
3、固件烧录
开发板通过micro USB线接电脑,按住BOOTSEL键后再短按一下RUN键,最后松开BOOTSEL键,电脑会将开发板识别成U盘。
将前面下载好的固件复制到此U盘,复制完成后开发板会自动重启,至此固件烧录完成。
4、BLINK
打开Thonny,通过软件右下角可以选择要开发的设备和端口,这里我的是COM8。
Shell窗口会显示固件版本。
在编辑区写入BLINK代码,从原理图能看出LED控制引脚是25号引脚,所以代码如下:
from machine import Pin
import network
import time
led = Pin(25, Pin.OUT)
def main():
while True:
led.value(1)
time.sleep(1)
led.value(0)
time.sleep(1)
if __name__ == "__main__":
main()
运行效果如下:
[localvideo]ac8d93a14b2706eef63acc709e4ffb89[/localvideo]
5、驱动液晶显示器
这是Adafruit Sharp Memory Display Breakout使用说明链接如下:
https://learn.adafruit.com/adafruit-sharp-memory-display-breakout/overview
根据此链接用W5500-EVB-Pico开发板使用CircuitPython一直没有驱动起来此屏幕,报GP10已经使用了的错误,网上找了一圈没有找到解决办法,想到自己手里还有一块Arduino DUE开发板,所以根据屏幕的使用说明用Arduino进行驱动,接线如下:
Microcontroller GND to LCD Gnd
Microcontroller 5V to LCD Vin
Microcontroller D13 to LCD Clk
Microcontroller D11 to LCD DI
Microcontroller D10 to LCD CS
Arduino IDE下载链接如下:
https://www.arduino.cc/en/software
这里根据自己的平台下载相应的版本,这里我下载Windows版
安装DUE开发板包:
安装Sharp Memory Display Library库:
弹出选项选INSTALL ALL:
打开Arduino显示屏对应的显示例程:
编译下载,对应的显示效果如下
/*********************************************************************
This is an example sketch for our Monochrome SHARP Memory Displays
Pick one up today in the adafruit shop!
------> http://www.adafruit.com/products/1393
These displays use SPI to communicate, 3 pins are required to
interface
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!
Written by Limor Fried/Ladyada for Adafruit Industries.
BSD license, check license.txt for more information
All text above, must be included in any redistribution
*********************************************************************/
#include <Adafruit_GFX.h>
#include <Adafruit_SharpMem.h>
// any pins can be used
#define SHARP_SCK 13
#define SHARP_MOSI 11
#define SHARP_SS 10
// Set the size of the display here, e.g. 144x168!
Adafruit_SharpMem display(SHARP_SCK, SHARP_MOSI, SHARP_SS, 144, 168);
// The currently-available SHARP Memory Display (144x168 pixels)
// requires > 4K of microcontroller RAM; it WILL NOT WORK on Arduino Uno
// or other <4K "classic" devices! The original display (96x96 pixels)
// does work there, but is no longer produced.
#define BLACK 0
#define WHITE 1
int minorHalfSize; // 1/2 of lesser of display width or height
void setup(void)
{
Serial.begin(9600);
Serial.println("Hello!");
// start & clear the display
display.begin();
display.clearDisplay();
// Several shapes are drawn centered on the screen. Calculate 1/2 of
// lesser of display width or height, this is used repeatedly later.
minorHalfSize = min(display.width(), display.height()) / 2;
// draw a single pixel
display.drawPixel(10, 10, BLACK);
display.refresh();
delay(500);
display.clearDisplay();
// draw many lines
testdrawline();
delay(500);
display.clearDisplay();
// draw rectangles
testdrawrect();
delay(500);
display.clearDisplay();
// draw multiple rectangles
testfillrect();
display.refresh();
delay(500);
display.clearDisplay();
// draw a circle, 10 pixel radius
display.fillCircle(display.width()/2, display.height()/2, 10, BLACK);
display.refresh();
delay(500);
display.clearDisplay();
testdrawroundrect();
display.refresh();
delay(500);
display.clearDisplay();
testfillroundrect();
display.refresh();
delay(500);
display.clearDisplay();
testdrawtriangle();
display.refresh();
delay(500);
display.clearDisplay();
testfilltriangle();
display.refresh();
delay(500);
display.clearDisplay();
testdrawchar();
display.refresh();
for(int i=0; i<4; i++) {
display.refresh();
delay(500);
}
}
void loop(void)
{
for(int i=0; i<4; i++) {
display.setRotation(i);
display.clearDisplay();
// text display tests
display.setTextSize(1);
display.setTextColor(BLACK);
display.setCursor(0,0);
display.println("Hello, world!");
display.setTextColor(WHITE, BLACK); // inverted text
display.println(3.141592);
display.setTextSize(2);
display.setTextColor(BLACK);
display.print("0x"); display.println(0xDEADBEEF, HEX);
// Screen must be refreshed at least once per second
for(int j=0; j<4; j++) {
display.refresh();
delay(500); // 1/2 sec delay
} // x4 = 2 second pause between rotations
}
}
///
void testdrawline() {
for (int i=0; i<display.width(); i+=4) {
display.drawLine(0, 0, i, display.height()-1, BLACK);
display.refresh();
}
for (int i=0; i<display.height(); i+=4) {
display.drawLine(0, 0, display.width()-1, i, BLACK);
display.refresh();
}
delay(250);
display.clearDisplay();
for (int i=0; i<display.width(); i+=4) {
display.drawLine(0, display.height()-1, i, 0, BLACK);
display.refresh();
}
for (int i=display.height()-1; i>=0; i-=4) {
display.drawLine(0, display.height()-1, display.width()-1, i, BLACK);
display.refresh();
}
delay(250);
display.clearDisplay();
for (int i=display.width()-1; i>=0; i-=4) {
display.drawLine(display.width()-1, display.height()-1, i, 0, BLACK);
display.refresh();
}
for (int i=display.height()-1; i>=0; i-=4) {
display.drawLine(display.width()-1, display.height()-1, 0, i, BLACK);
display.refresh();
}
delay(250);
display.clearDisplay();
for (int i=0; i<display.height(); i+=4) {
display.drawLine(display.width()-1, 0, 0, i, BLACK);
display.refresh();
}
for (int i=0; i<display.width(); i+=4) {
display.drawLine(display.width()-1, 0, i, display.height()-1, BLACK);
display.refresh();
}
delay(250);
}
void testdrawrect(void) {
for (int i=0; i<minorHalfSize; i+=2) {
display.drawRect(i, i, display.width()-2*i, display.height()-2*i, BLACK);
display.refresh();
}
}
void testfillrect(void) {
uint8_t color = BLACK;
for (int i=0; i<minorHalfSize; i+=3) {
// alternate colors
display.fillRect(i, i, display.width()-i*2, display.height()-i*2, color&1);
display.refresh();
color++;
}
}
void testdrawroundrect(void) {
for (int i=0; i<minorHalfSize/2; i+=2) {
display.drawRoundRect(i, i, display.width()-2*i, display.height()-2*i, minorHalfSize/2, BLACK);
display.refresh();
}
}
void testfillroundrect(void) {
uint8_t color = BLACK;
for (int i=0; i<minorHalfSize/2; i+=2) {
display.fillRoundRect(i, i, display.width()-2*i, display.height()-2*i, minorHalfSize/2, color&1);
display.refresh();
color++;
}
}
void testdrawtriangle(void) {
for (int i=0; i<minorHalfSize; i+=5) {
display.drawTriangle(display.width()/2, display.height()/2-i,
display.width()/2-i, display.height()/2+i,
display.width()/2+i, display.height()/2+i, BLACK);
display.refresh();
}
}
void testfilltriangle(void) {
uint8_t color = BLACK;
for (int i=minorHalfSize; i>0; i-=5) {
display.fillTriangle(display.width()/2 , display.height()/2-i,
display.width()/2-i, display.height()/2+i,
display.width()/2+i, display.height()/2+i, color & 1);
display.refresh();
color++;
}
}
void testdrawchar(void) {
display.setTextSize(1);
display.setTextColor(BLACK);
display.setCursor(0,0);
display.cp437(true);
for (int i=0; i < 256; i++) {
if (i == '\n') continue;
display.write(i);
}
display.refresh();
}
显示效果如下:
[localvideo]e4609feefac92fe7a759d6d36629010c[/localvideo]
二、基础任务一
1、W5500使用
参考W5500-EVB-Pico开发板MicroPython Getting Started例程对W5500初始化(静态IP配置),网址如下:
https://github.com/Wiznet/RP2040-HAT-MicroPython/blob/main/Ethernet%20Example%20Getting%20Started%20%5BMicropython%5D.md
from machine import Pin,SPI
import network
import time
import uping
led = Pin(25, Pin.OUT)
#W5x00 chip init
def w5x00_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)
nic.ifconfig(('192.168.31.120','255.255.255.0','192.168.31.1','8.8.8.8'))
while not nic.isconnected():
time.sleep(1)
print(nic.regs())
print(nic.ifconfig())
def main():
w5x00_init()
uping.ping('baidu.com')
while True:
led.value(1)
time.sleep(1)
led.value(0)
time.sleep(1)
if __name__ == "__main__":
main()
运行结果如图
使用局域网电脑ping通开发板结果如图:
开发板想要ping通互联网站点,需要添加uping.py文件,此文件下载网址如下:
https://gist.github.com/shawwwn/91cc8979e33e82af6d99ec34c38195fb
下载好文件后将文件保存进开发板即可。
W5500 ping通互联网站点(这里选择ping百度)结果如图:
2、Wireshark下载安装使用
下载Wireshark并安装,软件下载网址如下:
https://www.wireshark.org/download.html
根据自己的平台选择相应的版本,这里我用的是Windows x64 Installer版本。
使用Wireshark抓取PC网卡数据,结果如图:
数据太多了,对关心的数据进行筛选,筛选条件为ip.addr==192.168.31.120(开发板IP),结果如图,ping的数据包就比较清晰了。
可以看到,跟开发板相关的报文有8个,4个请求报文和4个应答报文,报文第一项是对整个报文的描述,第二项为报文前14个字节,分别为本机的MAC地址和路由器的MAC地址:
接下来的20个字节为IP报文:
关于IP报文的格式如下:
最后是IP报文的数据段,也就是ICMP报文:
三、基础任务二
1、开发板建立TCPIP服务器,并接收数据
参考W5500-EVB-Pico开发板MicroPython Getting Started例程用开发板创建TCP服务器,用网络调试助手创建TCP客户端连接开发板并发送数据
https://github.com/Wiznet/RP2040-HAT-MicroPython/blob/main/Ethernet%20Example%20Getting%20Started%20%5BMicropython%5D.md
from usocket import socket
from machine import Pin,SPI
import network
import time
#W5x00 chip init
def w5x00_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)
#None DHCP
nic.ifconfig(('192.168.31.120','255.255.255.0','192.168.31.1','8.8.8.8'))
#DHCP
#nic.ifconfig('dhcp')
print('IP address :', nic.ifconfig())
while not nic.isconnected():
time.sleep(1)
#print(nic.regs())
def server_loop():
s = socket()
s.bind(('192.168.31.120', 5000)) #Source IP Address
s.listen(5)
print("TEST server")
conn, addr = s.accept()
print("Connect to:", conn, "address:", addr)
print("Loopback server Open!")
while True:
data = conn.recv(2048)
print(data.decode('utf-8'))
if data != 'NULL':
conn.send(data)
def client_loop():
s = socket()
s.connect(('192.168.31.2', 5000)) #Destination IP Address
print("Loopback client Connect!")
while True:
data = s.recv(2048)
print(data.decode('utf-8'))
if data != 'NULL' :
s.send(data)
def main():
w5x00_init()
###TCP SERVER###
while True:
server_loop()
###TCP CLIENT###
#client_loop()
if __name__ == "__main__":
main()
运行结果如下:
2、将接收数据送显示屏模块显示
通过串口将W5500-EVB-Pico和Arduino DUE相连,W5500将要显示的内容通过串口发给DUE,DUE驱动屏幕显示。
W5500-EVB-Pico代码:
from usocket import socket
from machine import Pin,SPI,UART
import network
import time
uart = UART(0, baudrate=115200, bits=8, stop=1)
#W5x00 chip init
def w5x00_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)
#None DHCP
nic.ifconfig(('192.168.31.120','255.255.255.0','192.168.31.1','8.8.8.8'))
#DHCP
#nic.ifconfig('dhcp')
print('IP address :', nic.ifconfig())
while not nic.isconnected():
time.sleep(1)
#print(nic.regs())
def server_loop():
s = socket()
s.bind(('192.168.31.120', 5000)) #Source IP Address
s.listen(5)
print("TEST server")
conn, addr = s.accept()
print("Connect to:", conn, "address:", addr)
print("Loopback server Open!")
while True:
data = conn.recv(2048)
print(data.decode('utf-8'))
if data != 'NULL':
uart.write(data)
conn.send(data)
def client_loop():
s = socket()
s.connect(('192.168.31.2', 5000)) #Destination IP Address
print("Loopback client Connect!")
while True:
data = s.recv(2048)
print(data.decode('utf-8'))
if data != 'NULL' :
s.send(data)
def main():
w5x00_init()
#uart.write('hello-world')
###TCP SERVER###
while True:
server_loop()
###TCP CLIENT###
#client_loop()
if __name__ == "__main__":
main()
Arduino DUE代码:
/*********************************************************************
This is an example sketch for our Monochrome SHARP Memory Displays
Pick one up today in the adafruit shop!
------> http://www.adafruit.com/products/1393
These displays use SPI to communicate, 3 pins are required to
interface
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!
Written by Limor Fried/Ladyada for Adafruit Industries.
BSD license, check license.txt for more information
All text above, must be included in any redistribution
*********************************************************************/
#include <Adafruit_GFX.h>
#include <Adafruit_SharpMem.h>
// any pins can be used
#define SHARP_SCK 13
#define SHARP_MOSI 11
#define SHARP_SS 10
// Set the size of the display here, e.g. 144x168!
Adafruit_SharpMem display(SHARP_SCK, SHARP_MOSI, SHARP_SS, 144, 168);
// The currently-available SHARP Memory Display (144x168 pixels)
// requires > 4K of microcontroller RAM; it WILL NOT WORK on Arduino Uno
// or other <4K "classic" devices! The original display (96x96 pixels)
// does work there, but is no longer produced.
#define BLACK 0
#define WHITE 1
int minorHalfSize; // 1/2 of lesser of display width or height
String inString[5]="";
int i = 0;
void setup(void)
{
Serial.begin(115200);
// Serial.println("Hello!");
// start & clear the display
display.begin();
display.clearDisplay();
// testdrawchar();
display.refresh();
for(int i=0; i<4; i++) {
display.refresh();
delay(500);
}
}
void loop(void)
{
while(Serial.available()>0)
{
inString[i] += char(Serial.read());
delay(10); // 延时函数用于等待字符完全进入缓冲区,可以尝试没有延时,输出结果会是什么
}
// 检查是否接收到数据,如果接收到数据,则输出该数据
if(inString[i]!="")
{
i++;
if(i == 5)
{
inString[0] = inString[1];
inString[1] = inString[2];
inString[2] = inString[3];
inString[3] = inString[4];
inString[4] = "";
i = 4;
}
display.setRotation(1);
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(BLACK);
for(int y = 0; y < 4; y++)
{
display.setCursor(4,4 + 15 * y);
display.println(inString[y]);
}
display.refresh();
}
}
3、报文抓取
通过Wirshark抓取的数据包如下图,可以看到发送的数据EEworld在抓取的TCP数据包中。
四、进阶任务
进阶任务比较简单,注意最好选国内ntp服务器,比较稳定,运行结果如图:
W5500-EVB-Pico开发板代码如下:
from usocket import socket
from machine import Pin,SPI,UART,RTC
import network
import time
import ntptime
uart = UART(0, baudrate=115200, bits=8, stop=1)
#W5x00 chip init
def w5x00_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)
#None DHCP
nic.ifconfig(('192.168.31.120','255.255.255.0','192.168.31.1','8.8.8.8'))
#DHCP
#nic.ifconfig('dhcp')
print('IP address :', nic.ifconfig())
while not nic.isconnected():
time.sleep(1)
#print(nic.regs())
def show_local_time(timezone=8):
rtc = RTC()
now = time.time()
now += timezone * 3600
t = time.localtime(now)
print(f'{t[0]} - {t[1]:02d}-{t[2]:02d} {t[3]:02d}:{t[4]:02d}:{t[5]:02d}')
uart.write(f'{t[0]} - {t[1]:02d}-{t[2]:02d} {t[3]:02d}:{t[4]:02d}:{t[5]:02d}')
def main():
w5x00_init()
#先手动设置一个错误时间,模拟系统时间不准
rtc = RTC()
rtc.datetime((2020, 1, 1, 3, 9, 0, 0, 0)) #年、月、日、星期、时、分、秒、亚秒
print('校时前系统时间:')
show_local_time()
#NTP校时
print('开始NTP校时...')
ntptime.host = 'ntp1.aliyun.com'
ntptime.settime()
print(f'校时后系统时间:')
show_local_time()
while True:
show_local_time()
time.sleep(1)
if __name__ == "__main__":
main()
Arduino DUE代码如下:
/*********************************************************************
This is an example sketch for our Monochrome SHARP Memory Displays
Pick one up today in the adafruit shop!
------> http://www.adafruit.com/products/1393
These displays use SPI to communicate, 3 pins are required to
interface
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!
Written by Limor Fried/Ladyada for Adafruit Industries.
BSD license, check license.txt for more information
All text above, must be included in any redistribution
*********************************************************************/
#include <Adafruit_GFX.h>
#include <Adafruit_SharpMem.h>
// any pins can be used
#define SHARP_SCK 13
#define SHARP_MOSI 11
#define SHARP_SS 10
// Set the size of the display here, e.g. 144x168!
Adafruit_SharpMem display(SHARP_SCK, SHARP_MOSI, SHARP_SS, 144, 168);
// The currently-available SHARP Memory Display (144x168 pixels)
// requires > 4K of microcontroller RAM; it WILL NOT WORK on Arduino Uno
// or other <4K "classic" devices! The original display (96x96 pixels)
// does work there, but is no longer produced.
#define BLACK 0
#define WHITE 1
int minorHalfSize; // 1/2 of lesser of display width or height
String inString ="";
int i = 0;
void setup(void)
{
Serial.begin(115200);
// Serial.println("Hello!");
// start & clear the display
display.begin();
display.clearDisplay();
// testdrawchar();
display.refresh();
for(int i=0; i<4; i++) {
display.refresh();
delay(500);
}
}
void loop(void)
{
while(Serial.available()>0)
{
inString += char(Serial.read());
delay(10); // 延时函数用于等待字符完全进入缓冲区,可以尝试没有延时,输出结果会是什么
}
// 检查是否接收到数据,如果接收到数据,则输出该数据
if(inString!="")
{
display.setRotation(1);
display.clearDisplay();
display.setTextSize(2);
display.setTextColor(BLACK);
display.setCursor(4,4);
display.println(inString);
display.refresh();
inString = "";
}
}
[localvideo]8c5d7b0acecf2da41bc0f2623299590f[/localvideo]
四、终极任务二
1、驱动SD卡
首先下载sd卡类,下载网址如下:
https://github.com/micropython/micropython-lib/blob/master/micropython/drivers/storage/sdcard/sdcard.py
将下载的库文件内容复制到Thonny,再存到开发板。
# Filename: tfcard_test.py
import uos # os/uos
import machine
import sdcard
from machine import SPI, Pin
spi = SPI(1, sck=Pin(10), mosi=Pin(11), miso=Pin(12))
cs = Pin(13)
sd = sdcard.SDCard(spi, cs)
# 挂载文件到sd
uos.mount(sd,"/sd")
# 列出MicroSD/TF卡中的目录文件
print(uos.listdir('/sd'))
# 写文件测试
f = open('/sd/test.txt','w',encoding='utf-8')
f.write('MicroSD/TF存储卡访问测试!')
f.close()
# 读文件测试
f = open('/sd/test.txt','r')
print(f.read())
f.close()
运行结果如下:
可以看到开发板挂载了sd卡,并且有了test.txt文件
2、实现简易FTP服务
参考网上的使用MicroPython实现ftp的例子,参考网址如下:
https://blog.csdn.net/jd3096/article/details/123722188
由于参考程序是使用的ESP32来实现的,需要对程序进行一定的修改,主要修改网络初始化,修改完成后运行报超时
最后发现是原例程第186行需要修改addr获取方式,改后程序运行正常,ftp文件服务器也能正常上传和下载文件。
from usocket import socket
from machine import Pin,SPI
import network
import time
import socket
import uos
import gc
import sdcard
from time import localtime
spi = SPI(1, sck=Pin(10), mosi=Pin(11), miso=Pin(12))
cs = Pin(13)
sd = sdcard.SDCard(spi, cs)
# 挂载文件到sd
uos.mount(sd,"/sd")
# 列出MicroSD/TF卡中的目录文件
print(uos.listdir('/sd'))
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)
#None DHCP
nic.ifconfig(('172.22.51.220','255.255.255.0','172.22.51.1','8.8.8.8'))
print('IP address :', nic.ifconfig())
while not nic.isconnected():
time.sleep(1)
#print(nic.regs())
print(nic.ifconfig())
#W5x00 chip init
def w5x00_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)
#None DHCP
nic.ifconfig(('172.22.51.220','255.255.255.0','172.22.51.1','8.8.8.8'))
print('IP address :', nic.ifconfig())
while not nic.isconnected():
time.sleep(1)
#print(nic.regs())
print(nic.ifconfig())
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()
def main():
#w5x00_init()
ftpserver() #直接跑这个就成功建立服务器了
if __name__ == "__main__":
main()
[localvideo]a9a038d59b3ebe3977b3224d44ac3c72[/localvideo]
五、可编译下载的代码
https://download.eeworld.com.cn/detail/%E5%A4%AA%E9%98%B3%E4%B8%8A%E7%9A%84%E9%AA%91%E5%A3%AB/631243
https://download.eeworld.com.cn/detail/%E5%A4%AA%E9%98%B3%E4%B8%8A%E7%9A%84%E9%AA%91%E5%A3%AB/631244
https://download.eeworld.com.cn/detail/%E5%A4%AA%E9%98%B3%E4%B8%8A%E7%9A%84%E9%AA%91%E5%A3%AB/631245
https://download.eeworld.com.cn/detail/%E5%A4%AA%E9%98%B3%E4%B8%8A%E7%9A%84%E9%AA%91%E5%A3%AB/631246
https://download.eeworld.com.cn/detail/%E5%A4%AA%E9%98%B3%E4%B8%8A%E7%9A%84%E9%AA%91%E5%A3%AB/631247
https://download.eeworld.com.cn/detail/%E5%A4%AA%E9%98%B3%E4%B8%8A%E7%9A%84%E9%AA%91%E5%A3%AB/631248
https://download.eeworld.com.cn/detail/%E5%A4%AA%E9%98%B3%E4%B8%8A%E7%9A%84%E9%AA%91%E5%A3%AB/631249
https://download.eeworld.com.cn/detail/%E5%A4%AA%E9%98%B3%E4%B8%8A%E7%9A%84%E9%AA%91%E5%A3%AB/631250
https://download.eeworld.com.cn/detail/%E5%A4%AA%E9%98%B3%E4%B8%8A%E7%9A%84%E9%AA%91%E5%A3%AB/631251
https://download.eeworld.com.cn/detail/%E5%A4%AA%E9%98%B3%E4%B8%8A%E7%9A%84%E9%AA%91%E5%A3%AB/631252
六、用到的相关库和固件
七、项目短视频
https://training.eeworld.com.cn/video/39273
八、心得体会
感谢EEWorld和得捷举办这次活动,让我们有机会感受到RP2040和W5500组合起来能产生多大的魅力,但也在动手过程中发现MicroPython如果遇到某些问题很难在很快在网上找到答案,希望大家以后能一起壮大MicroPython生态。
-
加入了学习《Follow me 第4期任务视频》,观看 Follow me 第4期任务视频
- 2024-02-19
-
上传了资料:
组建简易FTP文件服务器
-
上传了资料:
开发板挂载SD卡
-
上传了资料:
DUE显示获取的时间
-
上传了资料:
W5500从NTP服务器同步时间