305|0

4

帖子

1

TA的资源

一粒金砂(中级)

楼主
 

【Follow me第二季第2期】任务汇总贴 [复制链接]

  本帖最后由 tangye 于 2024-11-2 23:02 编辑

非常荣幸能够参加电子工程世界和得捷电子举办得Follow me 第二季第2期活动。

我以前没有接触过嵌入式系统的开发,对电子技术略有了解。本次活动让我有机会接触到一些新的领域,学习了不少新知识。实验过程中遇到不少问题,有些通过参考各位大佬的帖子解决了,有些还需要将来进一步探索。

 

我的代码:https://download.eeworld.com.cn/detail/tangye/634556

我的视频:https://training.eeworld.com.cn/video/41255

 

活动任务分4个阶段

入门任务:搭建环境并开启第一步 Blink / 串口打印 Hello EEWorld!

基础任务:驱动 12x8 点阵 LED;用 DAC 生成正弦波;用 OPAMP 放大 DAC 信号;用 ADC 采集并且打印数据到串口等其他接口可上传到上位机显示曲线

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

扩展任务:

1. 通过 LTR-329 环境光传感器,上传光照度到 HA,通过 HA 面板显示数据;

2. 通过 SHT40温湿度传感器,上传光照度到 HA,通过 HA 面板显示数据;

 

我拿到的物料包括 Arduino uno R4 wifi 以及 LTR-329 光照传感器,SHT40 湿温度传感器。这是全家福照片

 

这是 Arduino uno R4 wifi 引脚图。后续实验的接线依赖这张图片

 

任务完成思路:

1. 入门任务:搭建环境并开启第一步Blink / 串口打印Hello EEWorld!
这部分的主要内容是安装Arduino-IDE环境,连接到开发板,并且根据IDE提供的范例,完成相应的代码。

Arduino IDE的官方下载位于

https://www.arduino.cc/en/software

我下载了 arduino-ide_2.3.2,在Windows 10环境中双击安装即可。

安装完成后,在“文件”--“首选项” 中,可以修改项目文件夹地址等内容,便于后续备份和维护。

 

打开示例文件Blink,可以看到相应的代码。

 

在这个文件的基础上,我加上串口输出指令,完成入门任务。

流程图

void setup() {
  // initialize digital pin LED_BUILTIN as an output.
  pinMode(LED_BUILTIN, OUTPUT);

  Serial.begin(9600);
}

void loop() {

  digitalWrite(LED_BUILTIN, HIGH);  // turn the LED on (HIGH is the voltage level)
  Serial.println("Hello World!");
  delay(500);                      // wait for 0.5 second

  digitalWrite(LED_BUILTIN, LOW);   // turn the LED off by making the voltage LOW
  Serial.println("This is Arduino UNO R4!");
  delay(500);                      // wait for 0.5 second

}

串口监视器输出如图

开发板闪灯视频,可以看到受控的LED灯以1Hz的频率闪烁,同时TX指示灯每秒闪2下

2.blink

 

2. 基础任务:驱动 12x8 点阵 LED;用 DAC 生成正弦波;用 OPAMP 放大 DAC 信号;用 ADC 采集并且打印数据到串口等其他接口可上传到上位机显示曲线

基础任务在任务讲解视频 https://training.eeworld.com.cn/video/40793 中有详细介绍。

根据视频和论坛的帮助,我设计了LED矩阵的驱动代码,在程序初始化阶段,显示红心持续2秒,然后转为字幕并滚动

流程图

#include "ArduinoGraphics.h"
#include "Arduino_LED_Matrix.h"

ArduinoLEDMatrix matrix;

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() {
  Serial.begin(115200);
  matrix.begin();
  matrix.renderBitmap(frame, 8, 12);
  delay(2000);

  matrix.beginDraw();
  matrix.stroke(0xFFFFFFFF);
  matrix.textFont(Font_4x6);
  matrix.beginText(0, 1, 0xFFFFFF);
  matrix.println("Hey");
  matrix.endText();

  matrix.endDraw();

  delay(2000);
}

void loop() {
  matrix.beginDraw();
  matrix.stroke(0xFFFFFFFF);
  matrix.textScrollSpeed(200);
  const char text[] = "Hello Digikey!";
  matrix.textFont(Font_5x7);
  matrix.beginText(0, 1, 0xFFFFFF);
  matrix.println(text);
  matrix.endText(SCROLL_LEFT);
  matrix.endDraw();
  delay(500);
}

3..Scroll

DAC生成正弦波,通过内部OPAMP放大,并输出到ADC最终显示在“串口绘图仪”,需要在模拟引脚上接线。

根据原理图,A0输出DAC波形,用导线连接到A1。在A2和A3之间接一个10K电阻,在A2和地之间接一个10K电阻。此时A3(即运放输出端)的电压信号为A0的2倍。

为了用内置的ADC测量并显示电压波形,需要分别连接A0和A4,A3和A5。我完成的接线如图

流程图

DAC/OPAMP/ADC代码

#include "analogWave.h"
#include <OPAMP.h>

// Create an instance of the analogWave class, using the DAC pin
analogWave wave(DAC);
int freq = 100;

void setup() {
  wave.sine(freq);       // Generate a sine wave 100Hz
  wave.amplitude(0.4);  // 0.0 ~ 1.0
  OPAMP.begin(OPAMP_SPEED_HIGHSPEED);
  analogWriteResolution(14);
  Serial.begin(230400);  // baud rate 230.4k
}
void loop() {
  Serial.print(analogRead(A4));
  Serial.print(" ");
  Serial.println(analogRead(A5));
}

示波器观察A0

示波器观察A3

“串口绘图仪” 的显示

7.14-04-00

 

3. 进阶任务:通过Wi-Fi,利用MQTT协议接入到开源的智能家居平台 HA(HomeAssistant)

这个任务,需要准备HomeAssistant和EMQX。我在ubuntu系统里,用Docker方式搭建了HA环境,主要遇到的问题是docker镜像拉取困难。

经过一番折腾,发现home-assistant官方镜像托管在github上,可以直接pull(就是有些慢)

$ docker pull ghcr.io/home-assistant/home-assistant:stable

EMQX镜像是单独找的,实际上直接安装也很方便。

分别启动两个镜像

$ docker run -d --name="home-assistant" -v ~/HA_config:/config -p 8123:8123 ghcr.io/home-assistant:stable

$ docker run -d --name="EMQX" --network host emqx/emqx:5.7.2

这里需要说明一下,EMQX启动的时候,我没有指定端口映射,而是直接让容器使用了host的IP。

原因是,如果让EMQX默认连接内部网络docker0,每次启动的时候容器会拿到dhcp地址。启动顺序会影响地址,配置home-assistant指定的地址有可能失效。

接下来,按照任务讲解视频,分别访问 http://ip:18083 和 http://ip:8123 完成 EMQX 和 home-assistant 的配置

后续内容参考了各位大佬的帖子,在此一并致谢。

通过“示例”--“WiFiS3”--“ConnectWithWPA” 这个例程,修改 arduino_secrets.h 文件,写入 ssid(设备只支持2.4GHz)和访问密码,编译运行后可以在串口监视器上确认无线网络是否正确连接。

然后在库管理中,安装ArduinoMqttClient,运行例程连接MQTT服务

最后,用开发板送出数据,在HomeAssistant面板上显示。

流程图

代码,通过DAC在A0引脚输出正弦波,开发板测量电压值,显示在HA面板上

#include <ArduinoMqttClient.h>
#include "analogWave.h"

#include <Wire.h>
#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;

WiFiClient wifiClient;
MqttClient mqttClient(wifiClient);
analogWave wave(DAC);

const char broker[] = "192.168.90.79";               //MQTT Server IP
int port = 1883;                                     //MQTT Server port
const char topic[] = "UNO/R4/ADC/volt_d";            //Topic
const char mqttuser[] = "admin";
const char mqttpassword[] = "admin";

//set interval for sending messages (milliseconds)
const long interval = 5000;
unsigned long previousMillis = 0;

int count = 0;

void setup() {
  // Generate Wave
  wave.sine(2);       // Generate a sine wave 2Hz
  wave.amplitude(0.8);  // 0.0 ~ 1.0
  analogWriteResolution(10);
  Serial.begin(115200);  // baud rate 115.2k

  // Try to connect WLAN:
  Serial.print("Attempting to connect to WPA SSID: ");
  Serial.println(ssid);
  while (WiFi.begin(ssid, pass) != WL_CONNECTED) {
    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() {
  mqttClient.poll();

  //通过ADC采集 A0上输出的波形
  float A0_voltage = analogRead(A0) * 4.7/1023;  //A0, 10bit ADC采样,修正为十进制数
  mqttClient.beginMessage(topic);
  mqttClient.print(A0_voltage);   //把计算出的电压值上传到MQTT服务器
  mqttClient.endMessage();
  delay(500);
}

在HA面板显示数据,需要修改 configuration.yaml 增加以下部分

mqtt:
  - sensor:
      - unique_id: arduino uno Voltage
        name: "arduino Volt"
        state_topic: "UNO/R4/ADC/volt_d"
        suggested_display_precision: 3
        unit_of_measurement: "V"
        value_template: "{{ value }}"

重新加载YAML配置后,HA面板显示变化的电压值

 

扩展任务:

1. 通过 LTR-329 环境光传感器,上传光照度到 HA,通过 HA 面板显示数据;

2. 通过 SHT40温湿度传感器,上传光照度到 HA,通过 HA 面板显示数据;

连接传感器,我直接用的I2C接口,在传感器上焊了插针,用跳线连接VCC/GND/SCL/SDA信号。

使用LTR-329的例程,直接可以在串口监视器上看到CH0和CH1的光照度

 

在例程的基础上,结合上一阶段的代码,就能把数据上传到MQTT服务器。

流程图

传感器有两个数据,上传到一个订阅里用了json格式。

#include <ArduinoMqttClient.h>

#include <Wire.h>
#include <WiFiS3.h>
#include <Arduino_JSON.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;

#include "Adafruit_LTR329_LTR303.h"

Adafruit_LTR329 ltr = Adafruit_LTR329();

WiFiClient wifiClient;
MqttClient mqttClient(wifiClient);

const char broker[] = "192.168.90.79";               //MQTT Server IP
int port = 1883;                                     //MQTT Server port
const char topic[] = "UNO/R4/LTR329";            //Topic
const char mqttuser[] = "admin";
const char mqttpassword[] = "admin";

//set interval for sending messages (milliseconds)
const long interval = 5000;
unsigned long previousMillis = 0;

int count = 0;

JSONVar dataObj;

void setup() {
  Serial.begin(115200);

  Serial.println("Adafruit LTR-329 advanced test");

  if ( ! ltr.begin() ) {
    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;
  }

  // Try to connect WLAN:
  Serial.print("Attempting to connect to WPA SSID: ");
  Serial.println(ssid);
  while (WiFi.begin(ssid, pass) != WL_CONNECTED) {
    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() {
  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);
    }
  }

  if (ltr.newDataAvailable()) {
    valid = ltr.readBothChannels(visible_plus_ir, infrared);
    if (valid) {
      dataObj["dataCH0"] = visible_plus_ir;
      dataObj["dataCH1"] = infrared;
      String jsonString = JSON.stringify(dataObj);
      mqttClient.beginMessage(topic);
      mqttClient.print(jsonString);
      mqttClient.endMessage();
    }
  }
  delay(500);
}

同样要修改 HomeAssistant的configuration.yaml 

mqtt:
  - sensor:
      - unique_id: CH0_Visible_IR
        name: "CH0_Visible_IR"
        state_topic: "UNO/R4/LTR329"
        suggested_display_precision: 1
        unit_of_measurement: "lux"
        value_template: "{{ value_json.dataCH0 }}"
      - unique_id: CH1_IR
        name: "CH1_IR"
        state_topic: "UNO/R4/LTR329"
        suggested_display_precision: 1
        unit_of_measurement: "lux"
        value_template: "{{ value_json.dataCH1 }}"

重新加载 YAML 配置,HA面板显示两个测量通道的数据

这是台灯的照度信息。关闭台灯后,照度下降,HA面板可以显示历史曲线

换上SHT40,可以测试温湿度数据。示例中的 SGP40_SHT40_Test 不能直接运行,需要删除SGP40的部分。

流程图

有了LTR329的使用经验,SHT40的代码如下:

#include <ArduinoMqttClient.h>

#include <Wire.h>
#include <WiFiS3.h>
#include <Arduino_JSON.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;

#include "Adafruit_SHT4x.h"
Adafruit_SHT4x sht4;


WiFiClient wifiClient;
MqttClient mqttClient(wifiClient);

const char broker[] = "192.168.90.79";               //MQTT Server IP
int port = 1883;                                     //MQTT Server port
const char topic[] = "UNO/R4/SHT40";            //Topic
const char mqttuser[] = "admin";
const char mqttpassword[] = "admin";

//set interval for sending messages (milliseconds)
const long interval = 5000;
unsigned long previousMillis = 0;

int count = 0;

JSONVar dataObj;

void setup() {
  Serial.begin(115200);

  Serial.println();
  Serial.println();
  Serial.println(F("##################################"));
  Serial.println(F("SHT40 test with 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 (! sht4.begin()) {
    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("----------------------------------"));
 


  // Try to connect WLAN:
  Serial.print("Attempting to connect to WPA SSID: ");
  Serial.println(ssid);
  while (WiFi.begin(ssid, pass) != WL_CONNECTED) {
    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() {
  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.println(t); 
  float h = humidity.relative_humidity;
  Serial.print("Hum. % = "); Serial.println(h); 

  dataObj["SHT40_temp"] = t;
  dataObj["SHT40_humi"] = h;
  String jsonString = JSON.stringify(dataObj);
  mqttClient.beginMessage(topic);
  mqttClient.print(jsonString);
  mqttClient.endMessage();

  delay(1000);
}

修改 HomeAssistant的configuration.yaml 

mqtt:
  - sensor:
      - unique_id: temperature
        name: "Temperature"
        state_topic: "UNO/R4/SHT40"
        suggested_display_precision: 1
        unit_of_measurement: "掳C"
        value_template: "{{ value_json.SHT40_temp }}"
      - unique_id: humidity
        name: "Humidity"
        state_topic: "UNO/R4/SHT40"
        suggested_display_precision: 1
        unit_of_measurement: "%"
        value_template: "{{ value_json.SHT40_humi }}"

HA面板显示当前的温湿度

 

遗留问题

HA面板的 YAML配置重新加载以后,之前环节出现的传感器依然显示(呈现灰色)。后续看看如何清理这些内容。

 

对本活动的心得体会

Fellow me 活动对于我这类没有经验的新手非常友好,教学视频、论坛帖子帮助我完成了从入门到进阶的每项实验。

通过这次活动,我对Arduino 开发环境,各种传感器和相应的库,MQTT都有了初步认识。Arduino UNO R4 WiFi 功能丰富,以后可以继续深入学习。

最后,再次感谢电子工程世界,感谢得捷电子,感谢论坛各位大佬,感谢活动管理员lightxixi 

点赞 关注
 
 

回复
举报
您需要登录后才可以回帖 登录 | 注册

查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/9 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表