【Follow me Season 2 Episode 2】Complete the task in one article
[Copy link]
This post was last edited by Jin Yuzhongzhi on 2024-10-31 15:40
Video link: https://training.eeworld.com.cn/video/41231
eeworld任务提交
I am very honored to participate in the second season of DigiKey Follow Me event. I am very grateful to the forum and DigiKey. Follow Me event is a large-scale development board experience event initiated by DigiKey and EEWorld. In each issue, technical experts recommend development boards/instrument kits with strong playability and learnability, and take everyone to practice. This time, I also mainly carried out this event with a learning attitude. In fact, I received the purchased components very early, but I waited until the experts had completed them before starting my learning journey.
1. Main components
Main development 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 projects. The sensor boards on this occasion are all sensors that conform to the Qwiic connector interface. At the same time, this event also provides detailed development board information for us to check.
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 miniature 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 in high ambient brightness. A total of six gain settings (1X, 2X, 4X, 8X, 48X, and 96X) 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 demanding environments. The four-pin dual flat no-lead package is suitable for surface mount technology (SMT) processing and includes an optional encapsulation patented PTFE[1] membrane or a removable protective cover. A sensor-specific calibration certificate compliant with ISO17025 is available, identifiable by a unique serial number.
Adhering to the principle of learning as much as possible, this time I directly purchased two sensors to complete the task. To be honest, they just cover the limit. The best way to use them is not to buy wires and just make them yourself. Moreover, these two sensors can be directly connected in series using a Qwiic connector interface. After all, there are only a few more real parameters. When completing the IoT display, there is no difference between displaying one and displaying two.
2. Learning Achievements Display
1. Configure the development environment
This time we use the official development environment, Arduino IDE. You can download the latest version of the adapter system from the official website:
Please note that there is also a version that does not require installation. Adhering to the principle of saving a step, it is a book that can be started without installation.
Connect the development board and PC via USB cable, and the software can directly detect the connected development board:
Then you can install the corresponding basic library through the development board and search through the development board manager:
2. Getting Started Task: Build the environment and start the first step Blink / Serial port print Hello EEWorld!
The beginning of programming is to realize lighting. Let's create a new project:
Obviously, there are two key functions: setup() and loop(). Among them, setup() plays the role of initialization configuration and is executed only once to set the initial state; while loop() is responsible for the content of loop execution, which runs continuously to maintain or change the state of the program.
The excellence of Arduino lies in its highly integrated nature, which allows us to easily control it with the preset functions in the firmware without having to delve into the complicated details of the hardware. Nevertheless, in order to have a more comprehensive understanding, we still briefly overview the hardware configuration of the LED:
It can be seen that only DL4 is actually controllable by us, DL3 is for power supply only, and the other two are for serial port transmission instructions. No additional firmware is needed for the control of LED and serial port, the onboard firmware can be used, we can achieve the following tasks:
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:
// turn the LED on (HIGH is the voltage level)
digitalWrite(LED_BUILTIN, HIGH);
// wait for a second
delay(500);
// turn the LED off by making the voltage LOW
digitalWrite(LED_BUILTIN, LOW);
// wait for a second
delay(500);
Serial.println("Hello EEWorld!");
}
This task is relatively simple. After all, it is the first task for beginners. Let's briefly introduce the above program. The LED serial port is mainly used in this task. We need to perform corresponding initialization. You can see that the initialization is basically completed by calling a function. Through the library files of different boards, the internal associations have been made. You can directly configure the important parameters, and then implement the flashing of the LED in a blocking manner, and send "Hello EEWorld!" in a loop at the same time.
Clicking Upload will automatically compile and download the project, and then you can observe the effect by observing the L of the board and the serial port monitor that comes with the IDE:
Make sure to configure the baud rate.
3. Basic tasks: drive 12x8 dot matrix LED; use DAC to generate sine wave; use OPAMP to amplify DAC signal; use ADC to collect and print data to serial port and other interfaces, which can be uploaded to the host computer to display the curve.
In fact, this task is a combination task, which can be split into multiple tasks, such as driving LED, DAC outputting sine wave, OPAMP signal amplification, ADC acquisition and uploading display through the interface. It can be split into multiple unrelated tasks. In order to achieve better effect display, we split and recombined it into the following three small tasks:
The first one is the control of the 12x8 dot matrix LED dot matrix;
The second is that the DAC generates a sine wave, which is then amplified by 2 times through the OPAMP, and then the signal is collected by the ADC for serial port output. Here we can use the oscilloscope to measure the corresponding node, such as the output of the DAC and the output of the amplified signal, which can be displayed through the oscilloscope.
Next, let's take a look at the control of the 12x8 dot matrix LED dot matrix:
The basic hardware is shown in the picture above. I have also learned from many experts that some people use static display methods to implement dot matrix design to display different characters, and some people use different library files to achieve dynamic display. I personally prefer the dynamic display method, which feels a bit like the banner of a small shop on the street.
The basic library of the dot matrix LED is "Arduino_LED_Matrix.h", and the library for dynamically displaying text is "ArduinoGraphics.h". Note that ArduinoGraphics needs to be installed separately:
#include "Arduino_LED_Matrix.h"
#include "ArduinoGraphics.h"
ArduinoLEDMatrix matrix;
void setup() {
matrix.begin();
}
void loop() {
matrix.beginDraw();
matrix.stroke(0xFFFFFFFF);
matrix.textScrollSpeed(50);
const char text[] = " EEWorld && DigiKey ";
matrix.textFont(Font_5x7);
matrix.beginText(0, 1, 0xFFFFFF);
matrix.println(text);
matrix.endText(SCROLL_LEFT);
matrix.endDraw();
}
Next is the control of the simulation part:
DAC output: We directly use the built-in "analogWave.h". Due to the requirements of the subsequent experiments, we need to limit the amplitude. The specific code is as follows:
#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 = 10; // in hertz, change accordingly
void setup() {
Serial.begin(115200); // Initialize serial communication at a baud rate of 115200
pinMode(A0, OUTPUT);
wave.amplitude(0.25); //设置幅度值为4.7 的1/4
wave.sine(freq); // Generate a sine wave with the initial frequency
}
void loop() {
// Read an analog value from pin A5 and map it to a frequency range
delay(500);
}
The results are as follows:
Next is the amplification part, which requires the use of OPAMP. It is very convenient to start OPAMP:
#include "analogWave.h"
#include <OPAMP.h>
void setup() {
Serial.begin(115200);
pinMode(A0, OUTPUT);
wave.amplitude(0.25);
wave.sine(freq);
OPAMP.begin(OPAMP_SPEED_HIGHSPEED);
}
At the same time, external connections are required:
As you can see from the figure above, the amplitude of Vpp increased from 1.23V to 2.44V. I used two identical resistors, so the effect was doubled.
Next we connect A3 and A5. Yes, we are going to use A5 for ADC acquisition. The following is the final code for this stage:
#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 = 10; // in hertz, change accordingly
void setup() {
Serial.begin(115200); // Initialize serial communication at a baud rate of 115200
pinMode(A0, OUTPUT);
pinMode(A5, INPUT);
analogReadResolution(12);// 设置 ADC 分辨率为 12 位
wave.amplitude(0.25); //设置幅度值为4.7 的1/4
wave.sine(freq); // Generate a sine wave with the initial frequency
OPAMP.begin(OPAMP_SPEED_HIGHSPEED);
}
void loop() {
// Read an analog value from pin A5 and map it to a frequency range
int value = analogRead(A5);// 读取 ADC 值
Serial.println(value);
}
The display effect is still not ideal, mainly because the number of displays is too limited, but the trend can still be seen:
4. Advanced and extended tasks
Through the analysis of the tasks, we can find that the advanced tasks and extended tasks are actually the same. They are both implemented through this development board to communicate with the HomeAssistant smart home platform. Here, the onboard wifi function is used and the communication protocol is Mqtt.
After breaking down the task and reorganizing it, we need to complete the following three tasks:
First: realize the collection of sensor data, that is, the collection of SH40 and light sensor data. This part does not involve wireless communication capabilities. Through the interface connection, data collection can be realized and then the data can be printed through the serial port, which can be viewed through the serial port tool;
Second: the operation and implementation of the HomeAssistant smart home platform. HA supports many systems, and we need to implement the construction of the HA platform;
Third: Implement the wifi driver, configure the relevant parameters of the Mqtt protocol, communicate with the HomeAssistant smart home platform, and realize online viewing of SH40 and light sensor data.
Next is the implementation process:
Connect the sensors in series and install the corresponding sensor library:
First, initialize the two sensors:
#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(9600);
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;
}
// You can have 3 different precisions, higher precision takes longer
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;
}
// 6 different heater settings
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);
}
}
Initialization successful:
The loop reading program is much simpler:
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));
Read successfully:
The next step is to realize HA communication and data upload. This part mainly includes the installation of the HA system. Since everyone uses it differently, you can see that there are container versions, Raspberry Pi, and virtual machines. For the current situation, it is more convenient to use a virtual machine, after all, there is no extra hardware. Here, according to the official installation guide, you can achieve a very convenient installation. Let's open HA and take a look:
The main thing is to add the mqtt firmware and register the device and entity through the MQTT simulator. We need to confirm that the light sensor has one parameter and the SH40 has two parameters. To this end, we create three entities:
The next step is to configure basic parameters through Mqtt, mainly to write corresponding data to "homeassistant/sensor/Roomsensor/state":
char ssid[] = "开发板连接的wifi";
char pass[] = "开发板连接的wifi密码";
const char broker[] = "目标地址ip";
int port = 1883;
const char state_topic[] = "homeassistant/sensor/Roomsensor/state";
然后就是循环采集发送:
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["light"] = visible_plus_ir;
dataObj["hum"] = hum;
dataObj["tem"] = tem;
String jsonString1 = JSON.stringify(dataObj);
mqttClient.beginMessage(state_topic);
mqttClient.print(jsonString1);
mqttClient.endMessage();
delay(1000);
}
Overall software process:
The results are as follows:
Block it:
It should be noted here that the serial port communication may affect the Mqtt connection. Previously, an error was reported, which reflected that the access to the target address was denied. Later, a while (!Serial) was added to solve it.
Code summary:
You can download the code and modify and test it directly. The entry-level tasks and advanced tasks are relatively simple, and the advanced tasks are quite memorable.
Summarize:
This activity was mainly carried out with a learning attitude. Indeed, the various Arduino firmwares are very suitable for functional verification. Thanks to the forum and netizens for their wonderful sharing.
|