活动链接:https://www.eeworld.com.cn/huodong/digikey_follow_me_2024_02/
视频链接:https://training.eeworld.com.cn/video/41236
代码链接:https://download.eeworld.com.cn/detail/eew_KAQaik/634540
项目链接:https://github.com/StarSphere-1024/DigiKey_Follow_me_II
一、主要器件
1.开发板:Arduino UNO R4 WiFi
二、学习成果展示
1、配置开发环境
由于个人习惯,这里不使用官方的开发环境,而是使用VScode + PlatformIO作为开发环境。
下面演示步骤:
1.下载VScode
下载链接:https://code.visualstudio.com/
根据提示安装即可
2.安装PlatformIO插件
打开VScode进入扩展页面,搜索PlatformIO,选择第一个安装
安装完成后自动弹出Home页面
3.创建项目
在Home页面单击New Project来创建项目
第一个栏Project Name我这里填写test
第二栏选择开发板,键入UNO R4,选择Arduino UNO R4 WiFi
单击Finish,IDE将自动创建项目文件,打开src下的main.cpp即可编写代码了
搭建环境并开启第一步Blink
软件流程图:
按照上面的创建项目流程创建Blink项目
在main.cpp写上如下代码
#include <Arduino.h>
// put function declarations here:
void setup() {
// put your setup code here, to run once:
pinMode(LED_BUILTIN ,OUTPUT);
}
void loop() {
// put your main code here, to run repeatedly:
digitalWrite(LED_BUILTIN,HIGH);
delay(500);
digitalWrite(LED_BUILTIN,LOW);
delay(500);
}
// put function definitions here:
然后单击此处进行编译
编译完成后,连接上开发板,单击上传按钮烧录代码
烧录完成后可以看到板载LED成功闪烁
串口打印Hello EEWorld!
流程同上,写入如下代码,编译上传
#include <Arduino.h>
void setup() {
Serial.begin(9600);
}
void loop() {
Serial.println("Hello EEWorld!");
delay(1000);
}
然后单击此处打开串口监视器
可以看到串口监视器上不断打印Hello EEWorld!
3、基础任务:
驱动12x8点阵LED;
这里我选择绘制一个简单的笑脸
软件流程图:
#include "Arduino_LED_Matrix.h"
ArduinoLEDMatrix matrix;
void setup() {
Serial.begin(115200);
matrix.begin();
}
uint8_t frame[8][12] = {
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
};
void leftEye(){
//Left eye
frame[1][3] = 1;
frame[1][4] = 1;
frame[2][3] = 1;
frame[2][4] = 1;
}
void wink(){
//Wink with the left eye
frame[1][3] = 0;
frame[1][4] = 0;
frame[2][3] = 1;
frame[2][4] = 1;
}
void rightEye(){
//Right eye
frame[1][8] = 1;
frame[1][9] = 1;
frame[2][8] = 1;
frame[2][9] = 1;
}
void mouth(){
//Mouth
frame[5][3] = 1;
frame[5][9] = 1;
frame[6][3] = 1;
frame[6][4] = 1;
frame[6][5] = 1;
frame[6][6] = 1;
frame[6][7] = 1;
frame[6][8] = 1;
frame[6][9] = 1;
}
void loop(){
leftEye();
rightEye();
mouth();
matrix.renderBitmap(frame, 8, 12);
delay(1000);
wink();
matrix.renderBitmap(frame, 8, 12);
delay(1000);
}
编译上传,即可看到在眨眼的笑脸了
用DAC生成正弦波;
软件流程图:
#include "analogWave.h"
analogWave wave(DAC);
int freq = 5;
void setup() {
Serial.begin(9600);
wave.sine(freq);
}
void loop() {
}
这里使用树莓派pico的ADC功能来检测正弦波波形
编译上传代码后,在上位机上可以看到成功生成了正弦波
用OPAMP放大DAC信号;
软件流程图:
#include <OPAMP.h>
#include "analogWave.h"
analogWave wave(DAC);
int freq = 3;
void setup () {
OPAMP.begin();
wave.sine(freq);
wave.amplitude(0.3);
}
void loop() {
}
再按照如下图示接线
实物接线如图
这里使用之前A0的DAC正弦波作为输入源,并将输入源和输出源一同接入树莓派Pico的两个ADC引脚
编译烧录后,可在上位机看到波形成功被放大了一倍
用ADC采集并且打印数据到串口等其他接口可上传到上位机显示曲线。
软件流程图:
#include <OPAMP.h>
#include "analogWave.h" // Include the library for analog waveform generation
analogWave wave(DAC);
int freq = 3;
void setup () {
Serial.begin(9600);
analogReadResolution(14);
wave.sine(freq);
wave.amplitude(0.5);
OPAMP.begin(OPAMP_SPEED_HIGHSPEED);
}
void loop() {
uint16_t dac_u16= analogRead(A4);// DAC output
uint16_t opamp_u16=analogRead(A5);// OPAMP output
double dac=dac_u16*5.5/65535;
double opamp=opamp_u16*5.5/65535;
Serial.print(dac);
Serial.print(",");
Serial.println(opamp);
delay(10);
}
这里直接使用Arduino的A4和A5引脚作为ADC,代替上个任务的树莓派Pico读取波形
编译上传,成功看到波形
4、进阶任务:
通过Wi-Fi,利用MQTT协议接入到开源的智能家居平台HA(HomeAssistant)
首先是安装HomeAssitant和EMQX
我直接是按照这个步骤来的https://bbs.eeworld.com.cn/thread-1293807-1-1.html
两个都成功安装完毕。
然后是代码,这里就简单实现下接入MQTT,接入HA在扩展任务中实现
首先来安装一下PubSubClient和ArduinoJson这两个库。
在PlatformIO添加库非常简单,打开PIO Home页面,点击Libraries,在搜索框中输入PubSubClient
点击搜索,可以看到检索出了很多库
直接选择第一个,进入
然后单击Add to Project
选择创建好的项目,点击Add按钮就直接添加完毕了
软件流程图:
#include <WiFi.h>
#include <PubSubClient.h>
#include <ArduinoJson.h>
// 设置WIFI
const char *ssid = "Mi4A-STAR";
const char *password = "star123!";
// 设置MQTT(EMQX)
const IPAddress mqttServer(192, 168, 31, 198);
const uint16_t mqtt_port = 1883;
const char *mqtt_user = "star";
const char *mqtt_pass = "sora";
WiFiClient wifiClient;
PubSubClient mqttClient(wifiClient);
void connectToWiFi()
{
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
// 等待WiFi连接,成功连接后输出成功信息
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi Connected!");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
}
void connectToMQTTServer()
{
String clientId = "ArduinoClient";
Serial.print("Attempting MQTT connection...");
// 连接MQTT服务器
if (mqttClient.connect(clientId.c_str(), mqtt_user, mqtt_pass))
{
Serial.println("MQTT Server Connected.");
Serial.print("Server Address: ");
Serial.println(mqttServer);
Serial.print("ClientId: ");
Serial.println(clientId);
}
else
{
Serial.print("failed, rc=");
Serial.print(mqttClient.state());
Serial.println(" try again in 5 seconds");
// Wait 5 seconds before retrying
delay(5000);
}
}
void callback(char *topic, byte *payload, unsigned int length)
{
Serial.print("Message arrived [");
Serial.print(topic);
Serial.println("] ");
// 解析 JSON 消息
StaticJsonDocument<512> doc;
DeserializationError error = deserializeJson(doc, payload);
// 检查解析是否成功
if (error)
{
Serial.print("JSON parse failed: ");
Serial.println(error.c_str());
return;
}
serializeJsonPretty(doc, Serial);
}
void setup()
{
Serial.begin(9600);
// 连接WiFi
connectToWiFi();
// 设置MQTT服务器和端口号
mqttClient.setServer(mqttServer, mqtt_port);
mqttClient.setCallback(callback);
// 连接MQTT服务器
connectToMQTTServer();
mqttClient.subscribe("testtopic/#");
}
void loop()
{
if (mqttClient.connected())
{ // 如果开发板成功连接服务器
mqttClient.loop(); // 保持客户端心跳
}
else
{ // 如果开发板未能成功连接服务器
connectToMQTTServer(); // 则尝试连接服务器
}
}
烧录代码后打开串口监视器,可以看到成功连上了WiFi并接入了MQTT
EMQX里也显示Arduino连上了
5、扩展任务二:
通过外部SHT40温湿度传感器,上传温湿度到HA,通过HA面板显示数据
首先把SHT40传感器接上
然后和进阶任务一样先添加PubSubClient和ArduinoJson库,除此之外还需要添加Adafruit_SHT4x驱动库
可以直接在platformio.ini文件添加如下内容,保存后,PlatformIO将自动添加对应的库文件
lib_deps =
bblanchon/ArduinoJson@^7.2.0
knolleary/PubSubClient@^2.8
adafruit/Adafruit SHT4x Library@^1.0.5
软件流程图:
#include <Arduino.h>
#include <WiFiS3.h>
#include <PubSubClient.h>
#include <ArduinoJson.h>
#include <Adafruit_SHT4x.h>
#include <string> // 添加string库
// 设置WIFI和MQTT参数
const char *ssid = "Mi4A-STAR";
const char *password = "star123!";
const IPAddress mqttServer(192, 168, 31, 198);
const uint16_t mqttPort = 1883;
const char *mqttUser = "star";
const char *mqttPass = "sora";
WiFiClient wifiClient;
PubSubClient mqttClient(wifiClient);
Adafruit_SHT4x sht40 = Adafruit_SHT4x();
// 连接WiFi
void connectToWiFi()
{
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}
Serial.println("\nWiFi Connected!");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
}
// 连接MQTT服务器
void connectToMQTTServer()
{
String clientId = "ArduinoClient";
Serial.print("Attempting MQTT connection...");
if (mqttClient.connect(clientId.c_str(), mqttUser, mqttPass))
{
Serial.println("MQTT Server Connected.");
}
else
{
Serial.print("failed, rc=");
Serial.print(mqttClient.state());
Serial.println(" try again in 5 seconds");
delay(5000);
}
}
// 发布传感器配置信息
void publishSensorConfig(const char *sensor, const char *name, const char *unit, const char *unique_id)
{
String topic = String("homeassistant/sensor/") + sensor + "/config"; // 自动补全topic
String state_topic = String("homeassistant/sensor/") + sensor + "/state"; // 自动补全topic
StaticJsonDocument<256> doc;
char buffer[256];
doc["name"] = name;
doc["state_topic"] = state_topic.c_str();
doc["unit_of_measurement"] = unit;
doc["value_template"] = "{{ value_json.state }}";
doc["unique_id"] = unique_id;
serializeJson(doc, buffer);
mqttClient.publish(topic.c_str(), buffer);
Serial.print(sensor);
Serial.println("sensor config success");
Serial.println(topic);
Serial.println(buffer);
Serial.println();
}
// 发布传感器状态信息
void publishSensorState(const char *sensor, float value)
{
String topic = String("homeassistant/sensor/") + sensor + "/state"; // 自动补全topic
StaticJsonDocument<64> doc;
char buffer[64];
doc["state"] = value;
serializeJson(doc, buffer);
mqttClient.publish(topic.c_str(), buffer);
}
void callback(char *topic, byte *payload, unsigned int length)
{
// 此处代码保留,可以用于接收HomeAssistant的控制信息
}
void setup()
{
Serial.begin(9600);
connectToWiFi();
mqttClient.setServer(mqttServer, mqttPort);
mqttClient.setCallback(callback);
connectToMQTTServer();
if (!sht40.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(sht40.readSerial(), HEX);
}
sht40.setPrecision(SHT4X_HIGH_PRECISION);
sht40.setHeater(SHT4X_NO_HEATER);
publishSensorConfig("temperature", "Temperature Sensor", "°C", "temperature_sensor");
publishSensorConfig("humidity", "Humidity Sensor", "%", "humidity_sensor");
}
void loop()
{
if (!mqttClient.connected())
{
connectToMQTTServer();
}
else
{
mqttClient.loop();
sensors_event_t humidity, temperature;
sht40.getEvent(&humidity, &temperature);
float temp = temperature.temperature;
float humi = humidity.relative_humidity;
Serial.print("temperature:");
Serial.println(temp);
Serial.print("humidity:");
Serial.println(humi);
Serial.println();
publishSensorState("temperature", temp);
publishSensorState("humidity", humi);
delay(5000);
}
}
编译上传,然后打开串口监视器
可以看到成功在HA创建了配置并发送了温湿度数据
HA面板也成功出现了传感器数据
三、心得体会
这次活动虽然不难,但我依然学会了不少东西,首先就是OPAMP,以前从来没接触过,看了网上不少资料才知道是怎么回事。再就是MQTT,以前了解过,但也仅停留在了解,通过这次活动我才真正实践了MQTT,也算是一次经验积累。然后建议的话,感觉就是基础任务的DAC,OPAMP,ADC完全可以合在一起作为一个任务,分成三个比较繁琐。总之,算是顺利的完成了这次活动,希望以后还有机会参加类似的活动。
本帖最后由 starsphere 于 2024-10-31 14:53 编辑