- 2024-10-20
-
加入了学习《【Follow me第二季第2期】Arduino UNO R4 WiFi 任务视频》,观看 【Follow me第二季第2期】Arduino UNO R4 WiFi 任务视频
-
加入了学习《【Follow me第二季第1期】Adafruit Circuit Playground Express 任务视频》,观看 【Follow me第二季第1期】Adafruit Circuit Playground Express 任务视频
-
上传了资料:
Follow me 第二季第2期任务Arduino UNO R4 WiFi学习源码
- 2024-10-06
-
发表了主题帖:
【Follow me第二季第2期】学习Arduino UNO R4 WiFi 之任务汇总
本帖最后由 md-llama-com 于 2024-10-20 22:28 编辑
# 学习Arduino UNO R4 WiFi任务汇总
Follow me 第二季第二期来了,又又又可以白嫖技术白嫖板子了 ~ 闲话少说 ~开启今日份任务汇总,这次是一份Arduino UNO R4 WiFi的板子,用的是日本瑞萨电子的RA4M1芯片,wifi用的是乐鑫ESP32,非常值得学习的方案。
# 汇总视频链接
[localvideo]bf33d481ab30092d6d1ba4513cc03fc2[/localvideo]
# 全部物料清单(含物料名称、实物图片)
1.最主要的控制板
Arduino UNO R4 WiFi
2.LTR-329 环境光传感器与SHT40温湿度传感器
3.跳线
4.示波器
# 入门任务(必做):搭建环境并开启第一步Blink / 串口打印Hello EEWorld!
搭配器件: Arduino UNO R4 WiFi
这就是今天的主角,这个项目一是为了确定板子的好坏,二是为了测试与电脑是否可以通讯。
## 搭建环境:
在arduino官网下载Arduino IDE
点击微软下载或者MAC下载
仅下载 JUST DOWNLOAD
下载好后点击安装包安装
同意,下一步,安装,三步走,尽量装在D盘
完成安装后在打开arduino IDE并授权一大堆权限后,我们进入了界面,开始获取Arduino UNO R4 WiFi 包
注意这里arduino IDE会要求安装一堆东西
安装这块板子的支持包后即可完成环境搭建
整个步骤就是:上官网->下载软件->安装arduino->配置Arduino UNO R4 WiFi板子扩展包
## Blink
写程序的第一句话是打印hello world
而玩儿开发板的第一步是点灯
在打开IDE后找到文件file->示例Exmples->基础Basics->BLink
用Type-C线连好板子与电脑
点击编译即可
效果如下:
代码如下:
```
void setup() {
// initialize digital pin LED_BUILTIN as an output.
pinMode(LED_BUILTIN, OUTPUT);
}
// the loop function runs over and over again forever
void loop() {
digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level)
delay(1000); // wait for a second
digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW
delay(1000); // wait for a second
}
```
## 串口打印Hello EEWorld!
串口打印是很多交互的基础
我们在刚刚的点灯程序下加入这一行:波特率设定为9600,波特率是电脑与单片机之间的通讯频率
```
Serial.println("Hello EEWorld!");
```
打开串口调试器,下载程序
效果如下:
代码如下:
```
void setup() {
// initialize digital pin LED_BUILTIN as an output.
pinMode(LED_BUILTIN, OUTPUT);
Serial.begin(9600);
}
// the loop function runs over and over again forever
void loop() {
digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level)
delay(1000); // wait for a second
Serial.println("Hello EEWorld!");
digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW
delay(1000); // wait for a second
}
```
## 程序流程图
# 基础任务(必做):驱动12x8点阵LED;用DAC生成正弦波;用OPAMP放大DAC信号;用ADC采集并且打印数据到串口等其他接口可上传到上位机显示曲线
搭配器件: Arduino UNO R4 WiFi
## 驱动12x8点阵LED
12X8点阵LED这是之前没遇到过的,通过查看原理图,原理图如下
至于怎么驱动这块LED屏幕,我们可以在示例里找到LED_Matrix,打开DisplaySingleFrame示例查看
代码如下
```
#include "Arduino_LED_Matrix.h" // Include the LED_Matrix library
#include "frames.h" // Include a header file containing some custom icons
ArduinoLEDMatrix matrix; // Create an instance of the ArduinoLEDMatrix class
void setup() {
Serial.begin(115200); // Initialize serial communication at a baud rate of 115200
matrix.begin(); // Initialize the LED matrix
}
void loop() {
// Load and display the "chip" frame on the LED matrix
matrix.loadFrame(chip);
delay(500); // Pause for 500 milliseconds (half a second)
// Load and display the "danger" frame on the LED matrix
matrix.loadFrame(danger);
delay(500);
// Load and display the "happy" frame on the LED matrix
matrix.loadFrame(happy);
delay(500);
// Load and display the "big heart" frame provided by the library
matrix.loadFrame(LEDMATRIX_HEART_BIG);
delay(500);
// Turn off the display
matrix.clear();
delay(1000);
// Print the current value of millis() to the serial monitor
Serial.println(millis());
}
```
效果如下:
## 程序流程图如下:
## 用DAC生成正弦波;用OPAMP放大DAC信号;用ADC采集并且打印数据到串口
这三个任务可以一起做
### 用DAC生成正弦波
打开案例库SineWave
其代码如下:
```
#include "analogWave.h" // Include the library for analog waveform generation
analogWave wave(DAC); // Create an instance of the analogWave class, using the DAC pin
int freq = 10; // in hertz, change accordingly
void setup(){
Serial.begin(115200);
wave.sine(freq);
wave.amplitude(0.5);//幅值倍数
}
void loop(){
Serial.println(analogRead(A5));
delay(10);
}
```
### 用OPAMP放大DAC信号
使用运算放大器(OP-AMP)放大数字到模拟转换器(DAC)的信号是一种常见的电子电路设计实践。这种配置可以增加信号的幅度,以满足特定的应用需求,例如驱动更大的负载或提供足够的信号强度以进行测量。
以下是电路图
代码如下:
```
#include "analogWave.h" // Include the library for analog waveform generation
#include "OPAMP.h"
analogWave wave(DAC); // Create an instance of the analogWave class, using the DAC pin
int freq = 200; // in hertz, change accordingly
void setup() {
Serial.begin(2000000); // Initialize serial communication at a baud rate of 115200
analogReadResolution(14);
wave.sine(freq); // Generate a sine wave with the initial frequency
wave.amplitude(0.5);//幅值倍数
OPAMP.begin(OPAMP_SPEED_HIGHSPEED);
}
void loop() {
delayMicroseconds(100);
}
```
### 用ADC采集并且打印数据到串口
只需要将输出分别导入A4,A5端口即可,循环loop如下
```
void loop() {
Serial.print(analogRead(A4));
Serial.print(",");
Serial.println(analogRead(A5));
delayMicroseconds(100);
}
```
用示波器显示如下
## 流程图
# 进阶任务(必做):通过Wi-Fi,利用MQTT协议接入到开源的智能家居平台HA(HomeAssistant)
搭配器件: Arduino UNO R4 WiFi
要接入到平台HA(HomeAssistant)平台,首先要有一个HA平台,常规做法是搭建一个服务器,在服务器中用docker容器安装HA,我们作为初学者,自己用的电脑直接安装HA
pip3 install homeassistant
在powershell中输入命令下载安装HA,时间会比较久
打开 127.0.0.1:8123 注册HA
接下来要搭建MQTT服务器,这里用的是Docker容器下的EMQX镜像
众所周知Docker安装是真的烦,我这里就遇到了Docker Engine stopped
**我是怎么解决的呢**
### 1.首先检查一下CPU是否开启虚拟化
如果虚拟化是禁用的,要进入BIOS打开虚拟化。我这里是没有问题的。
### 2.启动Docker Desktop Service服务
在windows powershell中(管理员运行),输入 **net start com.docker.service** 启动Docker Desktop Service服务
### 3.wsl安装
在windows powershell中输入**wsl --update**,开始安装wsl或者更新版本。
### 4.启动docker daemon
在windows powershell中输入 ** cd "C:\Program Files\Docker\Docker" ** 跳转到Docker Desktop安装路径
运行命令 **.\DockerCli.exe -SwitchDaemon** 把docker daemon启动
### 5.重启电脑
重启电脑非常重要,网上的步骤都没写这步,导致我一直失败,重启电脑后再运行docker desktop,就可以正常进入了。
正常进入docker后找到Docker Engine
将其中内容改为
```
{
"builder": {
"gc": {
"defaultKeepStorage": "20GB",
"enabled": true
}
},
"debug": true,
"experimental": false,
"insecure-registries":[],
"registry-mirrors":[
"https://docker.m.daocloud.io"
]
}
```
重启docker。
## 然后就可以在docker中拉取emqx
### 1.在windows命令行中输入以下命令搜索镜像,
```c
docker search emqx
```
### 2.回车后可以看到排名第一的 emqx 并且是official; 输入以下命令拉取最新版本镜像
```c
docker pull emqx
```
## 然后创建EMQX容器
```
docker run -d --name="EMQX_container" -v D:/HassWP_2024.4.3/EMQX -p 1883:1883 -p 8083:8083 -p 8883:8883 -p 8084:8084 -p 18083:18083 emqx
```
-v 后面接着的是容器保存路径
## 启动emqx
回到docker点击图示网址即可启动
http://localhost:18083/
默认账号:admin 默认密码:public
## EMQX的一些设置
进入EMQX后会让我们重新设置密码
访问控制 -> 客户端认证 -> 选 **创建** -> 选择 **Password-Based** -> **内置数据库** -> **下一步** -> 3个都默认 -> 点 **创建**
点击 **用户管理** -> 点 +(右侧)-> 填入新的用户名和密码
## EMQX 与 HA相连接
首先要找到EMQX服务器在docker内的地址,按照图片所示寻找即可
在HA中打开设置如下图
设备与服务
添加新设备
输入刚刚的地址与EMQX上新增的用户名与密码
完成后回到EMQX界面可以看到设备连接数加一
这样EMQX HA 之间就打通了
接下来要将咱们的主角与EMQX之间的连接打通。
## Arduino UNO R4 WiFi与EMQX连接
程序如下:
参数定义如下
```c
#define MQTT_SERVER "192.168.3.28"// 电脑无线网卡IP地址"xxx.xxx.xxx.xxX
#define MQTT_PORT 1883 //定义MQTT服务器的端口
#define MQTT_CLIENT_ID "arduino"// 定义客户端的ID'arduino'
#define MQTT_USERNAME "sdfa" // 定义用户名,EMQX定义"admin'
#define MQTT_PASSWORD "sdfda" // 定义密码,EMQX定义"admin"
#define TOPIC_SUBSCRIBE "UNO/arduino/switch/cmd_t"//定义订阅的主题
#define SECRET_SSID "dsdfai" // 路由器WiFi名称 也可使用win移动热点"xxXXX
#define SECRET_PASS "sfdfsf" // 路由器WiFi密码”xxxXX
```
主程序是HA网站上设定按钮,然后控制Arduino UNO R4 WiFi上14号引脚小灯亮灭。
主程序如下
```c
#include "ArduinoHA.h"
#include "OPAMP.h"
#include "Wire.h"
#include "WiFiS3.h"
#include "arduino_secrets.h"
#include "analogWave.h"
analogWave wave(DAC);
int status= WL_IDLE_STATUS;
unsigned long lastUpdateAt=0;
int freg=1;//max200 Hz limit by serial print
WiFiClient client;
HADevice device(MQTT_CLIENT_ID);//HADevice device (mac, sizeof(mac));
HAMqtt mqtt(client,device);
HAButton buttonON("myButtonON");
HAButton buttonOFF("myButtonOFF");
void setup()
{
pinMode(LED_BUILTIN, OUTPUT);
Serial.begin(115200);
wifi_and_mqtt_init();
analogReadResolution(14);//change to 14-bit resolution
wave.sine(freg);//wave.saw(freg);
wave.amplitude(0.5);
OPAMP.begin(OPAMP_SPEED_HIGHSPEED);
device.setName("Arduino");
device.setSoftwareVersion("1.0.0");
buttonON.setIcon("mdi:fire");
buttonON.setName("Click me ON");
buttonOFF.setIcon("mdi:home");
buttonOFF.setName("click me OFF");
buttonON.onCommand(onButtonCommand);//press callbacks
buttonOFF.onCommand(onButtonCommand);
}
void loop()
{
mqtt.loop();
if((millis() - lastUpdateAt) > 1000)
{//update in 1s interval
unsigned long uptimeValue=millis()/1000;
lastUpdateAt =millis();
}
}
void onMqttMessage(const char* topic, const uint8_t* payload, uint16_t length)
{
char message[length];
memcpy(message,payload,length);
message[length]= '\0';
Serial.print("dbglNew message on topic:");
Serial.println(topic);
Serial.print("Data:");
Serial.println((const char*)message);
if(strstr(message,"on")!=NULL)
{
int dutyCycle=0;
if (sscanf(message,"on#%d",&dutyCycle)==1)
{
}
}
else if(strstr(message,"off")!=NULL)
{
}
else
{
Serial.println("Unrecognized message");
}
memset(message,0, length);
}
void onMqttConnected()
{
Serial.println("Connected to the broker!");
//You can subscribe to custom topic if you need
mqtt.subscribe(TOPIC_SUBSCRIBE);//command
//mqtt.subscribe(TOPIC SUBSCRIBE2)://status
Serial.println("subscribed to topic:" TOPIC_SUBSCRIBE);
mqtt.publish(TOPIC_SUBSCRIBE,"Hi EMOX I'mArdinO UNO R4 WIFI^^");
}
void onMqttDisconnected()
{
Serial.println("Disconnected from the broker!");
}
void onMqttStateChanged(HAMqtt::ConnectionState state)
{
Serial.print("MoTT state changed to:");
Serial.println(static_cast(state));
}
void onButtonCommand(HAButton* sender)
{
if(sender ==&buttonON)
{
Serial.print("[dbg]buttonON");// button A was clicked, do your logic hereelse
digitalWrite(LED_BUILTIN, HIGH);
}
else if(sender==&buttonOFF)
{
Serial.print("[dbg]buttonOFF");// button B was clicked, do your logic here
digitalWrite(LED_BUILTIN, LOW);
}
}
void wifi_and_mqtt_init()
{
//check for the WiFi module:
if(WiFi.status()==WL_NO_MODULE)
{
Serial.println("Communication with WiFi module failed!");
while (true);
}
String fv = WiFi.firmwareVersion();
if(fv < WIFI_FIRMWARE_LATEST_VERSION)
{
Serial.println("Please upgrade the firmware");
}
//attempt to connect to wiFi network;
while(status!=WL_CONNECTED)
{
Serial.print("Attempting to connect to SSID:");
Serial.println(SECRET_SSID);
//Connect to WPA/WPA2 network, Change this line if using open or WEP network;
status=WiFi.begin(SECRET_SSID,SECRET_PASS);
delay(10000);
}
Serial.println("\nStarting connection to MoTT server...");
mqtt.onMessage(onMqttMessage);
mqtt.onConnected(onMqttConnected);
mqtt.onDisconnected(onMqttDisconnected);
mqtt.onStateChanged(onMqttStateChanged);
//If you want to change prefix only for non-discovery prefix:
mqtt.setDataPrefix("UNO");
if(!mqtt.begin(MQTT_SERVER,MQTT_PORT,MQTT_USERNAME,MQTT_PASSWORD))
{
Serial.print("Failed, rC=");
Serial.print(mqtt.getState());//0btaining state of the MoTr connection:
Serial.println("tryagain in 5 seconds");
delay(5000);
}
}
```
效果如下
## 流程图
# 扩展任务(必做,二选一,或根据自己的兴趣,自定义类似难度或更高难度的任务并完成)我选择两个都做
## ■ 扩展任务一:通过外部LTR-329 环境光传感器,上传光照度到HA,通过HA面板显示数据
搭配器件: Arduino UNO R4 WiFi、5591(LTR-329光传感器扩展板)、跳线
首先要处理一下接线问题,因为没有购买官方的跳线,我们需要自己把插针焊上
如下图
然后按照IIC的要求把时钟线 数据线接上,注意电源线要接3.3V的。
安装Adafruit LTR329 and LTR303 库
打开示例,将没用的语句简化,先测试一下模块是否正常使用,然后再与HA连接:
```
#include "Adafruit_LTR329_LTR303.h"
Adafruit_LTR303 ltr = Adafruit_LTR303();
void setup() {
Serial.begin(115200);
if ( ! ltr.begin() ) {
Serial.println("Couldn't find LTR sensor!");
while (1) delay(10);
}
//初始化传感器,如果没找到持续刷新,直到找到
Serial.println("Found LTR sensor!");
ltr.setGain(LTR3XX_GAIN_96);//设置传感器灵敏度
ltr.setIntegrationTime(LTR3XX_INTEGTIME_100);//设置传感器的积分时间ms
ltr.setMeasurementRate(LTR3XX_MEASRATE_200);//设置测量速率ms
// The LTR-303 has interrupt output support, we can enable the pin output!
ltr.enableInterrupt(true);
// The INT pin also has a polarity setting. For active LOW set to 'false',
// for active HIGH set to 'true'
ltr.setInterruptPolarity(false);
//设置低阈值和高阈值
// Then set the low threshold (values BELOW this trigger an interrupt)
ltr.setLowThreshold(2000);
// and set the high threshold (values ABOVE this trigger an interrupt)
ltr.setHighThreshold(30000);
Serial.print("Thresholds: "); Serial.print(ltr.getLowThreshold());
Serial.print(" & "); Serial.println(ltr.getHighThreshold());
// Finally, default is an interrupt on every value that is under/over the
// threshold ranges. However, you're more likely to get spurious IRQs, so
// we can set it to require "N counts in a row" before an IRQ. 1 count is
// IRQ for each reading, 2 count means we need two outside readings in a row, etc
// up to 16.
//设置中断的持续计数,连续4次超出阈值则中断
ltr.setIntPersistance(4);
Serial.print("Consecutive counts for IRQ: "); Serial.println(ltr.getIntPersistance());
}
void loop() {
bool valid;
uint16_t visible_plus_ir, infrared;
//检查是否有新的数据可用
if (ltr.newDataAvailable()) {
valid = ltr.readBothChannels(visible_plus_ir, infrared);
//如果数据有效,将可见光+红外和红外的光强度值打印到串行监视器。
if (valid) {
Serial.print("CH0 Visible + IR: ");
Serial.print(visible_plus_ir);
Serial.print("\t\tCH1 Infrared: ");
Serial.println(infrared);
}
}
delay(100);
}
```
运行效果如下
与HA结合程序如下
```
#include "ArduinoHA.h"
#include "OPAMP.h"
#include "Wire.h"
#include "WiFiS3.h"
#include "arduino_secrets.h"
#include "analogWave.h"
#include "Adafruit_LTR329_LTR303.h"
analogWave wave(DAC);
Adafruit_LTR303 ltr = Adafruit_LTR303();
int status= WL_IDLE_STATUS;
unsigned long lastUpdateAt=0;
int freg=1;//max200 Hz limit by serial print
WiFiClient client;
HADevice device(MQTT_CLIENT_ID);//HADevice device (mac, sizeof(mac));
HAMqtt mqtt(client,device);
HASensorNumber analogSensor("myAnalogInput", HASensorNumber::PrecisionP1);
HASensorNumber uptimeSensor("myUptime");
HAButton buttonON("myButtonON");
HAButton buttonOFF("myButtonOFF");
void setup()
{
pinMode(LED_BUILTIN, OUTPUT);
Serial.begin(115200);
wifi_and_mqtt_init();
analogReadResolution(14);//change to 14-bit resolution
wave.sine(freg);//wave.saw(freg);
wave.amplitude(0.5);
OPAMP.begin(OPAMP_SPEED_HIGHSPEED);
device.setName("Arduino");
device.setSoftwareVersion("1.0.0");
buttonON.setIcon("mdi:fire");
buttonON.setName("Click me ON");
buttonOFF.setIcon("mdi:home");
buttonOFF.setName("click me OFF");
buttonON.onCommand(onButtonCommand);//press callbacks
buttonOFF.onCommand(onButtonCommand);
if ( ! ltr.begin() ) {
Serial.println("Couldn't find LTR sensor!");
while (1) delay(10);
}
//初始化传感器,如果没找到持续刷新,直到找到
Serial.println("Found LTR sensor!");
ltr.setGain(LTR3XX_GAIN_96);//设置传感器灵敏度
ltr.setIntegrationTime(LTR3XX_INTEGTIME_100);//设置传感器的积分时间ms
ltr.setMeasurementRate(LTR3XX_MEASRATE_200);//设置测量速率ms
// The LTR-303 has interrupt output support, we can enable the pin output!
ltr.enableInterrupt(true);
// The INT pin also has a polarity setting. For active LOW set to 'false',
// for active HIGH set to 'true'
ltr.setInterruptPolarity(false);
//设置低阈值和高阈值
// Then set the low threshold (values BELOW this trigger an interrupt)
ltr.setLowThreshold(2000);
// and set the high threshold (values ABOVE this trigger an interrupt)
ltr.setHighThreshold(30000);
}
void loop()
{
bool valid;
uint16_t visible_plus_ir, infrared;
mqtt.loop();
//检查是否有新的数据可用
if (ltr.newDataAvailable()) {
valid = ltr.readBothChannels(visible_plus_ir, infrared);
//如果数据有效,将可见光+红外和红外的光强度值打印到串行监视器。
if (valid) {
if((millis() - lastUpdateAt) > 1000)
{//update in 1s interval
Serial.print("CH0 Visible + IR: ");
Serial.print(visible_plus_ir);
uptimeSensor.setValue(visible_plus_ir);
Serial.print("\t\tCH1 Infrared: ");
Serial.println(infrared);
analogSensor.setValue(infrared);
lastUpdateAt =millis();
}
}
}
}
void onMqttMessage(const char* topic, const uint8_t* payload, uint16_t length)
{
char message[length];
memcpy(message,payload,length);
message[length]= '\0';
Serial.print("dbglNew message on topic:");
Serial.println(topic);
Serial.print("Data:");
Serial.println((const char*)message);
void onMqttConnected()
{
Serial.println("Connected to the broker!");
//You can subscribe to custom topic if you need
mqtt.subscribe(TOPIC_SUBSCRIBE);//command
//mqtt.subscribe(TOPIC SUBSCRIBE2)://status
Serial.println("subscribed to topic:" TOPIC_SUBSCRIBE);
mqtt.publish(TOPIC_SUBSCRIBE,"Hi EMOX I'mArdinO UNO R4 WIFI^^");
}
void onMqttDisconnected()
{
Serial.println("Disconnected from the broker!");
}
void onMqttStateChanged(HAMqtt::ConnectionState state)
{
Serial.print("MoTT state changed to:");
Serial.println(static_cast(state));
}
void onButtonCommand(HAButton* sender)
{
if(sender ==&buttonON)
{
Serial.print("[dbg]buttonON");// button A was clicked, do your logic hereelse
digitalWrite(LED_BUILTIN, HIGH);
}
else if(sender==&buttonOFF)
{
Serial.print("[dbg]buttonOFF");// button B was clicked, do your logic here
digitalWrite(LED_BUILTIN, LOW);
}
}
void wifi_and_mqtt_init()
{
//check for the WiFi module:
if(WiFi.status()==WL_NO_MODULE)
{
Serial.println("Communication with WiFi module failed!");
while (true);
}
String fv = WiFi.firmwareVersion();
if(fv < WIFI_FIRMWARE_LATEST_VERSION)
{
Serial.println("Please upgrade the firmware");
}
//attempt to connect to wiFi network;
while(status!=WL_CONNECTED)
{
Serial.print("Attempting to connect to SSID:");
Serial.println(SECRET_SSID);
//Connect to WPA/WPA2 network, Change this line if using open or WEP network;
status=WiFi.begin(SECRET_SSID,SECRET_PASS);
delay(10000);
}
Serial.println("\nStarting connection to MoTT server...");
mqtt.onMessage(onMqttMessage);
mqtt.onConnected(onMqttConnected);
mqtt.onDisconnected(onMqttDisconnected);
mqtt.onStateChanged(onMqttStateChanged);
//If you want to change prefix only for non-discovery prefix:
mqtt.setDataPrefix("UNO");
if(!mqtt.begin(MQTT_SERVER,MQTT_PORT,MQTT_USERNAME,MQTT_PASSWORD))
{
Serial.print("Failed, rC=");
Serial.print(mqtt.getState());//0btaining state of the MoTr connection:
Serial.println("tryagain in 5 seconds");
delay(5000);
}
}
```
运行效果如下
### 流程图
## ■ 扩展任务二:通过外部SHT40温湿度传感器,上传温湿度到HA,通过HA面板显示数据
搭配器件: Arduino UNO R4 WiFi、4885(SHT40温湿度传感器扩展板)、跳线
安装Adafruit SHT4X库
与光照传感器一样,焊接引脚,用例程测试温湿度传感器好坏
与HA结合程序如下
```
#include "ArduinoHA.h"
#include "OPAMP.h"
#include "Wire.h"
#include "WiFiS3.h"
#include "arduino_secrets.h"
#include "analogWave.h"
#include "Adafruit_LTR329_LTR303.h"
#include "Adafruit_SHT4x.h"
Adafruit_SHT4x sht4 = Adafruit_SHT4x();
analogWave wave(DAC);
Adafruit_LTR303 ltr = Adafruit_LTR303();
int status= WL_IDLE_STATUS;
unsigned long lastUpdateAt=0;
int freg=1;//max200 Hz limit by serial print
WiFiClient client;
HADevice device(MQTT_CLIENT_ID);//HADevice device (mac, sizeof(mac));
HAMqtt mqtt(client,device);
HASensorNumber humidity2("myhumidity");
HASensorNumber Temperature2("Temperature");
HAButton buttonON("myButtonON");
HAButton buttonOFF("myButtonOFF");
void setup()
{
pinMode(LED_BUILTIN, OUTPUT);
Serial.begin(115200);
wifi_and_mqtt_init();
analogReadResolution(14);//change to 14-bit resolution
wave.sine(freg);//wave.saw(freg);
wave.amplitude(0.5);
OPAMP.begin(OPAMP_SPEED_HIGHSPEED);
device.setName("Arduino");
device.setSoftwareVersion("1.0.0");
buttonON.setIcon("mdi:fire");
buttonON.setName("Click me ON");
buttonOFF.setIcon("mdi:home");
buttonOFF.setName("click me OFF");
buttonON.onCommand(onButtonCommand);//press callbacks
buttonOFF.onCommand(onButtonCommand);
while (!Serial)
delay(10); // will pause Zero, Leonardo, etc until serial console opens
if (! sht4.begin()) {
Serial.println("Couldn't find SHT4x");
while (1) delay(1);
}
Serial.println(sht4.readSerial(), HEX);
// You can have 3 different precisions, higher precision takes longer
sht4.setPrecision(SHT4X_HIGH_PRECISION); //精度
// You can have 6 different heater settings
// higher heat and longer times uses more power
// and reads will take longer too!
sht4.setHeater(SHT4X_NO_HEATER);//加热传感器
}
void loop()
{
bool valid;
uint16_t visible_plus_ir, infrared;
sensors_event_t humidity, temp;
sht4.getEvent(&humidity, &temp);// populate temp and humidity objects with fresh data
Serial.print("Temperature: "); Serial.print(temp.temperature); Serial.println(" degrees C");
Serial.print("Humidity: "); Serial.print(humidity.relative_humidity); Serial.println("% rH");
mqtt.loop();
//检查是否有新的数据可用
if (sht4.getEvent(&humidity, &temp)) {
if((millis() - lastUpdateAt) > 1000)
{//update in 1s interval
Temperature2.setValue(temp.temperature);
humidity2.setValue(humidity.relative_humidity);
lastUpdateAt =millis();
}
}
}
void onMqttMessage(const char* topic, const uint8_t* payload, uint16_t length)
{
char message[length];
memcpy(message,payload,length);
message[length]= '\0';
Serial.print("dbglNew message on topic:");
Serial.println(topic);
Serial.print("Data:");
Serial.println((const char*)message);
if(strstr(message,"on")!=NULL)
{
int dutyCycle=0;
if (sscanf(message,"on#%d",&dutyCycle)==1) { }
}
else if(strstr(message,"off")!=NULL) { }
else
{
Serial.println("Unrecognized message");
}
memset(message,0, length);
}
void onMqttConnected()
{
Serial.println("Connected to the broker!");
//You can subscribe to custom topic if you need
mqtt.subscribe(TOPIC_SUBSCRIBE);//command
//mqtt.subscribe(TOPIC SUBSCRIBE2)://status
Serial.println("subscribed to topic:" TOPIC_SUBSCRIBE);
mqtt.publish(TOPIC_SUBSCRIBE,"Hi EMOX I'mArdinO UNO R4 WIFI^^");
}
void onMqttDisconnected()
{
Serial.println("Disconnected from the broker!");
}
void onMqttStateChanged(HAMqtt::ConnectionState state)
{
Serial.print("MoTT state changed to:");
Serial.println(static_cast(state));
}
void onButtonCommand(HAButton* sender)
{
if(sender ==&buttonON)
{
Serial.print("[dbg]buttonON");// button A was clicked, do your logic hereelse
digitalWrite(LED_BUILTIN, HIGH);
}
else if(sender==&buttonOFF)
{
Serial.print("[dbg]buttonOFF");// button B was clicked, do your logic here
digitalWrite(LED_BUILTIN, LOW);
}
}
void wifi_and_mqtt_init()
{
//check for the WiFi module:
if(WiFi.status()==WL_NO_MODULE)
{
Serial.println("Communication with WiFi module failed!");
while (true);
}
String fv = WiFi.firmwareVersion();
if(fv < WIFI_FIRMWARE_LATEST_VERSION)
{
Serial.println("Please upgrade the firmware");
}
//attempt to connect to wiFi network;
while(status!=WL_CONNECTED)
{
Serial.print("Attempting to connect to SSID:");
Serial.println(SECRET_SSID);
//Connect to WPA/WPA2 network, Change this line if using open or WEP network;
status=WiFi.begin(SECRET_SSID,SECRET_PASS);
delay(10000);
}
Serial.println("\nStarting connection to MoTT server...");
mqtt.onMessage(onMqttMessage);
mqtt.onConnected(onMqttConnected);
mqtt.onDisconnected(onMqttDisconnected);
mqtt.onStateChanged(onMqttStateChanged);
//If you want to change prefix only for non-discovery prefix:
mqtt.setDataPrefix("UNO");
if(!mqtt.begin(MQTT_SERVER,MQTT_PORT,MQTT_USERNAME,MQTT_PASSWORD))
{
Serial.print("Failed, rC=");
Serial.print(mqtt.getState());//0btaining state of the MoTr connection:
Serial.println("tryagain in 5 seconds");
delay(5000);
}
}
```
运行效果如下
对着传感器哈气后温度湿度都有所上升,温度从30度上升至35度。湿度由60%上升到90%
### 流程图
# 项目总结
在这个精彩纷呈的“Follow me”第二季项目中,我有幸深入探索了Arduino UNO R4 WiF这一功能强大的开发板,并从中获得了许多宝贵的知识和技能。通过这个项目,我掌握了如何自己搭建物联网服务器,花了我具多时间,一度想要放弃,感谢小助手从中的鼓励。同时也掌握了本地传感器数据上传。
在温度和光照传感器的学习过程中,我了解到了环境监测的重要性,并且学会了如何通过编程来收集和分析这些数据。这些技能在物联网(IoT)和智能家居项目中尤为重要,为我打开了一扇通往未来技术的大门。
这些项目的实践操作不仅锻炼了我的动手能力,更重要的是,它们加深了我对硬件编程的理解。我学会了如何将抽象的编程概念应用到具体的硬件设备上,并且能够解决实际问题。
我非常感激EEWorld和Digi-Key提供的这次学习机会。这次经历不仅丰富了我的技术储备,也为我未来的电子项目和职业生涯打下了坚实的基础。我期待着将这些新学到的技能应用到更多的创新项目中,并且希望能够继续在电子和编程领域不断探索和成长。
# 项目程序
# End
- 2024-09-02
-
加入了学习《【Follow me第二季第1期】全部任务演示短视频》,观看 【Follow me第二季第1期】任务演示视频
- 2024-09-01
-
上传了资料:
【Follow me第二季第1期】Adafruit Circuit Playground Express 代码
-
加入了学习《【得捷电子Follow me第2期】+项目汇报视频》,观看 【得捷电子Follow me第2期】+项目汇报视频
-
加入了学习《【Follow me第二季第1期】全部任务演示》,观看 全部任务演示2.0
-
加入了学习《FollowMe 第二季: 1 Adafruit Circuit Playground Express及任务讲解》,观看 Adafruit Circuit Playground Express 及任务讲解
-
发表了主题帖:
Follow me第二季第1期】汇总贴:Adafruit Circuit Playground Express学习
本帖最后由 md-llama-com 于 2024-10-10 11:17 编辑
Follow me 第二季终于来了,又可以白嫖技术白嫖板子了 ~ 闲话少说 ~开启今日份任务汇总
# [汇总视频链接](https://training.eeworld.com.cn/video/40996 "汇总视频链接")
# 全部物料清单(含物料名称、实物图片)
1.Adafruit Circuit Playground Express
2.USB线一根
3.杜邦线,跳线若干
4.水果,苹果什么的
# 必做任务
## 入门任务(必做):开发环境搭建,板载LED点亮
### 步骤 1.连接到 USB
### 步骤 2.按 RESET 进入 bootloader 模式
一定要绿色才是连上
### 步骤 3.打开arduino在左侧栏的Boards Manager,安装arduino SAMD
安装好后就能在工具一栏看到这个板子了
### 步骤 4.点亮LED
想要点亮一个LED,首先你要知道这块板子的引脚布局
D13正是这次要点亮的LED
在Arduino上新建项目并定义13号引脚为输出引脚
设定其高电平2秒低电平1秒
```cpp
void setup() {
pinMode(13, OUTPUT);
}
void loop() {
digitalWrite(13, HIGH);
delay(2000);
digitalWrite(13, LOW);
delay(1000);
}
```
**下面是效果**
## 基础任务一(必做):控制板载炫彩LED,跑马灯点亮和颜色变换
搭配器件: Adafruit Circuit Playground Express
跑马灯要用到彩色LED,与Adafruit_NeoPixel.h库。
其实跑马灯就是让颜色一次更替点亮形成的效果
```code
#include
#define PIN 8
// 定义按钮引脚
#define BUTTON_BRIGHTNESS 4 // 调节亮度
#define BUTTON_EFFECT 5 // 切换效果
#define NUM_LEDS 10 //LED灯数量
Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_LEDS, PIN, NEO_GRB + NEO_KHZ400);
int brightness = 50;
void setup() {
strip.begin();
strip.setBrightness(brightness);
strip.show();
Serial.begin(9600);
}
void loop() {
// 执行当前效果
Cycle(5);
}
// 使彩虹色均匀分布
void Cycle(uint8_t wait) {
uint16_t i, j;
for (j = 0; j < 256 * 5; j++) {
for (i = 0; i < strip.numPixels(); i++) {
strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + j) & 255));
}
strip.show();
delay(wait);
}
}
uint32_t Wheel(byte WheelPos) {
WheelPos = 255 - WheelPos;
if (WheelPos < 85) {
return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
}
if (WheelPos < 170) {
WheelPos -= 85;
return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
}
WheelPos -= 170;
return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}
```
**流程图**
**效果如下**
## 基础任务二(必做):监测环境温度和光线,通过板载LED展示舒适程度
搭配器件: Adafruit Circuit Playground Express
这个任务要用到板载传感器,以及Adafruit_CircuitPlayground.h库
搜索库Circuit Playground就可找到,这个库需要安装很多依赖
光照强度传感器在左侧那么就让左侧彩色LED显示光照强度,光照越亮LED点亮的越多,光照强度以50为单位。500为上限。
`map` 函数的工作原理是线性插值。它按照以下公式计算新的值:
这意味着 `brightness` 的值会被线性地缩放到0到100的范围内。例如,如果 `brightness` 是250,那么 `overallBrightness` 将会是50。
温度强度传感器在右侧那么就让右侧彩色LED显示温度强度,温度越高LED点亮的越多,今天天气30多度,那么设定30度亮3个LED
```cpp
#include
int prevTempLedCount = -1; // 初始化
int prevBrightnessLedCount = -1; // 初始化
void setup() {
CircuitPlayground.begin();
}
void loop() {
displayTemperature();
displayBrightness();
delay(1000); // 每秒更新
}
void displayTemperature() {
float temperature = CircuitPlayground.temperature() - 6;//校准,板载温度影响6度
int ledCount = 3; // 30-35度时亮三颗
uint32_t color = CircuitPlayground.colorWheel(85); // 绿色
if (temperature < 30) {
ledCount = max(0, 3 - (30 - temperature) / 5);
color = CircuitPlayground.colorWheel(170); // 蓝色
} else if (temperature > 35) {
ledCount = min(5, 3 + (temperature - 35) / 5);
color = CircuitPlayground.colorWheel(0); // 红色
}
// 如果LED数量没有变化,则不更新
if (ledCount != prevTempLedCount) {
for (int i = 0; i < 5; i++) {
if (i < ledCount) {
CircuitPlayground.setPixelColor(5+i, color);
} else {
CircuitPlayground.setPixelColor(5+i, 0); // 关闭LED
}
}
prevTempLedCount = ledCount; // 更新上一次的LED数量
}
}
void displayBrightness() {
int brightness = CircuitPlayground.lightSensor();
int ledCount = min(5, brightness / 50); // 亮度每增加50 LED增加一颗
uint8_t overallBrightness = map(brightness, 0, 500, 0, 100);
// 如果LED数量没有变化,则不更新
if (ledCount != prevBrightnessLedCount) {
for (int i = 0; i < 5; i++) {
if (i < ledCount) {
CircuitPlayground.setPixelColor(4-i, 255, 255, 255); // 白色
} else {
CircuitPlayground.setPixelColor(4-i, 0); // 关闭LED
}
}
prevBrightnessLedCount = ledCount; // 更新上一次的LED数量
}
}
```
**流程图**
**下面是温度效果,用的开水壶加热**
**下面是光照强度效果**
## 基础任务三(必做):接近检测——设定安全距离并通过板载LED展示,检测到入侵时,发起声音报警
搭配器件: Adafruit Circuit Playground Express
这个任务要用到板载传感器,以及Adafruit_CircuitPlayground.h库,红外发送及红外接收传感器。
定义红外接收和发射的引脚
const int irTransmitterPin = 25; //引脚定义
const int irReceiverPin = A10;
analogRead函数读取红外接收的数值
analogRead(irReceiverPin);
用串口输出LED点亮情况和距离情况
下面是程序内容
```code
#include
#define SAFE_DISTANCE 450 // 定义安全距离
const int alertTone = 1000; // 警报音调
const int iTPin = 25; //引脚定义
const int iRPin = A10;
void setup() {
CircuitPlayground.begin();
Serial.begin(9600); //
pinMode(iRPin, INPUT); // 红外传感器输入
pinMode(iTPin, OUTPUT);// 红外led输出
delay(100);
}
void loop() {
sendIRPulse();
int distance = analogRead(iRPin); // 读取红外传感器的值
// 打印距离
Serial.print("Distance: ");
Serial.println(distance);
Distance(distance);
checkForIntrusion(distance);
delay(300);
}
void Distance(int distance) {
int ledCount = map(distance, 290, SAFE_DISTANCE, 1, 10); // 将距离值映射到0-10的LED数量
Serial.print("LED Count: ");
Serial.println(ledCount);
for (int i = 0; i < 10; i++) {
if (i < ledCount) {
CircuitPlayground.setPixelColor(i, 0, 255, 0);
} 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(iTPin, HIGH);
delayMicroseconds(13);
digitalWrite(iTPin, LOW);
delayMicroseconds(13);
}
}
void playAlertTone() {
CircuitPlayground.playTone(alertTone, 500); // 播放警报音500ms
}
```
**流程图**
**下面是演示**
## 进阶任务(必做):制作不倒翁——展示不倒翁运动过程中的不同灯光效果
搭配器件: Adafruit Circuit Playground Express、不倒翁
这个任务要用到板载陀螺仪传感器,以及Adafruit_CircuitPlayground.h库和math.h库
不倒翁的制作需要读取加速度传感器的XYZ轴数据,并根据这些数据来控制LED灯的颜色和亮度。
因为加速度传感器给出的数据是非整数,所以定义XYZ为浮点型
float x = CircuitPlayground.motionX();
float y = CircuitPlayground.motionY();
float z = CircuitPlayground.motionZ();
使用 sqrt(Y x Y + Z x Z) 和 sqrt(X x X + Z x Z) 来计算与水平面的夹角,这样可以更准确地反映角度。
然后将角度映射到10个小灯位置上用的是if语句判断
**下面是程序**
```code
#include
#include
void setup() {
CircuitPlayground.begin();
Serial.begin(9600);
}
void loop() {
float x = CircuitPlayground.motionX();
float y = CircuitPlayground.motionY();
float z = CircuitPlayground.motionZ();
// 计算与水平面夹角
float angleX = atan2(x, sqrt(y * y + z * z)) * 180 / PI;
float angleY = atan2(y, sqrt(x * x + z * z)) * 180 / PI;
int ledToLight = -1;
// 映射到彩色灯珠
if (angleX > 11) {
if (angleY < -11) ledToLight = 1;
else if (angleY > 11) ledToLight = 3;
else ledToLight = 2;
} else if (angleX < -11) {
if (angleY < -11) ledToLight = 8;
else if (angleY > 11) ledToLight = 6;
else ledToLight = 7;
} else {
if (angleY > 11) {
ledToLight = 4;
} else if (angleY < -11) {
ledToLight = 0;
}
}
if (ledToLight == -1) {
for (int i = 0; i < 10; i++) {
CircuitPlayground.setPixelColor(i, CircuitPlayground.colorWheel(51)); // 水平时都点亮51代表颜色85是绿色0是红色
}
} else {
for (int i = 0; i < 10; i++) {
if (i == ledToLight || (ledToLight == 4 && i == 5) || (ledToLight == 0 && i == 9)) {
CircuitPlayground.setPixelColor(i, CircuitPlayground.colorWheel(32));//32代表颜色
} else {
CircuitPlayground.setPixelColor(i, 0);
}
}
}
delay(100);
}
```
**流程图**
**效果如下**
# 创意任务(选做,选择其中一个或多个都可)
## 创意任务三:水果钢琴——通过触摸水果弹奏音乐,并配合灯光效果
搭配器件: Adafruit Circuit Playground Express、水果我选的是苹果
其实就是把引脚视为电容开关,手触摸水果,引脚电容发生改变,从而被单片机检测到,最终让蜂鸣器发出声音
程序如下图
```code
#include
#define CAP_SAMPLES 10
#define TONE_DURATION_MS 100
uint16_t CAP_THRESHOLD = 1000;
void setup() {
CircuitPlayground.begin();
Serial.begin(115200);
}
unsigned long clearTime;
void playToneAndLightLEDs(int touchPoint) {
CircuitPlayground.clearPixels();
clearTime = millis();
int tones[] = {261, 293, 329, 349, 392, 440, 494};
int tone = tones[touchPoint - 15];
CircuitPlayground.playTone(tone, TONE_DURATION_MS);
for (int i = 0; i < 10; i++) {
bool light = true;
switch (touchPoint) {
case 15: light = i != 5; break;
case 16: light = i != 5 && i != 6; break;
case 17: light = i != 5 && i != 6 && i != 7; break;
case 18: light = i < 5; break;
case 19: light = i > 0 && i < 5; break;
case 20: light = i > 1 && i < 5; break;
case 21: light = i > 2 && i < 5; break;
}
if (light) {
CircuitPlayground.strip.setPixelColor(i, CircuitPlayground.colorWheel(256 / 10 * (i + 1)));
}
}
CircuitPlayground.strip.show();
}
void loop() {
if (millis() - clearTime > 2000) {
CircuitPlayground.clearPixels();
}
for (int i = 15; i CAP_THRESHOLD) {
playToneAndLightLEDs(i);
}
}
}
```
**流程图**
下面是手直接触摸的效果
接下来就是把A1,A2,A3,A4,A5,A6,A7接上线插入苹果中啦
# 项目总结
这次Follow me 第二季真的学到好多东西,基于Adafruit Circuit Playground Express 学到了红外测距,学到了触摸控制,温度,光照传感器,也学到了加速度传感器等等。通过这些项目,我不仅增强了自己的实践操作技能,同时也加深了我对硬件编程的认识。特别感谢EEWorld和Digi-Key提供这次宝贵的体验机会。
-
加入了学习《【Follow me第二季第一期】任务汇总(by cyz6668)》,观看 【Follow me第二季第一期】任务汇总(by cyz6668)