1144|2

22

帖子

3

TA的资源

一粒金砂(中级)

楼主
 

【得捷电子Follow me第4期】全部任务合集 [复制链接]

 


 

这次活动满满当当买了一堆东西,本来看到W5500-PICO管脚与原版树莓派pico一致,欢天喜地的配了一个pico专用的墨水屏,想着做显示器使用。但拿来才发现尴尬了,墨水屏和板载的W5500都使用的是pico默认的spi0,而且一些其他的控制管脚也都是重叠的。这下失算了,靠软件是没法解决问题了,只能用最原始的方法——面包板来解决问题。

入门任务:开发环境搭建,BLINK,驱动液晶显示器进行显示。

这个项目我使用vscode+platformio进行开发。首先要先在vscode中安装platformio插件

 

安装完成后,进入插件首页,创建新项目,板子选择raspberry pico就可以。

 

接着下载所需的库文件,这里我都整理好了,大家只需要在项目文件夹下的platformio.ini文件写入以下内容并保存,platform就会自动下载所需要的这些包。

; PlatformIO Project Configuration File
;
;   Build options: build flags, source filter
;   Upload options: custom upload port, speed and extra flags
;   Library options: dependencies, extra library storages
;   Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html

[env:pico]
platform = raspberrypi
board = pico
framework = arduino
lib_deps = 
	zinggjm/GxEPD2@^1.5.5
	https://github.com/masterx1981/Ethernet.git
	adafruit/Adafruit NeoPixel@^1.12.0
	adafruit/Adafruit INA219@^1.2.3

特别要注意的是,我们Ethernet用的并不是官方的库,而是第三方库。主要的原因是官方的库中缺少了使用icmp来ping的方法。这个具体到后面再说。我们先把灯点起来。

 

这里我点的灯是一颗外接的W2812B,接在28号引脚上。驱动代码非常简单,使用adafruit的库就可以轻松实现:

// Neopixel
#include <Arduino.h>
#include <Adafruit_NeoPixel.h>
Adafruit_NeoPixel pixels(1, 28, NEO_GRB + NEO_KHZ800);

void setup(){
  pixels.begin();
  pixels.clear();
  pixels.show();}

void loop(){
pixels.setPixelColor(0, pixels.Color(0, 100, 0);
pixels.show();
delay(1000);
pixels.setPixelColor(0, pixels.Color(0, 0, 0);
pixels.show();
delay(1000);}

这样就可以实现简单的绿灯闪烁。

 

点亮这块屏幕稍微麻烦一点,这块屏是一块2.9寸的单色墨水屏,由于我们把引脚改到了SPI1上,因此所有现成的例程都是无法使用的。这里我们要先在代码中定义好引脚,实际的接线方式大家可以参考这个代码:

arduino::MbedSPI SPIn(/*MISO=RX*/ 12, /*MOSI=TX*/ 15, /*SCK*/ 14);
GxEPD2_BW<GxEPD2_290_T5, GxEPD2_290_T5::HEIGHT> display(GxEPD2_290_T5(/*CS*/ 13, /*DC*/ 11, /*RST*/ 10, /*BUSY*/ 9));

切记,一定要在platformio中使用上述代码,因为arduino中pico的spi方式使用的并不上Mbed,因此上述代码并不会起作用。

接好线后,使用以下代码,我们就可打印信息在屏幕上:

#include <Arduino.h>
#include <GxEPD2_BW.h>
#include <Fonts/FreeMonoBold9pt7b.h>
arduino::MbedSPI SPIn(/*MISO=RX*/ 12, /*MOSI=TX*/ 15, /*SCK*/ 14);
GxEPD2_BW<GxEPD2_290_T5, GxEPD2_290_T5::HEIGHT> display(GxEPD2_290_T5(/*CS*/ 13, /*DC*/ 11, /*RST*/ 10, /*BUSY*/ 9));
void text(const char *string)
{
  display.setRotation(1);
  display.setFont(&FreeMonoBold9pt7b);
  display.setTextColor(GxEPD_BLACK);
  int16_t tbx, tby;
  uint16_t tbw, tbh;
  display.getTextBounds(string, 0, 0, &tbx, &tby, &tbw, &tbh);
  // center the bounding box by transposition of the origin:
  uint16_t x = ((display.width() - tbw) / 2) - tbx;
  uint16_t y = ((display.height() - tbh) / 2) - tby;
  display.setFullWindow();
  display.firstPage();
  do
  {
    display.fillScreen(GxEPD_WHITE);
    display.setCursor(x, y);
    display.print(string);
  } while (display.nextPage());
}

void setup(){
display.epd2.selectSPI(SPIn, SPISettings(4000000, MSBFIRST, SPI_MODE0));
display.init(115200); // default 10ms reset pulse, e.g. for bare panels with DESPI-C02
text("Hello EEWorld!")
}
void loop(){;}

 

更有意思的是,墨水屏显示内容并不需要通电保持,因此即使我们把屏幕拔下来,内容也还正常的显示在屏幕上。

 

 

基础任务一:完成主控板W5500初始化(静态IP配置),并能使用局域网电脑ping通,同时W5500可以ping通互联网站点;通过抓包软件(Wireshark、Sniffer等)抓取本地PC的ping报文,展示并分析。

网络配置这块比较简单,我们直接把他封装成一个函数,放到setup中即可。

#include <Arduino.h>

#include <Ethernet.h>
// 网络配置
byte mac[] = {0xDE, 0xAD, 0xBE, 0xE1, 0xF2, 0xE3};
// 仅静态配置有效
IPAddress ip(192, 168, 50, 173);
IPAddress gateway(192, 168, 50, 1);
IPAddress myDns(8, 8, 8, 8);
IPAddress subnet(255, 255, 255, 0);

IPAddress setNet()
{
  Serial.println("Ethernet Begin");
  // Ethernet.init(17); // Uncomment if use custom cs pin (default is 17)
  // DHCP
  // Ethernet.begin(mac);
  // 静态IP设置
  Ethernet.begin(mac, ip, myDns, gateway, subnet);

  // 打印INFO
  Serial.print("My IP address: ");
  Serial.println(Ethernet.localIP());
  Serial.print("My subnet: ");
  Serial.println(Ethernet.subnetMask());
  Serial.print("My DNS address: ");
  Serial.println(Ethernet.dnsServerIP());
  Serial.print("My GateWay address: ");
  Serial.println(Ethernet.gatewayIP());
  Serial.print("My Mac address: ");
  byte macBuffer[6];
  Ethernet.MACAddress(macBuffer);
  for (byte octet = 0; octet < 6; octet++)
  {
    Serial.print(macBuffer[octet], HEX);
    if (octet < 5)
    {
      Serial.print('-');
    }
  }
  Serial.println("");

  return Ethernet.localIP();
}

void setup()
{
  // 配置串口
  Serial.begin(115200);
  Serial.println("");

  setNet();
}

void loop(){;}

开发板其中mac码只需要符合一般规则,其余的可以任意填写。静态的ip和网关需要根据大家自己的路由器情况自行填写。当然如果不光是为了完成任务的话,更常见的方式是DHCP。我在手动配置的上面已经写了dhcp的方法,只需要将手动配置代码注释,dhcp解除注释即可。

 

接着我们打开Wiresharp,选择自己电脑当前连接路由器的网卡,根据手动填写的ip地址,在筛选框填入以下内容:

ip.src==192.168.50.173 or ip.dst==192.168.50.173

按右边箭头应用筛选后,我们应该会看到没有东西刷新了。这时候打开电脑的cmd,ping一下该地址,我们就可以看到抓取到了对应的包:

  

 

  

 

双击任意一条,打开后可以清晰看到是基于icmp的ping reply

 

 

 

接下来是用板子来ping互联网站点。这其实是由两个步骤完成的,第一步是DNS解析站点,将域名转化为ip,第二部是ping。实现ping需要导入EthernetICMP.h,但不知道为什么似乎这个库和SPI,I2C等外设库冲突,只要同时存在,就会导致板子不停重置,代码无法运行。因此我把ping这块都写在了一起,封装成了函数,不需要用的时候全部注释掉即可。

// Ping
#include <Dns.h>
DNSClient dnClient;
#include <EthernetICMP.h> // 与i2c冲突
SOCKET pingSocket = 4;
EthernetICMPPing ping(pingSocket, (uint8_t)random(0, 255));

void pingTest(const IPAddress &dstip)
{
  EthernetICMPEchoReply echoReply = ping(dstip, 4);
  char buffer[256];
  if (echoReply.status == SUCCESS)
  {
    sprintf(buffer,
            "Reply[%d] from: %d.%d.%d.%d: bytes=%d time=%ldms TTL=%d",
            echoReply.data.seq,
            echoReply.addr[0],
            echoReply.addr[1],
            echoReply.addr[2],
            echoReply.addr[3],
            REQ_DATASIZE,
            millis() - echoReply.data.time,
            echoReply.ttl);
  }
  else
  {
    sprintf(buffer, "Echo request failed; %d", echoReply.status);
  }
  Serial.println(buffer);
}

void pingloop()
{
  dnClient.begin(Ethernet.dnsServerIP());
  const char domains[3][20] = {"www.eeworld.com.cn", "www.digikey.cn", "www.digikey.com"};
  IPAddress dstip;
  for (int i = 0; i < 3; i++)
  {
    if (dnClient.getHostByName(domains[i], dstip) == 1)
    {
      Serial.print(domains[i]);
      Serial.print(" = ");
      Serial.println(dstip);
      pingTest(dstip);
    }
    else
      Serial.println(F("dns lookup failed"));
  }
}

在pingloop中我解析了三个网址,并分别对三个网站进行了一次ping。将pingloop放到loop中,每隔几秒运行一次,就可以看到ping的结果:

 

 

 

 

基础任务二:主控板建立TCPIP或UDP服务器,局域网PC使用TCPIP或UDP客户端进行连接并发送数据,主控板接收到数据后,送液晶屏显示(没有则通过串口打印显示);通过抓包软件抓取交互报文,展示并分析。

由于http服务是基于tcp的,因此这个任务我打算直接在pico上搭建一个http服务器,然后用电脑从网页端访问,相当于电脑作为客户端发送数据,以此来接收传感器读数,并控制led。

 

http协议如果将他简化,就只需要一个头文件的http报文就足够了。这里我们用最基础的tcp发送报文方式实现。

EthernetServer server(80);
void webs()
{
  EthernetClient client = server.available();
  if (client)
  {
    Serial.println("new client");
    String HTTP_req;
    // an http request ends with a blank line
    bool currentLineIsBlank = true;
    while (client.connected())
    {

      if (client.available())
      {
        char c = client.read();
        HTTP_req += String(c);
        // if you've gotten to the end of the line (received a newline
        // character) and the line is blank, the http request has ended,
        // so you can send a reply
        if (c == '\n' && currentLineIsBlank)
        {
          // send a standard http response header
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println();
          client.println("<!DOCTYPE HTML>");
          client.println("<html>");
          get();
          client.println("Bus Voltage:");
          client.println(busvoltage);
          client.println("V<br />");
          client.println("Shunt Voltage:");
          client.println(shuntvoltage);
          client.println("V<br />");
          client.println("Load Voltage:");
          client.println(loadvoltage);
          client.println("V<br />");
          client.println("Current:");
          client.println(current_mA);
          client.println("mA<br />");
          client.println("Power:");
          client.println(power_mW);
          client.println("mW<br />");

          client.println("<a href='?R=on'><button>Red ON</button></a>     <a href='?R=off'><button>Red OFF</button></a><br /><br />");
          client.println("<a href='?G=on'><button>Green ON</button></a>     <a href='?G=off'><button>Green OFF</button></a><br /><br />");
          client.println("<a href='?B=on'><button>Blue ON</button></a>     <a href='?B=off'><button>Blue OFF</button></a><br /><br />");
          client.println("<a href='?ntp'><button>NTP time update</button></a><br /><br />");
          client.println("</html>");
          ProcessRequest(HTTP_req);
          break;
        }
        if (c == '\n')
        {
          // you're starting a new line
          currentLineIsBlank = true;
        }
        else if (c != '\r')
        {
          // you've gotten a character on the current line
          currentLineIsBlank = false;
        }
      }
    }
  }
}

页面内容可以用简单的html来实现。

接着我们再接入传感器,传感器我使用的是INA219,可以用来检测开发板供电电压,用来在电压不足时报警。这个传感器依靠的是I2C通信。

// INA 219
#include <Adafruit_INA219.h>
float shuntvoltage = 0;
float busvoltage = 0;
float current_mA = 0;
float loadvoltage = 0;
float power_mW = 0;

TwoWire Wire1(2, 3);
Adafruit_INA219 ina219;
void get()
{
  busvoltage = ina219.getBusVoltage_V();
  shuntvoltage = ina219.getShuntVoltage_mV();
  loadvoltage = busvoltage + (shuntvoltage / 1000);
  current_mA = ina219.getCurrent_mA();
  power_mW = ina219.getPower_mW();

  Serial.print("Bus Voltage:   ");
  Serial.print(busvoltage);
  Serial.println(" V");
  Serial.print("Shunt Voltage: ");
  Serial.print(shuntvoltage);
  Serial.println(" mV");
  Serial.print("Load Voltage:  ");
  Serial.print(loadvoltage);
  Serial.println(" V");
  Serial.print("Current:       ");
  Serial.print(current_mA);
  Serial.println(" mA");
  Serial.print("Power:         ");
  Serial.print(power_mW);
  Serial.println(" mW");
  Serial.println("");
}

接着我们把之前导入的WS2812和传感器数据,加上接下来会细讲的ntp用html写入网页中,打开网页就可以看到如下界面,按动按钮就可以进行控制。

 

 

 

进阶任务:从NTP服务器(注意数据交互格式的解析)同步时间,获取时间送显示屏(串口)显示。

NTP基于的是UDP协议进行的,这里我们先定义了基本的获取NTP时间的函数,获取完成后,再将获取到的信息转换成字符串,更新到墨水屏上,实现在网页端按一下按钮,就可以在墨水屏上刷新当前时间的效果。

 

 
// A UDP instance to let us send and receive packets over UDP
#include <EthernetUdp.h>
EthernetUDP Udp;
const uint8_t NTP_PACKET_SIZE = 48;
byte packetBuffer[NTP_PACKET_SIZE];
char bjtime[256];
void sendNTPpacket(const char *address)
{
  // set all bytes in the buffer to 0
  memset(packetBuffer, 0, NTP_PACKET_SIZE);
  // Initialize values needed to form NTP request
  // (see URL above for details on the packets)
  packetBuffer[0] = 0b11100011; // LI, Version, Mode
  packetBuffer[1] = 0;          // Stratum, or type of clock
  packetBuffer[2] = 6;          // Polling Interval
  packetBuffer[3] = 0xEC;       // Peer Clock Precision
  // 8 bytes of zero for Root Delay & Root Dispersion
  packetBuffer[12] = 49;
  packetBuffer[13] = 0x4E;
  packetBuffer[14] = 49;
  packetBuffer[15] = 52;

  // all NTP fields have been given values, now
  // you can send a packet requesting a timestamp:
  Udp.beginPacket(address, 123); // NTP requests are to port 123
  Udp.write(packetBuffer, NTP_PACKET_SIZE);
  Udp.endPacket();
}
void getntp()
{
  while (true)
  {
    sendNTPpacket("time.nist.gov"); // send an NTP packet to a time server
    // wait to see if a reply is available
    delay(1000);
    if (Udp.parsePacket())
    {
      // We've received a packet, read the data from it
      Udp.read(packetBuffer, NTP_PACKET_SIZE); // read the packet into the buffer

      // the timestamp starts at byte 40 of the received packet and is four bytes,
      // or two words, long. First, extract the two words:

      unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
      unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);
      // combine the four bytes (two words) into a long integer
      // this is NTP time (seconds since Jan 1 1900):
      unsigned long secsSince1900 = highWord << 16 | lowWord;
      Serial.print("Seconds since Jan 1 1900 = ");
      Serial.println(secsSince1900);

      // now convert NTP time into everyday time:
      Serial.print("Unix time = ");
      // Unix time starts on Jan 1 1970. In seconds, that's 2208988800:
      const unsigned long seventyYears = 2208988800UL;
      // subtract seventy years:
      unsigned long epoch = secsSince1900 - seventyYears;
      // print Unix time:
      Serial.println(epoch);

      // print the hour, minute and second:
      sprintf(bjtime, "Current Time  %d : %d : %d",
              (epoch % 86400L) / 3600 + 8,
              (epoch % 3600) / 60,
              epoch % 60);
      Serial.println(bjtime);
      return;
    }
    // wait 3 seconds before asking for the time again
    Serial.println("Retry in 3 seconds...");
    delay(3000);
  }
}

 

这时候我们再用Wireshark抓包看一下,就可以看到tcp数据包和pico返回的http ok的报文。

  

终极任务二:使用外部存储器,组建简易FTP文件服务器,并能正常上传下载文件。

这个任务我原本想一并在platformio中完成,但无奈arduino中文件系统一直无法在rp2040上成功编译,且还需要外接SD模块。因此这块我是用micropython来完成。micropython有一些ftp的实现方法,但是是给esp9266用的,在开头需要导入wifi库。但幸运的是,代码实现全部依靠纯python使用socket发送ftp命令,wifi库仅用来获取ip。这下就简单了,我们只需要改一下ip的获取方式,就可以直接使用了。完整代码如下:

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.213','255.255.255.0','192.168.50.1','8.8.8.8'))#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()




 

 

 

特别注意,目前在测试传送py代码文件时一切正常,如果传大图片会报错。

 

源代码 https://download.eeworld.com.cn/detail/%E9%A1%BA%E7%AB%BF%E7%88%AC/6311

 

活动心得

借着fm4活动的机会,我尝试了之前从没有使用过的墨水屏。说实话墨水屏的刷新之慢确实有点出乎意料,但驱动的过程还是挺有趣的。得利于开源社区各种各样的现成的库,才能在这么短的时间内完成任务。

最新回复

传大图片会报错是因为什么   详情 回复 发表于 2024-2-7 09:09
点赞 关注
 
 

回复
举报

6828

帖子

0

TA的资源

五彩晶圆(高级)

沙发
 

传大图片会报错是因为什么

点评

好像是官方w5500的mpy驱动问题,测试了一下如果单纯使用socket收发大量数据的话一样也会莫名出错,出现os error。在esp上则无相关问题,说明问题与mpy的socket方法无关,那大概率就是驱动问题了。  详情 回复 发表于 2024-2-12 15:51
 
 
 

回复

22

帖子

3

TA的资源

一粒金砂(中级)

板凳
 
Jacktang 发表于 2024-2-7 09:09 传大图片会报错是因为什么

好像是官方w5500的mpy驱动问题,测试了一下如果单纯使用socket收发大量数据的话一样也会莫名出错,出现os error。在esp上则无相关问题,说明问题与mpy的socket方法无关,那大概率就是驱动问题了。

 
 
 

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

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

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

 
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
快速回复 返回顶部 返回列表