[作品提交] 【Follow me第二季第2期】Arduino UNO R4 WiFi 全部任务汇总

starsphere   2024-10-7 12:22 楼主

活动链接: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

   F1BF338230C25EC0BF3B8EF37A7106F5.jpg  
2.传感器:SHT40温湿度传感器扩展板

   07560BC16D30D1B8D4F438BD81E26533.jpg  

二、学习成果展示

1、配置开发环境

由于个人习惯,这里不使用官方的开发环境,而是使用VScode + PlatformIO作为开发环境。

下面演示步骤:

1.下载VScode

下载链接:https://code.visualstudio.com/

根据提示安装即可

2.安装PlatformIO插件

打开VScode进入扩展页面,搜索PlatformIO,选择第一个安装

截图 2024-10-04 11-14-24.png  

安装完成后自动弹出Home页面

截图 2024-10-04 11-16-26.png

3.创建项目

在Home页面单击New Project来创建项目

第一个栏Project Name我这里填写test

第二栏选择开发板,键入UNO R4,选择Arduino UNO R4 WiFi

  截图 2024-10-04 11-19-19.png  

单击Finish,IDE将自动创建项目文件,打开src下的main.cpp即可编写代码了

截图 2024-10-04 11-21-23.png  2、入门任务:

搭建环境并开启第一步Blink

软件流程图:

image.png  

按照上面的创建项目流程创建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:

然后单击此处进行编译

6eb209b886604f84bdbe33058baa2940.png  

编译完成后,连接上开发板,单击上传按钮烧录代码

bce909149010af3fcffacddfe0181bbf.png  

烧录完成后可以看到板载LED成功闪烁

   A44C20BAE43A534AA9361FA0FBC95381.jpg  

串口打印Hello EEWorld!

流程同上,写入如下代码,编译上传

#include <Arduino.h>
void setup() {
  Serial.begin(9600);
}
void loop() {
  Serial.println("Hello EEWorld!");
  delay(1000);
}

然后单击此处打开串口监视器

1e5e14575fa6f7dafc24e7aec174c091.png  

可以看到串口监视器上不断打印Hello EEWorld!

image.png  

3、基础任务:

驱动12x8点阵LED;

这里我选择绘制一个简单的笑脸

软件流程图:

image.png  

#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);
}

编译上传,即可看到在眨眼的笑脸了

40564581DBD7689F567CC8B26426118B.jpg   D1A532B130A2CDECF72AA34055CABF89.jpg  

 

用DAC生成正弦波;

软件流程图:

image.png  

#include "analogWave.h"

analogWave wave(DAC);

int freq = 5;

void setup() {
  Serial.begin(9600);
  wave.sine(freq);
}

void loop() {
  
}

这里使用树莓派pico的ADC功能来检测正弦波波形

B3F82A25197699BCDFC1522B0A637DEF.jpg  

编译上传代码后,在上位机上可以看到成功生成了正弦波

截图 2024-10-05 17-28-56.png  

用OPAMP放大DAC信号;

软件流程图:

image.png  

#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() {
}

再按照如下图示接线

094505kf0fhz4c225v9wht.png  

实物接线如图

     13DB603E1ECDC729680F317EB4B04B25.jpg  

这里使用之前A0的DAC正弦波作为输入源,并将输入源和输出源一同接入树莓派Pico的两个ADC引脚

编译烧录后,可在上位机看到波形成功被放大了一倍

截图 2024-10-05 18-24-50.png  

用ADC采集并且打印数据到串口等其他接口可上传到上位机显示曲线。

软件流程图:

image.png  

#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读取波形

24AF5D71F6CE9BE1248FF54A0B31F322.jpg  

编译上传,成功看到波形

截图 2024-10-05 18-46-13.png  

4、进阶任务:

通过Wi-Fi,利用MQTT协议接入到开源的智能家居平台HA(HomeAssistant)

首先是安装HomeAssitant和EMQX

我直接是按照这个步骤来的https://bbs.eeworld.com.cn/thread-1293807-1-1.html

截图 2024-10-05 19-17-07.png   截图 2024-10-05 19-17-16.png  

两个都成功安装完毕。

然后是代码,这里就简单实现下接入MQTT,接入HA在扩展任务中实现

首先来安装一下PubSubClient和ArduinoJson这两个库。

在PlatformIO添加库非常简单,打开PIO Home页面,点击Libraries,在搜索框中输入PubSubClient

  截图 2024-10-05 20-06-02.png  

点击搜索,可以看到检索出了很多库

   截图 2024-10-05 20-08-16.png  

直接选择第一个,进入

截图 2024-10-05 20-09-04.png  

然后单击Add to Project

image.png  

选择创建好的项目,点击Add按钮就直接添加完毕了

软件流程图:

image.png  

#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

image.png

EMQX里也显示Arduino连上了

  截图 2024-10-05 19-49-03.png  

5、扩展任务二:

通过外部SHT40温湿度传感器,上传温湿度到HA,通过HA面板显示数据

首先把SHT40传感器接上

37EB1734186D16BCD5BB92AABA68AE40.jpg  

然后和进阶任务一样先添加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

 软件流程图:

image.png  

#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);
  }
}

编译上传,然后打开串口监视器

image.png  

可以看到成功在HA创建了配置并发送了温湿度数据

   截图 2024-10-05 19-51-40.png  

HA面板也成功出现了传感器数据

三、心得体会

这次活动虽然不难,但我依然学会了不少东西,首先就是OPAMP,以前从来没接触过,看了网上不少资料才知道是怎么回事。再就是MQTT,以前了解过,但也仅停留在了解,通过这次活动我才真正实践了MQTT,也算是一次经验积累。然后建议的话,感觉就是基础任务的DAC,OPAMP,ADC完全可以合在一起作为一个任务,分成三个比较繁琐。总之,算是顺利的完成了这次活动,希望以后还有机会参加类似的活动。

 

 

本帖最后由 starsphere 于 2024-10-31 14:53 编辑

回复评论

暂无评论,赶紧抢沙发吧
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复