- 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期】任务汇总提交
本帖最后由 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第二季第1期视频》,观看 得捷Follow me第二季第1期视频
-
上传了资料:
Follow me 第二季第一期任务代码
- 2024-08-18
-
加入了学习《【Follow me第二季第1期】在arduino环境下多app调度全部任务》,观看 【Follow me第二季第1期】在arduino环境下多app调度全部任务