superw

  • 2024-11-14
  • 加入了学习《PX4固件二次开发课程》,观看 飞控软硬体系介绍1

  • 2024-10-08
  • 发表了主题帖: 【Follow me第二季第2期】+项目总结

    本帖最后由 superw 于 2024-11-6 02:00 编辑 文章中各任务均由图片中物料实现 物料清单: 厂商 厂商料号 名称 得捷链接 Arduino ABX00087  Arduino UNO R4 WiFi https://www.digikey.cn/zh/products/detail/arduino/ABX00087/20371539?s=N4IgTCBcDaIIICEAaAGNAOA7AApAXQF8g Adafruit 4991 Adafruit I2C STEMMA QT Rotary Encoder Breakout with Neopixel https://www.digikey.cn/zh/products/detail/adafruit-industries-llc/4991/14302511 Adafruit 5591 Adafruit LTR-329 Light Sensor https://www.digikey.cn/zh/products/detail/adafruit-industries-llc/5591/16733167   一、入门任务(必做):搭建环境并开启第一步Blink / 串口打印Hello EEWorld!   Arduino官方的板子,当然要用Arduino IDE来开发,在Arduino官网根据自己的操作系统下载对应的安装程序,一路next即可。当然电脑硬盘不够的也可以选择使用便携版IDE或者浏览器开发。 安装完成后,搭建环境。按照官方指南https://docs.arduino.cc/tutorials/uno-r4-wifi/r4-wifi-getting-started/,安装Board Package后,即可进行编译下载代码。 硬件分析:   板载DL4通过MOS管驱动,当P102输出高电平点亮DL4,当P102输出低电平熄灭DL4。 软件实现: 通过在loop函数中循环翻转P102电平,并附加相应延时,即可实现板载LED闪烁。Arduino官方开发板默认串口使用Serial.begin进行初始化,其他通信串口使用Serialx.begin初始化(x=1,2,...),串口初始化成功后,可通过print,println函数进行打印。 代码实现: void setup() { // put your setup code here, to run once: Serial.begin(115200); pinMode(LED_BUILTIN, OUTPUT); } void loop() { // put your main code here, to run repeatedly: Serial.println("Hello EEWorld!"); digitalWrite(LED_BUILTIN, HIGH); delay(1000); digitalWrite(LED_BUILTIN, LOW); delay(1000); }   上面代码实现任务一,控制板载LED Blink,同时通过串口打印Hello EEWorld! 实现效果:   二、基础任务(必做):驱动12x8点阵LED;用DAC生成正弦波;用OPAMP放大DAC信号;用ADC采集并且打印数据到串口等其他接口可上传到上位机显示曲线 对于Arduino UNO R4 WiFi板上资源,官方提供了详细的指南。 对于点阵LED,可参考https://docs.arduino.cc/tutorials/uno-r4-wifi/led-matrix/ 对于片上DAC,可参考https://docs.arduino.cc/tutorials/uno-r4-wifi/dac/ 对于片上OPAMP,可参考https://docs.arduino.cc/tutorials/uno-r4-wifi/opamp/ 对于片上ADC,可参考https://docs.arduino.cc/tutorials/uno-r4-wifi/adc-resolution/ 综合根据上面指南,可以完成任务二。 硬件分析:本任务涉及到的硬件资源,开发板上均已具备,且对于DAC、OPAMP、ADC均为MCU片上资源,直接通过对应函数操作硬件即可。 对于OPAMP放大DAC信号,需要使用面包板,通过片上OPAMP运放单元搭建一个简易的运算放大器。原理图如下: 上面的实现是一个电压跟随器,但电压跟随器可以理解为一个特殊的运算放大器,增益为1,输出电压与输入电压同幅值,同频率。电压跟随器在电路中经常起到缓冲和隔离的作用。 将A0(DAC输出)接入A1(OPAMP的正向输入端),A2(OPAMP的反向输入端)和A3短接(OPAMP的输出端),此时便可在A3用示波器观察到与A0的输出波形一致。将A3(OPAMP的输出端)与A4(ADC采集)短接,便可以获取到ADC采集到的信号电压。   代码实现: #include "analogWave.h" #include "OPAMP.h" #include "ArduinoGraphics.h" #include "Arduino_LED_Matrix.h" analogWave wave(DAC); ArduinoLEDMatrix matrix; int freq = 10; void setup() { // put your setup code here, to run once: Serial.begin(115200); wave.sine(freq); OPAMP.begin(OPAMP_SPEED_HIGHSPEED); analogReadResolution(14); matrix.begin(); } void loop() { // put your main code here, to run repeatedly: int adc_value = analogRead(A4); Serial.println("current adc value is " + String(adc_value)); // Make it scroll! matrix.beginDraw(); matrix.stroke(0xFFFFFFFF); matrix.textScrollSpeed(50); // add the text const char text[] = " EEWorld & DigiKey "; matrix.textFont(Font_4x6); matrix.beginText(0, 1, 0xFFFFFF); matrix.println(text); matrix.endText(SCROLL_LEFT); matrix.endDraw(); } 实现效果: 对于12x8点阵LED,上电后会看到EEWorld & DigiKey的字样。 手机相机拍的不是很清,人眼视觉效果会相对好点。 用DAC生成正弦波,并经过OPAMP放大DAC信号,现象可通过示波器观察得到。 由于手里没有插件电阻,将片上的OPAMP运放配置为电压跟随器模式,即输入为什么信号,输出就是什么信号。图中黄色为原始DAC正弦波信号,绿色为经过电压跟随器后输出的正弦波信号,二者幅值频率均相等。 用ADC采集生成的正弦波信号,并打印到串口,借助Arduino IDE的串口上位机可将波形大致呈现出来。   三、进阶任务(必做):通过Wi-Fi,利用MQTT协议接入到开源的智能家居平台HA(HomeAssistant) 四、扩展任务一:通过外部LTR-329 环境光传感器,上传光照度到HA,通过HA面板显示数据 首先,非常感谢这期老师给大家带来的直播任务讲解,里面清楚的介绍了如何在windows平台上搭建HomeAssistant环境。当然,我自己也尝试了在泰山派上通过docker安装HomeAssistant,但貌似是由于Docker Hub不稳定的问题,总是访问超时,在ubuntu上也不会魔法上网,只能放弃。后来又尝试安装CasaOS(系统本身已具有docker),但最终还是需要通过docker访问HomeAssistant的Docker Hub,也未能完整实现。最终选择了直播中老师讲解的方法,在windows上安装Docker Desktop,之后拉取HomeAssistant镜像,并创建容器。 具体搭建过程可参考直播讲解https://training.eeworld.com.cn/video/40793 HomeAssistant界面 EMQX(MQTT)服务器界面 硬件分析: 上图为任务推荐的LTR329光照传感器模块,板载Qwiic接口。对应Adafruit采购型号为5591。 上图为任务之外选购的编码器模块,板载Qwiic接口。对应Adafruit采购型号为4991。板载一个内置固件的MCU,采集板载的编码器信息,并且支持外部IIC总线访问来获取。 上图为Arduino开发板的J2接口,硬件形式为Qwiic,可通过SH1.0排线将上述两个模块串联到一块,共同挂载在IIC总线上,通过IIC主机寻址不同的设备地址,访问设备。 注意:LTR329的IIC地址为0x29,编码器模块的IIC地址为0x36。 软件实现: 打开Library Manager,搜索框输入LTR329,安装对应的Library。详细介绍及驱动代码可见https://learn.adafruit.com/adafruit-ltr-329-ltr-303/overview 本次活动选择的另一个器件是I2C QT ROTARY ENCODER,片上集成了一个编码器和一个WS2812,单片机下载seesaw固件,通过I2C接口获取命令,进一步通过单片机读取编码器的值,控制WS2812。搜索框输入seesaw,安装对应的Library。详细介绍及驱动代码可见https://learn.adafruit.com/adafruit-i2c-qt-rotary-encoder 当然,要通过WiFi接入HA平台,最重要的还需要一个home-assistant-integration库,通过这个库,可以创建各种设备类型,包括灯、按键、传感器、锁等等。具体库介绍可参考https://dawidchyrzynski.github.io/arduino-home-assistant/index.html 环境搭建和各种library安装好之后,就可以进行代码编写。 代码实现: #include "WiFiS3.h" #include "arduino_secrets.h" #include "Adafruit_LTR329_LTR303.h" #include <ArduinoHA.h> #include <seesaw_neopixel.h> #define MQTT_OBJECT_ID "followme" #define BROKER_ADDR IPAddress(192,168,10,246) #define MQTT_PORT 1883 #define MQTT_USERNAME "admin" #define MQTT_PASSWORD "123" #define SS_NEOPIX 6 #define SEESAW_ADDR 0x36 seesaw_NeoPixel sspixel = seesaw_NeoPixel(1, SS_NEOPIX, NEO_GRB + NEO_KHZ800, &Wire1); Adafruit_LTR329 ltr = Adafruit_LTR329(); WiFiClient client; HADevice device(MQTT_OBJECT_ID); HAMqtt mqtt(client, device); HAButton buttonR("myButtonR"); HAButton buttonG("myButtonG"); HAButton buttonB("myButtonB"); HASensorNumber lightSensor("mylight"); char ssid[] = SECRET_SSID; // your network SSID (name) char pass[] = SECRET_PASS; // your network password (use for WPA, or use as key for WEP) int status = WL_IDLE_STATUS; unsigned long lastUpdateAt = 0; void onButtonCommand(HAButton* sender) { if (sender == &buttonR) { // button A was clicked, do your logic here sspixel.setPixelColor(0, sspixel.Color(255, 0, 0)); } else if (sender == &buttonG) { // button B was clicked, do your logic here sspixel.setPixelColor(0, sspixel.Color(0, 255, 0)); } else if (sender == &buttonB) { sspixel.setPixelColor(0, sspixel.Color(0, 0, 255)); } sspixel.show(); } void setup() { // put your setup code here, to run once: Serial.begin(115200); while (!Serial) { ; // wait for serial port to connect. Needed for native USB port only } wifi_init(); ltr329_init(); pixel_init(); device.setName("Arduino"); device.setSoftwareVersion("1.0.0"); buttonR.setIcon("mdi:fire"); buttonR.setName("RED"); buttonG.setIcon("mdi:home"); buttonG.setName("GREEN"); buttonB.setIcon("mdi:water"); buttonB.setName("BLUE"); buttonR.onCommand(onButtonCommand); buttonG.onCommand(onButtonCommand); buttonB.onCommand(onButtonCommand); lightSensor.setIcon("mdi:home"); lightSensor.setName("light value"); mqtt.begin(BROKER_ADDR, MQTT_PORT, MQTT_USERNAME, MQTT_PASSWORD); } void loop() { // put your main code here, to run repeatedly: bool valid; uint16_t visible_plus_ir, infrared; mqtt.loop(); if ((millis() - lastUpdateAt) > 1000) { // 1000ms debounce time if (ltr.newDataAvailable()) { valid = ltr.readBothChannels(visible_plus_ir, infrared); if (valid) { Serial.print("CH0 Visible + IR: "); Serial.print(visible_plus_ir); Serial.print("\t\tCH1 Infrared: "); Serial.println(infrared); lightSensor.setValue(visible_plus_ir); } } lastUpdateAt = millis(); } } void wifi_init() { // check for the WiFi module: if (WiFi.status() == WL_NO_MODULE) { Serial.println("Communication with WiFi module failed!"); // don't continue while (true); } String fv = WiFi.firmwareVersion(); if (fv < WIFI_FIRMWARE_LATEST_VERSION) { Serial.println("Please upgrade the firmware"); } // attempt to connect to WiFi network: while (status != WL_CONNECTED) { Serial.print("Attempting to connect to SSID: "); Serial.println(ssid); // Connect to WPA/WPA2 network. Change this line if using open or WEP network: status = WiFi.begin(ssid, pass); // wait 10 seconds for connection: delay(10000); } printWifiStatus(); } void ltr329_init() { Serial.println("Adafruit LTR-329 advanced test"); if ( ! ltr.begin(&Wire1) ) { Serial.println("Couldn't find LTR sensor!"); while (1) delay(10); } Serial.println("Found LTR sensor!"); ltr.setGain(LTR3XX_GAIN_2); ltr.setIntegrationTime(LTR3XX_INTEGTIME_100); ltr.setMeasurementRate(LTR3XX_MEASRATE_200); } void pixel_init() { Serial.println("Looking for seesaw!"); if (!sspixel.begin(SEESAW_ADDR)) { Serial.println("ERROR! seesaw not found"); while(1) delay(1); } Serial.println("seesaw started"); // set not so bright! sspixel.setBrightness(20); sspixel.show(); } /* -------------------------------------------------------------------------- */ void printWifiStatus() { /* -------------------------------------------------------------------------- */ // print the SSID of the network you're attached to: Serial.print("SSID: "); Serial.println(WiFi.SSID()); // print your board's IP address: IPAddress ip = WiFi.localIP(); Serial.print("IP Address: "); Serial.println(ip); // print the received signal strength: long rssi = WiFi.RSSI(); Serial.print("signal strength (RSSI):"); Serial.print(rssi); Serial.println(" dBm"); } 上面代码实现了两个功能,一个是将LTR-329获取到的光照强度上传到HA平台,另一个是通过HA平台创建三个按键,分别用来控制WS2812的红、绿、蓝三种颜色。 硬件连接如图 实现效果 在HA平台上可看见上传的光照强度值,具体现象可见视频。 五、心得体会 非常感谢官方提供的Arduino板卡,这块板子22年发布的,在技术创新和功能上都非常有特色,最感兴趣的还是上面12x8点阵LED了,可以生成表情、动物、字符等信息。另外,这期活动还跟着教程学会了home assistant的搭建和使用,后面也要继续尝试在泰山派上成功搭建起来。最后希望follow me活动越办越好,给大家带来更多更优秀的大厂开发板。 六、可编译下载的代码      

  • 加入了学习《【Follow me第二季第2期】+视频介绍》,观看 【Follow me第二季第2期】

  • 加入了学习《FollowMe 第二季:2 - Arduino UNO R4 Wi-Fi 及任务讲解》,观看 Arduino UNO R4 Wi-Fi 及任务讲解

  • 2024-09-12
  • 加入了学习《Digi-Key: Follow Me 系列(2) 直播回放》,观看 Adafruit ESP32-S3 TFT Feather开发板使用入门

  • 2024-03-02
  • 加入了学习《泰克MSO6B探索营》,观看 MSO6B强大的测试和分析功能

  • 加入了学习《泰克MSO6B探索营》,观看 MSO6B多通道同步频谱分析

  • 加入了学习《泰克MSO6B探索营》,观看 如何完成AI芯片电源噪声测试

  • 2024-03-01
  • 加入了学习《泰克MSO6B探索营》,观看 MSO6B系列低噪声演示

  • 加入了学习《泰克MSO6B探索营》,观看 MSO6B技术介绍

  • 加入了学习《泰克MSO6B探索营》,观看 MSO6B-360度介绍

  • 2024-02-26
  • 加入了学习《 得捷电子Follow me第4期》,观看 得捷电子Follow me第4期

  • 发表了主题帖: 【得捷电子Follow me第4期】+项目总结

    本帖最后由 superw 于 2024-2-26 11:28 编辑 内容一、演示视频   内容二、 项目总结报告 入门任务:开发环境搭建,BLINK,驱动液晶显示器进行显示(没有则串口HelloWorld) # 在这里写上你的代码 :-) import time import board import busio import digitalio import adafruit_sharpmemorydisplay def display_init(): #SPI1 Display SPI1_SCK = board.GP10 SPI1_MOSI = board.GP11 SPI1_CSn = board.GP13 #配置display的SPI display_spi = busio.SPI(SPI1_SCK, SPI1_MOSI) display_scs = digitalio.DigitalInOut(SPI1_CSn) display = adafruit_sharpmemorydisplay.SharpMemoryDisplay(display_spi, display_scs, 144, 168, baudrate=8000000) return display def led_init(): #配置LED led = digitalio.DigitalInOut(board.LED) led.direction = digitalio.Direction.OUTPUT return led led=led_init() display=display_init() print("DigiKey & eeworld") print("Follow me") print("W5500-EVB-Pico with rp2040") display.fill(0) display.text(" DigiKey & eeworld", 0, 10, 1) display.text(" Follow me", 0, 20, 1) display.text(" W5500-EVB-Pico ", 0, 30, 1) display.text(" with rp2040 ", 0, 40, 1) display.show() while True: led.value = not led.value time.sleep(0.5)   通过使用adafruit_sharpmemorydisplay库完成液晶显示器的驱动,同时点亮板载LED。 基础任务一:完成主控板W5500初始化(静态IP配置),并能使用局域网电脑ping通,同时W5500可以ping通互联网站点;通过抓包软件(Wireshark、Sniffer等)抓取本地PC的ping报文,展示并分析。 # 在这里写上你的代码 :-) import board import busio import digitalio import time import adafruit_sharpmemorydisplay from adafruit_wiznet5k.adafruit_wiznet5k import WIZNET5K def led_init(): #配置LED led = digitalio.DigitalInOut(board.LED) led.direction = digitalio.Direction.OUTPUT return led def display_init(): #SPI1 Display SPI1_SCK = board.GP10 SPI1_MOSI = board.GP11 SPI1_CSn = board.GP13 #配置display的SPI display_spi = busio.SPI(SPI1_SCK, SPI1_MOSI) display_scs = digitalio.DigitalInOut(SPI1_CSn) display = adafruit_sharpmemorydisplay.SharpMemoryDisplay(display_spi, display_scs, 144, 168, baudrate=8000000) return display def w5500_init(): #SPI0 Ethernet SPI0_SCK = board.GP18 SPI0_TX = board.GP19 SPI0_RX = board.GP16 SPI0_CSn = board.GP17 #Ethernet reset W5500_RSTn = board.GP20 ethernetRst = digitalio.DigitalInOut(W5500_RSTn) ethernetRst.direction = digitalio.Direction.OUTPUT # Setup your network configuration below # random MAC, later should change this value on your vendor ID MY_MAC = (0x00, 0x01, 0x02, 0x03, 0x04, 0x05) IP_ADDRESS = (192, 168, 1, 100) SUBNET_MASK = (255, 255, 255, 0) GATEWAY_ADDRESS = (192, 168, 1, 1) DNS_SERVER = (8, 8, 8, 8) # For Adafruit Ethernet FeatherWing eth_cs = digitalio.DigitalInOut(SPI0_CSn) # For Particle Ethernet FeatherWing # cs = digitalio.DigitalInOut(board.D5) eth_spi = busio.SPI(SPI0_SCK, MOSI=SPI0_TX, MISO=SPI0_RX) # Reset W5500 first ethernetRst.value = False time.sleep(1) ethernetRst.value = True # Initialize ethernet interface with DHCP # eth = WIZNET5K(spi_bus, cs) # Initialize ethernet interface without DHCP eth = WIZNET5K(eth_spi, eth_cs, is_dhcp=False, mac=MY_MAC) # Set network configuration eth.ifconfig = (IP_ADDRESS, SUBNET_MASK, GATEWAY_ADDRESS, DNS_SERVER) print("Chip Version:", eth.chip) print("MAC Address:", [hex(i) for i in eth.mac_address]) print("My IP address is:", eth.pretty_ip(eth.ip_address)) display.text("Chip Version:"+eth.chip,0,20,0) display.text("MAC Address:",0,30,0) display.text(eth.pretty_mac(eth.mac_address),0,40,0) display.text("My IP address is:",0,50,0) display.text(eth.pretty_ip(eth.ip_address),0,60,0) display.show() return eth led = led_init() display = display_init() print("Wiznet5k Ping Test (no DHCP)") display.fill(1) display.text("Wiznet5k Ping Test ",0,10,0) display.show() eth = w5500_init() while True: if eth.link_status == False: print("PHY link is down...") display.text("PHY link is down...",0,70,0) display.show() time.sleep(0.1) else: print("PHY link is up") print("W5500 Connect Ethernet") display.text("PHY link is up",0,80,0) display.text("W5500 Connect Ethernet",0,90,0) display.show() break while True: led.value = not led.value time.sleep(0.5)   circuitpython下由于水平有限,目前只实现了PC端主动ping设备,设备主动实现ping电脑暂未实现,后面继续学习。     抓包如下:   基础任务二:主控板建立TCPIP或UDP服务器,局域网PC使用TCPIP或UDP客户端进行连接并发送数据,主控板接收到数据后,送液晶屏显示(没有则通过串口打印显示);通过抓包软件抓取交互报文,展示并分析。(TCP和UDP二选一,或者全都操作) import board import busio import digitalio import time import adafruit_sharpmemorydisplay from adafruit_wiznet5k.adafruit_wiznet5k import WIZNET5K import adafruit_wiznet5k.adafruit_wiznet5k_socket as socket def led_init(): #配置LED led = digitalio.DigitalInOut(board.LED) led.direction = digitalio.Direction.OUTPUT return led def display_init(): #SPI1 Display SPI1_SCK = board.GP10 SPI1_MOSI = board.GP11 SPI1_CSn = board.GP13 #配置display的SPI display_spi = busio.SPI(SPI1_SCK, SPI1_MOSI) display_scs = digitalio.DigitalInOut(SPI1_CSn) display = adafruit_sharpmemorydisplay.SharpMemoryDisplay(display_spi, display_scs, 144, 168, baudrate=8000000) return display def w5500_init(): #SPI0 Ethernet SPI0_SCK = board.GP18 SPI0_TX = board.GP19 SPI0_RX = board.GP16 SPI0_CSn = board.GP17 #Ethernet reset W5500_RSTn = board.GP20 ethernetRst = digitalio.DigitalInOut(W5500_RSTn) ethernetRst.direction = digitalio.Direction.OUTPUT # Setup your network configuration below # random MAC, later should change this value on your vendor ID MY_MAC = (0x00, 0x01, 0x02, 0x03, 0x04, 0x05) IP_ADDRESS = (192, 168, 1, 100) SUBNET_MASK = (255, 255, 255, 0) GATEWAY_ADDRESS = (192, 168, 1, 1) DNS_SERVER = (8, 8, 8, 8) # For Adafruit Ethernet FeatherWing eth_cs = digitalio.DigitalInOut(SPI0_CSn) # For Particle Ethernet FeatherWing # cs = digitalio.DigitalInOut(board.D5) eth_spi = busio.SPI(SPI0_SCK, MOSI=SPI0_TX, MISO=SPI0_RX) # Reset W5500 first ethernetRst.value = False time.sleep(1) ethernetRst.value = True # Initialize ethernet interface with DHCP # eth = WIZNET5K(spi_bus, cs) # Initialize ethernet interface without DHCP eth = WIZNET5K(eth_spi, eth_cs, is_dhcp=False, mac=MY_MAC) # Set network configuration eth.ifconfig = (IP_ADDRESS, SUBNET_MASK, GATEWAY_ADDRESS, DNS_SERVER) print("Chip Version:", eth.chip) print("MAC Address:", [hex(i) for i in eth.mac_address]) print("My IP address is:", eth.pretty_ip(eth.ip_address)) display.text("Chip Version:"+eth.chip,0,20,0) display.text("MAC Address:",0,30,0) display.text(eth.pretty_mac(eth.mac_address),0,40,0) display.text("My IP address is:",0,50,0) display.text(eth.pretty_ip(eth.ip_address),0,60,0) display.show() return eth def create_tcp_socket(mode): if mode == 1: #创建tcp server # Initialize a socket for our server socket.set_interface(eth) tcp_server = socket.socket() # Allocate socket for the server server_ip = None # IP address of server server_port = 5000 # Port to listen on tcp_server.bind((server_ip, server_port)) # Bind to IP and Port tcp_server.listen() # Begin listening for incoming clients conn, addr = tcp_server.accept() # Wait for a connection from a client. print("socket connected") return conn else: #创建tcp client print("create tcp client") def create_udp_socket(mode): if mode == 1: #创建udp server # Initialize a socket for our server socket.set_interface(eth) udp_server = socket.socket(socket.AF_INET,socket.SOCK_DGRAM) # Allocate socket for the server server_ip = '192.168.1.59' # IP address of server server_port = 5000 # Port to listen on port = 5000 udp_server.bind((eth.pretty_ip(eth.ip_address),port)) print("socket connected") else: #创建tcp client print("open socket") print("Wiznet5k SimpleServer Test ") led = led_init() display = display_init() display.fill(1) display.text("Wiznet5k SimpleServer ",0,10,0) display.show() eth = w5500_init() conn=create_tcp_socket(1) display.text("client connected ",0,80,0) display.text("recv data: ",0,90,0) display.show() while True: led.value = not led.value time.sleep(0.5) with conn: # data = conn.recv() # print(data) # conn.send(data) # Echo message back to client while True: data = conn.recv(10) if data: print(data) display.text(hex(i) for i in data,0,100,0) display.show() conn.send(data) # Echo message back to client break print("Done!")   通过在板端构建TCP服务器,抓包可以明显看到其三次握手、四次挥手的过程,以及每次数据传输中需要频繁ACK,证实了TCP属于一种可靠且稳定的网络通信协议。 现象如图:   进阶任务:从NTP服务器(注意数据交互格式的解析)同步时间,获取时间送显示屏(串口)显示 import board import busio import digitalio import time import adafruit_requests as requests from adafruit_wiznet5k.adafruit_wiznet5k import * import adafruit_wiznet5k.adafruit_wiznet5k_socket as socket from adafruit_wiznet5k.adafruit_wiznet5k_ntp import NTP import adafruit_wiznet5k.adafruit_wiznet5k_dns as dns days = ("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday") def led_init(): #配置LED led = digitalio.DigitalInOut(board.LED) led.direction = digitalio.Direction.OUTPUT return led def display_init(): #SPI1 Display SPI1_SCK = board.GP10 SPI1_MOSI = board.GP11 SPI1_CSn = board.GP13 #配置display的SPI display_spi = busio.SPI(SPI1_SCK, SPI1_MOSI) display_scs = digitalio.DigitalInOut(SPI1_CSn) display = adafruit_sharpmemorydisplay.SharpMemoryDisplay(display_spi, display_scs, 144, 168, baudrate=8000000) return display def w5500_init(): #SPI0 Ethernet SPI0_SCK = board.GP18 SPI0_TX = board.GP19 SPI0_RX = board.GP16 SPI0_CSn = board.GP17 #Ethernet reset W5500_RSTn = board.GP20 ethernetRst = digitalio.DigitalInOut(W5500_RSTn) ethernetRst.direction = digitalio.Direction.OUTPUT # Setup your network configuration below # random MAC, later should change this value on your vendor ID MY_MAC = (0x00, 0x01, 0x02, 0x03, 0x04, 0x05) IP_ADDRESS = (192, 168, 1, 100) SUBNET_MASK = (255, 255, 255, 0) GATEWAY_ADDRESS = (192, 168, 1, 1) DNS_SERVER = (8, 8, 8, 8) # For Adafruit Ethernet FeatherWing eth_cs = digitalio.DigitalInOut(SPI0_CSn) # For Particle Ethernet FeatherWing # cs = digitalio.DigitalInOut(board.D5) eth_spi = busio.SPI(SPI0_SCK, MOSI=SPI0_TX, MISO=SPI0_RX) # Reset W5500 first ethernetRst.value = False time.sleep(1) ethernetRst.value = True # Initialize ethernet interface with DHCP # eth = WIZNET5K(spi_bus, cs) # Initialize ethernet interface without DHCP eth = WIZNET5K(eth_spi, eth_cs, is_dhcp=False, mac=MY_MAC) # Set network configuration eth.ifconfig = (IP_ADDRESS, SUBNET_MASK, GATEWAY_ADDRESS, DNS_SERVER) print("Chip Version:", eth.chip) print("MAC Address:", [hex(i) for i in eth.mac_address]) print("My IP address is:", eth.pretty_ip(eth.ip_address)) display.text("Chip Version:"+eth.chip,0,20,0) display.text("MAC Address:",0,30,0) display.text(eth.pretty_mac(eth.mac_address),0,40,0) display.text("My IP address is:",0,50,0) display.text(eth.pretty_ip(eth.ip_address),0,60,0) display.show() return eth print("Wiznet5k ntp Test ") led = led_init() display = display_init() display.fill(1) display.text("Wiznet5k ntp Test",0,10,0) display.show() eth = w5500_init() # Initialize a socket for our server #socket.set_interface(eth) # Set network configuration #eth.ifconfig = (IP_ADDRESS, SUBNET_MASK, GATEWAY_ADDRESS, DNS_SERVER) #NTP ntpserver_ip = eth.pretty_ip(eth.get_host_by_name("time.google.com")) print("NTP : %s" % ntpserver_ip) #DNS Domain ntp = NTP(iface = eth, ntp_address =ntpserver_ip ,utc=9) cal = ntp.get_time() print("The date is %s %d/%d/%d" %(days[cal.tm_wday], cal.tm_mday,cal.tm_mon,cal.tm_year)) print("The time is %d:%02d:%02d" %(cal.tm_hour,cal.tm_min,cal.tm_sec))   该任务官方已经提供了示例程序,基于此又重新编写学习一下,但是不知道为什么,跑官方还有自己重新编写的程序都总是报错,提示少传入一个参数,后来又跟论坛上坛友发的贴子实现过程对照了一下,没什么太大出入,copy坛友的程序也跑不下来,不清楚什么原因。 现象如下:   DNS服务器已经根据域名解析出了目标NTP服务器的IP地址,证明网络应该是没问题的。 终极任务二:使用外部存储器,组建简易FTP文件服务器,并能正常上传下载文件。 使用一个SD NAND卡+一个TF卡的转接板,将SD NAND卡的信号引脚引出,用杜邦线通过SPI1接到SD NAND上。   根据坛友分享的帖子,大致了解了FTP的实现流程,分别需要两个socket,一个用来做控制,包括登录认证之类的,另一个用来做文件传输,并且FTP是基于TCP传输层协议的,另外还知道了TFTP是另一种基于UDP传输层协议的应用。 下面根据坛友分享的进行学习 # # Small ftp server for ESP8266 ans ESP32 Micropython # # Based on the work of chrisgp - Christopher Popp and pfalcon - Paul Sokolovsky # # The server accepts passive mode only. # It runs in foreground and quits, when it receives a quit command # Start the server with: # # import ftp # # Copyright (c) 2016 Christopher Popp (initial ftp server framework) # Copyright (c) 2016 Robert Hammelrath (putting the pieces together # and a few extensions) # Distributed under MIT License # import socket import network import uos import gc #from usocket import socket from machine import Pin,SPI,UART,PWM import time, network,framebuf ''' static netinfo ''' ip = '192.168.1.20' sn = '255.255.255.0' gw = '192.168.1.1' dns= '8.8.8.8' BL = 13 DC = 8 RST = 12 MOSI = 11 SCK = 10 CS = 9 netinfo=(ip, sn, gw, dns) localip = '' localport = 8000 listen_info = (localip, localport) conn_flag = False def w5x00_init(): global localip spi=SPI(0,2_000_000, mosi=Pin(19),miso=Pin(16),sck=Pin(18)) nic = network.WIZNET5K(spi,Pin(17),Pin(20)) nic.active(True) # use dhcp, if fail use static netinfo #try: # nic.ifconfig('dhcp') #except: nic.ifconfig(netinfo) localip = nic.ifconfig()[0] print('ip :', nic.ifconfig()[0]) print('sn :', nic.ifconfig()[1]) print('gw :', nic.ifconfig()[2]) print('dns:', nic.ifconfig()[3]) while not nic.isconnected(): time.sleep(1) # print(nic.regs()) print('no link') return nic def send_list_data(path, dataclient, full): try: # whether path is a directory name for fname in sorted(uos.listdir(path), key=str.lower): 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 sorted(uos.listdir(path), key=str.lower): if fncmp(fname, pattern): 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] description = "{} 1 owner group {:>10} Jan 1 2000 {}\r\n".format( file_permissions, file_size, fname) else: description = fname + "\r\n" return description def send_file_data(path, dataclient): with open(path, "rb") as file: chunk = file.read(512) while len(chunk) > 0: dataclient.sendall(chunk) chunk = file.read(512) def save_file_data(path, dataclient): with open(path, "wb") as file: chunk = dataclient.recv(512) while len(chunk) > 0: file.write(chunk) chunk = dataclient.recv(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:]): 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(net, port=21, timeout=None): 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", port)[0][4]) datasocket.bind(socket.getaddrinfo("0.0.0.0", DATA_PORT)[0][4]) ftpsocket.listen(1) ftpsocket.settimeout(timeout) datasocket.listen(1) datasocket.settimeout(None) msg_250_OK = '250 OK\r\n' msg_550_fail = '550 Failed\r\n' addr = net.ifconfig()[0] print("FTP Server started on ", addr) try: dataclient = None fromname = None do_run = True while do_run: cl, remote_addr = ftpsocket.accept() cl.settimeout(300) cwd = '/' try: # print("FTP connection from:", remote_addr) cl.sendall("220 Hello, this is Micropython.\r\n") while True: gc.collect() data = cl.readline().decode("utf-8").rstrip("\r\n") if len(data) <= 0: print("Client disappeared") do_run = False break command = data.split(" ")[0].upper() payload = data[len(command):].lstrip() path = get_absolute_path(cwd, payload) print("Command={}, Payload={}".format(command, payload)) 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" or command == "XPWD": cl.sendall('257 "{}"\r\n'.format(cwd)) elif command == "CWD" or command == "XCWD": 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') do_run = False break elif command == "PASV": 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) DATA_PORT = 13333 active = False elif command == "PORT": items = payload.split(",") if len(items) >= 6: data_addr = '.'.join(items[:4]) # replace by command session addr if data_addr == "127.0.1.1": data_addr = remote_addr DATA_PORT = int(items[4]) * 256 + int(items[5]) dataclient = socket.socket(socket.AF_INET, socket.SOCK_STREAM) dataclient.settimeout(10) dataclient.connect((data_addr, DATA_PORT)) print("FTP Data connection with:", data_addr) cl.sendall('200 OK\r\n') active = True else: cl.sendall('504 Fail\r\n') elif command == "LIST" or command == "NLST": if not payload.startswith("-"): place = path else: place = cwd try: cl.sendall("150 Here comes the directory listing.\r\n") send_list_data(place, dataclient, command == "LIST" or payload == "-l") 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: cl.sendall("150 Opening data connection.\r\n") send_file_data(path, dataclient) 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) 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" or command == "XRMD": try: uos.rmdir(path) cl.sendall(msg_250_OK) except: cl.sendall(msg_550_fail) elif command == "MKD" or command == "XMKD": 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 elif command == "MDTM": try: tm=localtime(uos.stat(path)[8]) cl.sendall('213 {:04d}{:02d}{:02d}{:02d}{:02d}{:02d}\r\n'.format(*tm[0:6])) except: cl.sendall('550 Fail\r\n') elif command == "STAT": if payload == "": cl.sendall("211-Connected to ({})\r\n" " Data address ({})\r\n" "211 TYPE: Binary STRU: File MODE:" " Stream\r\n".format( remote_addr[0], addr)) else: cl.sendall("213-Directory listing:\r\n") send_list_data(path, cl, True) cl.sendall("213 Done.\r\n") 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 except Exception as e: print(e) finally: datasocket.close() ftpsocket.close() if dataclient is not None: dataclient.close() if __name__ == "__main__": nic = w5x00_init() ftpserver(nic)   运行之后,SD NAND挂载正常,但是不知道为什么,在进行socket初始化的时候,又一个提示参数无效的报错,已经成功刷成micropython的固件,并且该导入的库我也导入了。 心得体会 本期是23年的第四期follow me活动,确实对得起这个第四期,个人感觉确实有些难度,刚开始不太懂网络协议栈确实有些吃力,后面跟着坛友们的分享,一步步走下去,虽然坑还是没少趟,但是收获也是有的,2024继续加油! 内容三、可编译下载的代码

  • 加入了学习《 【得捷电子Follow me第4期】》,观看 【得捷Follow me第4期】简易FTP文件服务器

  • 2024-02-04
  • 回复了主题帖: 共读入围名单:《原子嵌入式Linux驱动开发详解与实战(ARM Linux驱动)》

    个人信息无误,确认可以完成

  • 2024-02-02
  • 加入了学习《直播回放: FollowMe 4 W5500-EVB-Pico 使用入门》,观看 W5500-EVB-Pico 使用入门

  • 2023-12-21
  • 加入了学习《【DigiKey“智造万物,快乐不停”创意大赛】 钢铁侠的智能助手贾维斯》,观看 【DigiKey“智造万物,快乐不停”创意大赛】 钢铁侠的智能助手贾维斯

最近访客

< 1/4 >

统计信息

已有74人来访过

  • 芯积分:1801
  • 好友:--
  • 主题:15
  • 回复:9

留言

你需要登录后才可以留言 登录 | 注册


现在还没有留言