【Follow me第二季第2期】任务提交:智能家居-环境监测
[复制链接]
本帖最后由 太阳上的骑士 于 2024-10-7 21:19 编辑
一、项目视频
10月7日(1)
EE大学堂视频链接:
https://training.eeworld.com.cn/course/68689
二、任务实现
2.1 物料清单
这次的物料主要是Arduino UNO R4 WiFi开发板和SHT40温湿度传感器扩展板。
2.2.1 入门任务:搭建环境并开启第一步Blink
Arduino IDE下载地址:https://www.arduino.cc/en/software
下载页面选择适合自己操作系统的软件版本,我的是Windows 11,下载的是Windows版。下载后安装Arduino IDE软件并打开,在boards manager搜索UNO R4安装开发板对应的包。至此Arduino UNO R4 WiFi的软件开发环境搭建完成。
下面实现LED Blink,硬件如下:
软件流程图如下:
软件如下:
// the setup function runs once when you press reset or power the board
void setup() {
// initialize digital pin LED_BUILTIN as an output.
pinMode(LED_BUILTIN, OUTPUT);
}
// the loop function runs over and over again forever
void loop() {
digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level)
delay(1000); // wait for a second
digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW
delay(1000); // wait for a second
}
电脑连接开发板,Arduino IDE选择开发板进行连接,编译下载,运行效果如下:
2.2.2 入门任务:串口打印Hello EEWorld!
Arduino UNO R4 WiFi开发板串口使用需要先对串口进行初始化设置,初始化完成后就可以通过串口和外界通信。
软件流程图如下:
代码如下:
void setup() {
// start serial port at 9600 bps and wait for port to open:
Serial.begin(115200);
}
void loop() {
Serial.println("Hello EEWorld!"); // send an initial string
delay(300);
}
编译下载,打开Arduino IDE的Serial Monitor,运行效果如下:
2.3.1 基础任务:驱动12x8点阵LED
Arduino UNO R4 WiFi内置12x8整列LED。硬件如下:
控制LED矩阵灯需要创建帧,然后将帧加载到缓冲区。
要使用LED矩阵库,需要包含#include "Arduino_LED_Matrix.h",
该库提供两种控制方式,一种是创建二维数组,这种方式每个LED需要占用一个字节的内存,内存占用较多。还有一种方式是用3个32bit数据总共96bit数据来控制LED,每个LED占用1bit。
下面代码使所有灯一起闪烁。
软件流程图如下:
软件如下:
#include "Arduino_LED_Matrix.h"
ArduinoLEDMatrix matrix;
void setup() {
Serial.begin(115200);
matrix.begin();
}
const uint32_t lighton[] = {
0,
0,
0
};
const uint32_t lightoff[] = {
0xffffffff,
0xffffffff,
0xffffffff
};
void loop(){
matrix.loadFrame(lighton);
delay(500);
matrix.loadFrame(lightoff);
delay(500);
}
运行效果如下:
也可以安装ArduinoGraphics来打印字符。
软件如下:
// To use ArduinoGraphics APIs, please include BEFORE Arduino_LED_Matrix
#include "ArduinoGraphics.h"
#include "Arduino_LED_Matrix.h"
ArduinoLEDMatrix matrix;
void setup() {
Serial.begin(115200);
matrix.begin();
matrix.beginDraw();
matrix.stroke(0xFFFFFFFF);
delay(2000);
}
void loop() {
// Make it scroll!
matrix.beginDraw();
matrix.stroke(0xFFFFFFFF);
matrix.textScrollSpeed(50);
// add the text
const char text[] = " I Love China!";
matrix.textFont(Font_5x7);
matrix.beginText(0, 1, 0xFFFFFF);
matrix.println(text);
matrix.endText(SCROLL_LEFT);
matrix.endDraw();
}
运行效果如下:
Arduino还提供LED Matrix tool制作动画功能,网页所见即所得,首先给开发板烧录LivePreview例程,再在
里绘制动画页面,连接开发板显示,如果有出现位置对应不对的情况需要更新开发板固件后就能正常显示。
代码如下:
#include "Arduino_LED_Matrix.h" // Include the LED_Matrix library
ArduinoLEDMatrix matrix; // Create an instance of the ArduinoLEDMatrix class
void setup() {
Serial.begin(115200); // Initialize serial communication at a baud rate of 115200
matrix.begin(); // Initialize the LED matrix
}
// Define an array to hold pixel data for a single frame (4 pixels)
uint32_t frame[] = {
0, 0, 0, 0xFFFF
};
void loop() {
// Check if there are at least 12 bytes available in the serial buffer
if(Serial.available() >= 12){
// Read 4 bytes from the serial buffer and compose them into a 32-bit value for each element in the frame
frame[0] = Serial.read() | Serial.read() << 8 | Serial.read() << 16 | Serial.read() << 24;
frame[1] = Serial.read() | Serial.read() << 8 | Serial.read() << 16 | Serial.read() << 24;
frame[2] = Serial.read() | Serial.read() << 8 | Serial.read() << 16 | Serial.read() << 24;
// Load and display the received frame data on the LED matrix
matrix.loadFrame(frame);
}
}
运行效果如下:
2.3.2 基础任务:用DAC生成正弦波
软件如下:
#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 = 100; // in hertz, change accordingly
void setup() {
Serial.begin(115200); // Initialize serial communication at a baud rate of 115200
wave.amplitude(0.1);
wave.sine(freq); // Generate a sine wave with the initial frequency
}
void loop() {
}
流程图如下:
运行效果如下:
2.3.3 基础任务:用OPAMP放大DAC信号
开发板内置运算放大器,官方给出了电压放大的使用方式,硬件连接为:
放大公式为:
Av = Amplified Voltage (V)
R1 = Resistor connected to Ground (Ω)
R2 = Feedback resistor (Ω)
由于手上没有烙铁工具和洞洞板,所以找了一个开发板上的两个电阻来做:
放大倍数为11倍,放大电压低于4.7V,不会损坏硬件。
软件如下:
#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 = 100; // in hertz, change accordingly
void setup() {
Serial.begin(115200); // Initialize serial communication at a baud rate of 115200
wave.amplitude(0.1);
wave.sine(freq); // Generate a sine wave with the initial frequency
if (!OPAMP.begin(OPAMP_SPEED_HIGHSPEED)) {
Serial.println("Failed to start OPAMP!");
}
}
void loop() {
}
流程图如下:
运行效果如下:
2.3.4 基础任务:用ADC采集并且打印数据到串口等其他接口可上传到上位机显示曲线
串口上位机选择SerialChart,方便观察ADC采样数据。
SerialChart设置如下:
[_setup_]
port=COM11
baudrate=115200
width=1000
height=201
background_color = white
grid_h_origin = 100
grid_h_step = 10
grid_h_color = #EEE
grid_h_origin_color = #CCC
grid_v_origin = 0
grid_v_step = 10
grid_v_color = #EEE
grid_v_origin_color = transparent
[_default_]
min=-20
max=18000
[ch1]
color = green
软件如下:
#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 sensorPin = A1; // select the input pin for the potentiometer
int sensorValue = 0; // variable to store the value coming from the sensor
void setup() {
// declare the ledPin as an OUTPUT:
Serial.begin(115200); // Initialize serial communication at a baud rate of 115200
wave.sine(10); // Generate a sine wave with the initial frequency
analogReadResolution(14); //change to 14-bit resolution
}
void loop() {
// read the value from the sensor:
sensorValue = analogRead(sensorPin);
Serial.println(sensorValue);
delay(10); // Delay for one second before repeating
}
流程图如下:
运行效果如下:
2.4 进阶任务:通过Wi-Fi,利用MQTT协议接入到开源的智能家居平台HA(HomeAssistant)
虚拟机安装Ubuntu,Ubuntu下安装docker,docker拉取Home Assistant镜像和EMQX镜像。
环境搭建好以后开发板一直连不上EMQX,但是Ping能Ping通,尝试了两天后怀疑是虚拟机的问题,所以后面使用Windows 11来实现。
Win11安装docker
测试两个容器运行正常
搭建环境好以后测试,开发板还是连不上EMQX,然后使用MQTTX来模拟连接,还是连接不上,怀疑是HOST IP设置问题,尝试172.17.0.3不行,后又尝试localhost使用MQTTX能连接上,172.28.112.1使用MQTTX能连上,但是使用开发板使用172.28.112.1还是连不上。最终找到HOST IP需要设置为电脑网卡IP:192.168.31.7。
软件如下:
#include "WiFiS3.h"
#include <ArduinoMqttClient.h>
char ssid[] = "***"; // your network SSID (name)
char pass[] = "***"; // your network password
char mqtt_user[] = "test";
char mqtt_pass[] = "test";
WiFiClient wifiClient;
MqttClient mqttClient(wifiClient);
const char broker[] = "192.168.31.7"; //IP address of the EMQX broker.
int port = 1883;
const char subscribe_topic[] = "UNO/arduino/myButtonA/cmd_t";
const char publish_topic[] = "UNO/arduino/myButtonA/cmd_t";
void setup() {
// Create serial connection and wait for it to become available.
Serial.begin(115200);
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, LOW );
while (!Serial) {
;
}
// Connect to WiFi
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();
delay(2000);
// You can provide a username and password for authentication
mqttClient.setUsernamePassword(mqtt_user, mqtt_pass);
Serial.print("Attempting to connect to the MQTT broker.");
if (!mqttClient.connect(broker, port)) {
Serial.print("MQTT connection failed! Error code = ");
Serial.println(mqttClient.connectError());
while (1);
}
Serial.println("You're connected to the MQTT broker!");
Serial.print("Subscribing to topic: ");
Serial.println(subscribe_topic);
// subscribe to a topic
mqttClient.subscribe(subscribe_topic);
// topics can be unsubscribed using:
// mqttClient.unsubscribe(topic);
Serial.print("Waiting for messages on topic: ");
Serial.println(subscribe_topic);
}
void loop() {
static bool state = false;
int messageSize = mqttClient.parseMessage();
if (messageSize) {
// use the Stream interface to print the contents
while (mqttClient.available()) {
Serial.print((char)mqttClient.read());
}
Serial.println();
state = ~state;
if(state)
digitalWrite(LED_BUILTIN, HIGH );
else
digitalWrite(LED_BUILTIN, LOW );
}
// send message, the Print interface can be used to set the message contents
// delay(1000);
// mqttClient.beginMessage(publish_topic);
// mqttClient.print(random(1000));
// mqttClient.endMessage();
}
流程图如下:
运行效果如下:
2.5 扩展任务:通过外部SHT40温湿度传感器,上传温湿度到HA,通过HA面板显示数据
安装SHT40库:
配置文件添加信息:
- unique_id: SHT40
name: "SHT40_Template"
state_topic: "UNO/arduino/sht40/template"
unit_of_measurement: "℃"
value_template: "{{ value }}"
软件如下:
#include "WiFiS3.h"
#include <ArduinoMqttClient.h>
#include "DFRobot_SHT40.h"
DFRobot_SHT40 SHT40(SHT40_AD1B_IIC_ADDR);
uint32_t id = 0;
float temperature, humidity;
char ssid[] = "***"; // your network SSID (name)
char pass[] = "***"; // your network password
char mqtt_user[] = "test";
char mqtt_pass[] = "test";
WiFiClient wifiClient;
MqttClient mqttClient(wifiClient);
const char broker[] = "192.168.31.7"; //IP address of the EMQX broker.
int port = 1883;
const char subscribe_topic[] = "UNO/arduino/sht40/template";
const char publish_topic[] = "UNO/arduino/sht40/template";
void setup() {
// Create serial connection and wait for it to become available.
Serial.begin(115200);
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, LOW );
SHT40.begin();
while((id = SHT40.getDeviceID()) == 0){
Serial.println("ID retrieval error, please check whether the device is connected correctly!!!");
delay(1000);
}
while (!Serial) {
;
}
// Connect to WiFi
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();
delay(2000);
// You can provide a username and password for authentication
mqttClient.setUsernamePassword(mqtt_user, mqtt_pass);
Serial.print("Attempting to connect to the MQTT broker.");
if (!mqttClient.connect(broker, port)) {
Serial.print("MQTT connection failed! Error code = ");
Serial.println(mqttClient.connectError());
while (1);
}
Serial.println("You're connected to the MQTT broker!");
Serial.print("Subscribing to topic: ");
Serial.println(subscribe_topic);
// subscribe to a topic
mqttClient.subscribe(subscribe_topic);
// topics can be unsubscribed using:
// mqttClient.unsubscribe(topic);
Serial.print("Waiting for messages on topic: ");
Serial.println(subscribe_topic);
}
// void update_sensor(int value){
// StaticJsonDocument<200> doc;
// int a = value*100/1024;
// open_window(a);
// doc["light"] = a;
// String payload;
// serializeJson(doc, payload);
// mqttClient.beginMessage("homeassistant/sensor/light");
// mqttClient.print(payload.c_str());
// mqttClient.print("\0");
// mqttClient.endMessage();
// }
unsigned long previousMillis = 0;
void loop() {
static bool state = false;
unsigned long currentMillis = millis();
int messageSize = mqttClient.parseMessage();
if (messageSize) {
// use the Stream interface to print the contents
while (mqttClient.available()) {
Serial.print((char)mqttClient.read());
}
Serial.println();
state = ~state;
if(state)
digitalWrite(LED_BUILTIN, HIGH );
else
digitalWrite(LED_BUILTIN, LOW );
}
if (currentMillis - previousMillis >= 1000)
{
previousMillis = currentMillis;
temperature = SHT40.getTemperature(/*mode = */PRECISION_HIGH);
humidity = SHT40.getHumidity(/*mode = */PRECISION_HIGH);
Serial.print("Temperature :"); Serial.print(temperature); Serial.println(" C");
Serial.print("Humidity :"); Serial.print(humidity); Serial.println(" %RH");
mqttClient.beginMessage("UNO/arduino/sht40/template");
mqttClient.print(temperature);
mqttClient.print("\0");
mqttClient.endMessage();
}
// int time = 0;
// temperature = SHT40.getTemperature(/*mode = */PRECISION_HIGH);
// humidity = SHT40.getHumidity(/*mode = */PRECISION_HIGH);
// Serial.print("Temperature :"); Serial.print(temperature); Serial.println(" C");
// Serial.print("Humidity :"); Serial.print(humidity); Serial.println(" %RH");
// delay(1000);
}
流程图如下:
运行效果如下:
2.6 心得体会
很感谢EEWORLD和得捷举办这次活动,让我有机会实际使用Docker和MQTT,这些都是以前有听过但没实际尝试过,期待在以后的生产环境中运用这些工具。
三、可编译下载的代码
|