【Follow me第二季第2期】任务汇总
本帖最后由 sinc_sila 于 2024-11-1 14:25 编辑<p><span style="font-size:18px;"> 由于工作出差的原因,我未能在既定时间内完成任务,对此我深表歉意,并衷心感谢您给予我在规定时间之外完成任务的宝贵机会。</span></p>
<p><span style="font-size:18px;">此次DigiKey与EEWorld共同发起的Follow me活动第二季的第二期,通过使用Arduino UNO R4 WiFi,为我提供了一个令人难忘的学习经历。</span></p>
<p> </p>
<p><span style="color:#d35400;"><strong><span style="font-size:18px;">以下是此次任务的汇总报告:</span></strong></span></p>
<hr />
<p><span style="color:#16a085;"><span style="font-size:18px;"><strong>购买原件展示:</strong></span></span><br />
<span style="font-size:16px;">1、Arduino UNO R4 WiFi</span></p>
<p><span style="font-size:16px;">2、SHT40温湿度传感器扩展板</span></p>
<p><span style="font-size:16px;">3、Qwiic连接线</span></p>
<p> </p>
<div style="text-align: left;"></div>
<p><span style="font-size:16px;"> Arduino UNO R4 WiFi是一款采用32位Arm® Cortex®-M4 Renesas RA4M1微控制器的开发板,集成了支持Wi-Fi®和蓝牙功能的ESP32模块,赋予了它强大的运算能力和丰富的连接选项。该板配备了32kB的SRAM和256kB的闪存,工作频率可达48MHz。其USB端口已升级至USB-C标准,并且最大电源供应电压提升至24V。此外,Arduino UNO R4 WiFi还提供了一个CAN总线接口,使得用户能够通过连接多个扩展板来简化布线并实现多样化的功能。板载的Qwiic连接器设计使得创建即插即用的项目变得轻而易举。</span></p>
<p><span style="font-size:16px;"> SHT4x是一款高性能的数字传感器平台,专门设计用于精确测量不同精度级别的相对湿度和温度。该传感器通过I2C接口提供多个预设的I2C地址选项,同时维持极低的功耗水平,仅为0.4 μW。内置的电源调节加热器支持三个不同的加热等级,确保传感器能够在恶劣的环境条件下稳定运行。其四针双平面无引线封装设计非常适合于表面贴装技术(SMT)的应用,并可选择性地配备专利PTFE薄膜或易于移除的保护盖。每款传感器均配有依据ISO17025标准的特定校准证书,并可通过独一无二的序列号进行识别。</span></p>
<hr />
<p><span style="color:#16a085;"><span style="font-size:18px;"><strong>任务思路:</strong></span></span></p>
<h4>一、搭建Arduino开发环境</h4>
<ol>
<li>
<p><strong>硬件准备</strong></p>
</li>
<li>
<p><strong>软件准备</strong>:</p>
<ul>
<li>安装Arduino IDE</li>
<li>配置开发板型号和端口</li>
</ul>
</li>
<li>
<p><strong>入门任务:点灯</strong></p>
<ul>
<li>编写简单的代码,通过Arduino控制LED灯的开关</li>
<li>学习基本的数字输入输出操作</li>
<li><strong>串口通信</strong>:</li>
<li>使用Arduino的串口功能与计算机进行通信</li>
<li>编写代码实现通过串口控制LED灯的状态</li>
</ul>
</li>
</ol>
<h4><strong>二、基础任务:LED矩阵+DAC正弦波+放大信号+ADC采集</strong></h4>
<ol>
<li>
<p><strong>LED矩阵</strong>:</p>
<ul>
<li>熟悉板载12x8 LED 矩阵的原理</li>
<li>实现滚动类的显示</li>
</ul>
</li>
<li>
<p><strong>DAC正弦波</strong>:</p>
<ul>
<li>使用Arduino的DAC输出正弦波信号</li>
<li>学习模拟输出的基本操作</li>
</ul>
</li>
<li>
<p><strong>放大信号</strong>:</p>
<ul>
<li>使用OPAMP放大DAC输出的正弦波信号</li>
<li>观察放大后的信号效果</li>
</ul>
</li>
<li>
<p><strong>ADC采集</strong>:</p>
<ul>
<li>使用Arduino的ADC功能采集外部模拟信号</li>
<li>学习模拟输入的基本操作</li>
</ul>
</li>
</ol>
<h4><strong>三、进阶任务:通过UNRAID NAS系统中的docker搭建EMQX和Home Assistant</strong></h4>
<ol>
<li>
<p><strong>UNRAID NAS系统配置</strong>:</p>
<ul>
<li>安装并配置UNRAID NAS系统</li>
<li>安装Docker并创建容器</li>
</ul>
</li>
<li>
<p><strong>搭建EMQX</strong>:</p>
<ul>
<li>在Docker中安装并配置EMQX MQTT服务器</li>
<li>确保EMQX能够正常运行并接受连接</li>
</ul>
</li>
<li>
<p><strong>搭建Home Assistant</strong>:</p>
<ul>
<li>在Docker中安装并配置Home Assistant</li>
<li>配置Home Assistant连接到EMQX MQTT服务器</li>
</ul>
</li>
</ol>
<h4><strong>四、实现MQTT控制与温湿度监测</strong></h4>
<ol>
<li>
<p><strong>MQTT控制板载LED灯</strong>:</p>
<ul>
<li>编写Arduino代码,使其能够通过MQTT协议接收Home Assistant的控制命令</li>
<li>实现通过Home Assistant页面控制板载LED灯的功能</li>
</ul>
</li>
<li>
<p><strong>读取SHT40温湿度并通过MQTT上传</strong>:</p>
<ul>
<li>连接SHT40温湿度传感器到Arduino</li>
<li>编写代码读取温湿度数据并通过MQTT协议上传到Home Assistant</li>
<li>在Home Assistant面板上显示实时温湿度数据</li>
</ul>
</li>
</ol>
<hr />
<p><span style="color:#16a085;"><span style="font-size:18px;"><strong>任务实现:</strong></span></span></p>
<p><span style="font-size:16px;">1、入门任务分帖:</span></p>
<p><strong>环境搭建:</strong></p>
<p><img src="https://bbs.eeworld.com.cn/data/attachment/forum/202409/16/003441idhlfydhhghhh8db.jpg.thumb.jpg" /></p>
<p><strong>打开arduino软件,将开发板连接到电脑,选择对应的串口:</strong></p>
<p><img src="https://bbs.eeworld.com.cn/data/attachment/forum/202409/16/003702c3knxrmmozn5v4k3.jpg.thumb.jpg" /></p>
<p><b>此时已完成了编写代码前的准备。</b></p>
<p><strong>入门任务:</strong><strong>点亮板载LED灯并且串口打印Hello EEWorld!</strong></p>
<p><strong>通过开发板提供的原理图我们可以看到用户LED的引脚为:DL4(黄色)。</strong></p>
<p><img src="https://bbs.eeworld.com.cn/data/attachment/forum/202409/16/005213qw0noso0wnrwa0iw.jpg" /></p>
<p><b>打开文件--》示例--》Basics--》Bink <br />
创建一个Bink基础示例,并在此基础上增加串口打印。</b></p>
<p><img src="https://bbs.eeworld.com.cn/data/attachment/forum/202409/16/005214laan73wqxxq1m43i.jpg.thumb.jpg" /></p>
<div style="text-align: left;"></div>
<p> </p>
<p><strong>Arduino的内置LED每隔一秒闪烁一次,并在每次LED状态改变时通过串口发送"Hello EEWorld!"消息:</strong></p>
<pre>
<code>void setup() {
// 初始化内置LED引脚为输出模式。
pinMode(LED_BUILTIN, OUTPUT);
// 初始化串口通信,波特率为9600
Serial.begin(9600);
}
// loop函数会无限次地反复运行
void loop() {
digitalWrite(LED_BUILTIN, HIGH);// 打开LED(HIGH表示高电压水平)
Serial.println("Hello EEWorld!"); // 通过串口打印消息
delay(1000); // 等待一秒钟
digitalWrite(LED_BUILTIN, LOW); // 关闭LED,通过使电压变为LOW
Serial.println("Hello EEWorld!"); // 再次通过串口打印消息
delay(1000); // 等待一秒钟
}
</code></pre>
<p>效果展示视频:</p>
<p>b1c2921192dfab44d526dfbc94e77e3e<br />
</p>
<p><a href="https://bbs.eeworld.com.cn/thread-1294040-1-1.html">【Follow me第二季第2期】入门任务 - 搭建环境 - Blink - 串口打印 - DigiKey得捷技术专区 - 电子工程世界-论坛 (eeworld.com.cn)</a></p>
<p><span style="font-size:16px;">2、基础任务分帖:</span></p>
<p><strong data-immersive-translate-walked="ffe07d79-270c-4d45-a75b-eaf086df69fd">Arduino UNO R4 WiFi</strong>配有内置 12x8 LED 矩阵,可对其进行编程以显示图形、动画、充当界面,甚至玩游戏。</p>
<p><img src="https://bbs.eeworld.com.cn/data/attachment/forum/202409/16/111752lodk8ktoely4teor.png.thumb.jpg" /></p>
<p>UNO R4 WiFi 的 LED 矩阵库的工作原理是创建一个帧,然后将其加载到显示该帧的缓冲区中。</p>
<p>帧就是我们所说的在任意给定时刻显示在矩阵上的“图像”。如果动画是一系列图像,则帧就是该系列中的其中一个图像。</p>
<p>为了控制 UNO R4 WiFi 上的 12x8 LED 矩阵,您需要至少 96 位大小的内存空间。该库提供了两种方法来做到这一点。</p>
<p>我们接下来的代码将使用官方提供的LED 矩阵工具来创建:</p>
<p><img src="https://bbs.eeworld.com.cn/data/attachment/forum/202409/16/114302pg04w9g4qfgpz5ww.png.thumb.jpg" /></p>
<p>按照上述步骤,我们让led矩阵分别"DigKey”的两个首字母“D”和“K”,间隔时间500ms。</p>
<p> </p>
<div style="text-align: left;"></div>
<pre>
<code>// 引入Arduino_LED_Matrix库,用于控制LED矩阵
#include "Arduino_LED_Matrix.h"
// 创建一个ArduinoLEDMatrix对象,用于操作LED矩阵
ArduinoLEDMatrix matrix;
void setup() {
// 初始化串口通信,波特率为115200
Serial.begin(115200);
// 初始化LED矩阵
matrix.begin();
}
// 定义一个常量数组D,用于存储字母"D"的LED矩阵数据
const uint32_t D[] = {
0x1e011010,
0x81081081,
0x81101e0,
};
// 定义一个常量数组K,用于存储字母"K"的LED矩阵数据
const uint32_t K[] = {
0x10813014,
0x1801401,
0x30108108,
};
void loop(){
// 将字母"D"的LED矩阵数据加载到matrix对象中,并显示在LED矩阵上
matrix.loadFrame(D);
// 延时500毫秒,让字母"D"显示一段时间
delay(500);
// 将字母"K"的LED矩阵数据加载到matrix对象中,并显示在LED矩阵上
matrix.loadFrame(K);
// 延时500毫秒,让字母"K"显示一段时间
delay(500);
}
</code></pre>
<p>效果展示:</p>
<p>e20460dffccead7df26e830efc4ca6ee</p>
<p> </p>
<div style="text-align: center;">
<div style="text-align: left;"></div>
<p> </p>
</div>
<p><strong>滚动文本代码:</strong></p>
<pre>
<code>// 引入Arduino图形库和LED矩阵库
#include "ArduinoGraphics.h"
#include "Arduino_LED_Matrix.h"
// 创建一个ArduinoLEDMatrix对象,用于控制LED矩阵
ArduinoLEDMatrix matrix;
void setup() {
// 初始化LED矩阵
matrix.begin();
}
void loop() {
// 开始绘制图形
matrix.beginDraw();
// 设置画笔颜色为白色(0xFFFFFFFF表示ARGB格式的白色)
matrix.stroke(0xFFFFFFFF);
// 设置文本滚动速度为100毫秒
matrix.textScrollSpeed(100);
// 定义要显示的文本内容
const char text[] = "EEWorld!";
// 设置文本字体为5x7点阵字体
matrix.textFont(Font_5x7);
// 设置文本起始位置和颜色(0, 1表示从第二行开始,0xFFFFFF表示白色)
matrix.beginText(0, 1, 0xFFFFFF);
// 在LED矩阵上打印文本
matrix.println(text);
// 设置文本滚动方向为向左滚动
matrix.endText(SCROLL_LEFT);
// 结束绘制图形
matrix.endDraw();
}
</code></pre>
<p>代码效果:</p>
<p>a1e559f2164d0334cc891ba8cc72b5ef</p>
<p><strong>DAC正弦波:</strong></p>
<p>Arduino UNO R4 WiFi 具有内置<strong data-immersive-translate-walked="b668ca66-66f8-442f-9efb-13f44bda6898">DAC</strong> (数模转换器),用于将数字信号转换为模拟信号。此功能可用于构建大量有趣的音频项目,但也可用作专业实验室设备,例如廉价的函数发生器。</p>
<p>接线方式:</p>
<p><img src="https://bbs.eeworld.com.cn/data/attachment/forum/202410/15/213800a0vs77q11z7mzzcc.jpg.thumb.jpg" /></p>
<div style="text-align: left;"></div>
<p>用OPAMP放大DAC信号;用ADC采集并且打印数据到串口:</p>
<pre>
<code>#include "analogWave.h" // 包含用于模拟波形生成的库
#include <OPAMP.h> // 包含OPAMP库
analogWave wave(DAC); // 创建一个analogWave类的实例,使用DAC引脚
int freq = 10; // 频率,单位为赫兹,可根据需要更改
unsigned long previousMillis = 0; // 存储上一次读取ADC值的时间
const unsigned long interval = 10; // 读取ADC值的时间间隔,单位为毫秒
void setup() {
Serial.begin(921600); // 初始化串行通信,波特率为921600
wave.sine(freq); // 生成初始频率的正弦波
OPAMP.begin(OPAMP_SPEED_LOWSPEED); // 初始化OPAMP为低速模式
analogReadResolution(12); // 将模拟读取分辨率更改为12位
}
void loop() {
unsigned long currentMillis = millis(); // 获取当前时间
// 每隔interval毫秒读取一次ADC值
if (currentMillis - previousMillis >= interval) {
previousMillis = currentMillis; // 更新上一次读取的时间
int adcValue = analogRead(A5); // 返回0-4095之间的值
Serial.println(adcValue); // 将ADC值打印到串行监视器
}
}
</code></pre>
<p>串口波形显示:</p>
<p><img src="https://bbs.eeworld.com.cn/data/attachment/forum/202410/15/213854tyix9e878ep119yz.jpg.thumb.jpg" /></p>
<p> </p>
<p><a href="https://bbs.eeworld.com.cn/thread-1294051-1-1.html">【Follow me第二季第2期】LED矩阵+DAC正弦波+放大信号+ADC采集 - DigiKey得捷技术专区 - 电子工程世界-论坛 (eeworld.com.cn)</a></p>
<p><span style="font-size:16px;">3、进阶任务1分帖:</span></p>
<p>通过Wi-Fi,利用MQTT协议接入HA:</p>
<p><strong>MQTT部署:</strong></p>
<p><b>我通过UNRAID NAS系统中的Docker部署EMQX:</b></p>
<p><img src="https://bbs.eeworld.com.cn/data/attachment/forum/202410/15/162202hlrrxxxxixxjuil3.png.thumb.jpg" /></p>
<p><strong>通过18083端口来进行web端访问:</strong></p>
<p><img src="https://bbs.eeworld.com.cn/data/attachment/forum/202410/15/163526hq99hcwc6kz9c6k6.png.thumb.jpg" /></p>
<p><b>测试MQTT连接:</b></p>
<div style="text-align: left;"></div>
<p><b>1.</b>Arduino UNO R4 WiFi 烧录以下代码:</p>
<pre>
<code>#include <ArduinoMqttClient.h> // 引入MQTT客户端库
#include <WiFiS3.h> // 引入WiFi库
#include <WiFiClient.h> // 引入WiFi客户端库
char ssid[] = "Sinc"; // WiFi网络名称
char pass[] = "xc12345678"; // WiFi密码
int status = WL_IDLE_STATUS; // WiFi连接状态
const char broker[] = "xxxx"; // MQTT代理服务器地址
int port = 1883; // MQTT代理服务器端口
const char topic[] = "Aht10"; // MQTT主题
WiFiClient wifiClient; // 创建WiFi客户端对象
MqttClient mqttClient(wifiClient); // 创建MQTT客户端对象,并传入WiFi客户端对象
void setup() {
Serial.begin(9600); // 初始化串口通信
while (!Serial) {} // 等待串口监视器打开
if (WiFi.status() == WL_NO_MODULE) {
Serial.println("与WiFi模块通信失败!"); // 如果没有检测到WiFi模块,则停止程序
while (true);
}
String fv = WiFi.firmwareVersion(); // 获取WiFi固件版本
if (fv < WIFI_FIRMWARE_LATEST_VERSION) {
Serial.println("请升级固件"); // 如果固件版本过低,则提示升级
}
// 尝试连接到WiFi网络
while (status != WL_CONNECTED) {
Serial.print("尝试连接到WPA SSID: ");
Serial.println(ssid);
status = WiFi.begin(ssid, pass); // 连接到WiFi网络
delay(10000); // 等待10秒看是否连接成功
}
Serial.println("已连接到网络"); // 连接成功后的提示
printCurrentNet(); // 打印当前网络信息
printWifiData(); // 打印WiFi数据
// 尝试连接到MQTT代理服务器
if (!mqttClient.connect(broker, port)) {
Serial.print("MQTT连接失败!错误代码 = ");
Serial.println(mqttClient.connectError()); // 如果连接失败,则打印错误代码
while (1); // 停止程序
}
Serial.println("已连接到MQTT"); // 连接成功后的提示
}
// 打印当前网络信息
void printCurrentNet() {
Serial.print("SSID: "); Serial.println(WiFi.SSID()); // 打印网络名称
byte bssid; WiFi.BSSID(bssid); printMacAddress(bssid); // 打印路由器MAC地址
Serial.print("信号强度 (RSSI):"); Serial.println(WiFi.RSSI()); // 打印信号强度
Serial.print("加密类型: "); Serial.println(WiFi.encryptionType(), HEX); // 打印加密类型
Serial.println();
}
// 打印MAC地址
void printMacAddress(byte mac[]) {
for (int i = 0; i < 6; i++) {
if (i > 0) Serial.print(":");
if (mac < 16) Serial.print("0");
Serial.print(mac, HEX);
}
Serial.println();
}
// 打印WiFi数据
void printWifiData() {
IPAddress ip = WiFi.localIP(); // 获取本地IP地址
Serial.print("IP地址: "); Serial.println(ip); // 打印IP地址
byte mac; WiFi.macAddress(mac); Serial.print("MAC地址: "); printMacAddress(mac); // 打印MAC地址
}
// 主循环
void loop() {
mqttClient.beginMessage(topic); // 开始发送MQTT消息
mqttClient.print("Hello EEworld and Digikey!"); // 发送消息内容
mqttClient.endMessage(); // 结束发送MQTT消息
delay(1000); // 延迟1秒
}
</code></pre>
<p>烧录后串口通讯显示:</p>
<p><img src="https://bbs.eeworld.com.cn/data/attachment/forum/202410/15/162758r58yikj68m8m51ry.png" /></p>
<p> </p>
<p>下载MQTT 客户端工具可以直观的观察到MQTT主题通讯:</p>
<p><img src="https://bbs.eeworld.com.cn/data/attachment/forum/202410/15/162758dgi1rifl4r1irl33.png.thumb.jpg" /></p>
<p><strong>Home Assistant部署:</strong></p>
<p><b>同样UNRAID NAS系统中的Docker部署</b><strong>Home Assistant</strong><b>:</b></p>
<p><img src="https://bbs.eeworld.com.cn/data/attachment/forum/202410/15/163322mr2gnc0hzrcdnwjf.png.thumb.jpg" /></p>
<p><strong>通过18083端口来进行web端访问:</strong></p>
<p><img src="https://bbs.eeworld.com.cn/data/attachment/forum/202410/15/163702vcccsm4n3nn9tlm4.png.thumb.jpg" /></p>
<h2>配置MQTT:</h2>
<h3>参考官方配置方式: <a href="https://www.home-assistant.io/integrations/mqtt" rel="nofollow" target="_blank" title="MQTT - Home Assistant (home-assistant.io)">MQTT - Home Assistant (home-assistant.io)</a></h3>
<p>配置-->设备与服务-->集成-->添加集成-->搜索MQTT-->点击配置域名端口等信息:</p>
<p><img src="https://bbs.eeworld.com.cn/data/attachment/forum/202410/15/165640piymlzkuiuz2y4id.png.thumb.jpg" /></p>
<p><img src="https://bbs.eeworld.com.cn/data/attachment/forum/202410/15/165647cpvlzp582vuo588o.png.thumb.jpg" /></p>
<p>然后完成就配置成功了,下面是成功界面<strong>:</strong></p>
<p><img src="https://bbs.eeworld.com.cn/data/attachment/forum/202410/15/165648lbmewp8c5ppecblz.png" /></p>
<p><strong>通过配置configuration.yml文件,在Home Assistant首页创建了一个开关控制板载LED灯:</strong></p>
<p>找到homeassistant的根目录中的configuration.yml文件打开:</p>
<p><img src="https://bbs.eeworld.com.cn/data/attachment/forum/202410/15/170749fp5jpkck50izcoi0.png.thumb.jpg" /></p>
<p><strong>在此代码基础上增加以下代码:</strong></p>
<pre>
<code>mqtt:
switch:
- unique_id: R4_led #设备ID
name: "R4_led" #设备名称
state_topic: "Aht10" #订阅端口
command_topic: "Aht10" #同上
payload_on: "1" #开灯的指令
payload_off: "2" #关灯的指令
</code></pre>
<p><strong>保存代码后重启homeassistant,显示以下按钮表示创建成功:</strong></p>
<p><img src="https://bbs.eeworld.com.cn/data/attachment/forum/202410/15/171551ghxejxglegzbykh5.png.thumb.jpg" /></p>
<div style="text-align: left;"></div>
<p><strong>修改代码来控制板载led:</strong></p>
<pre>
<code>#include <ArduinoMqttClient.h> // 引入MQTT客户端库
#include <WiFiS3.h> // 引入WiFi库
#include <WiFiClient.h> // 引入WiFi客户端库
char ssid[] = "Sinc"; // WiFi网络名称
char pass[] = "xc12345678"; // WiFi密码
int status = WL_IDLE_STATUS; // WiFi连接状态
const char broker[] = "XXXX"; // MQTT代理服务器地址
int port = 1883; // MQTT代理服务器端口
const char topic[] = "Aht10"; // MQTT主题
WiFiClient wifiClient; // 创建WiFi客户端对象
MqttClient mqttClient(wifiClient); // 创建MQTT客户端对象,并传入WiFi客户端对象
void setup() {
Serial.begin(9600); // 初始化串口通信
while (!Serial) {} // 等待串口监视器打开
// 初始化内置LED引脚为输出模式。
pinMode(LED_BUILTIN, OUTPUT);
if (WiFi.status() == WL_NO_MODULE) {
Serial.println("与WiFi模块通信失败!"); // 如果没有检测到WiFi模块,则停止程序
while (true);
}
// 尝试连接到WiFi网络
while (status != WL_CONNECTED) {
Serial.print("尝试连接到WPA SSID: ");
Serial.println(ssid);
status = WiFi.begin(ssid, pass); // 连接到WiFi网络
delay(10000); // 等待10秒看是否连接成功
}
Serial.println("已连接到网络"); // 连接成功后的提示
printCurrentNet(); // 打印当前网络信息
printWifiData(); // 打印WiFi数据
// 尝试连接到MQTT代理服务器
if (!mqttClient.connect(broker, port)) {
Serial.print("MQTT连接失败!错误代码 = ");
Serial.println(mqttClient.connectError()); // 如果连接失败,则打印错误代码
while (1); // 停止程序
}
Serial.println("已连接到MQTT"); // 连接成功后的提示
// 订阅主题
mqttClient.subscribe(topic);
Serial.print("等待主题上的消息: ");
Serial.println(topic);
Serial.println();
// 设置消息接收回调
mqttClient.onMessage(onMqttMessage);
}
void printCurrentNet() {
Serial.print("SSID: "); Serial.println(WiFi.SSID()); // 打印网络名称
byte bssid; WiFi.BSSID(bssid); printMacAddress(bssid); // 打印路由器MAC地址
Serial.print("信号强度 (RSSI):"); Serial.println(WiFi.RSSI()); // 打印信号强度
Serial.print("加密类型: "); Serial.println(WiFi.encryptionType(), HEX); // 打印加密类型
Serial.println();
}
void printMacAddress(byte mac[]) {
for (int i = 0; i < 6; i++) {
if (i > 0) Serial.print(":");
if (mac < 16) Serial.print("0");
Serial.print(mac, HEX);
}
Serial.println();
}
void printWifiData() {
IPAddress ip = WiFi.localIP(); // 获取本地IP地址
Serial.print("IP地址: "); Serial.println(ip); // 打印IP地址
byte mac; WiFi.macAddress(mac); Serial.print("MAC地址: "); printMacAddress(mac); // 打印MAC地址
}
void loop() {
// 定期调用poll()以允许库接收MQTT消息并
// 发送MQTT保持活动信号,以避免被代理断开连接
mqttClient.poll();
}
void onMqttMessage(int messageSize) {
// 我们收到了一条消息,打印出主题和内容
Serial.println("收到一条消息:");
Serial.print(mqttClient.messageTopic());
Serial.print(", 长度 ");
Serial.print(messageSize);
Serial.println(" 字节:");
// 使用Stream接口打印内容
String message;
while (mqttClient.available()) {
message += (char)mqttClient.read();
}
Serial.println(message);
// 检查消息内容并控制LED
if (message == "1") {
digitalWrite(LED_BUILTIN, HIGH); // 打开LED
Serial.println("LED_BUILTIN 已打开");
} else if (message == "2") {
digitalWrite(LED_BUILTIN, LOW); // 关闭LED
Serial.println("LED_BUILTIN 已关闭");
}
Serial.println();
}
</code></pre>
<p>串口显示消息:</p>
<p><img src="https://bbs.eeworld.com.cn/data/attachment/forum/202410/15/195309l1mhkqceeezh2c2z.png.thumb.jpg" /></p>
<p>视频效果展示:</p>
<p>92ac7e7cc84a8a72e6fbe426cb28dd5e</p>
<p><a href="https://bbs.eeworld.com.cn/thread-1296180-1-1.html">【Follow me第二季第2期】进阶任务 :通过Wi-Fi,利用MQTT协议接入HA - DigiKey得捷技术专区 - 电子工程世界-论坛 (eeworld.com.cn)</a></p>
<p><span style="font-size:16px;">4、进阶任务2分帖:</span></p>
<p>将UNO R4 WiFi模块连接到外部的SHT40传感器,并通过MQTT协议将数据上传到Home Assistant。</p>
<h3>硬件准备</h3>
<p><strong>Arduino UNO R4</strong></p>
<p><strong>SHT40温湿度传感器</strong></p>
<p><img src="https://bbs.eeworld.com.cn/data/attachment/forum/202410/15/215147akijetazy5ylii9v.jpg.thumb.jpg" /></p>
<p>使用 Arduino IDE 中的库管理器安装适用于 Arduino 的 <strong data-immersive-translate-walked="6ddd5d85-d2aa-4237-8ce8-bf619d6fe1e4">Adafruit SHT4X 库</strong>:</p>
<p><img src="https://bbs.eeworld.com.cn/data/attachment/forum/202410/15/222022wmem3lem0ovvtnal.jpg" /></p>
<p><img src="https://bbs.eeworld.com.cn/data/attachment/forum/202410/15/222023tt25he78eszhipsy.jpg.thumb.jpg" /></p>
<p><strong>将范例简化后的代码:</strong></p>
<div style="text-align: left;"></div>
<pre>
<code>#include "Adafruit_SHT4x.h" // 引入SHT40传感器的Adafruit库
Adafruit_SHT4x sht4; // 创建SHT40传感器对象
void setup() {
Serial.begin(115200); // 初始化串口通信,波特率为115200
Serial.println(F("SGP40 test with SHT40 compensation")); // 打印开始测试的信息
// 设置SHT40传感器的测量精度
sht4.setPrecision(SHT4X_HIGH_PRECISION); // 设置为高精度
// 根据设置的精度打印信息
switch (sht4.getPrecision()) {
case SHT4X_HIGH_PRECISION:
Serial.println(F("SHT40 set to High precision")); // 高精度
break;
case SHT4X_MED_PRECISION:
Serial.println(F("SHT40 set to Medium precision")); // 中精度
break;
case SHT4X_LOW_PRECISION:
Serial.println(F("SHT40 set to Low precision")); // 低精度
break;
}
// 配置SHT40传感器的内置加热器状态
sht4.setHeater(SHT4X_NO_HEATER); // 关闭加热器
// 打印当前加热器的状态
switch (sht4.getHeater()) {
case SHT4X_NO_HEATER:
Serial.println(F("SHT40 Heater turned OFF")); // 加热器关闭
break;
// 其他加热器设置...
}
// 初始化SHT40传感器
if (!sht4.begin(&Wire1)) { // 如果传感器初始化失败
Serial.println(F("SHT40 sensor not found!")); // 打印错误信息
while (1); // 停止程序执行
} else {
Serial.print(F("SHT40 detected!\t")); // 打印传感器检测到的信息
Serial.print(F("Serial number:\t")); // 打印序列号信息
Serial.println(sht4.readSerial(), HEX); // 打印传感器的序列号(十六进制)
}
Serial.println(F("----------------------------------")); // 打印分隔线
}
void loop() {
sensors_event_t humidity, temp; // 创建温湿度事件对象
sht4.getEvent(&humidity, &temp); // 从传感器获取最新的温湿度数据
float t = temp.temperature; // 获取温度值
Serial.println("温度 *C = " + String(t)); // 打印温度值
float h = humidity.relative_humidity; // 获取相对湿度值
Serial.println("湿度 % = " + String(h)); // 打印湿度值
delay(1000); // 延时1秒,之后再次进行测量
}
</code></pre>
<p>烧录后串口打印显示:</p>
<p><img src="https://bbs.eeworld.com.cn/data/attachment/forum/202410/15/222023brtt3s0hmz4tdgkt.jpg.thumb.jpg" /></p>
<p>配置Home Assistant根目录中的configuration.yml :</p>
<pre>
<code> sensor:
- unique_id: R4_温度 # 设备ID,唯一标识这个温度传感器
name: "R4_温度" # 设备名称,显示在Home Assistant界面上的名称
state_topic: "STH40" # 订阅端口,用于接收温度传感器数据的消息
suggested_display_precision: 1 # 建议显示的小数位数
unit_of_measurement: "°C" # 测量单位,摄氏度
value_template: "{{ value_json.temperature }}"# 从消息中提取温度值的模板
- unique_id: R4_湿度 # 设备ID,唯一标识这个湿度传感器
name: "R4_湿度" # 设备名称,显示在Home Assistant界面上的名称
state_topic: "STH40" # 订阅端口,用于接收湿度传感器数据的消息
unit_of_measurement: "%" # 测量单位,百分比
value_template: "{{ value_json.humidity }}" # 从消息中提取湿度值的模板
</code></pre>
<p><img src="https://bbs.eeworld.com.cn/data/attachment/forum/202410/15/231801crnq2mh3ssomuoqn.jpg.thumb.jpg" /></p>
<p>保存后重启Home Assistant显示下图为配置成功:</p>
<p><img src="https://bbs.eeworld.com.cn/data/attachment/forum/202410/15/224604u8ix3b3bi31b333w.jpg.thumb.jpg" /></p>
<p>在进阶任务的代码基础上修改整合:</p>
<div style="text-align: left;"></div>
<pre>
<code>#include <ArduinoMqttClient.h> // 引入MQTT客户端库
#include <WiFiS3.h> // 引入WiFi库
#include <ArduinoJson.h>
#include <WiFiClient.h> // 引入WiFi客户端库
#include "Adafruit_SHT4x.h" // 引入SHT40传感器的Adafruit库
Adafruit_SHT4x sht4; // 创建SHT40传感器对象
char ssid[] = "xcxc"; // WiFi网络名称
char pass[] = "xc12345678"; // WiFi密码
int status = WL_IDLE_STATUS; // WiFi连接状态
const char broker[] = "XXXXXXXXX"; // MQTT代理服务器地址
int port = 1883; // MQTT代理服务器端口
const char topic[] = "SHT40"; // MQTT主题
WiFiClient wifiClient; // 创建WiFi客户端对象
MqttClient mqttClient(wifiClient); // 创建MQTT客户端对象,并传入WiFi客户端对象
void setup() {
Serial.begin(115200); // 初始化串口通信
while (!Serial) {} // 等待串口监视器打开
Serial.println(F("SGP40 test with SHT40 compensation")); // 打印开始测试的信息
if (WiFi.status() == WL_NO_MODULE) {
Serial.println("与WiFi模块通信失败!"); // 如果没有检测到WiFi模块,则停止程序
while (true);
}
// 尝试连接到WiFi网络
while (status != WL_CONNECTED) {
Serial.print("尝试连接到WPA SSID: ");
Serial.println(ssid);
status = WiFi.begin(ssid, pass); // 连接到WiFi网络
delay(10000); // 等待10秒看是否连接成功
}
Serial.println("已连接到网络"); // 连接成功后的提示
printCurrentNet(); // 打印当前网络信息
printWifiData(); // 打印WiFi数据
// 尝试连接到MQTT代理服务器
if (!mqttClient.connect(broker, port)) {
Serial.print("MQTT连接失败!错误代码 = ");
Serial.println(mqttClient.connectError()); // 如果连接失败,则打印错误代码
while (1); // 停止程序
}
Serial.println("已连接到MQTT"); // 连接成功后的提示
// 订阅主题
mqttClient.subscribe(topic);
Serial.print("等待主题上的消息: ");
Serial.println(topic);
Serial.println();
// 设置消息接收回调
mqttClient.onMessage(onMqttMessage);
// 设置SHT40传感器的测量精度
sht4.setPrecision(SHT4X_HIGH_PRECISION); // 设置为高精度
Serial.println("SHT40 set to High precision"); // 打印高精度
// 配置SHT40传感器的内置加热器状态
sht4.setHeater(SHT4X_NO_HEATER); // 关闭加热器
// 打印当前加热器的状态
switch (sht4.getHeater()) {
case SHT4X_NO_HEATER:
Serial.println(F("SHT40 Heater turned OFF")); // 加热器关闭
break;
}
// 初始化SHT40传感器
if (!sht4.begin(&Wire1)) { // 如果传感器初始化失败
Serial.println(F("SHT40 sensor not found!")); // 打印错误信息
while (1); // 停止程序执行
} else {
Serial.print(F("SHT40 detected!\t")); // 打印传感器检测到的信息
Serial.print(F("Serial number:\t")); // 打印序列号信息
Serial.println(sht4.readSerial(), HEX); // 打印传感器的序列号(十六进制)
}
Serial.println(F("----------------------------------")); // 打印分隔线
}
void printCurrentNet() {
Serial.print("SSID: "); Serial.println(WiFi.SSID()); // 打印网络名称
byte bssid; WiFi.BSSID(bssid); printMacAddress(bssid); // 打印路由器MAC地址
Serial.print("信号强度 (RSSI):"); Serial.println(WiFi.RSSI()); // 打印信号强度
Serial.print("加密类型: "); Serial.println(WiFi.encryptionType(), HEX); // 打印加密类型
Serial.println();
}
void printMacAddress(byte mac[]) {
for (int i = 0; i < 6; i++) {
if (i > 0) Serial.print(":");
if (mac < 16) Serial.print("0");
Serial.print(mac, HEX);
}
Serial.println();
}
void printWifiData() {
IPAddress ip = WiFi.localIP(); // 获取本地IP地址
Serial.print("IP地址: "); Serial.println(ip); // 打印IP地址
byte mac; WiFi.macAddress(mac); Serial.print("MAC地址: "); printMacAddress(mac); // 打印MAC地址
}
void loop() {
// 发送MQTT保持活动信号,以避免被代理断开连接
mqttClient.poll();
sensors_event_t humidity, temp; // 创建温湿度事件对象
sht4.getEvent(&humidity, &temp); // 从传感器获取最新的温湿度数据
if (isnan(temp.temperature) || isnan(humidity.relative_humidity)) {
Serial.println("Failed to read from SHT40 sensor!");
return;
}
float t = temp.temperature; // 获取温度值
float h = humidity.relative_humidity; // 获取相对湿度值
Serial.println("温度 *C = " + String(t));
Serial.println("湿度 % = " + String(h));
// 创建一个JSON对象
StaticJsonDocument<200> doc;
doc["temperature"] = t;
doc["humidity"] = h;
// 将JSON对象转换为字符串
String jsonString;
serializeJson(doc, jsonString);
// 发送JSON字符串到MQTT代理服务器
mqttClient.beginMessage(topic); // 使用之前定义的topic
mqttClient.print(jsonString);
mqttClient.endMessage();
delay(1000); // 延迟5秒发送下一次数据
}
void onMqttMessage(int messageSize) {
// 我们收到了一条消息,打印出主题和内容
Serial.println("收到一条消息:");
Serial.print(mqttClient.messageTopic());
// 使用Stream接口打印内容
String message;
while (mqttClient.available()) {
message += (char)mqttClient.read();
}
Serial.println(message);
}
</code></pre>
<p>烧录后串口显示:</p>
<p><img src="https://bbs.eeworld.com.cn/data/attachment/forum/202410/16/000856rgzox91aaw1m1t36.jpg.thumb.jpg" /></p>
<p>ha页面显示:<br />
<img src="https://bbs.eeworld.com.cn/data/attachment/forum/202410/16/000857y9ogco3l9r39r7nz.jpg.thumb.jpg" /></p>
<p><a href="https://bbs.eeworld.com.cn/thread-1296210-1-1.html">【Follow me第二季第2期】扩展任务二:通过外部SHT40温湿度传感器,上传温湿度到HA - DigiKey得捷技术专区 - 电子工程世界-论坛 (eeworld.com.cn)</a></p>
<hr />
<p><span style="color:#16a085;"><span style="font-size:18px;"><strong>代码分享:</strong></span></span></p>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<hr />
<p> </p>
<p><span style="color:#16a085;"><span style="font-size:18px;"><strong>任务视频演示:</strong></span></span></p>
<p> </p>
<p><a href="https://training.eeworld.com.cn/video/41322" target="_blank">FollowMe 第二季:1-2 - FollowMe 第二季:2 - Arduino UNO R4 Wi-Fi 及任务讲解 - EEWORLD大学堂</a></p>
<p><a href="https://training.eeworld.com.cn/video/41323" target="_blank">FollowMe 第二季:3-4 - FollowMe 第二季:2 - Arduino UNO R4 Wi-Fi 及任务讲解 - EEWORLD大学堂</a></p>
<p> </p>
<p><strong><span style="color:#16a085;"><span style="font-size:18px;">任务总结:</span></span></strong></p>
<p> </p>
<p><span style="font-size:16px;"><strong>在DigiKey与EEWorld共同发起的Follow me活动中,我从Arduino基础开发逐步过渡到复杂系统集成,完成了以下任务:</strong></span></p>
<ol>
<li>
<p><span style="font-size:16px;">Arduino开发环境搭建与基础任务: 成功安装Arduino IDE,配置开发板,编写代码控制LED灯并进行串口通信,掌握了数字输入输出操作。</span></p>
</li>
<li>
<p><span style="font-size:16px;">LED矩阵与信号处理任务: 熟悉LED矩阵原理,实现滚动显示,使用DAC输出正弦波,学习模拟输出与输入操作,并使用OPAMP放大信号。</span></p>
</li>
<li>
<p><span style="font-size:16px;">进阶任务:UNRAID NAS系统与智能家居集成: 配置UNRAID NAS系统,安装Docker,搭建EMQX MQTT服务器与Home Assistant,实现智能家居控制。</span></p>
</li>
<li>
<p><span style="font-size:16px;">MQTT控制与温湿度监测: 编写Arduino代码通过MQTT协议控制LED灯,连接SHT40传感器读取温湿度数据并上传至Home Assistant显示。</span></p>
</li>
</ol>
<p><span style="font-size:16px;"><strong>感悟:</strong></span></p>
<ul>
<li><span style="font-size:16px;">Arduino开发直观有趣,适合初学者。</span></li>
<li><span style="font-size:16px;">模拟信号处理增强了电路设计能力。</span></li>
<li><span style="font-size:16px;">UNRAID NAS与Docker的使用简化了软件部署与管理。</span></li>
<li><span style="font-size:16px;">MQTT协议展示了物联网设备通信的高效性。</span></li>
<li><span style="font-size:16px;">整个过程提升了我的技术水平,增强了对嵌入式系统与智能家居的理解与应用能力。</span></li>
</ul>
<p><span style="font-size:16px;"><strong>感谢DigiKey与EEWorld提供的宝贵学习机会!</strong></span></p>
<p><strong>任务视频演示:</strong></p>
<p><a href="https://training.eeworld.com.cn/video/41322" target="_blank">FollowMe 第二季:1-2 - FollowMe 第二季:2 - Arduino UNO R4 Wi-Fi 及任务讲解 - EEWORLD大学堂</a></p>
<p><a href="https://training.eeworld.com.cn/video/41323" target="_blank">FollowMe 第二季:3-4 - FollowMe 第二季:2 - Arduino UNO R4 Wi-Fi 及任务讲解 - EEWORLD大学堂</a></p>
页:
[1]