1085|7

109

帖子

25

TA的资源

一粒金砂(高级)

楼主
 

【得捷Follow me第4期】项目总结 [复制链接]

 
很高兴能参加得捷电子Follow me第4期活动,这次活动我使用MicroPython进行开发,相关的软件和源代码附在最后。

一、入门任务

1、固件下载

首先去MicroPython官网下载W5500-EVB-Pico开发板固件,固件下载网址如下:
可以看到有很多版本固件可供使用,这里我选择v1.22.1版本。
 
2、IDE下载安装
W5500-EVB-Pico开发板MicroPython Getting Started网址如下:
链接已隐藏,如需查看请登录或者注册
根据此开发板Getting Started的推荐,开发IDE选择Thonny,Thonny同时支持Windows、Mac和Linux,因为我用的是Windows系统,所以我下载thonny-4.1.4.exe (21 MB)版本。
Thonny下载网址如下:
Thonny安装完成后会有和技术不相关的东西,可以按照此链接操作对此进行屏蔽,链接如下:
 
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()

运行效果如下:

BLINK
5、驱动液晶显示器
这是Adafruit Sharp Memory Display Breakout使用说明链接如下:
根据此链接用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下载链接如下:
这里根据自己的平台下载相应的版本,这里我下载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();
}


显示效果如下:

Arduino sharpmemtest

二、基础任务一

 

1、W5500使用
参考W5500-EVB-Pico开发板MicroPython Getting Started例程对W5500初始化(静态IP配置),网址如下:
链接已隐藏,如需查看请登录或者注册
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文件,此文件下载网址如下:
链接已隐藏,如需查看请登录或者注册
下载好文件后将文件保存进开发板即可。
W5500 ping通互联网站点(这里选择ping百度)结果如图:
 
2、Wireshark下载安装使用
下载Wireshark并安装,软件下载网址如下:
根据自己的平台选择相应的版本,这里我用的是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客户端连接开发板并发送数据
链接已隐藏,如需查看请登录或者注册
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 = "";
  }

}


 

Task_A

四、终极任务二

 

1、驱动SD卡
首先下载sd卡类,下载网址如下:
链接已隐藏,如需查看请登录或者注册
将下载的库文件内容复制到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的例子,参考网址如下:
由于参考程序是使用的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()


 

TASK_L
五、可编译下载的代码
 
六、用到的相关库和固件
uping.py (3.37 KB, 下载次数: 0)

sdcard.py (9.71 KB, 下载次数: 1)

W5500_EVB_PICO-20240105-v1.22.1.uf2 (927.5 KB, 下载次数: 0)

七、项目短视频

八、心得体会
感谢EEWorld和得捷举办这次活动,让我们有机会感受到RP2040和W5500组合起来能产生多大的魅力,但也在动手过程中发现MicroPython如果遇到某些问题很难在很快在网上找到答案,希望大家以后能一起壮大MicroPython生态。
 

最新回复

MicroPython驱动屏幕应该不难,毕竟大部分都给封装好了。   详情 回复 发表于 2024-2-21 09:36
点赞(1) 关注
 
 

回复
举报

7244

帖子

2

TA的资源

版主

沙发
 

这一整套学习下来,感觉以后都可以开发一个不错的项目了。

点评

没用MicroPython直接驱动屏幕挺遗憾的,主要是时间太紧了,后面有时间再试试开发板直接驱动屏幕~  详情 回复 发表于 2024-2-20 21:17
 
 
 

回复

83

帖子

0

TA的资源

一粒金砂(中级)

板凳
 

根据此链接用W5500-EVB-Pico开发板使用CircuitPython一直没有驱动起来此屏幕,报GP10已经使用了的错误,网上找了一圈没有找到解决办法

 

楼主,我看你固件下载的是MicroPython,但是驱动显示使用的是CircuitPython,这有可能会导致不兼容。

点评

试显示屏驱动的时候开发板是烧录的CircuitPython的固件,估计此CircuitPython固件把GP10用作了其它外设,因为对CircuitPython不是很了解,试了一天没解决,最后换Due开发板来驱动屏幕了。  详情 回复 发表于 2024-2-20 21:15
 
 
 

回复

109

帖子

25

TA的资源

一粒金砂(高级)

4
 
bitter 发表于 2024-2-20 21:05 根据此链接用W5500-EVB-Pico开发板使用CircuitPython一直没有驱动起来此屏幕,报GP10已经使用了的错误,网 ...

试显示屏驱动的时候开发板是烧录的CircuitPython的固件,估计此CircuitPython固件把GP10用作了其它外设,因为对CircuitPython不是很了解,试了一天没解决,最后换Due开发板来驱动屏幕了。

 
 
 

回复

109

帖子

25

TA的资源

一粒金砂(高级)

5
 
wangerxian 发表于 2024-2-20 17:36 这一整套学习下来,感觉以后都可以开发一个不错的项目了。

没用MicroPython直接驱动屏幕挺遗憾的,主要是时间太紧了,后面有时间再试试开发板直接驱动屏幕~

点评

MicroPython驱动屏幕应该不难,毕竟大部分都给封装好了。  详情 回复 发表于 2024-2-21 09:36
 
 
 

回复

4942

帖子

12

TA的资源

版主

6
 
gpio口设置问题?

点评

应该是固件使用了这个I/O,我看论坛有用W5500那个接口能驱动屏幕,但W5500和屏幕项目都要用,只能二选一了  详情 回复 发表于 2024-2-21 09:08
 
 
 

回复

109

帖子

25

TA的资源

一粒金砂(高级)

7
 

应该是固件使用了这个I/O,我看论坛有用W5500那个接口能驱动屏幕,但W5500和屏幕项目都要用,只能二选一了

 
 
 

回复

7244

帖子

2

TA的资源

版主

8
 
太阳上的骑士 发表于 2024-2-20 21:17 没用MicroPython直接驱动屏幕挺遗憾的,主要是时间太紧了,后面有时间再试试开发板直接驱动屏幕~

MicroPython驱动屏幕应该不难,毕竟大部分都给封装好了。

 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/7 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表