Lab2 v2.0
Lab2 v2.0
(SADQ)
LAB 2: Visualization of
Temperature, Humidity and
Air pressure on an OLED
Screen Using a
Microcontroller.
2
1. Introduction
In this lab, we use an STM32 Nucleo board to interface with the Arduino Sensor Kit and display
processed information on an OLED screen. The objective is to establish communication between
the microcontroller and various sensors, acquire real-time data, and process them to generate
meaningful outputs. The procedure follows the structure of a given initial program skeleton,
which will be modified and completed by implementing the necessary functions for each sensor
in different sections. We implement data acquisition, processing, and visualization techniques
while ensuring proper integration of hardware and software components. This exercise helps to
develop skills in embedded systems programming, peripheral interfacing, and real-time data
representation, which are essential in engineering. You can get more information and examples
related to the Arduino Sensor Kit at https://sensorkit.arduino.cc/. At the end of the tasks
proposed in this program of activities, the student should be able to:
• Program the STM32 Nucleo board.
• Communicate with the sensors of the board using the I2C protocol.
• Display the processed information on an OLED screen.
3. Lab Task.
This is the lab task you must carry out and report for evaluation. It is important that you take
notes on every step of your experiments to complete the report document that will be
uploaded through Moodle as the result of your laboratory work.
You must carefully follow all steps while writing down the specific results that you will be asked
about. The lab steps are numbered as x.x.
The grades of this task will depend upon the quality of the report document. Thus, on the report
you will be required to answer each of the questions indicated as Qx.
The report must be 5 pages long maximum. It is recommended to add screenshots that can be
taken with your mobile phone or with the OpenChoice software in the case of using the
Oscilloscope. A cover page on the report document is always welcome (does not count among
the 5 pages). A template for the report is provided in Moodle.
3
3.1 First Steps
In this section we are going to set up the PlatformIO project. It is assumed that the student has
completed the STM32 Tutorial, so the VSCode, PlatformIO and STM32 drivers are already
installed in the computer and understood by the student.
• Click on the PlatformIO extension on the left extension bar . Two panels are unfolded
on the left part of the screen: PROJECT TASKS and QUICK ACCESS panels.
• Click on QUICK ACCESS -> PIO Home -> Libraries. The graphic interface of PIO Home will
appear in a new window.
• Search for Arduino_Sensorkit and click on the library developed by Leonard George.
• Ensure that the version is 1.4.0 and click on Add to Project.
• Select project Practica2. The files of this library are included in .pio/libdeps/
nucleo_f411re/Arduino_Sensorkit.
• Confirm that the platformio.ini file has included the dependency of this library:
[env:nucleo_f411re]
platform = ststm32
board = nucleo_f411re
framework = arduino
lib_deps = arduino-libraries/Arduino_Sensorkit@^1.4.0
4
• In the project path, open the file .pio/libdeps/nucleo_f411re/Arduino_Sensorkit/
src/Arduino_SensorKit.h.
• Modify the definitions by adding the text highlighted as below:
#if defined(ARDUINO_ARCH_AVR) || defined(ARDUINO_ARCH_MEGAAVR) ||
defined(ARDUINO_UNOR4_MINIMA) || defined(ARDUINO_UNOR4_WIFI)
#define _PIN_SDA SDA
#define _PIN_SCL SCL
#define _WIRE Wire
#elif defined(STM32F4xx)
#define _PIN_SDA SDA
#define _PIN_SCL SCL
#define _WIRE Wire
#elif defined(ARDUINO_GIGA)
#define _PIN_SDA I2C_SDA1
#define _PIN_SCL I2C_SCL1
#define _WIRE Wire1
#else
#error "This board is not supported by Arduino_SensorKit"
#endif
• Save and close the file. The library is now configured to support our ST board.
• Open src/main.cpp and copy-paste the next code that is the template for the lab work in
which we are going to work fill in and modify functions along the lab 2. When copy-pasting
the code, make sure that the page numbers of this document are not copied to the VSCode.
The code is also available in Moode and you can download it from there.
#include "Arduino_SensorKit.h"
// Function prototypes
float get_temperature_celsius();
float get_temperature_fahrenheit();
void display_temperature(float data1, float data2);
float mean(int length, float buffer[]);
void store_humidity();
void display_humidity(float data);
void store_pressure_hectopascals();
5
void display_pressure(float data);
// Global variables
float humd_buffer[HUMD_BUFF_LEN]; // Buffer
int humd_i = 0; // Position
float humd_mean = 0.0;
float pres_buffer[PRES_BUFF_LEN]; // Buffer
int pres_i = 0; // Position
float pres_mean = 0.0;
void setup() {
// Initialize I2C
Wire.begin();
// Initialization of the OLED screen
Oled.begin();
Oled.setFlipMode(true); // Sets the rotation of the screen
Oled.setFont(u8x8_font_chroma48medium8_r); // Sets the font
Oled.clearDisplay();
// DHT20 sensor (Temperature and humidity)
Environment.begin();
// BMP280 sensor (Air pressure)
Pressure.begin();
// Initialize all values of the buffer to 0
for(int i=0; i<HUMD_BUFF_LEN; i++){
humd_buffer[i] = 0.0;
}
for(int i=0; i<PRES_BUFF_LEN; i++){
pres_buffer[i] = 0.0;
}
}
void loop() {
delay(SAMPLE_RATE);
// Get and display temperature
float temp_celsius = get_temperature_celsius();
float temp_fahrenheit = get_temperature_fahrenheit();
display_temperature(temp_celsius, temp_fahrenheit);
// Get and display humidity
/* TODO : COMMENT THE LINE BELOW */
humd_mean = Environment.readHumidity();
/* TODO : UNCOMMENT THE LINES BELOW */
//store_humidity();
//humd_mean = mean(HUMD_BUFF_LEN, humd_buffer);
display_humidity(humd_mean);
// Get and display Pressure
store_pressure_hectopascals();
pres_mean = mean(PRES_BUFF_LEN, pres_buffer);
display_pressure(pres_mean);
}
float mean(int length, float buffer[]){
6
/* MODIFY ME */
return -1.0;
}
float get_temperature_celsius(){
return Environment.readTemperature();
}
float get_temperature_fahrenheit(){
/* MODIFY ME */
return -1.0;
}
void display_temperature(float data1, float data2){
Oled.setCursor(0, 1);
Oled.print("T = ");
Oled.print(data1);
Oled.print(" C");
Oled.refreshDisplay();
Oled.setCursor(0, 3);
Oled.print("T = ");
Oled.print(data2);
Oled.print(" F");
Oled.refreshDisplay();
}
void store_humidity(){
humd_buffer[humd_i] = Environment.readHumidity();
humd_i++;
if (humd_i==HUMD_BUFF_LEN)
humd_i=0;
}
void display_humidity(float data){
/* FILL ME */
}
void store_pressure_hectopascals(){
/* FILL ME */
}
void display_pressure(float data){
/* FILL ME */
}
If you have already done the Counter Tutorial, the structure of this program may be familiar.
First, we include the Arduino Sensor Kit library to call the different sensors that are included in
the board. Then, we define some constants, as the buffer lengths. After the constants, we define
the prototypes of the functions. The prototypes are the headers of the functions defined by the
user, whose body is placed at the end. Then, we include the code of the setup function. This
function is run only once at the beginning of the execution. It initializes the I2C communication,
the screen, the sensors, and gives default values to the global array variables. Then, we write
the loop function. This function runs iteratively. It calls the user functions sequentially and then
waits for some time to adjust the sampling rate of the sensors.
Some functions of the code are already completed, and others must be written by the student,
7
following the steps of this document. Specifically, the student has to fill in the body of the
functions marked with the /* FILL ME*/ and /* MODIFY ME*/ comments, when necessary,
along the document.
In this task, we are going to obtain the temperature of the room from the DHT20 sensor of the
Arduino Sensor Kit and display it on the OLED screen. The temperature is going to be displayed
in both Celsius and Fahrenheit degrees.
• Connect the Grove wires to the module of the board where the sensor is located. It appears
on the board with the name Temperature & Humidity. Remember that the sensor
communicates with the STM32 by the I2C protocol, so the sensor must be connected to an
I2C connector.
• Modify the body of the prototype function:
float get_temperature_fahrenheit()
This function first reads the value of the temperature from the DHT20 sensor and returns
the value converted into Fahrenheit using the appropriate formula. Remember that Celsius
and Fahrenheit degrees are related by the formula:
9
𝐹𝐹 = ∙ 𝐶𝐶 + 32
5
• Upload the code to the STM32 Nucleo.
• Observe the OLED screen to verify that the information of both the Celsius and Fahrenheit
units are correctly displayed.
Questions:
Q1: Take a photograph of the complete board so that the connections and the screen are clearly
shown. Do the calculations to verify that the degrees in Celsius and Fahrenheit fulfil the formula
that relates them.
Q2: Copy the code of the get_temperature_fahrenheit() function and explain any special
considerations that you have taken into account to carry out the calculations.
8
3.3 Humidity Sensor
During this task, the humidity information is obtained, processed and displayed on the OLED
screen along with the temperature information. The humidity information is obtained from the
DHT20 sensor, which also measures the temperature. Additionally, we will modify the code to
implement a circular buffer to store data and process it. A circular buffer considers an array of
length L. When the array is full and we want to store new data, the data of the first position of
the array is discarded and replaced by the new data obtained. This way, the data stored in the
circular buffer always includes the last L samples that have been received. We are going to
implement the mean operation of the data stored in the buffer and compare its output to the
original raw data. First, we are going to see the raw data that is read from the humidity sensor.
For this:
Questions:
Q3: Take a photograph of the complete board, so that the connections and the screen are clearly
shown. Copy the code of your display_humidity(float data). Explain how you achieve
that the humidity measurement is aligned properly on the OLED screen.
Q4: Put your finger on top of the temperature and humidity sensor. How do the measurements
displayed on the screen vary?
Now, we are going to study the behavior of the circular buffer. In order to see the values that
are stored in the circular buffer, we are going to use the debugger. The debugger lets the user
9
run the code line by line and stop to see the value of the variables at each point of the
execution. The intention is to see the humidity values stored in the circular buffer to study how
it is filled with new information, and how the mean value is calculated as new data is stored.
For this:
Questions:
Q5: Restart the debugger and annotate the values of the variables humd_buffer, humd_i and
humd_mean during six iterations of the loop() function. This means that the buffer is filled
during the first three iterations and replaced with new data during the next three iterations.
Show the behavior of the circular buffer and verify that the value returned by the mean function
is correct. What are the potential advantages of using the mean compared to using raw values?
Q6: Copy the code of your mean function and explain how you have implemented it.
10
3.4 Air Pressure Sensor
During this task, the air pressure information is obtained, processed and displayed on the OLED
screen under the temperature and humidity information. The air pressure information is
obtained from the BMP280 sensor. For this task:
• Connect the necessary cables to the module of the board where the “Air pressure” sensor
is located. Remember that the sensor communicates with the STM32 through the I2C
protocol, so the sensor must be connected to an I2C connector.
• Complete the body of the prototype function:
void store_pressure_hectopascals()
This function first reads the value of the air pressure from the BMP280, which gives the value
of air pressure in Pascals. Then, the function must convert this value to hectopascals using
the appropriate formula and finally store the value into the circular buffer pres_buffer.
HINT: Observe how the pressure sensor is initialized in the setup.
• Complete the body of the prototype function
void display_pressure(float data)
which prints in the OLED screen of the Arduino Sensor Kit the data given by the parameter,
with extra characters, including the units of the measurement.
• Upload the code to the STM32 Nucleo and verify that the air pressure information is added
to the OLED screen and can be seen under the temperature and humidity information.
Questions:
Q7: Take a photograph of the complete board so that the connections and the screen are clearly
shown. Copy the code of the function store_pressure_hectopascals() and the function
display_pressure(float data). Explain how you have implemented them.
In this section the Inter-integrated circuit (I2C) protocol will be studied and analyzed with the
oscilloscope. The I2C protocol allows us to connect several sensors or other devices such as
screens with just a few wires. One wire is used for the clock (SCL) and the other is used for
transmitting data (SDA). The I2C protocol is based on reading/writing data from/to a register
that is inside the chips of the sensors. The data message through SDA is organized as follows:
Read/Write
It consists of a serial communication, which means that data is sent bit after bit. These bits are
synchronized with the rising edges of the SCL signal. The microcontroller is in charge of starting
11
the transmission by sending first a ‘0’. Then the microcontroller sends 7 bits of the address of
the sensor and indicates with the next bit if data must be read (1) or written (0). If data must be
read, then the sensor sends the data that are stored in the sensor’s register. If data must be
written, then the microcontroller sends the new data to be stored in the sensor’s registers.
• Connect one Arduino wire to SDA, another Arduino wire to SCL and a third Arduino wire to
GND of the Arduino Sensor Kit board. The pins are the ones shown in the figure below.
GND
SDA
SCL
• Take two oscilloscope probes and measure the SDA voltage using Channel 1 of the
oscilloscope and SCL voltage using Channel 2. Remember to connect the ground of the board
to the ground cable of the oscilloscope.
• Remember that the oscilloscope probes and the oscilloscope configuration of the channels
must be in the same mode (10:1 or 1:1).
• Capture a data frame with the oscilloscope. For this, adjust the trigger level to the middle
level of the SCL signal. By default, the trigger is configured for CH1, but you can change it by
pressing MENU button in the trigger options (right part of the oscilloscope). Then, the source
that is displayed in the oscilloscope’s screen must change to CH2 that is the channel reserved
for the SCL signal. Finally, click on Single button in the right upper panel of the oscilloscope,
which captures a data frame of both SDA and SCL.
• Ensure that, minimum, 10 periods of the SCL signal are captured and can be clearly seen.
Otherwise, capture a new data frame.
• Adjust the vertical position of both signals so that one channel overlaps the other one.
Questions:
Q8: Take a photo of the oscilloscope screen, so that the SDA and SCL signals are clearly shown.
Remember that at least 10 periods of SCL must be clearly shown. Measure the period of the SCL
signal. How much is it?
12
Q9: According to the signals captured by the oscilloscope, which is the address of the register?
Provide it in binary and decimal. According to the table below, which sensor belongs this address
to?
Sensor Address
OLED Screen 0111100
DHT20 0111000
BMP280 1110111
Q10: According to the signals captured by the oscilloscope, is the register read or written by the
microcontroller?
13