- 2024-10-19
-
加入了学习《【Follow me 第二季第2期任务】所有任务汇总进行设计任务效果展示》,观看 【Follow me 第二季第2期任务】4个任务汇总视频
-
加入了学习《【Follow me第二季第2期】任务汇总贴》,观看 【Follow me第二季第2期】任务汇总贴
- 2024-09-30
-
发表了主题帖:
【Follow me 第二季第2期任务】任务汇总贴
本帖最后由 cqut面码 于 2024-10-19 21:51 编辑
1、所有任务的视频展示
视频中一种展示了4个任务,各个任务的时间节点如下:
视频中时间节点说明
对应具体完成的任务
00:00 —— 01:45
入门任务(必做):搭建环境并开启第一步Blink / 串口打印Hello EEWorld!
01:45 —— 06:32
基础任务(必做):驱动12x8点阵LED;用DAC生成正弦波;用OPAMP放大DAC信号;用ADC采集并且打印数据到串口等其他接口可上传到上位机显示曲线。
06:32 —— 09:51
进阶任务(必做):通过Wi-Fi,利用MQTT协议接入到开源的智能家居平台HA(HomeAssistant)。
09:51 —— 12:00
扩展任务二:通过外部SHT40温湿度传感器,上传温湿度到HA,通过HA面板显示数据。
2、使用物料的展示
ARDUIINO UNO R4 WIFI开发板
SHT40传感器
面板板
电阻
杜邦线若干
具体如下所示:
3、任务实现的详细
入门任务 搭建环境、Blink 、串口打印输出
入门任务(必做):搭建环境并开启第一步Blink / 串口打印Hello EEWorld!:
https://bbs.eeworld.com.cn/thread-1293710-1-1.html
一、环境的搭建
首先,根据自己电脑的操作系统从官网上下载 Arduino IDE https://www.arduino.cc,进行安装。然后打开Arduino IDE,把Arduino UNO R4 开发板通过type-c 线连接到电脑上。此时,IDE上如下图1中需要选择串口连接上的开发板版本型号,右下角会自动弹出安装对应的软件包,如下图2,点击等待安装完成即可。
图1.选择连接Arduino UNO R4开发板
图2.等待软件包的安装
二、软件流程图
三、运行Blink
点击文件,新建项目,然后进行保存。第一个我们要实现的是点灯,没错 哈哈哈哈,一个合格的嵌入式工程师就是得会各种点灯。
打开 Arduino UNO R4 的原理图,如下图3,可以看到LED的引脚是P102。
图3. LED引脚控制图
由原理图可知,直接控制P102 高低就可以实现DL4 灯进行翻转。根据Arduino UNO R4的引脚图,图4,可以知道P102是开发板子的D13。
图4. 开发板引脚图
所以代码中直接控制D13就可以了。具体代码如下,主要就是500ms去翻转一次电平,每次翻转前先读取电平,然后再取反电平进行翻转
void setup() {
// put your setup code here, to run once:
pinMode(13, OUTPUT); /* 设置13引脚为输出模式 */
digitalWrite(13, HIGH); /* 默认输出为高*/
}
void loop() {
// put your main code here, to run repeatedly:
delay(500);
digitalWrite(13, !digitalRead(13)); /* 每500ms进行一次LED灯的翻转*/
}
四、串口输出
官方文档告诉了D0 和D1 被用于USB的串口输入和输出。所以不需要我们再进行串口0的IO配置,直接拿来使用就可以
首先初始化设置波特率为115200,然后直接在loop循环函数中每500ms输出一次串口数据,具体代码如下:
/*串口初始化函数*/
void uart_init(uint32_t baud)
{
Serial.begin(baud);
}
void setup() {
// put your setup code here, to run once:
pinMode(13, OUTPUT); /* 设置13引脚为输出模式 */
digitalWrite(13, HIGH); /* 默认输出为高*/
uart_init(115200); /* 串口初始化 */
}
void loop() {
// put your main code here, to run repeatedly:
delay(500);
digitalWrite(13, !digitalRead(13)); /* 每500ms进行一次LED灯的翻转*/
Serial.println("Hello EEWorld !");
}
然后打开串口监视器,设置好波特率为115200,即可看到串口监视器每500ms输出一帧串口数据了。
基础任务 点阵LED+DAC正弦波+OPAMP+波形显示
基础任务(必做):驱动12x8点阵LED;用DAC生成正弦波;用OPAMP放大DAC信号;用ADC采集并且打印数据到串口等其他接口可上传到上位机显示曲线:
https://bbs.eeworld.com.cn/thread-1294700-1-1.html
1、前言
前面学习了环境的搭建、LED的点亮翻转、以及串口的输出。接着就来学习基础任务里面的一些内容, 驱动12x8点阵LED和用DAC生成正弦波。
2、 驱动12x8点阵LED
先放官方的链接https://docs.arduino.cc/tutorials/uno-r4-wifi/led-matrix/,官方给出了详细的这个LED矩阵点亮的实现方式,我们可以通过官方的文档来进行学习,
并完成这个矩阵LED的实验,嵌入式就是得多看看官方资料,不要一个人闭门造车。快速实现了,再去了解原理,深入消化,才不会打击学习的积极性。
官方已经给出一个驱动点了这个矩阵LED库函数,我们只需要包含使用就好了。如下是输出一个爱心的框图,详细的各个功能都在代码中进行了注释说明
核心思想就是通过把自己要显示的LED矩阵相关的数据,直接写入就好,实际就是通过IO通过LED矩阵的亮灭。
画出一个心形的代码的软件流程图:
画出一个心形的代码如下:
#include "Arduino_LED_Matrix.h" /*包含官方的驱动库*/
ArduinoLEDMatrix led_matrix; //实例化一个对象
/*串口初始化函数*/
void uart_init(uint32_t baud)
{
Serial.begin(baud);
}
/* 爱心的框图 */
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 }
};
void setup() {
// put your setup code here, to run once:
pinMode(13, OUTPUT); /* 设置13引脚为输出模式 */
digitalWrite(13, HIGH); /* 默认输出为高*/
Serial.begin(115200);
led_matrix.begin(); //初始化启动这个对象
led_matrix.renderBitmap(frame, 8, 12); //把LED矩阵的数据写入
}
void loop() {
// put your main code here, to run repeatedly:
delay(500);
digitalWrite(13, !digitalRead(13)); /* 每500ms进行一次LED灯的翻转*/
}
实际效果如下:
3、 用DAC生成正弦波
Arduino UNO R4 WiFi 内置DAC(数模转换器),用于将数字信号转换为模拟信号。这里我们直接用DAC输出一个正弦波,然后用示波器去观察器输出的波形
先看原理图DAC的输出口是哪个,从原理图上可以看到,开发板上引出的DAC引脚为A0,等会我们直接用示波器测量A0即可。
然后,参考官网的代码 https://docs.arduino.cc/tutorials/uno-r4-wifi/dac/,完成DAC正弦波的输出。
利用DAC生成正弦波输出的流程图如下:
代码我们在前面的基础上继续完善,具体如下:
这里只是生成可一个50HZ的sin波形并没有在循环中去改变频率或者波形等其他进操作
#include "Arduino_LED_Matrix.h" /*包含官方的驱动库*/
#include "analogWave.h" // 包含波形输出的模拟文件
ArduinoLEDMatrix led_matrix; //实例化一个对象
analogWave wave(DAC); //实例化一个对象
/*串口初始化函数*/
void uart_init(uint32_t baud)
{
Serial.begin(baud);
}
/* 爱心的框图 */
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 }
};
void setup() {
// put your setup code here, to run once:
pinMode(13, OUTPUT); /* 设置13引脚为输出模式 */
digitalWrite(13, HIGH); /* 默认输出为高*/
Serial.begin(115200);
led_matrix.begin(); //初始化启动这个对象
led_matrix.renderBitmap(frame, 8, 12); //把LED矩阵的数据写入
wave.sine(50); //产生一个50HZ的sin波形
}
void loop() {
// put your main code here, to run repeatedly:
delay(500);
digitalWrite(13, !digitalRead(13)); /* 每500ms进行一次LED灯的翻转*/
}
实际示波器测试的效果如下,可以看出最大值为4.6v,最小值为-13mv,频率为49.9HZ左右,波形确实比较难看,锯齿状态还是很严重的,按理说这个板子的12位的DAC性能应不止这样,
应该是内部封装的效果导致一个周期数据输出太少的原因,看来还是得上IDF编程才行。
另外还有一个问题就是,为啥最大值为4.6V,而不是5V,我怀疑是设计缺陷,DAC的参考电压不准,不是5V。时间原因就不去验证了
4、 使用OPAMP对上面的DAC信号放大
OPAMP 实际用处还是很大的,在性能要求不高的情况下,直接使用板载的OPAMP进行放大信号,可以节约成本,避免外部在接一个运放。
当然OPAMP还有一个作用就是做电压跟随器,电压跟随器具有高输入阻抗和低输出阻抗——这是它们缓冲作用的本质,它们增强信号,从而允许高阻抗源驱动低阻抗负载。
这里我们就只展示放大的作用。具官方文档可以参考学习https://docs.arduino.cc/tutorials/uno-r4-wifi/opamp
从前面的实验已经看出了,直接输出的波形已经幅度值已经达到了4.7V,这已经是DAC输出的最大值了。如果我们再在这个基础上去放大这个信号,无疑就会超过4.7V。
就会出现两种情况 1、会出现削波 2、可能损坏电路板。为了后续放大实验方便,我们限制一下幅度值,输出到最大值的1/4即可,便于后续放大波形:
代码很简单,实际就是在setup中多了一个对波形幅值的限制, wave.amplitude(0.25); //设置幅度值为4.7 的1/4
#include "Arduino_LED_Matrix.h" /*包含官方的驱动库*/
#include "analogWave.h" // 包含波形输出的模拟文件
ArduinoLEDMatrix led_matrix; //实例化一个对象
analogWave wave(DAC); //实例化一个对象
/*串口初始化函数*/
void uart_init(uint32_t baud)
{
Serial.begin(baud);
}
/* 爱心的框图 */
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 }
};
void setup() {
// put your setup code here, to run once:
pinMode(13, OUTPUT); /* 设置13引脚为输出模式 */
digitalWrite(13, HIGH); /* 默认输出为高*/
Serial.begin(115200);
led_matrix.begin(); //初始化启动这个对象
led_matrix.renderBitmap(frame, 8, 12); //把LED矩阵的数据写入
wave.sine(50); //产生一个50HZ的sin波形
wave.amplitude(0.25); //设置幅度值为4.7 的1/4
}
void loop() {
// put your main code here, to run repeatedly:
delay(500);
digitalWrite(13, !digitalRead(13)); /* 每500ms进行一次LED灯的翻转*/
}
实际示波器实测效果如果下,还是挺符合4.7V的 1/4 波形的。
好了,有了基础波形,我们就来搭建运放把。额,为了搭建运放的电路,我去找了好久的电阻,建议下次不搞这种,薄膜电阻真的很难找呀,还得找块面包板。
运算放大器放大电路示意图如下所示:
实际用于两个10K的电阻和洞洞板搭建的电路图如下所示:
下面是搭建了2倍放大后的示波器效果图:黄色为放大前的波形图,蓝色为经过放大后的波形图。
附上本次实验的代码:
相对于前面而言,只是添加了一句代码。打开了OPAMP
OPAMP.begin(OPAMP_SPEED_HIGHSPEED); //开启放大器
#include "Arduino_LED_Matrix.h" /*包含官方的驱动库*/
#include "analogWave.h" // 包含波形输出的模拟文件
#include <OPAMP.h>
ArduinoLEDMatrix led_matrix; //实例化一个对象
analogWave wave(DAC); //实例化一个对象
/*串口初始化函数*/
void uart_init(uint32_t baud)
{
Serial.begin(baud);
}
/* 爱心的框图 */
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 }
};
void setup() {
// put your setup code here, to run once:
OPAMP.begin(OPAMP_SPEED_HIGHSPEED); //开启放大器
pinMode(13, OUTPUT); /* 设置13引脚为输出模式 */
digitalWrite(13, HIGH); /* 默认输出为高*/
Serial.begin(115200);
led_matrix.begin(); //初始化启动这个对象
led_matrix.renderBitmap(frame, 8, 12); //把LED矩阵的数据写入
wave.sine(50); //产生一个50HZ的sin波形
wave.amplitude(0.25); //设置幅度值为4.7 的1/4
}
void loop() {
// put your main code here, to run repeatedly:
delay(500);
digitalWrite(13, !digitalRead(13)); /* 每500ms进行一次LED灯的翻转*/
}
5、上位机波形展示
我们使用A4 和 A5 引脚分别采集DAC的输出,和经过OPAMP放大之后的信号输出。然后通过串口发送到上位机进行波形的展示。
使用了 analogReadResolution(14); //change to 14-bit resolution 配置ADC的分辨率最高为14bit
使用了 float Rvalue1 = analogRead(A4) * 4.7/16383; //读取A4的引脚电压
整体的软件流程图如下:
实际的代码如下:
#include "Arduino_LED_Matrix.h" /*包含官方的驱动库*/
#include "analogWave.h" // 包含波形输出的模拟文件
#include <OPAMP.h>
ArduinoLEDMatrix led_matrix; //实例化一个对象
analogWave wave(DAC); //实例化一个对象
/*串口初始化函数*/
void uart_init(uint32_t baud)
{
Serial.begin(baud);
}
/* 爱心的框图 */
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 }
};
void setup() {
// put your setup code here, to run once:
OPAMP.begin(OPAMP_SPEED_HIGHSPEED); //开启放大器
pinMode(13, OUTPUT); /* 设置13引脚为输出模式 */
digitalWrite(13, HIGH); /* 默认输出为高*/
Serial.begin(2000000);
led_matrix.begin(); //初始化启动这个对象
led_matrix.renderBitmap(frame, 8, 12); //把LED矩阵的数据写入
wave.sine(50); //产生一个50HZ的sin波形
wave.amplitude(0.25); //设置幅度值为4.7 的1/4
//配置ADC的分辨率最高为14bit
analogReadResolution(14); //change to 14-bit resolution
}
void loop() {
float Rvalue1 = analogRead(A4) * 4.7/16383; //读取A4的引脚电压
float Rvalue2 = analogRead(A5) * 4.7/16383; //读取A5的引脚电压
Serial.print(Rvalue1);
Serial.print(",");
Serial.println(Rvalue2);
delay(2);
}
最后我们把我们的波形在IDE上自带的串口绘图仪展示出来,可以看到基本上波形2是波形1的2倍数据关系。
这个实验中,为了方便展示波形,我们把串口的波特率调整到了最高
基础任务 MQTT协议接入到开源的智能家居平台HA
进阶任务(必做):通过Wi-Fi,利用MQTT协议接入到开源的智能家居平台HA(HomeAssistant):
https://bbs.eeworld.com.cn/thread-1295058-1-1.html
一、Home Assistant 的安装
为了方便操作,这里直接在电脑上使用Docker进行安装。
官网上下载 https://www.docker.com/products/docker-desktop/ Docker安装包。
安装好了Docker之后,就需要在Docker中拉取Home Assistant 镜像了。可以参考大佬博主的一篇文章,有详细的介绍命令行的使用,我这里只是展示效果了。
https://bbs.eeworld.com.cn/thread-1293807-1-1.html
(1) 第一步先用cmd 搜索镜像
docker search home-assistant
(2)第二步进行拉取最新的镜像
docker pull homeassistant/home-assistant
漫长的等Docker中拉取Home Assistant镜像中。
(3)第三步进行进行创建容器
其中HA_container为可自定义的容器名称,D:/ProgramData/HA为可自定义配置保存路径(注意是右斜杠)
docker run -d --name="HA_container" -v D:/ProgramData/HA:/config -p 8123:8123 homeassistant/home-assistant
(4)最后一步在浏览器中输入 http://localhost:8123/ 就可看到成功了。
接着注册用户,进入主页就好了,具体如下:
二、EMQX 的安装
(1)第一步在Docker中拉取EMQX镜像
CMD中输入命令行,选择第一个进行安装
docker search emqx
docker pull emqx
然后又是漫长的拉取等待
(2)第二步创建EMQX容器
cmd输入以下命令,其中HA为可自定义的容器名称,D:/ProgramData/HA为可自定义配置保存路径(注意是右斜杠)
3)第三步测试EMQX是否OK
浏览器中输入网址 http://localhost:18083/ 默认账号:admin 默认密码:public,成功的界面如下
(4)设置EMQ
一路默认创建我们的内置数据库
再创建一个用户
然后打开docker 就可以看到我们安装的 home assistant 和 EMQ
(5)然后进行EMQ和HA之间的连接
找到EMQ的集群概览。找到节点的信息,如下
打开HA,设置添加MQTT
代理名字填前面在EMQ中获取到的地址,然后创建就OK了。
回到EMQ,可以发现HA已经通过MQTT接入可EMQ,说明HA与EMQ已经成功链接了。
三、实现WIFI联网功能
一步一来做,想要MQTT上传数据,就需要先学会怎么把板子通过WIFI连接上网络。
直接如下面所示,使用开发板的官方示例来进行连接。我们只要修改相应的参数即可了
/*
This example connects to an unencrypted WiFi network.
Then it prints the MAC address of the WiFi module,
the IP address obtained, and other network details.
created 13 July 2010
by dlf (Metodo2 srl)
modified 31 May 2012
by Tom Igoe
Find the full UNO R4 WiFi Network documentation here:
https://docs.arduino.cc/tutorials/uno-r4-wifi/wifi-examples#connect-with-wpa
*/
#include <WiFiS3.h>
#include "arduino_secrets.h"
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
char ssid[] = SECRET_SSID; // your network SSID (name)
char pass[] = SECRET_PASS; // your network password (use for WPA, or use as key for WEP)
int status = WL_IDLE_STATUS; // the WiFi radio's status
void setup() {
//Initialize serial and wait for port to open:
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
// check for the WiFi module:
if (WiFi.status() == WL_NO_MODULE) {
Serial.println("Communication with WiFi module failed!");
// don't continue
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 WPA SSID: ");
Serial.println(ssid);
// Connect to WPA/WPA2 network:
status = WiFi.begin(ssid, pass);
// wait 10 seconds for connection:
delay(10000);
}
// you're connected now, so print out the data:
Serial.print("You're connected to the network");
printCurrentNet();
printWifiData();
}
void loop() {
// check the network connection once every 10 seconds:
delay(10000);
printCurrentNet();
}
void printWifiData() {
// print your board's IP address:
IPAddress ip = WiFi.localIP();
Serial.print("IP Address: ");
Serial.println(ip);
// print your MAC address:
byte mac[6];
WiFi.macAddress(mac);
Serial.print("MAC address: ");
printMacAddress(mac);
}
void printCurrentNet() {
// print the SSID of the network you're attached to:
Serial.print("SSID: ");
Serial.println(WiFi.SSID());
// print the MAC address of the router you're attached to:
byte bssid[6];
WiFi.BSSID(bssid);
Serial.print("BSSID: ");
printMacAddress(bssid);
// print the received signal strength:
long rssi = WiFi.RSSI();
Serial.print("signal strength (RSSI):");
Serial.println(rssi);
// print the encryption type:
byte encryption = WiFi.encryptionType();
Serial.print("Encryption Type:");
Serial.println(encryption, HEX);
Serial.println();
}
void printMacAddress(byte mac[]) {
for (int i = 0; i < 6; i++) {
if (i > 0) {
Serial.print(":");
}
if (mac[i] < 16) {
Serial.print("0");
}
Serial.print(mac[i], HEX);
}
Serial.println();
}
唯一的修改点就是把 SECRET_SSID 和 SECRET_PASS分别替换为自己家里的WIFI名称和密码。注意,不要使用5G频段的WIFI,使用2.4G的WIFI,5G频段WIFI连接不上,应该是硬件不支持的原因。
修改如下:
#define SECRET_SSID "ChinaNet-T6zw"
#define SECRET_PASS "chu7p4s9"
编译下载,打开串口监视器,可以看到已经获取到了MAC地址和WIFI的强度,说明连接成功了
四、MQTT上传数据的准备工作
接着就需要开始准备MQTT相关的东西了
(1) MQTT BOX 的下载准备
MQTTBUX是一个客户端,方便我们调试的时候看MQTT发布的数据,下载链接如下:
https://apps.microsoft.com/detail/9nblggh55jzg?hl=zh-mo&gl=MO
安装之后,就进行一些基本的配置就可以使用了。
MQTT服务器的账户和密码就是我们前面设置的,服务器地址就是我们电脑的本机IP地址。EMQ(MQTT服务器)是通过docker安装在自己本地电脑上的,所有地址是本机电脑地址,直接使用ipconfig 命令可查。如果是把EMQ装在了树莓派上,需要填写树莓派的IP会地址。
设置好之后直接订阅一个主题就好了
这里我们订阅了这个主题 UNO/arduino/myAnalogInput/stat_t,等会开发板向这个主题发送数据,这个客户端就可以收到。
(2) Arduino IDE 安装 ArduinoMqttClient 库
具体如下图
五、代码实战实现数据上MQTT
实现了通过ADC A3接口来读取A0接口 DAC输出sin信号的电压值,然后把这个值通过MQTT协议发布出去,
实际的物理连接如下:
软件流程图如下:
具体的实现代码如下
#include <ArduinoMqttClient.h>
#include <WiFiS3.h>
#include <WiFiClient.h>
#include "Arduino_LED_Matrix.h" /*包含官方的驱动库*/
#include "analogWave.h" // 包含波形输出的模拟文件
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
char ssid[] = "ChinaNet-T6zw"; //WIFI名字
char pass[] = "chu7p4s9"; //WIFI密码
int status = WL_IDLE_STATUS;
//实例化
WiFiClient wifiClient;
MqttClient mqttClient(wifiClient);
analogWave wave(DAC); //实例化一个对象
const char broker[] = "192.168.1.11"; //MQTT服务器地址
int port = 1883; //MQTT服务器端口
const char topic[] = "UNO/arduino/myAnalogInput/stat_t"; //发布的主题
const char mqttuser[] = "lang.you"; //MQTT服务器的用户名
const char mqttpassword[] = "123456789"; //MQTT服务器密码
//set interval for sending messages (milliseconds)
const long interval = 8000;
unsigned long previousMillis = 0;
int count = 0;
void setup() {
//Initialize serial and wait for port to open:
Serial.begin(2000000);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
//A0 DAC 输出一个波形
wave.sine(50); //产生一个50HZ的sin波形
wave.amplitude(0.25); //设置幅度值为4.7 的1/4
// 设置ADC的分辨率
analogReadResolution(14); //change to 14-bit resolution
// attempt to connect to Wifi network:
Serial.print("Attempting to connect to WPA SSID: ");
Serial.println(ssid);
while (WiFi.begin(ssid, pass) != WL_CONNECTED) {
// failed, retry
Serial.print(".");
delay(5000);
}
Serial.println("You're connected to the network");
Serial.println();
Serial.print("Attempting to connect to the MQTT broker: ");
Serial.println(broker);
mqttClient.setUsernamePassword(mqttuser, mqttpassword);
while (!mqttClient.connect(broker, port)) {
Serial.print("MQTT connection failed! Error code = ");
Serial.println(mqttClient.connectError());
delay(1000);
}
Serial.println("You're connected to the MQTT broker!");
Serial.println();
}
void loop() {
// call poll() regularly to allow the library to send MQTT keep alive which
// avoids being disconnected by the broker
mqttClient.poll();
//通过ADC采集 A0上输出的sin波形
float Rvalue = analogRead(A3) * 4.7/16383; //读取A0引脚的值 A3和 A0连接 14bit ADC采样
mqttClient.beginMessage(topic);
mqttClient.print(Rvalue); //把读取的值进行上传到MQTT服务器
mqttClient.endMessage();
delay(10);
}
查看MQTT BOX,并订阅UNO/arduino/myAnalogInput/stat_t主题下面的数据,可以看到数据一直在推送刷新
打开HA查看上传的电压数据是一直在刷新的
这里为什么我的HA会有这个值的显示呢,其实可以参考直播大佬的配置,详情可见下面链接。实际配置了configuration.yaml文件,增加以下代码保存。
https://bbs.eeworld.com.cn/thread-1293807-1-1.html
mqtt:
- button:
- unique_id: arduino uno button A
name: "Arduino Click me A"
command_topic: "UNO/arduino/myButtonA/cmd_t"
payload_press: "restart"
- unique_id: arduino uno button B
name: "Arduino Click me B"
command_topic: "UNO/arduino/myButtonB/cmd_t"
payload_press: "restart"
- sensor:
- unique_id: arduino uno Time
name: "arduino Time"
state_topic: "UNO/arduino/myUptime/stat_t"
suggested_display_precision: 1
unit_of_measurement: "s"
value_template: "{{ value }}"
- unique_id: arduino uno Voltage
name: "arduino Volt"
state_topic: "UNO/arduino/myAnalogInput/stat_t"
suggested_display_precision: 3
unit_of_measurement: "V"
value_template: "{{ value }}"
再来看看EMQ的情况
实际显示了3设备连接,一个就是我们板子,一个HA,一个是MQTT BOX,三个都作为了MQTT的客户端连接到了MQTT服务器
拓展任务 SHT40温湿度数据上次HA,并在HA面板显示
扩展任务二:通过外部SHT40温湿度传感器,上传温湿度到HA,通过HA面板显示数据:
https://bbs.eeworld.com.cn/thread-1295288-1-1.html
1、使用到的硬件介绍
这次实验的主要实现目标是通过外部SHT40温湿度传感器,上传温湿度到HA,通过HA面板显示数据。想了解一下SHT40这个模块
这是SHT40的数据手册 https://edm.eeworld.com.cn/SHT40-datasheet.pdf
简单总结来说,就是一个IIC接口的传感器,可以获取到温湿度,精度为Accuracies ΔRH = ±1.0 %RH, ΔT = ±0.1 °C
内部框图如下,是通过IIC接口来通信获取数据的
把SHT40 传感器和板子相连接
2、相关环境的准备
我们都清楚,Arduino 开发的一个优势就在于,各种驱动非常的丰富,根本不用像其他MCU一样,还要去看寄存器,去手搓底层代码。所以Arduino可以快速实现demo,验证其效果。
拿到一个模块的第一步,去Arduino驱动库翻一下,有没有现成的驱动是直接可以拿来使用的。果然有,赶紧装上,这样我们开发就是非常的快了。
3、读取温湿度代码demo
如下图操作打开示例代码,来进行研究研究
直接编译代码。报了错,我们一步一步来解决,下面的错误说明我们缺了Adafruit_BusIO库。
进行安装Adafruit_BusIO库
安装好了之后,继续编译,还是报错,还是缺少库
如下继续安装依赖库
编译通过了,但是下载后板子没有任何的反应。这时,我们就需要对示例代码进行改造了。如下所示屏蔽所有与SGP40相关的代码,
因为我们的模块中并不包含SGP40,必然初始化不过,另外还要修改的一个地方是 sht4.begin() 修改为 sht4.begin(&Wire1))即可。具体代码如下
/***************************************************************************
Example for the SGP40+SHT40 board
written by Thiago Barros for BlueDot UG (haftungsbeschränkt)
BSD License
Version 1.0.0 (2023-04-22)
This sketch was written for the sensors SGP40 and SHT40 from Sensirion and is based on the Adafruit libraries for these sensors.
The SGP40 is a device for measuring volatile organic compounds (VOC) and for evaluating indoor air quality.
The SHT40 is a digital temperature and relative humidity sensor.
The VOC Algorithm from Sensirion integrates the output values from the SHT40 to improve the calculation of the VOC index.
For more technical information on the SGP40 and on the SHT40, go to ------> http://www.bluedot.space
***************************************************************************/
// #include "Adafruit_SGP40.h"
#include "Adafruit_SHT4x.h"
// Adafruit_SGP40 sgp;
Adafruit_SHT4x sht4;
void setup() {
Serial.begin(115200);
Serial.println();
Serial.println();
Serial.println(F("##################################"));
Serial.println(F("SGP40 test with SHT40 compensation"));
//*********************************************************************
//*************ADVANCED SETUP - SAFE TO IGNORE!************************
//Here we can configure the SHT40 Temperature and Humidity Sensor
//First we set the measurement precision
//There are three precision levels: High, Medium and Low
//The precision levels direclty affect the measurement duration, noise level and energy consumption
//On doubt, just leave it on default (High precision)
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;
}
//*********************************************************************
//*************ADVANCED SETUP - SAFE TO IGNORE!************************
// The SHT40 has a built-in heater, which can be used for self-decontamination.
// The heater can be used for periodic creep compensation in prolongued high humidity exposure.
// For normal operation, leave the heater turned off.
sht4.setHeater(SHT4X_NO_HEATER);
switch (sht4.getHeater()) {
case SHT4X_NO_HEATER:
Serial.println(F("SHT40 Heater turned OFF"));
break;
case SHT4X_HIGH_HEATER_1S:
Serial.println(F("SHT40 Heater: High heat for 1 second"));
break;
case SHT4X_HIGH_HEATER_100MS:
Serial.println(F("SHT40 Heater: High heat for 0.1 second"));
break;
case SHT4X_MED_HEATER_1S:
Serial.println(F("SHT40 Heater: Medium heat for 1 second"));
break;
case SHT4X_MED_HEATER_100MS:
Serial.println(F("SHT40 Heater: Medium heat for 0.1 second"));
break;
case SHT4X_LOW_HEATER_1S:
Serial.println(F("SHT40 Heater: Low heat for 1 second"));
break;
case SHT4X_LOW_HEATER_100MS:
Serial.println(F("SHT40 Heater: Low heat for 0.1 second"));
break;
}
//*********************************************************************
//*************ADVANCED SETUP IS OVER - LET'S CHECK THE CHIP ID!*******
// if (! sgp.begin())
// {
// Serial.println(F("SGP40 sensor not found!"));
// while (1); }
// else
// {
// Serial.print(F("SGP40 detected!\t"));
// Serial.print(F("Serial number:\t"));
// Serial.print(sgp.serialnumber[0], HEX);
// Serial.print(sgp.serialnumber[1], HEX);
// Serial.println(sgp.serialnumber[2], HEX);
// }
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("----------------------------------"));
}
//*********************************************************************
//*************NOW LET'S START MEASURING*******************************
void loop() {
sensors_event_t humidity, temp;
sht4.getEvent(&humidity, &temp);// populate temp and humidity objects with fresh data
float t = temp.temperature;
Serial.print("Temp *C = "); Serial.print(t); Serial.print("\t\t");
float h = humidity.relative_humidity;
Serial.print("Hum. % = "); Serial.print(h); Serial.print("\t\t");
// uint16_t sraw;
// sraw = sgp.measureRaw(t, h);
// Serial.print("Raw measurement: ");
// Serial.print(sraw); Serial.print("\t\t");
// int32_t voc_index;
// voc_index = sgp.measureVocIndex(t, h);
// Serial.print("Voc Index: ");
// Serial.println(voc_index);
delay(1000);
}
编译下载,就可以看到我们运行采集到的温湿度结果了
接着就是这些数据需要通过MQTT协议传输到HA中进行显示了。
根据上一节的操作,我们来配置一个HA的配置configuration.yml 。在主页上添加一下温度和湿度的显示
# Loads default set of integrations. Do not remove.
default_config:
# Load frontend themes from the themes folder
frontend:
themes: !include_dir_merge_named themes
automation: !include automations.yaml
script: !include scripts.yaml
scene: !include scenes.yaml
mqtt:
- button:
- unique_id: arduino uno button A
name: "Arduino Click me A"
command_topic: "UNO/arduino/myButtonA/cmd_t"
payload_press: "restart"
- unique_id: arduino uno button B
name: "Arduino Click me B"
command_topic: "UNO/arduino/myButtonB/cmd_t"
payload_press: "restart"
- sensor:
- unique_id: arduino uno Time
name: "arduino Time"
state_topic: "UNO/arduino/myUptime/stat_t"
suggested_display_precision: 1
unit_of_measurement: "s"
value_template: "{{ value }}"
- unique_id: arduino uno Voltage
name: "arduino Volt"
state_topic: "UNO/arduino/myAnalogInput/stat_t"
suggested_display_precision: 3
unit_of_measurement: "V"
value_template: "{{ value }}"
- unique_id: arduino uno Temperature
name: "arduino Temperature"
state_topic: "UNO/arduino/myTemperature/stat_t"
suggested_display_precision: 3
unit_of_measurement: "°C"
value_template: "{{ value }}"
- unique_id: arduino uno Humidity
name: "arduino Humidity"
state_topic: "UNO/arduino/myHumidity/stat_t"
suggested_display_precision: 3
unit_of_measurement: "%"
value_template: "{{ value }}"
重新加载configuration.yml 后,就可以看到传感器列表中增加了两行
代码也和上一节类似。
软件流程图如下:
直接把采集到的温湿度数据上传到MQTT,具体代码如下:
#include <Adafruit_SGP40.h>
#include <Adafruit_SHT4x.h>
#include <sensirion_arch_config.h>
#include <sensirion_voc_algorithm.h>
#include <ArduinoMqttClient.h>
#include <WiFiS3.h>
#include <WiFiClient.h>
#include "Adafruit_SHT4x.h"
Adafruit_SHT4x sht4;
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
char ssid[] = "ChinaNet-T6zw"; //WIFI名字
char pass[] = "chu7p4s9"; //WIFI密码
int status = WL_IDLE_STATUS;
//实例化
WiFiClient wifiClient;
MqttClient mqttClient(wifiClient);
const char broker[] = "192.168.1.11"; //MQTT服务器地址
int port = 1883; //MQTT服务器端口
const char topic1[] = "UNO/arduino/myTemperature/stat_t"; //发布的主题
const char topic2[] = "UNO/arduino/myHumidity/stat_t"; //发布的主题
const char mqttuser[] = "lang.you"; //MQTT服务器的用户名
const char mqttpassword[] = "123456789"; //MQTT服务器密码
//set interval for sending messages (milliseconds)
const long interval = 8000;
unsigned long previousMillis = 0;
int count = 0;
void init_sht40() {
Serial.println();
Serial.println();
Serial.println(F("##################################"));
Serial.println(F("SGP40 test with SHT40 compensation"));
//Here we can configure the SHT40 Temperature and Humidity Sensor
//First we set the measurement precision
//There are three precision levels: High, Medium and Low
//The precision levels direclty affect the measurement duration, noise level and energy consumption
//On doubt, just leave it on default (High precision)
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;
}
//*********************************************************************
//*************ADVANCED SETUP - SAFE TO IGNORE!************************
// The SHT40 has a built-in heater, which can be used for self-decontamination.
// The heater can be used for periodic creep compensation in prolongued high humidity exposure.
// For normal operation, leave the heater turned off.
sht4.setHeater(SHT4X_NO_HEATER);
switch (sht4.getHeater()) {
case SHT4X_NO_HEATER:
Serial.println(F("SHT40 Heater turned OFF"));
break;
case SHT4X_HIGH_HEATER_1S:
Serial.println(F("SHT40 Heater: High heat for 1 second"));
break;
case SHT4X_HIGH_HEATER_100MS:
Serial.println(F("SHT40 Heater: High heat for 0.1 second"));
break;
case SHT4X_MED_HEATER_1S:
Serial.println(F("SHT40 Heater: Medium heat for 1 second"));
break;
case SHT4X_MED_HEATER_100MS:
Serial.println(F("SHT40 Heater: Medium heat for 0.1 second"));
break;
case SHT4X_LOW_HEATER_1S:
Serial.println(F("SHT40 Heater: Low heat for 1 second"));
break;
case SHT4X_LOW_HEATER_100MS:
Serial.println(F("SHT40 Heater: Low heat for 0.1 second"));
break;
}
//*********************************************************************
//*************ADVANCED SETUP IS OVER - LET'S CHECK THE CHIP ID!*******
// if (! sgp.begin())
// {
// Serial.println(F("SGP40 sensor not found!"));
// while (1); }
// else
// {
// Serial.print(F("SGP40 detected!\t"));
// Serial.print(F("Serial number:\t"));
// Serial.print(sgp.serialnumber[0], HEX);
// Serial.print(sgp.serialnumber[1], HEX);
// Serial.println(sgp.serialnumber[2], HEX);
// }
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 setup() {
//Initialize serial and wait for port to open:
Serial.begin(115200);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
init_sht40();
// attempt to connect to Wifi network:
Serial.print("Attempting to connect to WPA SSID: ");
Serial.println(ssid);
while (WiFi.begin(ssid, pass) != WL_CONNECTED) {
// failed, retry
Serial.print(".");
delay(5000);
}
Serial.println("You're connected to the network");
Serial.println();
Serial.print("Attempting to connect to the MQTT broker: ");
Serial.println(broker);
mqttClient.setUsernamePassword(mqttuser, mqttpassword);
while (!mqttClient.connect(broker, port)) {
Serial.print("MQTT connection failed! Error code = ");
Serial.println(mqttClient.connectError());
delay(1000);
}
Serial.println("You're connected to the MQTT broker!");
Serial.println();
}
void loop() {
// call poll() regularly to allow the library to send MQTT keep alive which
// avoids being disconnected by the broker
sensors_event_t humidity, temp;
sht4.getEvent(&humidity, &temp); // populate temp and humidity objects with fresh data
float t = temp.temperature;
Serial.print("Temp *C = ");
Serial.print(t);
Serial.print("\t\t");
float h = humidity.relative_humidity;
Serial.print("Hum. % = ");
Serial.print(h);
Serial.print("\t\t");
mqttClient.poll();
mqttClient.beginMessage(topic1);
mqttClient.print(t); //把读取的温度值进行上传到MQTT服务器
mqttClient.endMessage();
mqttClient.beginMessage(topic2);
mqttClient.print(h); //把读取的湿度值进行上传到MQTT服务器
mqttClient.endMessage();
delay(10);
}
在HA界面上可以看到采集到的温湿度值一直在更新
4、对参加本次活动的心得体会
通过参加本次 Follow me 第二季第2期任务 ,学会使用了Arduino UNO R4 WiFi 板子,也学会了HA以及搭建MQTT服务器。
同时也看到了使用Arduino开发的快捷性,为之后工作提供了验证思路,比如某一些传感器可以使用Arduino+现有的库进行快速实现demo,验证效果。
另外,通过本次的学习,了解到了HA,后续我也会在家里慢慢通过HA+MQTT实现家里一些电子设备的控制。后面也尝试将HA和EMQ部署上树莓派上,实现一个小的服务器。
非常的感谢DigiKey和EEWorld发起的大型开发板体验活动,让我学会了很多技术知识。后面我也会积极参加社区里这样的活动,和网友在微信群以及论坛里交流技术很开心。
期望后续Follow me 可以出一些linux的小板子,实现一些小的功能。或者出一些MCU系列的板子,使用C语言编程的,可以评估板子性能的,期望能出NXP、瑞萨、英飞凌等的。
5、可编译下载的代码
可编译的代码已将上传到资源,具体可以参考这个链接。
https://download.eeworld.com.cn/detail/cqut%E9%9D%A2%E7%A0%81/634530
6、附录上完成的各个任务贴
入门任务(必做):搭建环境并开启第一步Blink / 串口打印Hello EEWorld!:
https://bbs.eeworld.com.cn/thread-1293710-1-1.html
基础任务(必做):驱动12x8点阵LED;用DAC生成正弦波;用OPAMP放大DAC信号;用ADC采集并且打印数据到串口等其他接口可上传到上位机显示曲线:
https://bbs.eeworld.com.cn/thread-1294700-1-1.html
进阶任务(必做):通过Wi-Fi,利用MQTT协议接入到开源的智能家居平台HA(HomeAssistant):
https://bbs.eeworld.com.cn/thread-1295058-1-1.html
扩展任务二:通过外部SHT40温湿度传感器,上传温湿度到HA,通过HA面板显示数据:
https://bbs.eeworld.com.cn/thread-1295288-1-1.html
-
加入了学习《【Follow me 第二季第2期任务】 各个任务实现的展示效果》,观看 【Follow me 第二季第2期任务】通过外部SHT40温湿度传感器,上传温湿度到HA,通过HA面板显示数据
-
发表了主题帖:
【Follow me第二季第2期】+ SHT40温湿度数据上次HA,并在HA面板显示
本帖最后由 cqut面码 于 2024-9-30 22:03 编辑
1、使用到的硬件介绍
这次实验的主要实现目标是通过外部SHT40温湿度传感器,上传温湿度到HA,通过HA面板显示数据。想了解一下SHT40这个模块
这是SHT40的数据手册 https://edm.eeworld.com.cn/SHT40-datasheet.pdf
简单总结来说,就是一个IIC接口的传感器,可以获取到温湿度,精度为Accuracies ΔRH = ±1.0 %RH, ΔT = ±0.1 °C
内部框图如下,是通过IIC接口来通信获取数据的
把SHT40 传感器和板子相连接
2、相关环境的准备
我们都清楚,Arduino 开发的一个优势就在于,各种驱动非常的丰富,根本不用像其他MCU一样,还要去看寄存器,去手搓底层代码。所以Arduino可以快速实现demo,验证其效果。
拿到一个模块的第一步,去Arduino驱动库翻一下,有没有现成的驱动是直接可以拿来使用的。果然有,赶紧装上,这样我们开发就是非常的快了。
3、读取温湿度代码demo
如下图操作打开示例代码,来进行研究研究。
直接编译代码。报了错,我们一步一步来解决,下面的错误说明我们缺了Adafruit_BusIO库。
进行安装Adafruit_BusIO库
安装好了之后,继续编译,还是报错,还是缺少库
如下继续安装依赖库
编译通过了,但是下载后板子没有任何的反应。这时,我们就需要对示例代码进行改造了。如下所示屏蔽所有与SGP40相关的代码,
因为我们的模块中并不包含SGP40,必然初始化不过,另外还要修改的一个地方是 sht4.begin() 修改为 sht4.begin(&Wire1))即可。具体代码如下:
/***************************************************************************
Example for the SGP40+SHT40 board
written by Thiago Barros for BlueDot UG (haftungsbeschränkt)
BSD License
Version 1.0.0 (2023-04-22)
This sketch was written for the sensors SGP40 and SHT40 from Sensirion and is based on the Adafruit libraries for these sensors.
The SGP40 is a device for measuring volatile organic compounds (VOC) and for evaluating indoor air quality.
The SHT40 is a digital temperature and relative humidity sensor.
The VOC Algorithm from Sensirion integrates the output values from the SHT40 to improve the calculation of the VOC index.
For more technical information on the SGP40 and on the SHT40, go to ------> http://www.bluedot.space
***************************************************************************/
// #include "Adafruit_SGP40.h"
#include "Adafruit_SHT4x.h"
// Adafruit_SGP40 sgp;
Adafruit_SHT4x sht4;
void setup() {
Serial.begin(115200);
Serial.println();
Serial.println();
Serial.println(F("##################################"));
Serial.println(F("SGP40 test with SHT40 compensation"));
//*********************************************************************
//*************ADVANCED SETUP - SAFE TO IGNORE!************************
//Here we can configure the SHT40 Temperature and Humidity Sensor
//First we set the measurement precision
//There are three precision levels: High, Medium and Low
//The precision levels direclty affect the measurement duration, noise level and energy consumption
//On doubt, just leave it on default (High precision)
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;
}
//*********************************************************************
//*************ADVANCED SETUP - SAFE TO IGNORE!************************
// The SHT40 has a built-in heater, which can be used for self-decontamination.
// The heater can be used for periodic creep compensation in prolongued high humidity exposure.
// For normal operation, leave the heater turned off.
sht4.setHeater(SHT4X_NO_HEATER);
switch (sht4.getHeater()) {
case SHT4X_NO_HEATER:
Serial.println(F("SHT40 Heater turned OFF"));
break;
case SHT4X_HIGH_HEATER_1S:
Serial.println(F("SHT40 Heater: High heat for 1 second"));
break;
case SHT4X_HIGH_HEATER_100MS:
Serial.println(F("SHT40 Heater: High heat for 0.1 second"));
break;
case SHT4X_MED_HEATER_1S:
Serial.println(F("SHT40 Heater: Medium heat for 1 second"));
break;
case SHT4X_MED_HEATER_100MS:
Serial.println(F("SHT40 Heater: Medium heat for 0.1 second"));
break;
case SHT4X_LOW_HEATER_1S:
Serial.println(F("SHT40 Heater: Low heat for 1 second"));
break;
case SHT4X_LOW_HEATER_100MS:
Serial.println(F("SHT40 Heater: Low heat for 0.1 second"));
break;
}
//*********************************************************************
//*************ADVANCED SETUP IS OVER - LET'S CHECK THE CHIP ID!*******
// if (! sgp.begin())
// {
// Serial.println(F("SGP40 sensor not found!"));
// while (1); }
// else
// {
// Serial.print(F("SGP40 detected!\t"));
// Serial.print(F("Serial number:\t"));
// Serial.print(sgp.serialnumber[0], HEX);
// Serial.print(sgp.serialnumber[1], HEX);
// Serial.println(sgp.serialnumber[2], HEX);
// }
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("----------------------------------"));
}
//*********************************************************************
//*************NOW LET'S START MEASURING*******************************
void loop() {
sensors_event_t humidity, temp;
sht4.getEvent(&humidity, &temp);// populate temp and humidity objects with fresh data
float t = temp.temperature;
Serial.print("Temp *C = "); Serial.print(t); Serial.print("\t\t");
float h = humidity.relative_humidity;
Serial.print("Hum. % = "); Serial.print(h); Serial.print("\t\t");
// uint16_t sraw;
// sraw = sgp.measureRaw(t, h);
// Serial.print("Raw measurement: ");
// Serial.print(sraw); Serial.print("\t\t");
// int32_t voc_index;
// voc_index = sgp.measureVocIndex(t, h);
// Serial.print("Voc Index: ");
// Serial.println(voc_index);
delay(1000);
}
编译下载,就可以看到我们运行采集到的温湿度结果了
接着就是这些数据需要通过MQTT协议传输到HA中进行显示了。
根据上一节的操作,我们来配置一个HA的配置configuration.yml 。在主页上添加一下温度和湿度的显示
# Loads default set of integrations. Do not remove.
default_config:
# Load frontend themes from the themes folder
frontend:
themes: !include_dir_merge_named themes
automation: !include automations.yaml
script: !include scripts.yaml
scene: !include scenes.yaml
mqtt:
- button:
- unique_id: arduino uno button A
name: "Arduino Click me A"
command_topic: "UNO/arduino/myButtonA/cmd_t"
payload_press: "restart"
- unique_id: arduino uno button B
name: "Arduino Click me B"
command_topic: "UNO/arduino/myButtonB/cmd_t"
payload_press: "restart"
- sensor:
- unique_id: arduino uno Time
name: "arduino Time"
state_topic: "UNO/arduino/myUptime/stat_t"
suggested_display_precision: 1
unit_of_measurement: "s"
value_template: "{{ value }}"
- unique_id: arduino uno Voltage
name: "arduino Volt"
state_topic: "UNO/arduino/myAnalogInput/stat_t"
suggested_display_precision: 3
unit_of_measurement: "V"
value_template: "{{ value }}"
- unique_id: arduino uno Temperature
name: "arduino Temperature"
state_topic: "UNO/arduino/myTemperature/stat_t"
suggested_display_precision: 3
unit_of_measurement: "°C"
value_template: "{{ value }}"
- unique_id: arduino uno Humidity
name: "arduino Humidity"
state_topic: "UNO/arduino/myHumidity/stat_t"
suggested_display_precision: 3
unit_of_measurement: "%"
value_template: "{{ value }}"
重新加载configuration.yml 后,就可以看到传感器列表中增加了两行
代码也和上一节类似。直接把采集到的温湿度数据上传到MQTT,具体代码如下:
#include <Adafruit_SGP40.h>
#include <Adafruit_SHT4x.h>
#include <sensirion_arch_config.h>
#include <sensirion_voc_algorithm.h>
#include <ArduinoMqttClient.h>
#include <WiFiS3.h>
#include <WiFiClient.h>
#include "Adafruit_SHT4x.h"
Adafruit_SHT4x sht4;
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
char ssid[] = "ChinaNet-T6zw"; //WIFI名字
char pass[] = "chu7p4s9"; //WIFI密码
int status = WL_IDLE_STATUS;
//实例化
WiFiClient wifiClient;
MqttClient mqttClient(wifiClient);
const char broker[] = "192.168.1.11"; //MQTT服务器地址
int port = 1883; //MQTT服务器端口
const char topic1[] = "UNO/arduino/myTemperature/stat_t"; //发布的主题
const char topic2[] = "UNO/arduino/myHumidity/stat_t"; //发布的主题
const char mqttuser[] = "lang.you"; //MQTT服务器的用户名
const char mqttpassword[] = "123456789"; //MQTT服务器密码
//set interval for sending messages (milliseconds)
const long interval = 8000;
unsigned long previousMillis = 0;
int count = 0;
void init_sht40() {
Serial.println();
Serial.println();
Serial.println(F("##################################"));
Serial.println(F("SGP40 test with SHT40 compensation"));
//Here we can configure the SHT40 Temperature and Humidity Sensor
//First we set the measurement precision
//There are three precision levels: High, Medium and Low
//The precision levels direclty affect the measurement duration, noise level and energy consumption
//On doubt, just leave it on default (High precision)
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;
}
//*********************************************************************
//*************ADVANCED SETUP - SAFE TO IGNORE!************************
// The SHT40 has a built-in heater, which can be used for self-decontamination.
// The heater can be used for periodic creep compensation in prolongued high humidity exposure.
// For normal operation, leave the heater turned off.
sht4.setHeater(SHT4X_NO_HEATER);
switch (sht4.getHeater()) {
case SHT4X_NO_HEATER:
Serial.println(F("SHT40 Heater turned OFF"));
break;
case SHT4X_HIGH_HEATER_1S:
Serial.println(F("SHT40 Heater: High heat for 1 second"));
break;
case SHT4X_HIGH_HEATER_100MS:
Serial.println(F("SHT40 Heater: High heat for 0.1 second"));
break;
case SHT4X_MED_HEATER_1S:
Serial.println(F("SHT40 Heater: Medium heat for 1 second"));
break;
case SHT4X_MED_HEATER_100MS:
Serial.println(F("SHT40 Heater: Medium heat for 0.1 second"));
break;
case SHT4X_LOW_HEATER_1S:
Serial.println(F("SHT40 Heater: Low heat for 1 second"));
break;
case SHT4X_LOW_HEATER_100MS:
Serial.println(F("SHT40 Heater: Low heat for 0.1 second"));
break;
}
//*********************************************************************
//*************ADVANCED SETUP IS OVER - LET'S CHECK THE CHIP ID!*******
// if (! sgp.begin())
// {
// Serial.println(F("SGP40 sensor not found!"));
// while (1); }
// else
// {
// Serial.print(F("SGP40 detected!\t"));
// Serial.print(F("Serial number:\t"));
// Serial.print(sgp.serialnumber[0], HEX);
// Serial.print(sgp.serialnumber[1], HEX);
// Serial.println(sgp.serialnumber[2], HEX);
// }
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 setup() {
//Initialize serial and wait for port to open:
Serial.begin(115200);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
init_sht40();
// attempt to connect to Wifi network:
Serial.print("Attempting to connect to WPA SSID: ");
Serial.println(ssid);
while (WiFi.begin(ssid, pass) != WL_CONNECTED) {
// failed, retry
Serial.print(".");
delay(5000);
}
Serial.println("You're connected to the network");
Serial.println();
Serial.print("Attempting to connect to the MQTT broker: ");
Serial.println(broker);
mqttClient.setUsernamePassword(mqttuser, mqttpassword);
while (!mqttClient.connect(broker, port)) {
Serial.print("MQTT connection failed! Error code = ");
Serial.println(mqttClient.connectError());
delay(1000);
}
Serial.println("You're connected to the MQTT broker!");
Serial.println();
}
void loop() {
// call poll() regularly to allow the library to send MQTT keep alive which
// avoids being disconnected by the broker
sensors_event_t humidity, temp;
sht4.getEvent(&humidity, &temp); // populate temp and humidity objects with fresh data
float t = temp.temperature;
Serial.print("Temp *C = ");
Serial.print(t);
Serial.print("\t\t");
float h = humidity.relative_humidity;
Serial.print("Hum. % = ");
Serial.print(h);
Serial.print("\t\t");
mqttClient.poll();
mqttClient.beginMessage(topic1);
mqttClient.print(t); //把读取的温度值进行上传到MQTT服务器
mqttClient.endMessage();
mqttClient.beginMessage(topic2);
mqttClient.print(h); //把读取的湿度值进行上传到MQTT服务器
mqttClient.endMessage();
delay(10);
}
在HA界面上可以看到采集到的温湿度值一直在更新
4、展示效果和源码附件
-
上传了资料:
【Follow me 第二季第2期任务】4个任务实现的源码
-
加入了学习《【Follow me 第二季第2期任务】 各个任务实现的展示效果》,观看 【Follow me 第二季第2期任务】Blink / 串口打印Hello EEWorld!
-
加入了学习《【Follow me 第二季第2期任务】 各个任务实现的展示效果》,观看 【Follow me 第二季第2期任务】MQTT接入到HomeAssistant
-
加入了学习《【Follow me 第二季第2期任务】 各个任务实现的展示效果》,观看 【Follow me 第二季第2期任务】驱动12x8点阵LED;用DAC生成正弦波;OPAMP放大DAC信号;用ADC采集并上传波形
- 2024-09-28
-
加入了学习《FollowMe 第二季:2 - Arduino UNO R4 Wi-Fi 及任务讲解》,观看 Arduino UNO R4 Wi-Fi 及任务讲解
-
发表了主题帖:
【Follow me第二季第2期】MQTT协议接入到开源的智能家居平台HA
本帖最后由 cqut面码 于 2024-9-29 22:06 编辑
一、Home Assistant 的安装
为了方便操作,这里直接在电脑上使用Docker进行安装。
官网上下载 https://www.docker.com/products/docker-desktop/ Docker安装包。
安装好了Docker之后,就需要在Docker中拉取Home Assistant 镜像了。可以参考大佬博主的一篇文章,有详细的介绍命令行的使用,我这里只是展示效果了。
https://bbs.eeworld.com.cn/thread-1293807-1-1.html
(1) 第一步先用cmd 搜索镜像
docker search home-assistant
(2)第二步进行拉取最新的镜像
docker pull homeassistant/home-assistant
漫长的等Docker中拉取Home Assistant镜像中。
(3)第三步进行进行创建容器
其中HA_container为可自定义的容器名称,D:/ProgramData/HA为可自定义配置保存路径(注意是右斜杠)
docker run -d --name="HA_container" -v D:/ProgramData/HA:/config -p 8123:8123 homeassistant/home-assistant
(4)最后一步在浏览器中输入 http://localhost:8123/ 就可看到成功了。
接着注册用户,进入主页就好了,具体如下:
二、EMQX 的安装
(1)第一步在Docker中拉取EMQX镜像
CMD中输入命令行,选择第一个进行安装
docker search emqx
docker pull emqx
然后又是漫长的拉取等待
(2)第二步创建EMQX容器
cmd输入以下命令,其中HA为可自定义的容器名称,D:/ProgramData/HA为可自定义配置保存路径(注意是右斜杠)
(3)第三步测试EMQX是否OK
浏览器中输入网址 http://localhost:18083/ 默认账号:admin 默认密码:public,成功的界面如下
(4)设置EMQ
一路默认创建我们的内置数据库
再创建一个用户
然后打开docker 就可以看到我们安装的 home assistant 和 EMQ
(5)然后进行EMQ和HA之间的连接
找到EMQ的集群概览。找到节点的信息,如下
打开HA,设置添加MQTT
代理名字填前面在EMQ中获取到的地址,然后创建就OK了。
回到EMQ,可以发现HA已经通过MQTT接入可EMQ,说明HA与EMQ已经成功链接了。
三、实现WIFI联网功能
一步一来做,想要MQTT上传数据,就需要先学会怎么把板子通过WIFI连接上网络。
直接如下面所示,使用开发板的官方示例来进行连接。我们只要修改相应的参数即可了
/*
This example connects to an unencrypted WiFi network.
Then it prints the MAC address of the WiFi module,
the IP address obtained, and other network details.
created 13 July 2010
by dlf (Metodo2 srl)
modified 31 May 2012
by Tom Igoe
Find the full UNO R4 WiFi Network documentation here:
https://docs.arduino.cc/tutorials/uno-r4-wifi/wifi-examples#connect-with-wpa
*/
#include <WiFiS3.h>
#include "arduino_secrets.h"
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
char ssid[] = SECRET_SSID; // your network SSID (name)
char pass[] = SECRET_PASS; // your network password (use for WPA, or use as key for WEP)
int status = WL_IDLE_STATUS; // the WiFi radio's status
void setup() {
//Initialize serial and wait for port to open:
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
// check for the WiFi module:
if (WiFi.status() == WL_NO_MODULE) {
Serial.println("Communication with WiFi module failed!");
// don't continue
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 WPA SSID: ");
Serial.println(ssid);
// Connect to WPA/WPA2 network:
status = WiFi.begin(ssid, pass);
// wait 10 seconds for connection:
delay(10000);
}
// you're connected now, so print out the data:
Serial.print("You're connected to the network");
printCurrentNet();
printWifiData();
}
void loop() {
// check the network connection once every 10 seconds:
delay(10000);
printCurrentNet();
}
void printWifiData() {
// print your board's IP address:
IPAddress ip = WiFi.localIP();
Serial.print("IP Address: ");
Serial.println(ip);
// print your MAC address:
byte mac[6];
WiFi.macAddress(mac);
Serial.print("MAC address: ");
printMacAddress(mac);
}
void printCurrentNet() {
// print the SSID of the network you're attached to:
Serial.print("SSID: ");
Serial.println(WiFi.SSID());
// print the MAC address of the router you're attached to:
byte bssid[6];
WiFi.BSSID(bssid);
Serial.print("BSSID: ");
printMacAddress(bssid);
// print the received signal strength:
long rssi = WiFi.RSSI();
Serial.print("signal strength (RSSI):");
Serial.println(rssi);
// print the encryption type:
byte encryption = WiFi.encryptionType();
Serial.print("Encryption Type:");
Serial.println(encryption, HEX);
Serial.println();
}
void printMacAddress(byte mac[]) {
for (int i = 0; i < 6; i++) {
if (i > 0) {
Serial.print(":");
}
if (mac[i] < 16) {
Serial.print("0");
}
Serial.print(mac[i], HEX);
}
Serial.println();
}
唯一的修改点就是把 SECRET_SSID 和 SECRET_PASS分别替换为自己家里的WIFI名称和密码。注意,不要使用5G频段的WIFI,使用2.4G的WIFI,5G频段WIFI连接不上,应该是硬件不支持的原因。
修改如下:
#define SECRET_SSID "ChinaNet-T6zw"
#define SECRET_PASS "chu7p4s9"
编译下载,打开串口监视器,可以看到已经获取到了MAC地址和WIFI的强度,说明连接成功了
四、MQTT上传数据的准备工作
接着就需要开始准备MQTT相关的东西了
(1) MQTT BOX 的下载准备
MQTTBUX是一个客户端,方便我们调试的时候看MQTT发布的数据,下载链接如下:
https://apps.microsoft.com/detail/9nblggh55jzg?hl=zh-mo&gl=MO
安装之后,就进行一些基本的配置就可以使用了。
MQTT服务器的账户和密码就是我们前面设置的,服务器地址就是我们电脑的本机IP地址。EMQ(MQTT服务器)是通过docker安装在自己本地电脑上的,所有地址是本机电脑地址,直接使用ipconfig 命令可查。如果是把EMQ装在了树莓派上,需要填写树莓派的IP会地址。
设置好之后直接订阅一个主题就好了
这里我们订阅了这个主题 UNO/arduino/myAnalogInput/stat_t,等会开发板向这个主题发送数据,这个客户端就可以收到。
(2) Arduino IDE 安装 ArduinoMqttClient 库
具体如下图
五、代码实战实现数据上MQTT
实现了通过ADC A3接口来读取A0接口 DAC输出sin信号的电压值,然后把这个值通过MQTT协议发布出去,
实际的物理连接如下:
具体的实现代码如下
#include <ArduinoMqttClient.h>
#include <WiFiS3.h>
#include <WiFiClient.h>
#include "Arduino_LED_Matrix.h" /*包含官方的驱动库*/
#include "analogWave.h" // 包含波形输出的模拟文件
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
char ssid[] = "ChinaNet-T6zw"; //WIFI名字
char pass[] = "chu7p4s9"; //WIFI密码
int status = WL_IDLE_STATUS;
//实例化
WiFiClient wifiClient;
MqttClient mqttClient(wifiClient);
analogWave wave(DAC); //实例化一个对象
const char broker[] = "192.168.1.11"; //MQTT服务器地址
int port = 1883; //MQTT服务器端口
const char topic[] = "UNO/arduino/myAnalogInput/stat_t"; //发布的主题
const char mqttuser[] = "lang.you"; //MQTT服务器的用户名
const char mqttpassword[] = "123456789"; //MQTT服务器密码
//set interval for sending messages (milliseconds)
const long interval = 8000;
unsigned long previousMillis = 0;
int count = 0;
void setup() {
//Initialize serial and wait for port to open:
Serial.begin(2000000);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
//A0 DAC 输出一个波形
wave.sine(50); //产生一个50HZ的sin波形
wave.amplitude(0.25); //设置幅度值为4.7 的1/4
// 设置ADC的分辨率
analogReadResolution(14); //change to 14-bit resolution
// attempt to connect to Wifi network:
Serial.print("Attempting to connect to WPA SSID: ");
Serial.println(ssid);
while (WiFi.begin(ssid, pass) != WL_CONNECTED) {
// failed, retry
Serial.print(".");
delay(5000);
}
Serial.println("You're connected to the network");
Serial.println();
Serial.print("Attempting to connect to the MQTT broker: ");
Serial.println(broker);
mqttClient.setUsernamePassword(mqttuser, mqttpassword);
while (!mqttClient.connect(broker, port)) {
Serial.print("MQTT connection failed! Error code = ");
Serial.println(mqttClient.connectError());
delay(1000);
}
Serial.println("You're connected to the MQTT broker!");
Serial.println();
}
void loop() {
// call poll() regularly to allow the library to send MQTT keep alive which
// avoids being disconnected by the broker
mqttClient.poll();
//通过ADC采集 A0上输出的sin波形
float Rvalue = analogRead(A3) * 4.7/16383; //读取A0引脚的值 A3和 A0连接 14bit ADC采样
mqttClient.beginMessage(topic);
mqttClient.print(Rvalue); //把读取的值进行上传到MQTT服务器
mqttClient.endMessage();
delay(10);
}
查看MQTT BOX,并订阅UNO/arduino/myAnalogInput/stat_t主题下面的数据,可以看到数据一直在推送刷新
打开HA查看上传的电压数据是一直在刷新的
再来看看我们实际的HA上显示的sin信号的电压值
这里为什么我的HA会有这个值的显示呢,其实可以参考直播大佬的配置,详情可见下面链接。实际配置了configuration.yaml文件,增加以下代码保存。
https://bbs.eeworld.com.cn/thread-1293807-1-1.html
mqtt:
- button:
- unique_id: arduino uno button A
name: "Arduino Click me A"
command_topic: "UNO/arduino/myButtonA/cmd_t"
payload_press: "restart"
- unique_id: arduino uno button B
name: "Arduino Click me B"
command_topic: "UNO/arduino/myButtonB/cmd_t"
payload_press: "restart"
- sensor:
- unique_id: arduino uno Time
name: "arduino Time"
state_topic: "UNO/arduino/myUptime/stat_t"
suggested_display_precision: 1
unit_of_measurement: "s"
value_template: "{{ value }}"
- unique_id: arduino uno Voltage
name: "arduino Volt"
state_topic: "UNO/arduino/myAnalogInput/stat_t"
suggested_display_precision: 3
unit_of_measurement: "V"
value_template: "{{ value }}"
再来看看EMQ的情况
实际显示了3设备连接,一个就是我们板子,一个HA,一个是MQTT BOX,三个都作为了MQTT的客户端连接到了MQTT服务器
六、视频展示和最终工程代码代码
- 2024-09-24
-
发表了主题帖:
【Follow me第二季第2期】+ 基础任务 点阵LED+DAC正弦波+OPAMP+波形显示
本帖最后由 cqut面码 于 2024-9-30 00:39 编辑
1、前言
前面学习了环境的搭建、LED的点亮翻转、以及串口的输出。接着就来学习基础任务里面的一些内容, 驱动12x8点阵LED和用DAC生成正弦波。
2、 驱动12x8点阵LED
先放官方的链接https://docs.arduino.cc/tutorials/uno-r4-wifi/led-matrix/,官方给出了详细的这个LED矩阵点亮的实现方式,我们可以通过官方的文档来进行学习,
并完成这个矩阵LED的实验,嵌入式就是得多看看官方资料,不要一个人闭门造车。快速实现了,再去了解原理,深入消化,才不会打击学习的积极性。
官方已经给出一个驱动点了这个矩阵LED库函数,我们只需要包含使用就好了。如下是输出一个爱心的框图,详细的各个功能都在代码中进行了注释说明
核心思想就是通过把自己要显示的LED矩阵相关的数据,直接写入就好,实际就是通过IO通过LED矩阵的亮灭。
画出一个心形的代码如下:
#include "Arduino_LED_Matrix.h" /*包含官方的驱动库*/
ArduinoLEDMatrix led_matrix; //实例化一个对象
/*串口初始化函数*/
void uart_init(uint32_t baud)
{
Serial.begin(baud);
}
/* 爱心的框图 */
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 }
};
void setup() {
// put your setup code here, to run once:
pinMode(13, OUTPUT); /* 设置13引脚为输出模式 */
digitalWrite(13, HIGH); /* 默认输出为高*/
Serial.begin(115200);
led_matrix.begin(); //初始化启动这个对象
led_matrix.renderBitmap(frame, 8, 12); //把LED矩阵的数据写入
}
void loop() {
// put your main code here, to run repeatedly:
delay(500);
digitalWrite(13, !digitalRead(13)); /* 每500ms进行一次LED灯的翻转*/
}
实际效果如下:
3、 用DAC生成正弦波
Arduino UNO R4 WiFi 内置DAC(数模转换器),用于将数字信号转换为模拟信号。这里我们直接用DAC输出一个正弦波,然后用示波器去观察器输出的波形
先看原理图DAC的输出口是哪个,从原理图上可以看到,开发板上引出的DAC引脚为A0,等会我们直接用示波器测量A0即可。
然后,参考官网的代码 https://docs.arduino.cc/tutorials/uno-r4-wifi/dac/,完成DAC正弦波的输出,代码我们在前面的基础上继续完善,具体如下:
这里只是生成可一个50HZ的sin波形并没有在循环中去改变频率或者波形等其他进操作
#include "Arduino_LED_Matrix.h" /*包含官方的驱动库*/
#include "analogWave.h" // 包含波形输出的模拟文件
ArduinoLEDMatrix led_matrix; //实例化一个对象
analogWave wave(DAC); //实例化一个对象
/*串口初始化函数*/
void uart_init(uint32_t baud)
{
Serial.begin(baud);
}
/* 爱心的框图 */
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 }
};
void setup() {
// put your setup code here, to run once:
pinMode(13, OUTPUT); /* 设置13引脚为输出模式 */
digitalWrite(13, HIGH); /* 默认输出为高*/
Serial.begin(115200);
led_matrix.begin(); //初始化启动这个对象
led_matrix.renderBitmap(frame, 8, 12); //把LED矩阵的数据写入
wave.sine(50); //产生一个50HZ的sin波形
}
void loop() {
// put your main code here, to run repeatedly:
delay(500);
digitalWrite(13, !digitalRead(13)); /* 每500ms进行一次LED灯的翻转*/
}
实际示波器测试的效果如下,可以看出最大值为4.6v,最小值为-13mv,频率为49.9HZ左右,波形确实比较难看,锯齿状态还是很严重的,按理说这个板子的12位的DAC性能应不止这样,
应该是内部封装的效果导致一个周期数据输出太少的原因,看来还是得上IDF编程才行。
另外还有一个问题就是,为啥最大值为4.6V,而不是5V,我怀疑是设计缺陷,DAC的参考电压不准,不是5V。时间原因就不去验证了
4、 使用OPAMP对上面的DAC信号放大
OPAMP 实际用处还是很大的,在性能要求不高的情况下,直接使用板载的OPAMP进行放大信号,可以节约成本,避免外部在接一个运放。
当然OPAMP还有一个作用就是做电压跟随器,电压跟随器具有高输入阻抗和低输出阻抗——这是它们缓冲作用的本质,它们增强信号,从而允许高阻抗源驱动低阻抗负载。
这里我们就只展示放大的作用。具官方文档可以参考学习https://docs.arduino.cc/tutorials/uno-r4-wifi/opamp
从前面的实验已经看出了,直接输出的波形已经幅度值已经达到了4.7V,这已经是DAC输出的最大值了。如果我们再在这个基础上去放大这个信号,无疑就会超过4.7V。
就会出现两种情况 1、会出现削波 2、可能损坏电路板。为了后续放大实验方便,我们限制一下幅度值,输出到最大值的1/4即可,便于后续放大波形:
代码很简单,实际就是在setup中多了一个对波形幅值的限制, wave.amplitude(0.25); //设置幅度值为4.7 的1/4
#include "Arduino_LED_Matrix.h" /*包含官方的驱动库*/
#include "analogWave.h" // 包含波形输出的模拟文件
ArduinoLEDMatrix led_matrix; //实例化一个对象
analogWave wave(DAC); //实例化一个对象
/*串口初始化函数*/
void uart_init(uint32_t baud)
{
Serial.begin(baud);
}
/* 爱心的框图 */
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 }
};
void setup() {
// put your setup code here, to run once:
pinMode(13, OUTPUT); /* 设置13引脚为输出模式 */
digitalWrite(13, HIGH); /* 默认输出为高*/
Serial.begin(115200);
led_matrix.begin(); //初始化启动这个对象
led_matrix.renderBitmap(frame, 8, 12); //把LED矩阵的数据写入
wave.sine(50); //产生一个50HZ的sin波形
wave.amplitude(0.25); //设置幅度值为4.7 的1/4
}
void loop() {
// put your main code here, to run repeatedly:
delay(500);
digitalWrite(13, !digitalRead(13)); /* 每500ms进行一次LED灯的翻转*/
}
实际示波器实测效果如果下,还是挺符合4.7V的 1/4 波形的。
好了,有了基础波形,我们就来搭建运放把。额,为了搭建运放的电路,我去找了好久的电阻,建议下次不搞这种,薄膜电阻真的很难找呀,还得找块面包板。
运算放大器放大电路示意图如下所示:
实际用于两个10K的电阻和洞洞板搭建的电路图如下所示:
下面是搭建了2倍放大后的示波器效果图:黄色为放大前的波形图,蓝色为经过放大后的波形图。
最后附上本次实验的代码:
相对于前面而言,只是添加了一句代码。打开了OPAMP
OPAMP.begin(OPAMP_SPEED_HIGHSPEED); //开启放大器
#include "Arduino_LED_Matrix.h" /*包含官方的驱动库*/
#include "analogWave.h" // 包含波形输出的模拟文件
#include <OPAMP.h>
ArduinoLEDMatrix led_matrix; //实例化一个对象
analogWave wave(DAC); //实例化一个对象
/*串口初始化函数*/
void uart_init(uint32_t baud)
{
Serial.begin(baud);
}
/* 爱心的框图 */
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 }
};
void setup() {
// put your setup code here, to run once:
OPAMP.begin(OPAMP_SPEED_HIGHSPEED); //开启放大器
pinMode(13, OUTPUT); /* 设置13引脚为输出模式 */
digitalWrite(13, HIGH); /* 默认输出为高*/
Serial.begin(115200);
led_matrix.begin(); //初始化启动这个对象
led_matrix.renderBitmap(frame, 8, 12); //把LED矩阵的数据写入
wave.sine(50); //产生一个50HZ的sin波形
wave.amplitude(0.25); //设置幅度值为4.7 的1/4
}
void loop() {
// put your main code here, to run repeatedly:
delay(500);
digitalWrite(13, !digitalRead(13)); /* 每500ms进行一次LED灯的翻转*/
}
5、上位机波形展示
我们使用A4 和 A5 引脚分别采集DAC的输出,和经过OPAMP放大之后的信号输出。然后通过串口发送到上位机进行波形的展示。
使用了 analogReadResolution(14); //change to 14-bit resolution 配置ADC的分辨率最高为14bit
使用了 float Rvalue1 = analogRead(A4) * 4.7/16383; //读取A4的引脚电压
实际的代码如下:
#include "Arduino_LED_Matrix.h" /*包含官方的驱动库*/
#include "analogWave.h" // 包含波形输出的模拟文件
#include <OPAMP.h>
ArduinoLEDMatrix led_matrix; //实例化一个对象
analogWave wave(DAC); //实例化一个对象
/*串口初始化函数*/
void uart_init(uint32_t baud)
{
Serial.begin(baud);
}
/* 爱心的框图 */
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 }
};
void setup() {
// put your setup code here, to run once:
OPAMP.begin(OPAMP_SPEED_HIGHSPEED); //开启放大器
pinMode(13, OUTPUT); /* 设置13引脚为输出模式 */
digitalWrite(13, HIGH); /* 默认输出为高*/
Serial.begin(2000000);
led_matrix.begin(); //初始化启动这个对象
led_matrix.renderBitmap(frame, 8, 12); //把LED矩阵的数据写入
wave.sine(50); //产生一个50HZ的sin波形
wave.amplitude(0.25); //设置幅度值为4.7 的1/4
//配置ADC的分辨率最高为14bit
analogReadResolution(14); //change to 14-bit resolution
}
void loop() {
float Rvalue1 = analogRead(A4) * 4.7/16383; //读取A4的引脚电压
float Rvalue2 = analogRead(A5) * 4.7/16383; //读取A5的引脚电压
Serial.print(Rvalue1);
Serial.print(",");
Serial.println(Rvalue2);
delay(2);
}
最后我们把我们的波形在IDE上自带的串口绘图仪展示出来,可以看到基本上波形2是波形1的2倍数据关系。
这个实验中,为了方便展示波形,我们把串口的波特率调整到了最高
6、源代码以及展示视频
- 2024-09-14
-
加入了学习《串口打印Hello EEWorld!》,观看 串口打印
- 2024-09-11
-
发表了主题帖:
【Follow me第二季第2期】+ 入门任务 搭建环境、Blink 、串口打印输出
本帖最后由 cqut面码 于 2024-9-30 00:43 编辑
一、环境的搭建
首先,根据自己电脑的操作系统从官网上下载 Arduino IDE https://www.arduino.cc,进行安装。然后打开Arduino IDE,把Arduino UNO R4 开发板通过type-c 线连接到电脑上。此时,IDE上如下图1中需要选择串口连接上的开发板版本型号,右下角会自动弹出安装对应的软件包,如下图2,点击等待安装完成即可。
图1.选择连接Arduino UNO R4开发板
图2.等待软件包的安装
二、运行Blink
点击文件,新建项目,然后进行保存。第一个我们要实现的是点灯,没错 哈哈哈哈,一个合格的嵌入式工程师就是得会各种点灯。
打开 Arduino UNO R4 的原理图,如下图3,可以看到LED的引脚是P102。
图3. LED引脚控制图
由原理图可知,直接控制P102 高低就可以实现DL4 灯进行翻转。根据Arduino UNO R4的引脚图,图4,可以知道P102是开发板子的D13。
图4. 开发板引脚图
所以代码中直接控制D13就可以了。具体代码如下,主要就是500ms去翻转一次电平,每次翻转前先读取电平,然后再取反电平进行翻转
void setup() {
// put your setup code here, to run once:
pinMode(13, OUTPUT); /* 设置13引脚为输出模式 */
digitalWrite(13, HIGH); /* 默认输出为高*/
}
void loop() {
// put your main code here, to run repeatedly:
delay(500);
digitalWrite(13, !digitalRead(13)); /* 每500ms进行一次LED灯的翻转*/
}
三、串口输出
官方文档告诉了D0 和D1 被用于USB的串口输入和输出。所以不需要我们再进行串口0的IO配置,直接拿来使用就可以
首先初始化设置波特率为115200,然后直接在loop循环函数中每500ms输出一次串口数据,具体代码如下:
/*串口初始化函数*/
void uart_init(uint32_t baud)
{
Serial.begin(baud);
}
void setup() {
// put your setup code here, to run once:
pinMode(13, OUTPUT); /* 设置13引脚为输出模式 */
digitalWrite(13, HIGH); /* 默认输出为高*/
uart_init(115200); /* 串口初始化 */
}
void loop() {
// put your main code here, to run repeatedly:
delay(500);
digitalWrite(13, !digitalRead(13)); /* 每500ms进行一次LED灯的翻转*/
Serial.println("Hello EEWorld !");
}
然后打开串口监视器,设置好波特率为115200,即可看到串口监视器每500ms输出一帧串口数据了。
四、展示视频和源码文件