- 2024-10-03
-
发表了主题帖:
【Follow me第二季第2期】一文全面完成任务
本帖最后由 金玉其中 于 2024-10-31 15:40 编辑
视频链接:https://training.eeworld.com.cn/video/41231
[localvideo]06051b9dd994149c47eb26948d9b04bf[/localvideo]
本次有幸参与得捷电子Follow Me第二季第2期活动,非常感谢论坛和得捷电子。Follow me活动是DigiKey联合EEWorld发起的大型开发板体验活动,每期技术大咖推荐可玩性与可学性较强的开发板/仪器套件,带着大家实际操作,我这次也是主要秉承着学习的态度进行本次的活动,实际上很早就已经收到了采购到的器件,不过还是等到大佬们都完成了才开始我的学习之旅。
一、主要器件
主开发板:Arduino UNO R4 WiFi
Arduino UNO R4 WiFi 是一款基于32位Arm® Cortex®-M4 Renesas RA4M1微控制器,具有用于 Wi-Fi® 和蓝牙连接的ESP32模块,具备强大的计算能力和多种连接功能。该板SRAM 32kB,闪存256kB,时钟频率为48MHz,USB端口升级为USB-C,并且最大电源供应电压增加到24V。该板提供了一个CAN总线,允许用户通过连接多个扩展板来最小化布线并执行不同的任务。
板载的Qwiic 连接器可以方便地创建即插即用风格的项目。本次的传感板也都是符合Qwiic 连接器接口的传感器。同时本次活动也提供详尽的开发板资料供我们查略。
传感器1:LTR-329光传感器扩展板
LTR-329ALS-01是一款低压I2C数字光传感器[ALS],采用低成本微型芯片无铅表面贴装封装。该传感器将光强度转换为能够直接I2C接口的数字输出信号。它在0.01勒克斯至64k勒克斯的宽动态范围内提供线性响应,非常适合高环境亮度下的应用。总共有六种增益设置(1X、2X、4X、8X、48X和96X)可供用户配置。
传感器2:SHT40温湿度传感器扩展板
SHT4x是一个数字传感器平台,用于测量不同精度等级的相对湿度和温度。其I2C接口提供多个预配置的I2C地址,同时保持超低功耗预算(0.4μW)。功率微调的内部加热器可以在三个加热水平下使用,从而使传感器能够在要求苛刻的环境中运行。四针双扁平无引线封装适用于表面贴装技术(SMT)加工,包括可选的封装专利PTFE[1]膜或可拆卸的保护盖。可提供符合ISO17025的传感器特定校准证书,可通过唯一序列号进行识别。
秉承着尽可能多的学习,这次直接采购的两个传感器来完成任务,说实话,正好极限的覆盖了,最好的利用方式,线就没有买了,自己做一下就可以了,而且这两个传感器可以直接串联起来,使用一个Qwiic 连接器接口皆可以,毕竟就是多了几个现实参数,在完成物联网显示的时候,显示一个和显示两个没什么差异。
二、学习成果展示
1、配置开发环境
本次使用的是官方的开发环境,Arduino IDE,可以通过官网下载适配系统的最新版:
注意哦,还有免安装版本,秉承着能省一步是一本,直接免安装无脑启动;
通过USB线连接开发板和PC,软件可以直接检测到连接到的开发板:
然后就可以通过开发板安装对应的基础库了,通过开发板管理器进行搜索:
2、入门任务:搭建环境并开启第一步Blink / 串口打印Hello EEWorld!
编程的开始就是实现点灯,我们新建一个工程:
显然,存在两个关键函数:setup()和 loop()。其中,setup()扮演着初始化配置的角色,仅执行一次以设置初始状态;而 loop()则负责循环执行的内容,持续不断地运行以维持或改变程序的状态。
Arduino的卓越之处,在于其高度集成化的特性,让我们无需深究硬件的繁复细节,仅凭固件内预设的函数便能轻松驾驭。尽管如此,为了更全面地理解,我们还是简要概览一下LED的硬件配置:
可以看出来只有DL4是实际上我们可以控制的,DL3是供电只是等,另外两个是串口传输指示。对于LED和串口的控制不需要而外的固件,板载固件就可以使用,我们实现一下任务:
void setup() {
// put your setup code here, to run once:
pinMode(LED_BUILTIN, OUTPUT);
Serial.begin(9600);
}
void loop() {
// put your main code here, to run repeatedly:
// turn the LED on (HIGH is the voltage level)
digitalWrite(LED_BUILTIN, HIGH);
// wait for a second
delay(500);
// turn the LED off by making the voltage LOW
digitalWrite(LED_BUILTIN, LOW);
// wait for a second
delay(500);
Serial.println("Hello EEWorld!");
}
本次的任务还是比较简单,毕竟是入门的第一个任务,对上面的程序进行一下简单的介绍,本次任务主要用到的LED串口口,我们需要进行一下相应的初始化,可以看到初始化直接调用一个函数就本上就完成了,通过不同的板子的库文件,内部都已经进行好了关联,直接配置重要的参数就可以,然后就是阻塞式的实现LED的闪烁,并同时循环的发送“Hello EEWorld!”。
点击上传会自动进行工程的编译和下载,然后就可以通过观察板子的L等和IDE自带的串口监视器进行效果观察了:
注意配置好波特率。
3、基础任务:驱动12x8点阵LED;用DAC生成正弦波;用OPAMP放大DAC信号;用ADC采集并且打印数据到串口等其他接口可上传到上位机显示曲线。
其实这个任务是一个组合任务,可以拆分出多个任务,比如驱动LED、DAC输出正弦波、OPAMP信号放大、ADC的采集并通过接口上传显示。可以拆分出多个不相关的任务,为了实现更好的效果展示,我们经过拆分和再组合,分成了下面三个小任务:
第一个就是12x8点阵LED点阵的控制;
第二个就是DAC生成正弦波,然后通过OPAMP放大2倍,在通过ADC采集信号进行串口输出,这里面我们可以通过示波器进行对应节点的一个测量,例如DAC的输出,放大信号的输出,都可以通过示波器进行状态展示。
接下来我们先看看12x8点阵LED点阵的控制:
基本硬件如上图,也通过各位大佬的学习,有的人是通过静态显示的方法实现点阵的设计实现不同字符的显示,也有人通过不同的库文件实现动态的显示,个人也比较喜欢动态显示的方式,有点大街上小店的横幅的感觉。
点阵的LED的基础库是"Arduino_LED_Matrix.h",而动态显示文本的库是"ArduinoGraphics.h",注意ArduinoGraphics需要单独安装:
#include "Arduino_LED_Matrix.h"
#include "ArduinoGraphics.h"
ArduinoLEDMatrix matrix;
void setup() {
matrix.begin();
}
void loop() {
matrix.beginDraw();
matrix.stroke(0xFFFFFFFF);
matrix.textScrollSpeed(50);
const char text[] = " EEWorld && DigiKey ";
matrix.textFont(Font_5x7);
matrix.beginText(0, 1, 0xFFFFFF);
matrix.println(text);
matrix.endText(SCROLL_LEFT);
matrix.endDraw();
}
接下来就是模拟部分的控制:
DAC输出:我们直接使用内置的"analogWave.h",由于后面的实验要求,我们需要限制一下幅值,具体代码如下:
#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); // Initialize serial communication at a baud rate of 115200
pinMode(A0, OUTPUT);
wave.amplitude(0.25); //设置幅度值为4.7 的1/4
wave.sine(freq); // Generate a sine wave with the initial frequency
}
void loop() {
// Read an analog value from pin A5 and map it to a frequency range
delay(500);
}
结果如下:
接下来是放大部分,需要使用OPAMP,启动OPAMP很方便:
#include "analogWave.h"
#include <OPAMP.h>
void setup() {
Serial.begin(115200);
pinMode(A0, OUTPUT);
wave.amplitude(0.25);
wave.sine(freq);
OPAMP.begin(OPAMP_SPEED_HIGHSPEED);
}
同时需要进行外部的连接:
有上图也可以看到,Vpp的幅值有1.23V增加到了2.44V,我是用的是两个一样的电阻,所以是增加两倍的效果。
接下来我们将A3和A5连接,是的,我们准备用A5进行ADC采集,一下为本阶段最终代码:
#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 = 10; // in hertz, change accordingly
void setup() {
Serial.begin(115200); // Initialize serial communication at a baud rate of 115200
pinMode(A0, OUTPUT);
pinMode(A5, INPUT);
analogReadResolution(12);// 设置 ADC 分辨率为 12 位
wave.amplitude(0.25); //设置幅度值为4.7 的1/4
wave.sine(freq); // Generate a sine wave with the initial frequency
OPAMP.begin(OPAMP_SPEED_HIGHSPEED);
}
void loop() {
// Read an analog value from pin A5 and map it to a frequency range
int value = analogRead(A5);// 读取 ADC 值
Serial.println(value);
}
效果显示还是不太理想,主要是显示个数限制太厉害了,不过也是可以看到趋势的:
4、进阶任务及扩展任务
通过对任务的分析,实际上进阶任务和扩展任务是一致的内容,都是通过本开发板实现和HomeAssistant智能家居平台进行通信,这里通过时板载的wifi功能,通信协议为Mqtt。
将任务打碎后重组,我们需要完成一下三个工作:
第一:实现传感器数据的采集,也就是SH40和光传感器数据的采集,这一部分还不涉及无线通信能力,通过接口连接,实现数据采集后通过串口进行数据打印即可,可以通过串口工具进行查看;
第二:HomeAssistant智能家居平台的操作实现,HA支持很多种系统,我们需要实现HA平台的搭建工作;
第三:实现wifi的驱动,同时配置Mqtt协议的相关参数,实现和HomeAssistant智能家居平台的沟通,实现SH40和光传感器数据的在线查看。
接下来就实现过程:
通过串联的方式连接传感器,安装对应的传感器库:
首先进行两个传感器的初始化:
#include "Adafruit_SHT4x.h"
#include "Adafruit_LTR329_LTR303.h"
Adafruit_SHT4x sht4;
Adafruit_LTR329 ltr = Adafruit_LTR329();
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
if ( ! ltr.begin(&Wire1) ) {
Serial.println("Couldn't find LTR sensor!");
while (1) delay(10);
}
Serial.println("Found LTR sensor!");
ltr.setGain(LTR3XX_GAIN_2);
Serial.print("Gain : ");
switch (ltr.getGain()) {
case LTR3XX_GAIN_1: Serial.println(1); break;
case LTR3XX_GAIN_2: Serial.println(2); break;
case LTR3XX_GAIN_4: Serial.println(4); break;
case LTR3XX_GAIN_8: Serial.println(8); break;
case LTR3XX_GAIN_48: Serial.println(48); break;
case LTR3XX_GAIN_96: Serial.println(96); break;
}
ltr.setIntegrationTime(LTR3XX_INTEGTIME_100);
Serial.print("Integration Time (ms): ");
switch (ltr.getIntegrationTime()) {
case LTR3XX_INTEGTIME_50: Serial.println(50); break;
case LTR3XX_INTEGTIME_100: Serial.println(100); break;
case LTR3XX_INTEGTIME_150: Serial.println(150); break;
case LTR3XX_INTEGTIME_200: Serial.println(200); break;
case LTR3XX_INTEGTIME_250: Serial.println(250); break;
case LTR3XX_INTEGTIME_300: Serial.println(300); break;
case LTR3XX_INTEGTIME_350: Serial.println(350); break;
case LTR3XX_INTEGTIME_400: Serial.println(400); break;
}
ltr.setMeasurementRate(LTR3XX_MEASRATE_200);
Serial.print("Measurement Rate (ms): ");
switch (ltr.getMeasurementRate()) {
case LTR3XX_MEASRATE_50: Serial.println(50); break;
case LTR3XX_MEASRATE_100: Serial.println(100); break;
case LTR3XX_MEASRATE_200: Serial.println(200); break;
case LTR3XX_MEASRATE_500: Serial.println(500); break;
case LTR3XX_MEASRATE_1000: Serial.println(1000); break;
case LTR3XX_MEASRATE_2000: Serial.println(2000); break;
}
// You can have 3 different precisions, higher precision takes longer
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;
}
// 6 different heater settings
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;
}
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);
}
}
初始化成功:
循环读取程序就简单的多了:
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);
}
}
sensors_event_t humidity, temp;
sht4.getEvent(&humidity, &temp);// populate temp and humidity objects with fresh data
float tem = temp.temperature;
Serial.println("Temp *C = " + String(tem));
float hum = humidity.relative_humidity;
Serial.println("Hum. % = " + String(hum));
读取成功:
接下来就是实现HA的通信和数据上传,这一部分主要包括的事HA系统的安装和,由于每个人使用的都不一样,可以看到有容器版的,有用树莓派的,也有用虚拟机的,对于当前的情况来说,使用虚拟机会比较方便一点,毕竟没有多余的硬件。这里根据官方的安装指南可以实现非常方便的安装,咱们打开HA看一下:
主要是需要加入mqtt固件,并通过MQTT模拟器进行设备和实体的注册,我们需要确认光照传感器有一个参数,SH40有两个参数,为此,我们创建三个实体:
接下来就是通过Mqtt,配置基本参数,主要是往"homeassistant/sensor/Roomsensor/state"写对应的数据:
char ssid[] = "开发板连接的wifi";
char pass[] = "开发板连接的wifi密码";
const char broker[] = "目标地址ip";
int port = 1883;
const char state_topic[] = "homeassistant/sensor/Roomsensor/state";
然后就是循环采集发送:
void loop() {
// put your main code here, to run repeatedly:
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);
}
}
sensors_event_t humidity, temp;
sht4.getEvent(&humidity, &temp);// populate temp and humidity objects with fresh data
float tem = temp.temperature;
Serial.println("Temp *C = " + String(tem));
float hum = humidity.relative_humidity;
Serial.println("Hum. % = " + String(hum));
dataObj["light"] = visible_plus_ir;
dataObj["hum"] = hum;
dataObj["tem"] = tem;
String jsonString1 = JSON.stringify(dataObj);
mqttClient.beginMessage(state_topic);
mqttClient.print(jsonString1);
mqttClient.endMessage();
delay(1000);
}
整体软件流程:
结果如下:
遮挡一下:
这里需要注意一下,串口的通信可能会影响Mqtt的连接,之前一直报错,反应的是目标地址访问被拒绝,后来加个while (!Serial)解决的。
代码汇总:
大家可以下载代码直接进行修改测试,入门任务以及进阶任务都是比较简单的,进阶任务还是挺让人回味的
总结:
本次的活动主要依着学习的态度进行,确实Arduino的各种丰富的固件非常适合功能验证,也感谢论坛和各位网友的精彩分享。
-
加入了学习《【Follow me第二季第2期】任务视频》,观看 【Follow me第二季第2期】
- 2024-02-06
-
回复了主题帖:
“写一副工程师专属的对联,赢新年甜蜜首礼!”颁奖啦!
个人地址确认无误,估计到不了了,我们三十放假
- 2024-01-29
-
回复了主题帖:
写一副工程师专属的对联,赢新年甜蜜首礼!
上联:代码间调试器,电子精英创未来
下联:创新中实践者,科技力量谱新篇
横批:智造辉煌
-
回复了主题帖:
来聊个五毛钱的天,聊聊未来科技发展
相对于未来的憧憬,我刚喜欢对过于的未知,南无袈裟理科佛申请出战