This event is coming to an end. We have learned and realized the basic process of the Internet of Things. This event is the second issue of the second season of the Follow me event initiated by DigiKey and EEWorld. We have selected development boards and instrument sets with high playability and educational value, and we will join hands in a practical feast.
1. Material display
Main control board : Arduino UNO R4 WiFi
Arduino UNO R4 WiFi is a 32-bit Arm Cortex-M4 Renesas RA4M1 microcontroller with an ESP32 module for Wi-Fi and Bluetooth connectivity, with powerful computing power and multiple connectivity features. The board has 32kB SRAM, 256kB flash memory, a clock frequency of 48MHz, the USB port is upgraded to USB-C, and the maximum power supply voltage is increased to 24V. The board provides a CAN bus that allows users to minimize wiring and perform different tasks by connecting multiple expansion boards. The onboard Qwiic connector makes it easy to create plug-and-play style projects.
Sensor 1: LTR-329 light sensor expansion board
The LTR-329ALS-01 is a low voltage I2C digital light sensor [ALS] in a low cost, micro-chip leadless surface mount package. The sensor converts light intensity into a digital output signal capable of direct I2C interface. It provides a linear response over a wide dynamic range of 0.01 lux to 64k lux, making it ideal for applications with high ambient brightness. There are six gain settings (1X, 2X, 4X, 8X, 48X and 96X) that are user configurable.
Sensor 2: SHT40 temperature and humidity sensor expansion board
The SHT4x is a digital sensor platform for measuring relative humidity and temperature with different accuracy levels. Its I2C interface offers multiple preconfigured I2C addresses while maintaining an ultra-low power budget (0.4 μW). A power-trimmed internal heater can be used at three heating levels, allowing the sensor to operate in harsh environments. The four-pin dual-planar leadless package is suitable for surface mount technology (SMT) processing and includes an optional patented PTFE[1] membrane on the package or a removable protective cover. Sensor-specific calibration certificate according to ISO17025, identifiable by a unique serial number.
2. Overall thinking
The two sensor boards communicate through the Qwiic connector, but the connection wires were not purchased this time because the limit was exceeded. However, it is still worthwhile to have an extra sensor. The connection wires were made by myself, and connected in series to achieve the connection between the sensor and the main control board. The development board has a wifi module that can realize wireless connection, and communicate with the HA platform through the MQTT protocol.
3. Task Implementation
This part is mainly written in each sub-post, and it is introduced and transmitted.
Unboxing:
Configure the development environment:
Getting Started Tasks:
The entry task is to build the environment and start the first step Blink / serial port printing Hello EEWorld! We have already built the environment in the previous chapter. Here we mainly implement the flipping of LED and serial port printing. These two small functions are also the beginning of our familiarity with the new development board. In fact, there are two functions, setup() and loop(). One is executed once, which is equivalent to initialization, and the other is a loop operation. The convenience of Arduino is that many operations have been packaged and can be used directly. The code is as follows:
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:
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
Serial.println("Hello EEWorld!");
}
Only two functions are used to start GPIO and serial port, and then the LED flipping is realized by loop control through delay method:
And after executing once, the serial port prints "Hello EEWorld!" once:
Basic tasks:
The basic task is to drive 12x8 dot matrix LED; generate sine wave with DAC; amplify DAC signal with OPAMP; collect and print data with ADC to serial port and other interfaces, which can be uploaded to the host computer to display the curve. In fact, this can be divided into several tasks. The matrix composed of 96 LEDs is actually a separate control, each LED corresponds to one bit, so we need to design several characters for cyclic display and implement them in loop():
The loop display code is as follows:
ArduinoLEDMatrix matrix;
void setup() {
// put your setup code here, to run once:
matrix.begin();
}
void loop() {
// put your main code here, to run repeatedly:
matrix.loadFrame(show_1);
delay(500); // wait for a second
matrix.loadFrame(show_2);
delay(500); // wait for a second
matrix.loadFrame(show_3);
delay(500); // wait for a second
matrix.loadFrame(show_4);
delay(500); // wait for a second
matrix.loadFrame(show_E);
delay(400); // wait for a second
matrix.clear();
delay(100); // wait for a second
matrix.loadFrame(show_E);
delay(500); // wait for a second
matrix.loadFrame(show_W);
delay(1000); // wait for a second
}
The effect is as follows:
The video effect can be seen in the last effect video of Task 2 - LED whole row display part;
The other parts are the operations of ADC, DAC, amplification, etc., and the serial port printing used in our task one is used. At this time, some external connections are required:
The external configuration of the amplifier is more important. The basic configuration of the hardware is carried out in the form of a forward amplifier. The ADC is connected to the positive input of the OPAMP, that is, A1. The voltage of A2 is virtually shorted and equal to the voltage at A1, and then amplified by two equal resistors. One is connected to the ground of A2 and the other to the output. In this way, the output at A3 is twice that at A1, and the serial output is plotted through ADC acquisition.
Some of the code is as follows:
void setup() {
// put your setup code here, to run once:
pinMode(A0, OUTPUT);
pinMode(A5, INPUT);
analogReadResolution(12);// 设置 ADC 分辨率为 12 位
pinMode(LED_BUILTIN, OUTPUT);
Serial.begin(115200);
matrix.begin();
matrix.loadFrame(show_4);
}
void loop() {
// put your main code here, to run repeatedly:
for(int i = 0; i < 360; i++){
float rad = i * PI / 180.0;
int outputValue = (127 + 127 * sin(rad))/5;// 生成正弦波信号
analogWrite(A0, outputValue);// 输出到 DAC
// 控制输出频率
delay(100);
int value = analogRead(A5);// 读取 ADC 值
Serial.println(value);
}
}
The software process is as follows:
Some of the effects are as follows:
The display is viewed through the serial port tool that comes with Arduino. Since it can only display 50 values, only part of the sine wave can be seen. For details, please refer to Task 2 - ADC Acquisition in the video explanation;
For details, please go to the sub-post to view:
Advanced tasks:
Through Wi-Fi, use the MQTT protocol to access the open source smart home platform HA (HomeAssistant). This mainly includes two parts, one is the use of wifi, and the other is the establishment of the smart home platform HA (HomeAssistant). Of course, many forum friends may have already created this part. After all, many people who play with the Internet of Things or wireless have been exposed to it. You can refer to the official documents and choose a method that suits you to create it. Then use the MQTT simulator to create the entity. After that, we can directly send data through the MQTT protocol. In this part, we can also test it by randomly sending data without connecting any sensors, just to verify whether the MQTT protocol and the smart home platform HA are connected:
#include <ArduinoMqttClient.h>
#include <WiFiS3.h>
#include <WiFiClient.h>
#include <Arduino_JSON.h>
char ssid[] = "xxx";
char pass[] = "xxx";
const char broker[] = "192.168.72.127";
int port = 1883;
const char state_topic2[] = "homeassistant/sensor/sensorsth40/state";
WiFiClient wifiClient;
MqttClient mqttClient(wifiClient);
JSONVar dataObj;
const long interval = 1000;
unsigned long previousMillis = 0;
int count = 0;
void setup() {
Serial.begin(115200);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
Serial.println("HA com test");
Serial.println("connect to WPA SSID: ");
Serial.println(ssid);
// attempt to connect to WiFi network:
while (WiFi.begin(ssid, pass) != WL_CONNECTED) {
Serial.print("......");
delay(5000);
}
Serial.print("connect wifi succeed!");
Serial.println();
Serial.println(WiFi.localIP());
// You can provide a unique client ID, if not set the library uses Arduino-millis()
// Each client must have a unique client ID
mqttClient.setId("clientId");
// You can provide a username and password for authentication
mqttClient.setUsernamePassword("admin", "admin");
Serial.print("connect to the MQTT broker: ");
Serial.println(broker);
if (!mqttClient.connect(broker, port)) {
Serial.print("MQTT connection failed! Error code = ");
Serial.println(mqttClient.connectError());
while (1);
}
Serial.println("connected to the MQTT succeed!");
Serial.println();
}
void loop() {
// put your main code here, to run repeatedly:
mqttClient.poll();
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
// save the last time a message was sent
previousMillis = currentMillis;
dataObj["cnt"] = count;
String jsonString = JSON.stringify(dataObj);
// send message, the Print interface can be used to set the message contents
mqttClient.beginMessage(state_topic);
mqttClient.print(jsonString);
mqttClient.endMessage();
count++;
if(count>=90)
count = 0;
delay(1000);
}
}
The overall software process is as follows:
For details, please go to the sub-post to view:
Expand the tasks together:
We chose two sensors this time to maximize resource utilization. For this, we need to make connecting wires. The Arduino board has a ready-made interface that matches the board. A single line connection is enough. The interface addresses of these two sensors are different, so they can be connected in series. Fortunately, I bought this terminal before. It is really hard to pinch it:
Next, we just need to realize the driving of these two sensors. Thanks to the high integration of Arduino, we only need to use the corresponding application functions. However, we need to configure some sensors to complete the initialization part:
#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(115200);
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;
}
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;
}
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);
}
}
Just keep acquiring data in the loop, and finally associate it with the uploaded data. What we see in HA is the data collected by the sensor in real time:
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["cnt"] = count;
dataObj["hum"] = hum;
dataObj["tem"] = tem;
String jsonString1 = JSON.stringify(dataObj);
mqttClient.beginMessage(state_topic1);
mqttClient.print(jsonString1);
mqttClient.endMessage();
dataObj["LTR"] = visible_plus_ir;
String jsonString2 = JSON.stringify(dataObj);
mqttClient.beginMessage(state_topic2);
mqttClient.print(jsonString2);
mqttClient.endMessage();
delay(1000);
}
The overall software process is as follows:
You can check the corresponding posts for related configurations and key points.
4. Code Sharing
All task codes can be directly placed in the corresponding project and opened. Note that the supported library functions need to be adapted and downloaded, and some configuration places need to be configured to their own content.
5. Video Explanation
Digi-Key Follow Me Season 2 Episode 2 - Digi-Key Follow Me Season 2 Episode 2 - EEWORLD University
Or just click on the video below to watch:
VI. Activity Summary
This event can be the first time to realize the function of the Internet of Things. The HA platform used this time can be said to be one of the biggest gains of this event, which is to realize the construction of the HA platform. Another thing is that the use of Arduino is really very convenient, which is very convenient for the verification of functional modules. Thumbs up for the event! We also look forward to more forum friends joining the EEW family!