eew_gz8e7C

  • 2024-12-10
  • 加入了学习《【Follow me第二季第4期】任务汇报》,观看 【Follow me第二季第4期】任务汇报

  • 加入了学习《Follow me第二季第1期》,观看 创意任务二:章鱼哥

  • 加入了学习《Follow me第二季第1期》,观看 创意任务三:触摸钢琴

  • 加入了学习《Follow me第二季第1期》,观看 创意任务一:可穿戴装饰——报警器

  • 2024-10-07
  • 发表了主题帖: 【Follow me第二季第2期】任务汇总贴

    本帖最后由 eew_gz8e7C 于 2024-10-7 15:30 编辑 一 、视频介绍   二、任务实现   2.1 入门任务(必做):搭建环境并开启第一步Blink / 串口打印Hello EEWorld! 软件流程:   代码: void setup() { // put your setup code here, to run once: //配置波特率 Serial.begin(115200); while (!Serial) { } //配置LED引脚为输出模式 //pinMode(102, OUTPUT); pinMode(LED_BUILTIN, OUTPUT); } void loop() { // put your main code here, to run repeatedly: //演示控制板载LED亮灭,并且打印LED状态 digitalWrite(LED_BUILTIN, LOW); printf("LED ON\n"); delay(1000); digitalWrite(LED_BUILTIN, HIGH); printf("LED OFF\n"); delay(1000); } 效果展示: [localvideo]ec0a5858a7dcf0f85c9950ccb593d237[/localvideo] 实现过程: 【Follow me第二季第2期】开箱+环境搭建+Blink&串口打印 - DigiKey得捷技术专区 - 电子工程世界-论坛 (eeworld.com.cn)   2.2 基础任务(必做):驱动12x8点阵LED;用DAC生成正弦波;用OPAMP放大DAC信号;用ADC采集并且打印数据到串口等其他接口可上传到上位机显示曲线 软件流程:        代码: // LED_MX #include "Arduino_LED_Matrix.h" //调用LED_Matrix库 ArduinoLEDMatrix matrix; //实例化点阵对象 void setup() { // put your setup code here, to run once: Serial.begin(115200); //设置波特率 matrix.begin(); //点阵使能 byte frame[8][12] = { { 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0 }, { 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0 }, { 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }; //点阵爱心数据 matrix.renderBitmap(frame, 8, 12); //点阵渲染显示 } void loop() { // put your main code here, to run repeatedly: }   //DAC #include "analogWave.h" analogWave wave(DAC); // 使用DAC引脚实例化模拟曲线对象wave float freq = 0.5; // 设置曲线初始频率 void setup() { Serial.begin(115200); // 串口波特率 wave.sine(freq); // 使用模拟曲线对象wave按照初始频率生成正弦波 wave.amplitude(0.5); } void loop() { printf("%d\n",analogRead(A4)); // 读取正弦值 delay(100); }   //OPAMP #include "analogWave.h" #include <OPAMP.h> analogWave wave(DAC); // 使用DAC引脚实例化模拟曲线对象wave float freq = 1; // 设置曲线初始频率 void setup() { Serial.begin(250000); // 串口波特率 OPAMP.begin(OPAMP_SPEED_HIGHSPEED); //设置OPAMP wave.sine(freq); // 使用模拟曲线对象wave按照初始频率生成正弦波 wave.amplitude(0.4); //设置正弦曲线幅值为0.4 } void loop() { printf("%d\n",analogRead(A4)); // 读取DAC输出正弦值 Serial.print(" "); printf("%d\n",analogRead(A5)); // 读取OPAMP输出正弦值 delay(100); } 效果展示: LED_MX [localvideo]8987fd7d0371bf40d459191834415b3a[/localvideo] [localvideo]1df186dd57e7f6fa0f96498f07afe472[/localvideo] 实现过程: 【Follow me第二季第2期】基础任务 点阵+DAC正弦波+OPAMP放大+串口打印与曲线输出 - DigiKey得捷技术专区 - 电子工程世界-论坛 (eeworld.com.cn) 2.3 进阶任务(必做):通过Wi-Fi,利用MQTT协议接入到开源的智能家居平台HA(HomeAssistant) 软件流程:      代码: #include <ArduinoMqttClient.h> #include <WiFiS3.h> #include "secrets.h" //wifi信息 char ssid[] = WIFISSID; char pass[] = WIFIPWD; //mqtt服务器信息 const char broker[] = BROKER; const int port = BROKER_PORT; //mqtt客户端 WiFiClient wifiClient; MqttClient mqttClient(wifiClient); //最大重连次数 const int maxTryTimes = 10; //测试用发送订阅主题 const char sendTopic[] = "HA/echo"; //测试用接收订阅主题 const char backTopic[] = "HA/back"; //发送间隔 const long interval = 1000; unsigned long previousMillis = 0; int count = 0; void setup() { //初始化串口 Serial.begin(115200); while (!Serial) { ; } // 连接WIFI Serial.print("Attempting to connect to WPA SSID: "); Serial.println(ssid); while (WiFi.begin(ssid, pass) != WL_CONNECTED) { Serial.print("."); delay(1000); } Serial.println("You're connected to the network"); Serial.println(WiFi.localIP()); Serial.print("Attempting to connect to the MQTT broker: "); Serial.println(broker); int tryTimes=0; //连接MQTT服务器 while (!mqttClient.connect(broker, port)) { Serial.print("MQTT connection failed! Error code = "); Serial.println(mqttClient.connectError()); if (tryTimes>maxTryTimes-1) { printf("MQTT connection failed over %d times",maxTryTimes); while(1){}; } delay(500); printf("Try more %d times\n",++tryTimes); } Serial.println("You're connected to the MQTT broker!"); Serial.println(); Serial.print("Subscribing to topic: "); Serial.println(backTopic); Serial.println(); //订阅主题 mqttClient.subscribe(backTopic); Serial.print("Waiting for messages on topic: "); Serial.println(backTopic); Serial.println(); } void loop() { // 查看主题消息 int messageSize = mqttClient.parseMessage(); if (messageSize) { // we received a message, print out the topic and contents Serial.print("Received a message with topic '"); Serial.print(mqttClient.messageTopic()); Serial.print("', length "); Serial.print(messageSize); Serial.println(" bytes:"); // 打印输出主题消息 while (mqttClient.available()) { Serial.print((char)mqttClient.read()); } Serial.println(); Serial.println(); } unsigned long currentMillis = millis(); //发送测试消息到主题 if (currentMillis - previousMillis >= interval) { previousMillis = currentMillis; Serial.print("Sending message to topic: "); Serial.println(sendTopic); Serial.print("echo "); Serial.println(count); mqttClient.beginMessage(sendTopic); mqttClient.print("echo "); mqttClient.print(count); mqttClient.endMessage(); Serial.println(); count++; } } 效果展示: [localvideo]f924b9457d2c86b2d70e4e27d9e9bd84[/localvideo] 实现过程: 【Follow me第二季第2期】进阶任务 MQTT协议接入到开源的智能家居HomeAssistant - DigiKey得捷技术专区 - 电子工程世界-论坛 (eeworld.com.cn) 2.4 扩展任务 通过外部 环境光传感器,上传光照度到HA,通过HA面板显示数据+通过外部温湿度传感器,上传温湿度到HA,通过HA面板显示数据 软件流程:   代码: //LIGHT #include "secrets.h" #include <WiFiS3.h> #include <ArduinoHA.h> #include <Wire.h> #define LIGHT_SENSOR A4 //wifi信息 char ssid[] = WIFISSID; char pass[] = WIFIPWD; //mqtt服务器信息 const char broker[] = BROKER; const int port = BROKER_PORT; byte mac[] = { 0x00, 0x10, 0xFA, 0x6E, 0x38, 0x4A }; //tcp客户端 WiFiClient client; //HA虚拟设备配置 HADevice device(mac, sizeof(mac)); //mqtt客户端实例化 HAMqtt mqtt(client, device); //HA传感器实例化 HASensorNumber lightSensor("LightSensor", HABaseDeviceType::PrecisionP2); //参考上次更新时间 unsigned long lastUpdateAt = 0; //光线传感器 void getLightValue(float* const pval) { int sensorValue = analogRead(LIGHT_SENSOR); *pval = sensorValue/1023.0; } void setup() { //初始化串口 Serial.begin(115200); while (!Serial) { ; } // 连接WIFI Serial.print("Attempting to connect to WPA SSID: "); Serial.println(ssid); while (WiFi.begin(ssid, pass) != WL_CONNECTED) { Serial.print("."); delay(1000); } Serial.println("You're connected to the network"); Serial.println(WiFi.localIP()); Serial.print("Attempting to connect to the MQTT broker: "); Serial.println(broker); device.setName("亮度"); device.setSoftwareVersion("1.0.0"); lightSensor.setIcon("mdi:home"); lightSensor.setName("亮度"); lightSensor.setUnitOfMeasurement("%"); mqtt.begin(BROKER, BROKER_PORT); } void loop() { mqtt.loop(); float light; if ((millis() - lastUpdateAt) > 1000) { lightSensor.setValue(light*100); Serial.print("light:"); Serial.print(light*100); Serial.println("%"); lastUpdateAt = millis(); } } //TEMP&HUMI #include "secrets.h" #include <WiFiS3.h> #include <ArduinoHA.h> #include <Wire.h> #include "AHT20.h" //wifi信息 char ssid[] = WIFISSID; char pass[] = WIFIPWD; //mqtt服务器信息 const char broker[] = BROKER; const int port = BROKER_PORT; byte mac[] = { 0x00, 0x10, 0xFA, 0x6E, 0x38, 0x4A }; //tcp客户端 WiFiClient client; //HA虚拟设备配置 HADevice device(mac, sizeof(mac)); //mqtt客户端实例化 HAMqtt mqtt(client, device); //HA传感器实例化 HASensorNumber tempSensor("tempSensor", HABaseDeviceType::PrecisionP2); HASensorNumber humiSensor("humiSensor", HABaseDeviceType::PrecisionP2); //参考上次更新时间 unsigned long lastUpdateAt = 0; //温湿度传感器AHT20 AHT20 AHT; void setup() { //初始化串口 Serial.begin(115200); while (!Serial) { ; } AHT.begin(); // 连接WIFI Serial.print("Attempting to connect to WPA SSID: "); Serial.println(ssid); while (WiFi.begin(ssid, pass) != WL_CONNECTED) { Serial.print("."); delay(1000); } Serial.println("You're connected to the network"); Serial.println(WiFi.localIP()); //设置MQTT服务器 Serial.print("Attempting to connect to the MQTT broker: "); Serial.println(broker); //设置HA虚拟设备信息 device.setName("温湿度"); device.setSoftwareVersion("1.0.0"); tempSensor.setIcon("mdi:home"); tempSensor.setName("温度"); tempSensor.setUnitOfMeasurement("°C"); humiSensor.setIcon("mdi:home"); humiSensor.setName("湿度"); humiSensor.setUnitOfMeasurement("%"); mqtt.begin(BROKER, BROKER_PORT); } void loop() { mqtt.loop(); float humi, temp, light; if ((millis() - lastUpdateAt) > 1000) { int ret = AHT.getSensor(&humi, &temp); if (ret) { tempSensor.setValue(temp); humiSensor.setValue(humi * 100); Serial.print("humidity: "); Serial.print(humi * 100); Serial.print("%\t temerature: "); Serial.println(temp); } lastUpdateAt = millis(); } } 效果展示: [localvideo]93edf11b65f728a3059856114e416e5e[/localvideo] [localvideo]b219ef71ed177c22136ff5c9a4344897[/localvideo] 实现过程: 【Follow me第二季第2期】扩展任务 HA面板显示温湿度、光照度数据 - DigiKey得捷技术专区 - 电子工程世界-论坛 (eeworld.com.cn) 三、心得体会     工作之余能够通过论坛活动学习并掌握uno r4 wifi的使用,并且深入了解了开源智能家居Home Assistant系统的使用,收获满满。虽然过程中遇到了许多问题,但是通过和坛友们沟通询问也都全部一一解决。感谢eeworld和得捷提供的活动机会。祝类似的活动越办越好。 四、任务代码汇总 https://download.eeworld.com.cn/detail/eew_gz8e7C/634546  

  • 加入了学习《Follow Me第二季第二期》,观看 Follow Me第二季第二期

  • 加入了学习《Follow Me 第二季第二期总结视频》,观看 follow me 集合

  • 上传了资料: Follow me第二季第二期任务代码

  • 发表了主题帖: 【Follow me第二季第2期】扩展任务 HA面板显示温湿度、光照度数据

    本帖最后由 eew_gz8e7C 于 2024-10-7 10:39 编辑 Follow me第二季第2期扩展任务之 环境光传感器,温湿度传感器,上传数据到HA,通过HA面板显示数据     本节任务采用Follow me第一季采购的传感器模块Grove - Light Sensor v1.2、Grove - AHT20 I2C来实现。     首先安装home-assistant-integration库,调用该库可以快速构建HA能够自动发现的MQTT传感器实例。     环境光传感器数据上传到HA,通过HA面板显示数据     根据Grove - Light Sensor v1.2传感器模块引脚定义完成连线。                                   光传感器信号为模拟信号,通过UNO R4 WIFIF A4引脚读取光照值并转化为%值输出。 #include "secrets.h" #include <WiFiS3.h> #include <ArduinoHA.h> #include <Wire.h> #define LIGHT_SENSOR A4 //wifi信息 char ssid[] = WIFISSID; char pass[] = WIFIPWD; //mqtt服务器信息 const char broker[] = BROKER; const int port = BROKER_PORT; byte mac[] = { 0x00, 0x10, 0xFA, 0x6E, 0x38, 0x4A }; //tcp客户端 WiFiClient client; //HA虚拟设备配置 HADevice device(mac, sizeof(mac)); //mqtt客户端实例化 HAMqtt mqtt(client, device); //HA传感器实例化 HASensorNumber lightSensor("LightSensor", HABaseDeviceType::PrecisionP2); //参考上次更新时间 unsigned long lastUpdateAt = 0; //光线传感器 void getLightValue(float* const pval) { int sensorValue = analogRead(LIGHT_SENSOR); *pval = sensorValue/1023.0; } void setup() { //初始化串口 Serial.begin(115200); while (!Serial) { ; } // 连接WIFI Serial.print("Attempting to connect to WPA SSID: "); Serial.println(ssid); while (WiFi.begin(ssid, pass) != WL_CONNECTED) { Serial.print("."); delay(1000); } Serial.println("You're connected to the network"); Serial.println(WiFi.localIP()); Serial.print("Attempting to connect to the MQTT broker: "); Serial.println(broker); device.setName("亮度"); device.setSoftwareVersion("1.0.0"); lightSensor.setIcon("mdi:home"); lightSensor.setName("亮度"); lightSensor.setUnitOfMeasurement("%"); mqtt.begin(BROKER, BROKER_PORT); } void loop() { mqtt.loop(); float light; if ((millis() - lastUpdateAt) > 1000) { // update in 2s interval getLightValue(&light); lightSensor.setValue(light*100); Serial.print("light:"); Serial.print(light*100); Serial.println("%"); lastUpdateAt = millis(); } }     效果展示 [localvideo]70715e1f28e45fd802052367d52f5408[/localvideo]     温湿度传感器数据上传到HA,通过HA面板显示数据     根据Grove - AHT20 I2C传感器模块引脚定义完成连线。                   Grove - AHT20 I2C传感器模块通过I2C总线传输传感器数据,Arduino IDE中搜索下载Seed_Arduino_AHT20库可以快速调用并读取传感器数据。 #include "secrets.h" #include <WiFiS3.h> #include <ArduinoHA.h> #include <Wire.h> #include "AHT20.h" //wifi信息 char ssid[] = WIFISSID; char pass[] = WIFIPWD; //mqtt服务器信息 const char broker[] = BROKER; const int port = BROKER_PORT; byte mac[] = { 0x00, 0x10, 0xFA, 0x6E, 0x38, 0x4A }; //tcp客户端 WiFiClient client; //HA虚拟设备配置 HADevice device(mac, sizeof(mac)); //mqtt客户端实例化 HAMqtt mqtt(client, device); //HA传感器实例化 HASensorNumber tempSensor("tempSensor", HABaseDeviceType::PrecisionP2); HASensorNumber humiSensor("humiSensor", HABaseDeviceType::PrecisionP2); //参考上次更新时间 unsigned long lastUpdateAt = 0; //温湿度传感器AHT20 AHT20 AHT; void setup() { //初始化串口 Serial.begin(115200); while (!Serial) { ; } AHT.begin(); // 连接WIFI Serial.print("Attempting to connect to WPA SSID: "); Serial.println(ssid); while (WiFi.begin(ssid, pass) != WL_CONNECTED) { Serial.print("."); delay(1000); } Serial.println("You're connected to the network"); Serial.println(WiFi.localIP()); //设置MQTT服务器 Serial.print("Attempting to connect to the MQTT broker: "); Serial.println(broker); //设置HA虚拟设备信息 device.setName("温湿度"); device.setSoftwareVersion("1.0.0"); tempSensor.setIcon("mdi:home"); tempSensor.setName("温度"); tempSensor.setUnitOfMeasurement("°C"); humiSensor.setIcon("mdi:home"); humiSensor.setName("湿度"); humiSensor.setUnitOfMeasurement("%"); mqtt.begin(BROKER, BROKER_PORT); } void loop() { mqtt.loop(); float humi, temp, light; if ((millis() - lastUpdateAt) > 1000) { int ret = AHT.getSensor(&humi, &temp); if (ret) { tempSensor.setValue(temp); humiSensor.setValue(humi * 100); Serial.print("humidity: "); Serial.print(humi * 100); Serial.print("%\t temerature: "); Serial.println(temp); } lastUpdateAt = millis(); } }         效果展示 [localvideo]b0b2b2063c613ebb80f80d1d49814c13[/localvideo]  

  • 2024-09-30
  • 加入了学习《【Follow me第二季第2期】任务提交》,观看 【Follow me第二季第2期】

  • 发表了主题帖: 【Follow me第二季第2期】进阶任务 MQTT协议接入到开源的智能家居HomeAssistant

    本帖最后由 eew_gz8e7C 于 2024-9-30 12:08 编辑 Follow me第二季第2期进阶任务之 通过Wi-Fi,利用MQTT协议接入到开源的智能家居平台HA(HomeAssistant)         本期活动购置了树莓派zerow用于部署HA,首先介绍如何部署HA;         树莓派zerow部署HA  树莓派zerow系统烧录         首先下载安装树莓派镜像安装工具,准备好SD卡和读卡器用于安装树莓派系统;         安装Imager后,通过单击树莓派Imager图标或运行来启动应用程序,单击CHOOSE DEVICE并从列表中选择您的树莓派zero。             接下来,单击选择操作系统并选择要安装的操作系统。Imager始终在列表顶部显示适合您的型号的树莓派OS推荐版本,这里选择Raspberry Pi OS(32-bit)。               然后单击选择SD卡并选择您的存储设备。             接下来,点击NEXT。             在弹出窗口中,自定义操作系统设置,包括:​ 用户名和密码 WiFi认证 主机名 时区 键盘布局 远程连接             SERVICES选项卡用于远程连接树莓派的相关设置,根据需要进行设置,保存后即可开始写入。           完成后插入SD卡即可完成启动。启动后树莓派指示灯开始闪烁,通过SSH登录树莓派终端进行后续配置。             执行 sudo apt-get update、sudo apt-get upgrade进行软件环境的更新。           树莓派zerow部署HA         这里采用docker进行HA的部署。         首先完成docker的安装,由于网络不畅通,需要采用国内镜像源进行安装,这里采用腾讯源。 # 卸载旧版本(如果有): for pkg in docker.io docker-doc docker-compose podman-docker containerd runc; do sudo apt-get remove $pkg; done # 添加 Docker 官方 GPG key: sudo apt-get update sudo apt-get install ca-certificates curl sudo install -m 0755 -d /etc/apt/keyrings sudo curl -fsSL http://mirrors.tencent.com/docker-ce/linux/raspbian/gpg -o /etc/apt/keyrings/docker_tencentyun.asc sudo chmod a+r /etc/apt/keyrings/docker_tencentyun.asc # 添加仓库到 Apt 源: echo \ "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker_tencentyun.asc] http://mirrors.tencent.com/docker-ce/linux/raspbian \ $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \ sudo tee /etc/apt/sources.list.d/docker_tencentyun.list > /dev/null sudo apt-get update # 安装 Docker 软件包 sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin # 验证 sudo docker run hello-world         docker安装完毕后即可拉取HA镜像。 docker pull homeassistant/home-assistant         待镜像拉取完成即可运行HA容器。 docker run -d \ --name homeassistant \ --privileged \ --restart=unless-stopped \ -e TZ=Asia/Shanghai \ -v /data/homeassistant:/config \ #将物理机/data/homeassistant目录挂载至容器的/config目录 -v /run/dbus:/run/dbus:ro \ #将物理机/run/dbus目录挂载至容器的/run/dbus目录,否则HA蓝牙不可用 --network=host \ homeassistant/home-assistant         运行后执行docker ps即可查看运行状态,如果已经正常运行,则打开树莓派主机地址:8123端口即可进入HA页面进行注册配置,至此HA部署完成。     树莓派zerow搭建MQTT服务器         通过docker镜像搭建MQTT服务器,这里使用eclipse-mosquitto开源MQTT服务器。 #1. 拉取eclipse-mosquitto镜像 docker pull eclipse-mosquitto #2. 为容器创建配置、数据等文件夹 sudo mkdir -p /data/mosquitto/config sudo mkdir -p /data/mosquitto/data sudo mkdir -p /data/mosquitto/log #3. 更改文件夹权限 sudo chmod -R 755 /data/mosquitto sudo chmod chmod -R 777 /data/ /mosquitto/log #4. 设置配置文件 sudo nano /data/mosquitto/config/mosquitto.conf # 配置文件内容: # 配置端口号及远程访问IP listener 1883 # 配置websocket的连接端口 listener 9001 # 以websocket方式连接mqtt服务 #protocol websockets persistence true # 数据存储路径 persistence_location /mosquitto/data/ # 运行日志存储路劲 log_dest file /mosquitto/log/mosquitto.log # 设置匿名访问 allow_anonymous true #5. 运行容器 docker run -td \ --name mqtt \ --privileged \ --restart=unless-stopped \ -v /data/mosquitto/config:/mosquitto/config \ -v /data/mosquitto/data:/mosquitto/data \ -v /data/mosquitto/log:/mosquitto/log \ --network=host \ eclipse-mosquitto 配置内网穿透实现MQTT服务器、HA面板远程访问         有需要远程访问MQTT服务器、HA面板的朋友可以参考在树莓派安装cpolar实现内网穿透。下载安装可以参考官网教程,需要注意配置文件的设置,可以参考: authtoken: ***** tunnels: mqtt: proto: tcp addr: "1883" #对应MQTT服务器端口 ha: proto: tcp addr: "8123" #对应HA面板服务器端口           UNO R4 WIFI 通过MQTT接入HA         下载安装ArduinoMqttClient库,可以快速调用实现MQTT客户端。   核心代码 #include <ArduinoMqttClient.h> #include <WiFiS3.h> #include "secrets.h" //wifi信息 char ssid[] = SSID; char pass[] = WIFIPWD; //mqtt服务器信息 const char broker[] = BROKER; const int port = BROKER_PORT; //mqtt客户端 WiFiClient wifiClient; MqttClient mqttClient(wifiClient); //最大重连次数 const int maxTryTimes = 10; //测试用订阅主题 const char topic[] = "HA/echo"; //发送间隔 const long interval = 1000; unsigned long previousMillis = 0; int count = 0; void setup() { //初始化串口 Serial.begin(115200); while (!Serial) { ; } // 连接WIFI Serial.print("Attempting to connect to WPA SSID: "); Serial.println(ssid); while (WiFi.begin(ssid, pass) != WL_CONNECTED) { Serial.print("."); delay(1000); } Serial.println("You're connected to the network"); Serial.println(WiFi.localIP()); Serial.print("Attempting to connect to the MQTT broker: "); Serial.println(broker); int tryTimes=0; //连接MQTT服务器 while (!mqttClient.connect(broker, port)) { Serial.print("MQTT connection failed! Error code = "); Serial.println(mqttClient.connectError()); if (tryTimes>maxTryTimes-1) { printf("MQTT connection failed over %d times",maxTryTimes); while(1){}; } delay(500); printf("Try more %d times\n",++tryTimes); } Serial.println("You're connected to the MQTT broker!"); Serial.println(); Serial.print("Subscribing to topic: "); Serial.println(topic); Serial.println(); //订阅主题 mqttClient.subscribe(topic); Serial.print("Waiting for messages on topic: "); Serial.println(topic); Serial.println(); } void loop() { // 查看主题消息 int messageSize = mqttClient.parseMessage(); if (messageSize) { // we received a message, print out the topic and contents Serial.print("Received a message with topic '"); Serial.print(mqttClient.messageTopic()); Serial.print("', length "); Serial.print(messageSize); Serial.println(" bytes:"); // 打印输出主题消息 while (mqttClient.available()) { Serial.print((char)mqttClient.read()); } Serial.println(); Serial.println(); } unsigned long currentMillis = millis(); //发送测试消息到主题 if (currentMillis - previousMillis >= interval) { previousMillis = currentMillis; Serial.print("Sending message to topic: "); Serial.println(topic); Serial.print("echo "); Serial.println(count); mqttClient.beginMessage(topic); mqttClient.print("echo "); mqttClient.print(count); mqttClient.endMessage(); Serial.println(); count++; } }                  进入HA面板,依次进入 设置->设备与服务->添加集成,搜索加载MQTT,然后进入MQTT配置如下,启动unr4 wifi的mqtt程序测试主题消息的发送与接收。   效果展示 [localvideo]1a1093c5331ec44e3be36ff309ec3b9a[/localvideo]    

  • 回复了主题帖: 【Follow me第二季第2期】开箱+环境搭建+Blink&串口打印

    戈壁滩上的辉煌 发表于 2024-9-13 09:00 感觉Arduino UNO R4 WiFi还是挺好玩的,是不是都可以用这个板子进行啊 可以的,HA可以通过docker安装在PC上

  • 发表了主题帖: 【Follow me第二季第2期】基础任务 点阵+DAC正弦波+OPAMP放大+串口打印与曲线输出

    本帖最后由 eew_gz8e7C 于 2024-9-30 09:39 编辑 Follow me第二季第2期基础任务之 驱动12x8点阵LED; 用DAC生成正弦波; 用OPAMP放大DAC信号; 用ADC采集并且打印数据到串口等其他接口可上传到上位机显示曲线; 驱动12x8点阵LED         通过Arduino_LED_Matrix库可以便捷调用点阵,只需要关注点阵内容矩阵即可,通过byte类型的二维向量存储点阵内容,元素0代表灭,元素1代表亮。 核心代码 #include "Arduino_LED_Matrix.h"//调用LED_Matrix库 ArduinoLEDMatrix matrix;//实例化点阵对象 void setup() { // put your setup code here, to run once: Serial.begin(115200);//设置波特率 matrix.begin();//点阵使能 byte frame[8][12] = { { 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0 }, { 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0 }, { 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } };//点阵爱心数据 matrix.renderBitmap(frame, 8, 12);//点阵渲染显示 } void loop() { // put your main code here, to run repeatedly: } 效果展示            用DAC生成正弦波,并打印到串口用上位机显示曲线         UNO R4 WiFi 还包含一个 DAC,它可以作为真正的模拟输出引脚。         此 DAC 引脚默认的写入分辨率为 10 位。写入到引脚的值应该在 0-1023 之间。设置正弦波的幅值为0.5,则输出波形幅值在0~511之间。         因为没有示波器,使用A4引脚ADC采集通过串口输出观察波形。     核心代码 #include "analogWave.h" analogWave wave(DAC); // 使用DAC引脚实例化模拟曲线对象wave float freq = 0.5; // 设置曲线初始频率 void setup() { Serial.begin(115200); // 串口波特率 wave.sine(freq); // 使用模拟曲线对象wave按照初始频率生成正弦波 wave.amplitude(0.5); } void loop() { printf("%d\n",analogRead(A4)); // 读取正弦值 delay(100); } 效果展示 [localvideo]b7fe640bf630efe99f8db8bede74c20b[/localvideo] 用OPAMP放大DAC信号         OPAMP 是一种用途广泛且应用广泛的电子元件,属于模拟集成电路类。它的主要功能是放大电压信号。如图所示,R1为接地端的电阻,R2为放大器输出端的电阻。输入电压为v,放大倍数为A,则R1、R2、A、v满足Av=1+R2/R1,在确定放大倍数后需要根据放大倍数选择对应比例的R1和R2。这里我选择两个2kΩ电阻实现2倍的放大。            核心代码 #include "analogWave.h" #include <OPAMP.h> analogWave wave(DAC); // 使用DAC引脚实例化模拟曲线对象wave float freq = 1; // 设置曲线初始频率 void setup() { Serial.begin(250000); // 串口波特率 OPAMP.begin(OPAMP_SPEED_HIGHSPEED); //设置OPAMP wave.sine(freq); // 使用模拟曲线对象wave按照初始频率生成正弦波 wave.amplitude(0.4); //设置正弦曲线幅值为0.4 } void loop() { printf("%d\n",analogRead(A4)); // 读取DAC输出正弦值 Serial.print(" "); printf("%d\n",analogRead(A5)); // 读取OPAMP输出正弦值 delay(100); } 效果展示 [localvideo]411afb3d93a0903f8a86cc80182f05e6[/localvideo]  

  • 2024-09-09
  • 发表了主题帖: 【Follow me第二季第2期】开箱+环境搭建+Blink&串口打印

    本帖最后由 eew_gz8e7C 于 2024-9-9 10:05 编辑         物料开箱         本期活动为Arduino UNO R4 WiFi,活动中有利用MQTT协议接入到开源的智能家居平台HA(HomeAssistant)的相关任务,故本次活动物料额外购买了树莓派zerow用于部署HA。         下单两周左右物料到货了,特地给树莓派zerow也配备了外壳和散热片。                   环境搭建         既然是Arduino的板子,开发环境自然选用Arduino。         安装并打开Arduino后,在开发板管理器中搜索安装 UNO R4 WIFI支持库。                      然后配置开发板和串口。           Blink&串口打印         查看LED引脚信息为LED_BUILTIN P102。           通过演示控制LED引脚高低电平实现BLINK,同时打印输出LED状态。 void setup() { // put your setup code here, to run once: //配置波特率 Serial.begin(115200); while (!Serial) { } //配置LED引脚为输出模式 //pinMode(102, OUTPUT); pinMode(LED_BUILTIN, OUTPUT); } void loop() { // put your main code here, to run repeatedly: //演示控制板载LED亮灭,并且打印LED状态 digitalWrite(LED_BUILTIN, LOW); printf("LED ON\n"); delay(1000); digitalWrite(LED_BUILTIN, HIGH); printf("LED OFF\n"); delay(1000); }         效果 [localvideo]d0ba9afa2fa617ccea2cefc775c804ee[/localvideo]  

  • 2024-08-31
  • 加入了学习《【Follow me第二季第1期】全部任务演示》,观看 全部任务演示2.0

  • 加入了学习《得捷Follow me第二季第1期视频》,观看 得捷Follow me第二季第1期视频

  • 发表了主题帖: 【Follow me第二季第1期】任务汇总提交

    本帖最后由 eew_gz8e7C 于 2024-8-31 18:15 编辑   一、项目介绍     感谢得捷和eeworld提供的活动机会,首先简单自我介绍,我是机械专业毕业,当前从事新能源汽车行业,去年也有幸参加了几次Follow me的活动,Follow me活动选的板子非常好,上手简单能快速实现有趣的功能,几期活动下来学到了许多,祝Follow me越办越好。     本次Follow me第二季第1期的任务主板为Circuit Playground Express,基于ATSAMD21微控制器,采用32位ARM® Cortex®-M0+内核,具有10颗Mini NeoPixel LED、光线/温度/湿度/声音/加速度/红外传感器,板载一个迷你扬声器、一个滑动开关、两个用户按钮,其可玩性非常高。       二、任务实现 1. 入门任务(必做):开发环境搭建,板载LED点亮     环境搭建     Circuit Playground Express 支持Microsoft MakeCode,可以进行可视化编程或者采用JavaScript编程。同时,他也支持Arduino和CircuitPython,使用起来相当灵活方便。这里我采用CircuitPython作为开发环境。     首先从官网下载CircuitPython 9.1.1 ;     Usb连接电脑,双击reset按键进入bootloader模式,此时出现CPLAYBOOT盘,然后将CircuitPython 9.1.1拖入即可开始CPY刷入;     刷入完成后出现CIRCUITPY盘;          下载安装Thony(VS Code/ mu editor)IDE。     至此CircuitPython环境搭建完成。          点亮板载红色LED     进入REPL,运行下面命令,可以输出板载资源信息,可以看到板载的LED已经被封装进borad模块。 >>>dir(board)     调用board的LED,设置其为数字IO输出,设置其值为True或False即可控制LED的亮灭。   代码如下: #task0.1 import board import digitalio import time led = digitalio.DigitalInOut(board.LED) led.direction = digitalio.Direction.OUTPUT while True: led.value = True time.sleep(1) led.value = False time.sleep(1)       另外,可以安装adafruit_circuitplayground库,adafruit_circuitplayground对板载资源进一步封装,使得板载资源调用更加方便。 #task0.2 from adafruit_circuitplayground import cp import time while True: cp.red_led = True time.sleep(1) cp.red_led = False time.sleep(1) [localvideo]ea559db11bce1cc944f6d8c709ced584[/localvideo]   2. 基础任务一(必做):控制板载炫彩LED,跑马灯点亮和颜色变换     通过设置RGB三原色的亮度值可以调配出各种想要的色彩,板载炫彩LED可以通过adafruit_circuitplayground模块中的pixel来调用,其调用过程类似给长度为10的链表中的元素进行赋值,例如cp.pixels[0] = (255, 0, 0)即将第1颗灯珠设置为红色,另外其fill方法可以一次性设置所有灯珠的颜色。     下面的代码通过随机数来设置rgb色彩值,给所有灯珠设置随机颜色: #task1.1 from adafruit_circuitplayground import cp import time import random cp.pixels.brightness=0.01 while True: x=random.randint(0,255) y=random.randint(0,255) z=random.randint(0,255) print((x,y,z)) time.sleep(1) [localvideo]b6d1baf3a22a22b03505d626f4725237[/localvideo]       另外,使用CircuitPython 的rainbowio库的colorwheel函数可以帮助我们按照色环数值选取色彩,colorwheel函数接受一个介于0至255之间的整数作为参数,返回一个对应于该位置的RGB颜色值。这个函数会生成一个完整的彩虹色谱,从红色开始,经过橙色、黄色、绿色、青色、蓝色、洋红色,再回到红色。  [localvideo]be9c34597bbc7da9f2898db7ce73a544[/localvideo]   3.基础任务二(必做):监测环境温度和光线,通过板载LED展示舒适程度     温度读取     板载环境温度传感器为热敏电阻,其接有一个10k下拉电阻,通过采集电路的电压值反应温度变化,adafruit_circuitplayground库已经封装好了温度的计算可以直接调用。       import time from adafruit_circuitplayground import cp while True: print(cp.temperature) time.sleep(0.1)     光线强度读取     import time from adafruit_circuitplayground import cp while True: print(cp.light) time.sleep(0.1)     根据温度和光线的舒适度分别在两侧的炫彩灯珠显示。前5个灯珠指示温度,以温度25℃为最舒适温度(温度范围-20~40℃),此时前5个灯珠均显示为绿色,高于25℃向红色渐变,低于25摄氏度向蓝色渐变。后5个灯珠指示亮度,以亮度200为最舒适亮度(亮度范围0~400),此时后5个灯珠均显示为绿色,高于200向红色渐变,低于200向蓝色渐变。 # task2 import time from adafruit_circuitplayground import cp import time from rainbowio import colorwheel cp.pixels.brightness=0.1 #前5个灯珠指示温度,以温度25℃为最舒适温度(温度范围-20~40℃),此时4个灯珠均显示为绿色,高于25℃向红色渐变,低于25摄氏度向蓝色渐变 #后5个灯珠指示亮度,以l亮度200为最舒适亮度(亮度范围0~400),此时4个灯珠均显示为绿色,高于200向红色渐变,低于200摄氏度向蓝色渐变 tmpMax=40 tmpMin=-20 tmpOk=25 lightOk=200 lightMax=400 lightMin=0 def trans(value,valueMax,valueMin,valueOk): if value>=25: if value>valueMax: value=valueMax val=255/3-(value-valueOk)/(valueMax-valueOk)*(255/3) else: if value<valueMin: value=valueMin val=255/3+(valueOk-value)/(valueOk-valueMin)*(255/3) return colorwheel(val) while True: print(cp.temperature,cp.light) cp.pixels[0:5]=[trans(cp.temperature,tmpMax,tmpMin,tmpOk)]*5 cp.pixels[5:10]=[trans(cp.light,lightMax,lightMin,lightOk)]*5 time.sleep(0.1) 温度读取与展示 [localvideo]a3563e0a58e0e2285e4cde4d8f76beed[/localvideo]   光线强度读取与展示 [localvideo]0b9769581757e768f82a4b1c1290ed93[/localvideo]   4.基础任务三(必做):接近检测——设定安全距离并通过板载LED展示,检测到入侵时,发起声光报警        红外实现        利用红外发射管发出红外脉冲,然后检测红外接收器信号强度来测算遮挡距离,在到达设定阈值后发出声光报警。 from adafruit_circuitplayground import cp from rainbowio import colorwheel import pulseio import board import time import array import analogio #设置灯珠 cp.pixels.brightness=0.05 cp.pixels.auto_write=False #红外接收和发射引脚 tx_pin = board.REMOTEOUT ds_pin = board.IR_PROXIMITY #设置脉冲输出 pulseout = pulseio.PulseOut(tx_pin, frequency=38000, duty_cycle=2 ** 15) # 定义发射脉冲序列 pulse_sequence = array.array('H', [1024]) # 脉冲宽度,单位是微秒 # 红外接近传感器模拟量读取 dispin = analogio.AnalogIn(ds_pin) # 距离阈值 maxVal=40000 minVal=31000 #滤波窗口设置 windowSize=5 #距离检测 def distanceLv(): #信号滤波 irValList=[] for i in range(windowSize+2): pulseout.send(pulse_sequence) irValList.append(dispin.value) time.sleep(0.001) #信号处理,转换为0~10的距离等级 irVal=(sum(irValList)-max(irValList)-min(irValList))/windowSize if irVal<minVal: irVal=minVal elif irVal>maxVal: irVal=maxVal distanceLv=round(((maxVal-irVal)/(maxVal-minVal)*10)**4/(10**3)) return distanceLv #距离展示 def disShow(value): #达到最小距离,开始报警 if value==0: cp.pixels.fill((255,0,0)) cp.pixels.show() time.sleep(0.1) cp.pixels.fill((0,0,0)) cp.pixels.show() time.sleep(0.1) cp.play_tone(1500, 0.05) #距离等级展示 else: l=11-value for i in range(l): cp.pixels[i]=colorwheel(85-i*9.44) cp.pixels.show() cp.pixels[l:10]=[(0,0,0)]*(10-l) cp.pixels.show() time.sleep(0.2) #主循环 while True: d=distanceLv() disShow(d) print((d,)) time.sleep(0.1) [localvideo]7772fed79710d188b8345fc4dbc2d06e[/localvideo]       超声波距离传感器实现 import time import board from adafruit_circuitplayground import cp from rainbowio import colorwheel i2c = board.I2C() # 距离阈值 maxVal=300000 minVal=15000 #设置灯珠 cp.pixels.brightness=0.05 cp.pixels.auto_write=False #距离展示 def disShow(value): #达到最小距离,开始报警 if value==0: cp.pixels.fill((255,0,0)) cp.pixels.show() time.sleep(0.1) cp.pixels.fill((0,0,0)) cp.pixels.show() time.sleep(0.1) cp.play_tone(1500, 0.05) #距离等级展示 else: l=11-value for i in range(l): cp.pixels[i]=colorwheel(85-i*9.44) cp.pixels.show() cp.pixels[l:10]=[(0,0,0)]*(10-l) cp.pixels.show() time.sleep(0.2) #距离检测 def distanceLv(irVal): if irVal<minVal: irVal=minVal elif irVal>maxVal: irVal=maxVal distanceLv=round(((irVal-minVal)/(maxVal-minVal)*10)) return distanceLv while not i2c.try_lock(): print("waiting for i2c bus") try: while True: i2cAds=[hex(device_address) for device_address in i2c.scan()] print( "I2C addresses found:", i2cAds, ) if '0x57' in i2cAds: print("1601 connectted!") break time.sleep(2) while True: i2c.writeto(0x57, bytearray([1])) time.sleep(0.5) bt=bytearray([0,0,0]) i2c.readfrom_into(0x57, bt) # print(bt) dis=int.from_bytes(bt, 'big') print(dis) disShow(distanceLv(dis)) finally: i2c.unlock()   [localvideo]9696fa717bdaa0ddcc207670d121d599[/localvideo]   5.进阶任务(必做):制作不倒翁——展示不倒翁运动过程中的不同灯光效果     根据板载三轴加速度传感器的数值估算出不倒翁偏摆的方向,将偏摆方向映射到10个彩灯上,当不倒翁处于立直状态彩灯全为绿色,当发生偏摆则偏摆向下一侧的彩灯向红色变换,偏摆向上的彩灯向蓝色变换。 import time import math from adafruit_circuitplayground import cp from rainbowio import colorwheel cp.pixels.brightness=0.08 highColorIndex=255/3*2 lowColorIndex=0 g=9.81 #计算不倒翁的方向 def calDirection(): x, y, z = cp.acceleration y=-y xyz=[x,y,z] for i in range(3): if xyz[i]>g: xyz[i]=g elif xyz[i]<-g: xyz[i]=-g elif xyz[i]==0: xyz[i]=0.0001 xyz[i]=xyz[i]/g # print((xyz)) alph=math.atan(xyz[0]/xyz[1]) if xyz[1]<0: alph=alph+math.pi if alph<0: alph=alph+2*math.pi if xyz[2]<0: xyz[2]=0 beta=1-xyz[2] #返回倾斜方向角度和倾斜程度 return alph,beta #炫彩灯珠显示不倒翁状态 def pixelsShow(alph,beta): colorIndexRange=abs((highColorIndex-lowColorIndex))*(beta**0.7)/2 for i in range(10): colorIndexChange=math.cos(((i+0.5)/10.0*2*math.pi-alph))*colorIndexRange colorIndex=255/3-colorIndexChange print(i,colorIndexChange,colorIndex) cp.pixels[i]=colorwheel(colorIndex) while True: alph,beta=calDirection() pixelsShow(alph,beta) # time.sleep(0.05) [localvideo]4a6dcc3268bbb20ae6f1a6c0ae2daf9c[/localvideo]   6  创意任务二:章鱼哥——章鱼哥的触角根据环境声音的大小,章鱼哥的触角可舒展或者收缩 首先根据舵机的引脚完成连线。           调用板载麦克风采集声音,初始化麦克风时根据当前环境声的幅值作为初始基准值,超出基准值的声音幅值将根据大小分为10个等级,根据等级值点亮彩灯,同时在大于2级时根据幅值大小设置舵机转速快慢并在对应转速分别转动0.1s,由舵机来回转动引起的振动来使章鱼的触角伸缩。 import time import board import pwmio import audiobusio from adafruit_motor import servo import array import math import neopixel mic = audiobusio.PDMIn(board.MICROPHONE_CLOCK, board.MICROPHONE_DATA, sample_rate=16000, bit_depth=16) pwm = pwmio.PWMOut(board.A2, duty_cycle=2 ** 15, frequency=50) PEAK_COLOR = (100, 0, 255) NUM_PIXELS = 10 CURVE = -2 SCALE_EXPONENT = math.pow(10, CURVE * -0.1) NUM_SAMPLES = 160 pixels = neopixel.NeoPixel(board.NEOPIXEL, NUM_PIXELS, brightness=0.1, auto_write=False) pixels.fill(0) pixels.show() def constrain(value, floor, ceiling): return max(floor, min(value, ceiling)) def log_scale(input_value, input_min, input_max, output_min, output_max): normalized_input_value = (input_value - input_min) / \ (input_max - input_min) return output_min + \ math.pow(normalized_input_value, SCALE_EXPONENT) \ * (output_max - output_min) def normalized_rms(values): minbuf = int(mean(values)) samples_sum = sum( float(sample - minbuf) * (sample - minbuf) for sample in values ) return math.sqrt(samples_sum / len(values)) def mean(values): return sum(values) / len(values) def volume_color(volume): return 200, volume * (255 // NUM_PIXELS), 0 my_servo = servo.ContinuousServo(pwm) samples = array.array('H', [0] * NUM_SAMPLES) mic.record(samples, len(samples)) samples = array.array('H', [0] * NUM_SAMPLES) mic.record(samples, len(samples)) input_floor = normalized_rms(samples) + 10 input_ceiling = input_floor + 500 peak = 0 while True: mic.record(samples, len(samples)) magnitude = normalized_rms(samples) c = log_scale(constrain(magnitude, input_floor, input_ceiling), input_floor, input_ceiling, 0, NUM_PIXELS) print(c) pixels.fill(0) for i in range(NUM_PIXELS): if i < c: pixels[i] = volume_color(i) if c >= peak: peak = min(c, NUM_PIXELS - 1) elif peak > 0: peak = peak - 1 if peak > 0: pixels[int(peak)] = PEAK_COLOR pixels.show() if c>2.0: my_servo.throttle = c/10.0 time.sleep(0.1) my_servo.throttle = -c/10.0 time.sleep(0.11) my_servo.throttle = 0.0 [localvideo]964094efd0d6836bbdaa61e8d04fde90[/localvideo]   三、可编译下载的代码 download.eeworld.com.cn/detail/eew_gz8e7C/634236

  • 上传了资料: Follow me 第二季第一期任务代码

  • 2024-08-18
  • 加入了学习《【Follow me第二季第1期】在arduino环境下多app调度全部任务》,观看 【Follow me第二季第1期】在arduino环境下多app调度全部任务

  • 2024-02-25
  • 发表了主题帖: 【得捷Follow me第4期】W5500-EVB-Pico--树莓派PICO与W5500的学习与使用

    本帖最后由 eew_gz8e7C 于 2024-2-25 22:21 编辑         很高兴能获得本期FOLLOW ME活动的参与机会,通过本期活动学习了W5500-EVB-Pico的基本使用,将学习成果汇总如下: Follow me第4期-总结视频-Follow me第4期 总结视频-EEWORLD大学堂                 一、任务及硬件简介         本期任务的主板为W5500-EVB-Pico,其具备了RP2040的易用性,MPY\CPY\Arduino都能很好的兼容,同时加持了W5500网口,使其能够便捷的接入以太网,做网络应用的开发。        主板介绍:           板载的W5500及LED占用了部分IO如下:                显示组件:         根据坛内大佬推荐,本期活动选用pervasivedisplays的电子纸显示器及转接板作为显示套件。pervasivedisplays官方有详细的配套树莓派pico的使用说明,这里摘出重要部分,其他的可参考官方链接。         1.显示屏与转接板连接           2.转接板与PICO连接:           3.连接后效果:                二、任务实现及成果展示         1.开发环境搭建,BLINK,驱动液晶显示器进行显示(没有则串口HelloWorld)         1)开发环境选用Arduino,需要安装第三方平台支持库:https://github.com/WIZnet-ArduinoEthernet/arduino-pico/releases/download/global/package_rp2040-ethernet_index.json,安装方法 文件-》首选项-》其他开发板管理地址处填入确认。              2)安装W5500-EVB-Pico支持库:         工具-》选项-》开发板管理器 搜索wiznet,然后选择开发板                     另外,对于电子纸屏幕可以安装官方提供的arduino驱动,在工具-》库管理中搜索ext3即可找到安装。           3)核心代码: // SDK #include <Arduino.h> // Screen #include "PDLS_EXT3_Basic_Global.h" #include "hV_HAL_Peripherals.h" // Configuration #include "hV_Configuration.h" // #define EPD_EXT3_266 #define EPD_EXT3_154 #ifdef EPD_EXT3_266 // // Define variables and constants for 2.66 296x152 Screen_EPD_EXT3 epd(eScreen_EPD_EXT3_266, boardRaspberryPiPico_RP2040); #define LINE1_POS 40, 30 #define LINE2_POS 40, 80 #define FONT Font_Terminal16x24 #endif #ifdef EPD_EXT3_154 // // Define variables and constants for 1.54 152 x 152 Screen_EPD_EXT3 epd(eScreen_EPD_EXT3_154, boardRaspberryPiPico_RP2040); #define LINE1_POS 20, 40 #define LINE2_POS 20, 80 #define FONT Font_Terminal8x12 #endif // Utilities /// /// @brief Wait with countdown /// @param second duration, s /// void wait(uint8_t second) { for (uint8_t i = second; i > 0; i--) { Serial.print(formatString(" > %i \r\n", i)); delay(1000); } Serial.print(" \r\n"); } // Add setup code /// /// @brief Setup /// void setup() { Serial.begin(115200); delay(500); pinMode(LED_BUILTIN, OUTPUT); Serial.println("begin... "); epd.begin(); Serial.println("Characters... "); epd.clear(); epd.setOrientation(1);//set orientation epd.selectFont(FONT); epd.gText(LINE1_POS, "Follow me 4", myColours.red); epd.gText(LINE2_POS, "w5500-evb-pico", myColours.black); epd.flush(); wait(8); } // Add loop code /// /// @brief Loop, empty /// void loop() { Serial.print("Follow me 4\n"); digitalWrite(LED_BUILTIN, HIGH); delay(1000); digitalWrite(LED_BUILTIN, LOW); delay(1000); }         4)效果展示:           2.基础任务一:完成主控板W5500初始化(静态IP配置),并能使用局域网电脑ping通,同时W5500可以ping通互联网站点;通过抓包软件(Wireshark、Sniffer等)抓取本地PC的ping报文,展示并分析。         1)核心代码: 局域网ping #include <SPI.h> #include <Ethernet.h> #include <Arduino.h> // 网卡mac地址 byte mac[] = { 0xAE, 0x5D, 0x10, 0x75, 0x88, 0xAD }; // 静态ip地址、DNS服务、网关、子网掩码 // byte ip[] = { 192, 168, 1, 188 }; IPAddress ip(192, 168, 1, 100); IPAddress dns(192, 168, 1, 1); IPAddress gateway(192, 168, 1, 1); IPAddress subnet(255, 255, 255, 0); void setup() { // 配置串口 Serial.begin(115200); delay(500); // 静态IP设置 Ethernet.init(17); Ethernet.begin(mac, ip, dns, gateway, subnet); } void loop() { Serial.print("RP2040 IP address: "); Serial.println(Ethernet.localIP()); delay(5000); }         互联网ping #include <SPI.h> #include <Ethernet.h> #include <Dns.h> // 网卡mac地址 byte mac[] = { 0xAE, 0x5D, 0x10, 0x75, 0x88, 0xAD }; // 静态ip地址、DNS服务、网关、子网掩码 // byte ip[] = { 192, 168, 1, 188 }; IPAddress ip(192, 168, 1, 100); IPAddress dns(192, 168, 1, 1); IPAddress gateway(192, 168, 1, 1); IPAddress subnet(255, 255, 255, 0); DNSClient dnClient; IPAddress dstip; void setup() { // 配置串口 Serial.begin(115200); delay(500); // 静态IP设置 Ethernet.init(17); Ethernet.begin(mac, ip, dns, gateway, subnet); } void loop() { Serial.print("RP2040 IP address: "); Serial.println(Ethernet.localIP()); dnClient.begin(Ethernet.dnsServerIP()); const char domains[3][20] = { "www.eeworld.com.cn", "www.digikey.cn", "www.digikey.com" }; for (int i = 0; i < 3; i++) { if (dnClient.getHostByName(domains[i], dstip) == 1) { Serial.print(domains[i]); Serial.print(" = "); Serial.println(dstip); } else Serial.println(F("dns lookup failed")); } delay(5000); }         2)效果展示:             3)抓包分析:         打开wireshark,选择和开发板共网的网卡,设置筛选条件为  (ip.dst==192.168.1.172 and ip.src==192.168.1.100) or (ip.src==192.168.1.172 and ip.dst==192.168.1.100)         可以筛选出pc与pico间的报文,可以看到四组报文对应ping命令执行后的四次通信:           3.基础任务二:主控板建立TCPIP或UDP服务器,局域网PC使用TCPIP或UDP客户端进行连接并发送数据,主控板接收到数据后,送液晶屏显示(没有则通过串口打印显示);通过抓包软件抓取交互报文,展示并分析。(TCP和UDP二选一,或者全都操作)         1.TCP服务器核心代码: #include<Ethernet.h> //网络配置 // 网卡mac地址 byte mac[] = { 0xAE, 0x5D, 0x10, 0x75, 0x88, 0xAD }; // 静态ip地址、DNS服务、网关、子网掩码 // byte ip[] = { 192, 168, 1, 188 }; IPAddress ip(192, 168, 1, 100); IPAddress dns(192, 168, 1, 1); IPAddress gateway(192, 168, 1, 1); IPAddress subnet(255, 255, 255, 0); // 网络服务客户端 EthernetClient client; bool haveClient = false; #define SERVER_PORT 2024 int LEDSTATE = 0; // 有线网络服务 EthernetServer server(SERVER_PORT); void setup() { // 配置串口 Serial.begin(115200); delay(500); pinMode(LED_BUILTIN,OUTPUT); digitalWrite(LED_BUILTIN,LEDSTATE); // 静态IP设置 Ethernet.init(17); Ethernet.begin(mac, ip, dns, gateway, subnet); Serial.println("TCP server Begin @ 192.168.1.100:2024\n"); server.begin(); } void loop() { // 处理客户端连接 if (!haveClient) { // 检查新连接 client = server.available(); if (client) { haveClient = true; Serial.println("New client"); while (client.connected()){ if (client.available()){ String buff = client.readStringUntil('\r'); Serial.println(buff); if (LEDSTATE){ LEDSTATE=0; }else{ LEDSTATE=1; } digitalWrite(LED_BUILTIN,LEDSTATE); } } } } else if ((!client.connected()) && haveClient) { client.stop(); client = EthernetClient(); haveClient = false; Serial.println("client closed!"); } }         2)tcp通信效果:              3)TCP抓包分析:         可以看到从TCP握手连接到数据传输再到挥手断开的过程:             4.进阶任务:从NTP服务器(注意数据交互格式的解析)同步时间,获取时间送显示屏(串口)显示。         1)安装支持库,arduino有ntp支持库,可以搜索NTPClient下载。         2)核心代码:         注意标准授时结果与北京时间相差8小时,需要设置8*60*60s的补偿方可得到北京时间。 #include <NTPClient.h> //NTP库 #include <Ethernet.h> //网络配置 // 网卡mac地址 byte mac[] = { 0xAE, 0x5D, 0x10, 0x75, 0x88, 0xAD }; // 静态ip地址、DNS服务、网关、子网掩码 // byte ip[] = { 192, 168, 1, 188 }; IPAddress ip(192, 168, 1, 100); IPAddress dns(192, 168, 1, 1); IPAddress gateway(192, 168, 1, 1); IPAddress subnet(255, 255, 255, 0); EthernetUDP ntpUDP; long timeOffSet=60*60*8; NTPClient timeClient(ntpUDP,timeOffSet); // NTP获取时间 void setup() { // 静态IP设置 Ethernet.init(17); Ethernet.begin(mac, ip, dns, gateway, subnet); delay(80000); //等待网络配置 timeClient.begin(); } char buffer[100]; void loop() { timeClient.update(); Serial.print(timeClient.getFormattedTime()); Serial.print("\n"); delay(1000); }         3)效果展示:           5.终极任务二:使用外部存储器,组建简易FTP文件服务器,并能正常上传下载文件。         原想使用arduino实现ftp但是始终未能成功,无奈只能换个思路采用mpy实现。         1)核心代码: import gc import uos import time import socket import network from time import localtime from machine import Pin, SPI from micropython import const _LED_PIN = const(25) # 绿色 LED 引脚 _SPI_SPEED = const(2_000_000) # SPI 速率 _MOSI_PIN = const(19) # SPI MOSI 引脚 _MISO_PIN = const(16) # SPI MISO 引脚 _SCK_PIN = const(18) # SPI SCK 引脚 _CS_PIN = const(17) # SPI CS 引脚 _RST_PIN = const(20) # SPI RESET 引脚 FTP_ROOT_PATH = const("/ftp") # FTP 根目录 month_name = ["", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"] # SPI 定义 spi=SPI(0, _SPI_SPEED, mosi=Pin(_MOSI_PIN), miso=Pin(_MISO_PIN), sck=Pin(_SCK_PIN)) nic = None """ W5500 初始化 """ def w5500_start(): global nic # 网口初始化 nic = network.WIZNET5K(spi, Pin(_CS_PIN), Pin(_RST_PIN)) #spi,cs,reset pin nic.active(True) # 配置网络 nic.ifconfig(('192.168.1.100','255.255.255.0','192.168.1.1','192.168.1.1')) while not nic.isconnected(): time.sleep(1) print(nic.regs()) print("IP地址: %s" %nic.ifconfig()[0]) print("子网掩码: %s" %nic.ifconfig()[1]) print("网关: %s" %nic.ifconfig()[2]) print("DNS: %s" %nic.ifconfig()[3]) """ 响应文件列表请求 """ 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): try: with open(path, "rb") as file: chunk = file.read(512) print("chunk 0: ", len(chunk)) while len(chunk) > 0: print("chunk: ", len(chunk)) dataclient.sendall(chunk) chunk = file.read(512) except Exception as err: print("error: ", err.args, err.value, err.errno) """ 保存文件上传数据 """ 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 """ 文件名比较 """ 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 """ 启动FTP服务 """ 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) print("FTP服务启动成功!监听端口:21"); 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 = FTP_ROOT_PATH try: print("新的FTP连接来自: %s:%s" %(remote_addr[0], remote_addr[1])) cl.sendall("220 Welcome! This is the W5500_EVB_PICO!\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("命令={}, 参数={}, 路径={}".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数据连接来自: %s:%s" %(data_addr[0], data_addr[1])) 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, "wb") 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() if __name__ == "__main__": print("run in main") w5500_start() # 初始化网络 ftpserver() # 运行 FTP Server         2)效果展示:           三、任务源码         https://download.eeworld.com.cn/detail/eew_gz8e7C/631389   补充内容 (2024-3-1 19:11): 四、心得体会与建议: 通过本次活动的任务实现,入门了arduino IDE的使用,另外对以太网网络通信也加深了理解。感谢eeworld和得捷提供的活动机会,期待下次还能有幸参与!

最近访客

现在还没有访客

< 1/0 >

统计信息

已有--人来访过

  • 芯积分:115
  • 好友:--
  • 主题:9
  • 回复:2

留言

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


现在还没有留言