- 2024-09-27
-
加入了学习《【Follow me第二季第1期】任务提交》,观看 【Follow me第二季第1期】任务提交
- 2024-09-01
-
发表了主题帖:
【Follow me第二季第1期】任务提交
本帖最后由 bitter 于 2024-9-27 21:48 编辑
【Follow me第二季第1期】任务提交
很高兴能够参加本期由得捷电子和eeworld社区共同举办得本次【Follow me第二季第1期】活动,想想前前后后也参加过好几次follow me活动了,这次应该是第三次了,还是很感谢得捷电子和eeworld社区提供的机会,期待后续活动再能出现一些有意思的板子~
由于最近比较忙,收到板子后也是拖了比较长的时间直到最后几天才开始相关的活动,时间比较匆忙,完成的不是很好,希望各位审核大大能够手下留情、高抬贵手。
物料清单
我购买物料为活动必备物料开发板、推荐物料舵机、排针,还有一个传感器适配器,还以为是传感器本身,到手一看才发生是一个适配器。
物料展示
项目视频演示
【Follow me第二季第1期】任务提交-【Follow me第二季第1期】任务提交-EEWORLD大学堂
入门任务:开发环境搭建,板载LED点亮
按照Arduino | Adafruit Circuit Playground Express | Adafruit Learning System里的教程一步一步搭建arduino开发环境,并点亮板载LED。
官网下载IDE,https://www.arduino.cc/en/software
安装完成后,打开IDE,点击Tools->Board->Boards Manager,安装Arduino SAMD
安装完成后输入示例代码,使用MicroUSB 线连接开发板,选择对应得端口,点击upload即可烧录程序,观察到如下输出即代表烧录成功。
烧录成功后,重启开发板可以看到开发板上得红灯开始闪烁。
// the setup function runs once when you press reset or power the board
void setup() {
// initialize digital pin 13 as an output.
pinMode(13, OUTPUT);
}
// the loop function runs over and over again forever
void loop() {
digitalWrite(13, HIGH); // turn the LED on (HIGH is the voltage level)
delay(1000); // wait for a second
digitalWrite(13, LOW); // turn the LED off by making the voltage LOW
delay(1000); // wait for a second
}
演示图片:
软件流程图:
基础任务一:控制板载炫彩LED,跑马灯点亮和颜色变换
在本次任务中,我们使用到了Mini NeoPixel LED,需要借助Adafruit NeoPixel Library这个库。下载完成后,点击->Sketch->Include Library->Add .ZIP Library…,将对应得库文件导入即可。
#include <Adafruit_NeoPixel.h>
#define PIN 8
// 定义按钮引脚
#define BUTTON_COLOR 4 // 调节亮度
Adafruit_NeoPixel strip = Adafruit_NeoPixel(10, PIN, NEO_GRB + NEO_KHZ400);
int currentColor = 0;
int brightness = 50;
void setup() {
pinMode(BUTTON_COLOR, INPUT); // 设置按钮
strip.begin();
strip.setBrightness(brightness);
strip.show();
}
void loop() {
// 检查按钮状态
checkButtons();
// 执行当前效果
switch (currentColor) {
case 0:
colorWipe(strip.Color(255, 0, 0), 50);
break;
case 1:
colorWipe(strip.Color(0, 255, 0), 50);
break;
case 2:
colorWipe(strip.Color(0, 0, 255), 50);
break;
case 3:
colorWipe(strip.Color(0, 0, 0, 255), 50);
break;
}
}
bool checkButtons() {
bool buttonPressed = false;
static int lastButtonState = LOW;
int buttonState = digitalRead(BUTTON_COLOR);
if (buttonState == HIGH && lastButtonState == LOW) {
delay(50);
if (buttonState == HIGH && lastButtonState == LOW)
{
currentColor = (currentColor + 1)%4;
buttonPressed = true;
}
}
lastButtonState = buttonState;
return buttonPressed;
}
void colorWipe(uint32_t c, uint8_t wait) {
for (uint16_t i = 0; i < strip.numPixels(); i++) {
strip.setPixelColor(i, c);
strip.show();
if (checkButtons()) return; // 如果按钮被按下,则中断循环
}
}
该程序主要是实现了每按一次按钮后,彩色LED在红、绿、蓝和灭四种状态转换。
演示图片:
软件流程图:
基础任务二:监测环境温度和光线,通过板载LED展示舒适程度
在本次任务中,我们除了需要使用上一个任务使用得Mini NeoPixel LED,还额外需要使用温度传感器和光传感器,需要借助Adafruit_CircuitPlayground这个库。安装方式按上一个任务将对应得库文件添加即可。
#include <Adafruit_CircuitPlayground.h>
void setup() {
CircuitPlayground.begin();
Serial.begin(921600);
}
void loop() {
displayTemperature();
delay(250);
displayBrightness();
delay(250);
}
void displayTemperature() {
uint8_t ledCount;
float temperature = CircuitPlayground.temperature();
uint32_t color;
Serial.println("current temperature is");
Serial.println(temperature);
ledCount= (int)temperature/5;
color = CircuitPlayground.colorWheel((11-ledCount)*25);
for (int i = 0; i < 10; i++) {
if (i < ledCount) {
CircuitPlayground.setPixelColor(9 - i, color);
} else {
CircuitPlayground.setPixelColor(9 - i, 0); // 关闭LED
}
}
}
void displayBrightness() {
uint16_t brightness = CircuitPlayground.lightSensor();
uint8_t overallBrightness = map(brightness, 0, 500, 0, 100);
Serial.println("current brightness is");
Serial.println(brightness);
CircuitPlayground.setBrightness(overallBrightness); //调整所有灯珠亮度
}
该程序将通过串口实时输出当前的温度和环境亮度。根据当前温度将会实时点亮不同个数的LED并显示不同颜色;根据当前的环境亮度将会调整所有LED的亮度。
演示图片:
软件流程图:
基础任务三:接近检测——设定安全距离并通过板载LED展示,检测到入侵时,发起声音报警
在本次任务中,使用了Mini NeoPixel LED、红外发射器和接收器,还有蜂鸣器。
#include <Adafruit_CircuitPlayground.h>
#define SAFE_DISTANCE 450
const int alertTone = 1000;
const int irTransmitterPin = 25;
const int irReceiverPin = A10;
void setup() {
CircuitPlayground.begin();
Serial.begin(921600);
pinMode(irReceiverPin, INPUT);
pinMode(irTransmitterPin, OUTPUT);
}
void loop() {
sendIRPulse();
int distance = analogRead(irReceiverPin);
displayDistance(distance);
checkForIntrusion(distance);
delay(300);
}
void displayDistance(int distance) {
int ledCount = map(distance, 290, SAFE_DISTANCE, 1, 10);
uint32_t color;
Serial.print("Distance: ");
Serial.print(distance);
Serial.print(", LED Count: ");
Serial.println(ledCount);
color = CircuitPlayground.colorWheel((11-ledCount)*25);
for (int i = 0; i < 10; i++) {
if (i < ledCount) {
CircuitPlayground.setPixelColor(i, color);
} else {
CircuitPlayground.setPixelColor(i, 0);
}
}
}
void checkForIntrusion(int distance) {
if (distance > SAFE_DISTANCE) {
Serial.println("Intrusion detected!");
playAlertTone();
}
}
void sendIRPulse() {
for (int i = 0; i < 32; i++) {
digitalWrite(irTransmitterPin, HIGH);
delayMicroseconds(13);
digitalWrite(irTransmitterPin, LOW);
delayMicroseconds(13);
}
}
void playAlertTone() {
CircuitPlayground.playTone(alertTone, 1000);
}
在靠近的过程中将逐渐点亮不同个数的LED并显示不同颜色,超过安全范围时蜂鸣器将会发出警告。
演示图片:
软件流程图:
进阶任务:制作不倒翁——展示不倒翁运动过程中的不同灯光效果
由于条件有限,没办法制作相应的不倒翁,所以我实际上是用板载陀螺仪检测板子的姿态,然后给出对应的灯光效果:即往哪边倾斜就点亮哪一边的LED,水平则全部点亮。
#include <Adafruit_CircuitPlayground.h>
#include <math.h>
void setup() {
CircuitPlayground.begin();
Serial.begin(921600);
}
void loop() {
float x = CircuitPlayground.motionX();
float y = CircuitPlayground.motionY();
float z = CircuitPlayground.motionZ();
int ledToLight = -1;
Serial.print("X: ");
Serial.print(x);
Serial.print(" - Y: ");
Serial.print(y);
Serial.print(" - Z: ");
Serial.print(z);
z -= 9.8;
if(abs(x)<2 && abs(y)<2 && abs(z)<2)
ledToLight = -1;
else if(y<-2 && abs(x)<2)
ledToLight = 0;
else if(y<-2 && x>2)
ledToLight = 1;
else if(x>2 && abs(y)<2)
ledToLight = 2;
else if(x>2 && y>2)
ledToLight = 3;
else if(y>2 && abs(x)<2)
ledToLight = 4;
else if(y>2 && x<-2)
ledToLight = 6;
else if(x<-2 && abs(y)<2)
ledToLight = 7;
else if(x<-2 && y<-2)
ledToLight = 8;
uint8_t color= map( ledToLight, 0, 9, 0, 255);
if (ledToLight == -1) {
for (int i = 0; i < 10; i++) {
CircuitPlayground.setPixelColor(i, CircuitPlayground.colorWheel(85)); //水平时都点亮
}
} else {
for (int i = 0; i < 10; i++) {
if (i == ledToLight || (ledToLight == 4 && i == 5) || (ledToLight == 0 && i == 9)) {
CircuitPlayground.setPixelColor(i, CircuitPlayground.colorWheel(color));//点亮对应位置的
} else {
CircuitPlayground.setPixelColor(i, 0);
}
}
}
Serial.print(" - LED To Light: ");
Serial.println(ledToLight);
delay(100);
}
演示图片:
软件流程图:
创意任务二:章鱼哥——章鱼哥的触角根据环境声音的大小,章鱼哥的触角可舒展或者收缩
由于时间和外部条件的限制,没有制作章鱼模型。本次任务是使用麦克风识别环境音量,根据环境音量的大小点亮不同个数的LED并显示不同颜色。除此之外,根据环境音量的变化逆时针或顺时针旋转舵机。
#include <Adafruit_CircuitPlayground.h>
#include <Servo.h>
float SoundLevel,lastsoundLevel;
// 舵机定义
const int servoPin = A3; // 舵机连接的引脚
Servo myServo;
int Speed=90;
void setup() {
CircuitPlayground.begin();
Serial.begin(921600);
myServo.attach(servoPin);
myServo.write(Speed);
}
void loop() {
uint32_t color;
int ledCount;
float soundLevel = CircuitPlayground.mic.soundPressureLevel(10);
ledCount = map(soundLevel, 50, 100, 0, 10);
color = CircuitPlayground.colorWheel((11-ledCount)*25);
Serial.print("Raw Sound Level: ");
Serial.println(soundLevel);
for (int i = 0; i < 10; i++) {
if (i < ledCount) {
CircuitPlayground.setPixelColor(i, color);
} else {
CircuitPlayground.setPixelColor(i, 0);
}
}
if(fabs((lastsoundLevel-soundLevel))>1)
{
static uint8_t i=0;
if(i++ % 2)
Speed -= (int)(lastsoundLevel-soundLevel);
else
Speed += (int)(lastsoundLevel-soundLevel);
}
else
Speed = 90;
lastsoundLevel = soundLevel;
myServo.write(Speed);
Serial.print("Speed:");
Serial.println(Speed);
delay(200);
}
演示图片:
软件流程图:
项目总结
总的来说,由于时间匆忙,没有很深入的了解这款开发板,但是即使是在有限的条件下也了解了这块板子的多样性和强大功能。第一次使用Arduino,也学会了很多。
最后,感谢得捷电子和eeworld社区提供的机会,期待后续活动!
-
加入了学习《Follow me第二季第一期 任务演示》,观看 Follow me第二季第一期 任务演示
-
加入了学习《Follow me第二季第1期》,观看 创意任务二:章鱼哥
-
加入了学习《FollowMe 第二季: 1 Adafruit Circuit Playground Express及任务讲解》,观看 Adafruit Circuit Playground Express 及任务讲解
- 2024-08-31
-
加入了学习《【Follow me第二季第1期】全部任务演示》,观看 全部任务演示2.0
-
加入了学习《【Follow me第二季第1期】任务提交-使用makecode开发(JavaScript)》,观看 【Follow me第二季第1期】任务提交-使用makecode开发(JavaScript)
- 2024-08-29
-
加入了学习《【Follow me第二季第1期】视频展示》,观看 得捷电子Follow me第二季第期视频展示
- 2024-04-17
-
加入了学习《泰克MSO6B探索营:应用案例深度解析》,观看 通用串行总线USB技术演进及测试方案
- 2024-03-14
-
回复了主题帖:
【Luckfox幸狐 RV1103】——文件传输+SDK 环境部署
Jacktang 发表于 2024-3-14 07:34
文件传输+SDK 环境部署
之后下面准备怎么整
网友们都说内置的NOR FLASH 太小了,所以下一步打算使用SD卡烧录,连接摄像头,跑一下RKNN推理测试
- 2024-03-12
-
发表了主题帖:
【Luckfox幸狐 RV1103】——文件传输+SDK 环境部署
一、文件传输
Win +R 在 Windows 地址栏输入 \\172.32.0.93,用户名为 root,密码为 luckfox。
拖动文件到想要存放的目录,完成传输。
二、SDK 环境部署
首先安装依赖环境。
sudo apt update
sudo apt-get install -y git ssh make gcc gcc-multilib g++-multilib module-assistant expect g++ gawk texinfo libssl-dev bison flex fakeroot cmake unzip gperf autoconf device-tree-compiler libncurses5-dev pkg-config bc python-is-python3 passwd openssl openssh-server openssh-client vim file cpio rsync
获取最新的 SDK。
git clone https://gitee.com/LuckfoxTECH/luckfox-pico.git
在luckfox-pico根目录,输入
./build.sh
按照对应的硬件选择,即可进行编译。
-
发表了主题帖:
【Luckfox幸狐 RV1103】——ADB 登录+串口登录
ADB 登录
下载 ADB 安装包, 右键我的电脑属性—>高级系统设置—>环境变量,
系统变量—>编辑—>将adb解压路径新建进去。
登录之前配置 RNDIS 虚拟网口,可以参考之前的文章。
使用adb connect 172.32.0.93命令连接 Luckfox Pico 。
使用adb devices命令查看 ADB 设备。
使用adb -s 172.32.0.93:5555 shell命令登录到开发板。
串口登录
根据原理图,将UART2_TX和UART2_RX与串口调试工具连接,使用串口调试助手连接。
打开串口调试助手,选择对应测串口,设置串口的波特率波特率为115200。
点击OK,按下回车,输入登录名:root 和登录密码:luckfox 就可以登陆了。
- 2024-03-04
-
加入了学习《泰克MSO6B探索营》,观看 如何完成AI芯片电源噪声测试
-
加入了学习《泰克MSO6B探索营》,观看 MSO6B系列低噪声演示
-
加入了学习《泰克MSO6B探索营》,观看 MSO6B-360度介绍
-
加入了学习《泰克MSO6B探索营》,观看 工程师说走就走的旅行
- 2024-02-25
-
回复了主题帖:
【得捷电子Follow me第4期】扩展U8G2移植支持LCD显示
厉害厉害,学习了
-
加入了学习《 【得捷电子Follow me第4期】》,观看 【得捷Follow me第4期】入门任务:开发环境搭建
-
加入了学习《【得捷Follow me第4期】项目总结》,观看 【得捷Follow me第4期】项目总结
- 2024-02-24
-
发表了主题帖:
【得捷Follow me第4期】项目总结
本帖最后由 bitter 于 2024-2-24 23:47 编辑
【得捷Follow me第4期】项目总结
很高兴能参加得捷电子Follow me第4期活动。
一、任务实现视频
【得捷Follow me第4期】项目总结-【得捷Follow me第4期】项目总结-EEWORLD大学堂
二、项目任务总结报告
1.入门任务:开发环境搭建,BLINK,驱动液晶显示器进行显示(没有则串口HelloWorld)
硬件环境
W5500-EVB-PICO(主控)
AdafruitSharp Memory Display(显示)
根据相关资料,显示模块是通过SPI接口操作的,所以需要选定主控合适的引脚与显示模块引脚连接,完成spi驱动,选择以下引脚向连接。
W5500-EVB-PICO
AdafruitSharp Memory Display
GPIO13
CS
GPIO14
CLK
GPIO15
DI
GND
GND
3V3
VIN
软件环境
下载Thonny:Thonny, Python IDE for beginners
安装完成后,打开,点击右下角对应的端口即可。
下载固件:
Circuitpython:W5500-EVB-Pico Download (circuitpython.org)
MicroPython:MicroPython - Python for microcontrollers
将开发板通过micro USB线接电脑,按住BOOTSEL键后再短按一下RUN键,最后松开BOOTSEL键,电脑会将开发板识别成U盘。
将前面下载好的固件复制到此U盘,复制完成后开发板会自动重启,至此固件烧录完成。
下载库文件:Libraries (circuitpython.org)
这里需要注意,我们应该选择与之前下载的固件版本对应的库下载。
将下载的压缩包解压,并将需要的库文件复制到CIRCUITPY的盘符的lib文件夹下。
这里需要将font5x8.bin文件放入CIRCUITPY的盘符下,否则后续使用将报错。
相关代码
屏幕显示相关文字,并且每0.5s闪烁LED灯。
import time
import board
import busio
import digitalio
import adafruit_sharpmemorydisplay
def led_flush():
led.value = not led.value
time.sleep(0.5)
def clear_disp():
# Clear the display. Always call show after changing pixels to make the display
# update visible!
display.fill(1)
display.show()
def disp_helloworld():
print("hello world")
display.fill(1)
display.text(" hello world!", 30, 50, 0)
display.show()
if __name__ == '__main__':
led = digitalio.DigitalInOut(board.GP25)
led.direction = digitalio.Direction.OUTPUT
# Initialize SPI bus and control pins
spi = busio.SPI(board.GP14, MOSI=board.GP15)
scs = digitalio.DigitalInOut(board.GP13) # inverted chip select
# pass in the display size, width and height, as well
# display = adafruit_sharpmemorydisplay.SharpMemoryDisplay(spi, scs, 96, 96)
display = adafruit_sharpmemorydisplay.SharpMemoryDisplay(spi, scs, 144, 168)
clear_disp()
disp_helloworld()
while True:
led_flush()
2.基础任务一:完成主控板W5500初始化(静态IP配置),并能使用局域网电脑ping通,同时W5500可以ping通互联网站点;通过抓包软件(Wireshark、Sniffer等)抓取本地PC的ping报文,展示并分析。
实现过程
将以下库文件复制到CIRCUITPY的盘符的lib文件夹下。
根据相关资料,RP2040与W5500引脚连接如下:
将W5500-EVB-PICO接入网络,并确保与本机IP地址处于同一网段。
查询本机IP地址为192.168.6.4
配置w5500的IP地址为192.168.6.100,网关为192.168.6.1
效果图
本地PC Ping W5500-EVB-PICO
抓包软件Wireshark抓取本地PC的ping报文
相关代码
屏幕初始化
def init():
led = digitalio.DigitalInOut(board.GP25)
led.direction = digitalio.Direction.OUTPUT
# Initialize SPI bus and control pins
spi = busio.SPI(board.GP14, MOSI=board.GP15)
scs = digitalio.DigitalInOut(board.GP13) # inverted chip select
# pass in the display size, width and height, as well
# display = adafruit_sharpmemorydisplay.SharpMemoryDisplay(spi, scs, 96, 96)
display = adafruit_sharpmemorydisplay.SharpMemoryDisplay(spi, scs, 144, 168)
return led,display
w5500初始化
def init_w5500(ip, subnet, gateway, dns):
##SPI0
SPI0_SCK = board.GP18
SPI0_TX = board.GP19
SPI0_RX = board.GP16
SPI0_CSn = board.GP17
##reset
W5x00_RSTn = board.GP20
print("Wiznet5k Ping Test (no DHCP)")
ethernetRst = digitalio.DigitalInOut(W5x00_RSTn)
ethernetRst.direction = digitalio.Direction.OUTPUT
# For Adafruit Ethernet FeatherWing
cs = digitalio.DigitalInOut(SPI0_CSn)
# For Particle Ethernet FeatherWing
# cs = digitalio.DigitalInOut(board.D5)
spi_bus = 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 without DHCP
eth = WIZNET5K(spi_bus, cs, is_dhcp=False)
# Set network configuration
eth.ifconfig = (ip, subnet, gateway, dns)
print("Chip Version:", eth.chip)
print("My IP address is:", eth.pretty_ip(eth.ip_address))
return eth
完整代码
import time
import board
import busio
import digitalio
import array
import struct
import adafruit_sharpmemorydisplay
from adafruit_wiznet5k.adafruit_wiznet5k import WIZNET5K
import adafruit_wiznet5k.adafruit_wiznet5k_socket as socket
IP_ADDRESS = (192, 168, 6, 100)
SUBNET_MASK = (255, 255, 255, 0)
GATEWAY_ADDRESS = (192, 168, 6, 1)
DNS_SERVER = (8, 8, 8, 8)
def init():
led = digitalio.DigitalInOut(board.GP25)
led.direction = digitalio.Direction.OUTPUT
# Initialize SPI bus and control pins
spi = busio.SPI(board.GP14, MOSI=board.GP15)
scs = digitalio.DigitalInOut(board.GP13) # inverted chip select
# pass in the display size, width and height, as well
# display = adafruit_sharpmemorydisplay.SharpMemoryDisplay(spi, scs, 96, 96)
display = adafruit_sharpmemorydisplay.SharpMemoryDisplay(spi, scs, 144, 168)
return led,display
def led_flush():
led.value = not led.value
time.sleep(0.5)
def clear_disp():
# Clear the display. Always call show after changing pixels to make the display
# update visible!
display.fill(1)
display.show()
def init_w5500(ip, subnet, gateway, dns):
##SPI0
SPI0_SCK = board.GP18
SPI0_TX = board.GP19
SPI0_RX = board.GP16
SPI0_CSn = board.GP17
##reset
W5x00_RSTn = board.GP20
print("Wiznet5k Ping Test (no DHCP)")
ethernetRst = digitalio.DigitalInOut(W5x00_RSTn)
ethernetRst.direction = digitalio.Direction.OUTPUT
# For Adafruit Ethernet FeatherWing
cs = digitalio.DigitalInOut(SPI0_CSn)
# For Particle Ethernet FeatherWing
# cs = digitalio.DigitalInOut(board.D5)
spi_bus = 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 without DHCP
eth = WIZNET5K(spi_bus, cs, is_dhcp=False)
# Set network configuration
eth.ifconfig = (ip, subnet, gateway, dns)
print("Chip Version:", eth.chip)
print("My IP address is:", eth.pretty_ip(eth.ip_address))
return eth
def disp_w5500():
clear_disp()
display.fill(1)
cst = "chip version:" + eth.chip
display.text(cst, 0, 0, 0)
cst = "ip:" + eth.pretty_ip(eth.ip_address)
display.text(cst, 0, 10, 0)
cst = "mac:" + eth.pretty_mac(eth.mac_address)
display.text(cst, 0, 20, 0)
display.show()
if __name__ == '__main__':
# 初始化led和显示模块
led,display = init()
#静态初始化w5500
eth = init_w5500(IP_ADDRESS, SUBNET_MASK, GATEWAY_ADDRESS, DNS_SERVER)
disp_w5500()
while True:
led_flush()
3.基础任务二:主控板建立TCPIP或UDP服务器,局域网PC使用TCPIP或UDP客户端进行连接并发送数据,主控板接收到数据后,送液晶屏显示(没有则通过串口打印显示);通过抓包软件抓取交互报文,展示并分析。(TCP和UDP二选一,或者全都操作)
实现过程
TCP连接过程
创建TCP服务器
使用调试工具连接
数据发送报错,不清楚是什么问题
相关代码
建立tcp服务器
def create_tcpserver(port):
# Initialize a socket for our server
socket.set_interface(eth)
server = socket.socket() # Allocate socket for the server
server_ip = None # IP address of server
server_port = port # Port to listen on
server.bind((server_ip, server_port)) # Bind to IP and Port
server.listen() # Begin listening for incoming clients
return server
完整代码
import time
import board
import busio
import digitalio
import array
import struct
import adafruit_sharpmemorydisplay
from adafruit_wiznet5k.adafruit_wiznet5k import WIZNET5K
import adafruit_wiznet5k.adafruit_wiznet5k_socket as socket
IP_ADDRESS = (192, 168, 6, 100)
SUBNET_MASK = (255, 255, 255, 0)
GATEWAY_ADDRESS = (192, 168, 6, 1)
DNS_SERVER = (8, 8, 8, 8)
def init():
led = digitalio.DigitalInOut(board.GP25)
led.direction = digitalio.Direction.OUTPUT
# Initialize SPI bus and control pins
spi = busio.SPI(board.GP14, MOSI=board.GP15)
scs = digitalio.DigitalInOut(board.GP13) # inverted chip select
# pass in the display size, width and height, as well
# display = adafruit_sharpmemorydisplay.SharpMemoryDisplay(spi, scs, 96, 96)
display = adafruit_sharpmemorydisplay.SharpMemoryDisplay(spi, scs, 144, 168)
return led,display
def led_flush():
led.value = not led.value
time.sleep(0.5)
def clear_disp():
# Clear the display. Always call show after changing pixels to make the display
# update visible!
display.fill(1)
display.show()
def init_w5500(ip, subnet, gateway, dns):
##SPI0
SPI0_SCK = board.GP18
SPI0_TX = board.GP19
SPI0_RX = board.GP16
SPI0_CSn = board.GP17
##reset
W5x00_RSTn = board.GP20
ethernetRst = digitalio.DigitalInOut(W5x00_RSTn)
ethernetRst.direction = digitalio.Direction.OUTPUT
# For Adafruit Ethernet FeatherWing
cs = digitalio.DigitalInOut(SPI0_CSn)
# For Particle Ethernet FeatherWing
# cs = digitalio.DigitalInOut(board.D5)
spi_bus = 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 without DHCP
eth = WIZNET5K(spi_bus, cs, is_dhcp=False)
# Set network configuration
eth.ifconfig = (ip, subnet, gateway, dns)
print("Chip Version:", eth.chip)
print("My IP address is:", eth.pretty_ip(eth.ip_address))
return eth
def disp_w5500():
clear_disp()
display.fill(1)
cst = "chip version:" + eth.chip
display.text(cst, 0, 0, 0)
cst = "ip:" + eth.pretty_ip(eth.ip_address)
display.text(cst, 0, 10, 0)
cst = "mac:" + eth.pretty_mac(eth.mac_address)
display.text(cst, 0, 20, 0)
display.show()
def disp_str(s, addr):
display.fill_rect(0,addr,144,10,1)
display.text(s, 0, addr, 0)
display.show()
def create_tcpserver(port):
# Initialize a socket for our server
socket.set_interface(eth)
server = socket.socket() # Allocate socket for the server
server_ip = None # IP address of server
server_port = port # Port to listen on
server.bind((server_ip, server_port)) # Bind to IP and Port
server.listen() # Begin listening for incoming clients
return server
if __name__ == '__main__':
# 初始化led和显示模块
led,display = init()
clear_disp()
#静态初始化w5500
eth = init_w5500(IP_ADDRESS, SUBNET_MASK, GATEWAY_ADDRESS, DNS_SERVER)
disp_w5500()
# 创建一个tcp服务器
server = create_tcpserver(5000)
conn, addr = server.accept() # Wait for a connection from a client.
print("socket connected")
print(addr)
disp_str("TCP Server TEST", 30)
disp_str('client:'+addr[0]+','+str(addr[1]), 50)
disp_str('receive:', 60)
linenum = 70
while True:
led_flush()
with server:
while True:
data = conn.recv(20)
if data:
print(data)
disp_str(data.decode('utf-8'),linenum)
linenum += 10
if linenum > 150:
linenum = 70
4.进阶任务:从NTP服务器(注意数据交互格式的解析)同步时间,获取时间送显示屏(串口)显示。
实现过程
不知道为什么使用CircuitPython官方例程都报错
所以更换MicroPython,这里参考了@太阳上的骑士的代码
实现效果
相关代码
完整代码
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.6.100','255.255.255.0','192.168.6.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()
5.终极任务二:使用外部存储器,组建简易FTP文件服务器,并能正常上传下载文件。
实现过程
这里参考了@ eew_uscYT9的代码
在window的文件夹内搜索ftp服务器
将文件文件拖入其中
断开连接,重新访问
下载文件
相关代码
完整代码
#
# 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.6.100'
sn = '255.255.255.0'
gw = '192.168.6.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)
三、心得体会
很高兴能够参加本期由EEWORLD和得捷电子共同举办得捷电子Follow me第4期活动。在这次活动,我了解了如何建立TCP或UDP连接,如何从NTP服务器同步时间,如何组建简易FTP文件服务器。
最后,希望电子工程世界和得捷电子越办越好,以后能够多多的举办这样的活动,也希望大家能够从中收获满满。