Week 4 — Embedded programming

This week was about embedded programming ( Fab Academy — Embedded Programming). For my individual assignment, I built a Wokwi simulation in Cursor Desktop: an Arduino Uno reads a DHT22 temperature and humidity sensor, shows the values on a 1602 LCD with an I2C backpack at address 0x27, and prints the same readings to the serial monitor. My final project will use temperature and humidity sensing to monitor a plant’s growing environment; this simulation is an early way to test the sense → display path before building the full physical circuit.

Individual assignment — Wokwi simulation: Uno + DHT22 + LCD1602 (I2C)

Assignment checklist

The Fab Academy individual assignment asks us to browse a microcontroller datasheet, write and test a program for an embedded system, interact with local input/output devices, communicate with a wired or wireless connection, include source code, and document the programming process. My work covers those points as follows:

  • Microcontroller documentation: I used an Arduino Uno R3 based on the ATmega328P. I checked the Uno pinout and ATmega328P documentation to confirm that D2 can be used as a digital data pin, and that Uno hardware I2C uses SDA=A4 and SCL=A5.
  • Input and output: the DHT22 is the input device; the LCD1602 and serial monitor are the output devices.
  • Communication: the LCD communicates with the Uno through I2C, and the Uno reports readings to the computer through Serial.
  • Programming process: I edited the sketch in Cursor Desktop, used the Wokwi extension to run the circuit, and checked both the LCD and the serial monitor while debugging.
  • Source and hero shots: the full sketch is included below and stored at code/week04/wokwi/sketch.ino. The screenshots show the circuit, simulator window, and serial output.
  • Group work: see the group assignment section on this page.

1. Task And Motivation

Because my final project will rely on temperature and humidity sensors to watch the plant’s growing environment, I wanted a low‑risk way to prove the circuit and code first. I chose to do that in simulation (Wokwi) so I could iterate on wiring and software before committing to a breadboard or a specific lab session.

Within that goal, I wanted to test the basic sensing path before working with physical wiring: environment → sensor → microcontroller → readable output. The DHT22 gives temperature and humidity readings, and the LCD makes the result visible without depending only on the serial monitor.

I chose a DHT22 because it is a common classroom sensor, has better resolution than a DHT11, and is suitable for indoor temperature and humidity experiments. I used a 1602 LCD with an I2C backpack because it needs only two signal wires instead of many parallel LCD pins.

My workflow was: install the Wokwi extension in Cursor Desktop, create the circuit in diagram.json, write the Arduino sketch, start the simulator, check the LCD and serial monitor, then document the process with screenshots and source code.

2. Learning

I pushed myself to learn beyond the simulator: I wanted to see what a real character LCD actually looks like on the bench, so I hunted around the lab and found an LCD2004 with an I2C backpack (my Wokwi build still uses a 1602 because that part is easy to fit in the diagram, but the hardware idea is the same). On the back I noticed three small address pads and no obvious label telling me the I2C address out of the box. Rather than guess, I followed that curiosity into DFRobot’s Chinese wiki for the classic backpack style ( A0/A1/A2 as the low address bits). There I learned how jumper soldering maps to the 0x20–0x27 range, and how to match a real module to the right LiquidCrystal_I2C address—then I confirmed that against the pads on the board I had in hand.

The DHT22 uses a single-wire digital protocol. In the Arduino environment I used the DHT library, which also recommends waiting about 2 s between readings. The LCD backpack uses I2C. Many boards in the lab use a backpack based on an I/O expander such as the PCF8574, where those three address lines pick one of eight addresses in the 0x20–0x27 range (other chip families sometimes default to 0x3F instead). In my Wokwi project and in code I used address 0x27, consistent with what I inferred from the wiki and from inspecting the solder bridges on the backpack.

How the I2C address is set on the backpack

On the DFRobot DFR0063-style I2C LCD module, the wiki documents that the last three address bits are controlled by small solder jumpers (or bridges) on the back of the backpack: each of A0, A1, and A2 can be read as 0 or 1 depending on how that pad is connected, and the combination picks the 7‑bit I2C address. Below is the lab module (LCD2004) from the back—the three pads that set the address are circled; then the manufacturer table I pulled from the wiki to interpret them and lock in 0x27 for LiquidCrystal_I2C.

Back of a lab LCD2004 I2C backpack; three address jumper pads circled in red
Lab LCD2004 module, back side: the three pads that set A0–A2 (marked in red) determine the I2C address; compare them to the manufacturer table next before choosing 0x27 versus another value in code. (Simulation still uses a 1602 for convenience.)
DFRobot DFR0063 wiki: A2 A1 A0 jumper settings and matching I2C addresses 0x20 through 0x27
Address table from DFRobot’s DFR0063 documentation: the three LSBs A2–A0 select the module’s I2C address in the 0x20–0x27 range.

Reference: DFRobot — I2C LCD1602 module DFR0063 (documentation and address setup).

One important detail is that the Wokwi DHT22 data pin is labelled SDA, but it is not the same SDA line as I2C. In this circuit, the DHT22 data pin goes to D2. The LCD is the part that uses real I2C, with SDA → A4 and SCL → A5 on the Arduino Uno.

For the microcontroller reference, I checked the ATmega328P documentation and the Arduino Uno pinout. This confirmed the digital pin and I2C pin choices before I finished the Wokwi wiring.

I also kept one earlier ESP32-S3 draft in the repository as a reference for a possible future board change: code/week04/esp32-s3-dht-lcd-main.cpp.txt. This week’s documented circuit and screenshots use the Arduino Uno project in diagram.json.

3. Plan

  1. Install and open the Wokwi simulator from Cursor Desktop.
  2. Add an Arduino Uno, DHT22, and LCD1602 with I2C pins to the Wokwi diagram.
  3. Connect power, ground, DHT data, and LCD I2C lines.
  4. Add the required Arduino libraries for DHT and LCD control.
  5. Write a sketch that reads every 2 s, updates the LCD, and prints to Serial.
  6. Run the simulation, take screenshots, and save the source files in the repository.

4. Process

Step A — Installing Wokwi In Cursor Desktop

  1. I opened Cursor Desktop and used +Shift+X to open the Extensions panel.
  2. I searched for Wokwi, selected Wokwi Simulator, and clicked Install.
  3. I followed the Wokwi extension setup guide to enable the simulator in the editor.
  4. I opened the project folder code/week04/wokwi/ in Cursor, because that folder contains diagram.json, sketch.ino, and the project settings.
  5. From the Command Palette I ran Wokwi: Start Simulator. When the simulator opened, I used the serial monitor to check the printed sensor values.

If the simulator does not start, the first things I check are whether the opened folder contains diagram.json, whether sketch.ino is in the same project folder, and whether the libraries listed in libraries.txt are available.

Step B — Building The Circuit

Wokwi simulation with Arduino Uno, DHT22, LCD1602 I2C module, and wiring
Wokwi circuit view with the Arduino Uno, DHT22, and LCD1602 I2C module.

The wiring in my diagram.json is:

Signal Component pin Arduino Uno pin
5 V DHT22 VCC, LCD VCC 5V
GND DHT22 GND, LCD GND GND
DHT22 data DHT22 pin labelled SDA D2
I2C LCD SDA / SCL A4 / A5

I set the LCD to I2C mode and used address 0x27. On real hardware, if the LCD stays blank, I would first check the I2C address and the contrast setting on the backpack.

Step C — Code And Libraries

The project uses the Arduino framework. The dependency list is saved as libraries.txt. The sketch initializes the LCD, reads the DHT22 every two seconds, calculates heat index in Celsius, updates both LCD rows, and prints the same values to the serial monitor. If the DHT read fails, the LCD shows a short error message.

Downloadable source: code/week04/wokwi/sketch.ino.

/**
 * Fab Week 4 — Wokwi: Arduino Uno + DHT22 + LCD1602 (I2C)
 * See diagram.json in this folder for wiring.
 */

#include <Arduino.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <DHT.h>

#define DHT_PIN 2
#define DHTTYPE DHT22

#define LCD_I2C_ADDR 0x27
#define LCD_COLS 16
#define LCD_ROWS 2

DHT dht(DHT_PIN, DHTTYPE);
LiquidCrystal_I2C lcd(LCD_I2C_ADDR, LCD_COLS, LCD_ROWS);

static void showSensorError(void) {
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("DHT read error");
  lcd.setCursor(0, 1);
  lcd.print("chk D2 / DHT22");
}

void setup() {
  Serial.begin(9600);
  lcd.init();
  lcd.backlight();
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Uno + DHT22");
  lcd.setCursor(0, 1);
  lcd.print("LCD I2C 0x27");
  delay(800);
  dht.begin();
  Serial.println(F("Arduino Uno — DHT22 @ D2, LCD1602 I2C SDA=A4 SCL=A5 addr=0x27"));
}

void loop() {
  delay(2000);

  float rh = dht.readHumidity();
  float tC = dht.readTemperature();

  if (isnan(rh) || isnan(tC)) {
    Serial.println(F("[err] DHT read failed — wiring / type / 2s sample"));
    showSensorError();
    return;
  }

  float hiC = dht.computeHeatIndex(tC, rh, false);

  char line0[17];
  char line1[17];
  (void)snprintf(line0, sizeof(line0), "T:%4.1fC H:%4.0f%%", tC, rh);
  (void)snprintf(line1, sizeof(line1), "HeatIdx:%5.1fC", hiC);

  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print(line0);
  lcd.setCursor(0, 1);
  lcd.print(line1);

  Serial.print(F("RH: "));
  Serial.print(rh, 1);
  Serial.print(F("%  T: "));
  Serial.print(tC, 1);
  Serial.print(F(" C  HI: "));
  Serial.print(hiC, 1);
  Serial.println(F(" C"));
}

Step D — Running The Simulator And Serial Monitor

Wokwi simulator opened in Cursor Desktop, showing the board and LCD
Wokwi simulator running in Cursor Desktop. The LCD updates with two rows of readings.
Wokwi serial monitor printing humidity, temperature, and heat index
Serial monitor at 9600 baud. It prints the same data shown on the LCD, which makes debugging easier.
Wokwi run: Uno, DHT22, and I2C LCD with live humidity, temperature, heat index; serial log aligned with the display
Result — full run: one frame from the live simulation: the LCD shows humidity, temperature, and heat index (feel), and the serial panel below prints the matching values so the sense → display → log path is obvious.

Step E — Reproducing The Simulation

  1. Open code/week04/wokwi/ as the project folder in Cursor Desktop.
  2. Install the Wokwi Simulator extension and run Wokwi: Start Simulator.
  3. Check that the libraries in libraries.txt are available.
  4. Watch the LCD and serial monitor while the simulated DHT22 values update.
  5. Click the DHT22 part in Wokwi and change the simulated temperature or humidity to test the program.
  6. For real hardware, check the DHT module pull-up requirement, LCD I2C address, and 5 V/GND wiring before powering the circuit.

5. Conclusion

This exercise gave me a working chain from a physical quantity to a readable output: the DHT22 turns temperature and humidity into values in the sketch, the LCD shows them locally, and Serial sends them back to the computer. The main wiring detail I learned is that the DHT22 data pin label can be confusing in Wokwi: it says SDA, but in this circuit it is a single data line connected to D2, not the LCD's I2C bus.

Files: the Wokwi project is stored in code/week04/wokwi/ (sketch.ino, diagram.json, and libraries.txt). Screenshots and photos are in images/week04/, including the Wokwi captures, the combined result frame, and the two LCD backpack address figures (wiki table and hardware photo).

My next step is to connect the same type of sensor to a real board, compare the simulated values with physical readings, and decide what temperature thresholds the final project character should respond to.

Group assignment

Guangzhou (Chaihuo) — group documentation: comparing toolchains and development workflows across embedded architectures.

Abstract

The group demonstrates and contrasts what is available on different embedded architectures in the lab: not only compilers and link scripts, but the full toolchain (build system, programmer/debug probe, flashing utilities, debug servers, and board-support packages) and the day-to-day workflow from “edit code” to “running firmware on hardware.” The write-up compares development software (IDEs, extensions, vendor tools), programming languages in use (C, C++, Rust, MicroPython, etc.), and pre-deployment utilities (linters, simulators, packaging, CI) as part of one coherent story. It should make it obvious why a student would pick one stack versus another for a given board or assignment.

Case study: RP2040 vs ESP32-C3 (Seeed XIAO)

The group uses Raspberry Pi RP2040 and Espressif ESP32-C3 as two common Fab-lab paths: RP2040 highlights PIO, dual-core MCU, USB device capability, and an “MCU + external flash” model without on-chip radio; ESP32-C3 adds 2.4 GHz Wi‑Fi and Bluetooth 5 LE on a single-core RISC-V for connected / low-power IoT. The thumb-sized Seeed XIAO RP2040 and XIAO ESP32C3 share a similar footprint, so they are a fair pair for a toolchain comparison.

Seeed XIAO RP2040 development board
Figure 1: Seeed XIAO RP2040 — RP2040 toolchain case study hardware.
Seeed XIAO ESP32-C3 development board
Figure 2: Seeed XIAO ESP32C3 — ESP32-C3 / wireless toolchain case study hardware.

References: Seeed Studio — XIAO series introduction (online) · offline copy in this repo: xiao-series-introduction-seeed-wiki.html.

Chip capabilities (check datasheets for your revision)

Comparison chart of multiple MCU families and features
Figure 3: Multi-MCU comparison chart — use with the table below and vendor datasheets for your silicon revision.
Topic RP2040 ESP32-C3
CPU Dual ARM Cortex-M0+, typically 133 MHz (overclocking depends on board and firmware) Single-core 32-bit RISC-V, up to about 160 MHz
On-chip SRAM 264 KB (multi-bank) About 400 KB (partitioning per Espressif datasheet)
Program storage No in-package flash; external QSPI serial flash (often 2–16 MB) In-package or on-board flash common (~4 MB class for many modules)
Wireless No built-in Wi‑Fi / Bluetooth 2.4 GHz Wi‑Fi (802.11 b/g/n) + Bluetooth 5 LE
USB USB 1.1 controller + PHY (device or host roles depend on SDK and hardware) USB serial / JTAG paths for flash and debug (exact options depend on chip revision and board)
Notable peripherals PIO (eight state machines) for custom fast I/O protocols Rich connectivity: wireless stacks, GDMA, multiple SPI / I2C / UART, PWM, ADC, etc.
ADC On-chip ADC (channels and resolution per RP2040 datasheet) 12-bit SAR ADC (available GPIO count depends on package / module)
GPIO (chip) Up to about 30 multifunction GPIO About 22 programmable GPIO (XIAO exposes a subset)
Security Typical MCU features (no integrated wireless security stack) Optional secure boot, flash encryption, hardware crypto accelerators (series / config dependent)
Typical supply Often about 1.8–5.5 V (confirm on Pico / XIAO schematic) Often 3.0–3.6 V at the module (USB 5 V via LDO)

XIAO boards break out far fewer pins than the chip maximum; routing, antenna, and USB front-end affect which GPIO and RF performance you actually get.

Toolchains and workflows (typical class paths)

Stage RP2040 (e.g. XIAO RP2040) ESP32-C3 (e.g. XIAO ESP32C3)
Official SDK Pico SDK (CMake + GCC); verify pin map and clocks for XIAO ESP-IDF (FreeRTOS components); idf.py build flash monitor
Arduino Arduino-Pico core arduino-esp32 — select ESP32-C3 board target
Scripting MicroPython / CircuitPython (mature on RP2040) MicroPython and other scripting options; many Wi‑Fi examples
Debug SWD (Pico Probe, DAPLink, etc.); printf-style trace in some setups OpenOCD + GDB, USB-JTAG paths depending on silicon and board
Flash UF2 drag-and-drop (BOOTSEL) or SWD to external flash UART download, USB flash; ESP-IDF integration
Pre-flash tooling clangd, PIO tooling ideas from Raspberry Pi docs, optional static analysis idf.py menuconfig, partition table, Wi‑Fi provisioning, log levels
Ecosystem strengths USB gadgets, LED / display drivers, PIO for odd protocols MQTT / HTTP, BLE, provisioning, OTA (with security care)

How to choose (for coursework)

  • Sensor-heavy, real-time GPIO, custom protocols, no network: RP2040 is often simpler; PIO can implement timing without saturating the CPU.
  • Cloud / phone BLE / always-on connectivity: ESP32-C3 ships wireless stacks and examples; Arduino and ESP-IDF communities are large.
  • Documentation tip: for each board, write one command sequence from new project → build → flash → serial monitor → (optional) step debug, and log one real failure (wrong COM port, boot mode, CMake toolchain version, etc.).

1. Architectures and boards

Name at least two embedded families or boards the lab actually uses (e.g. AVR, SAMD, STM32, ESP32, RP2040, RISC-V) and what each is good for in coursework.

2. Toolchain inventory per target

For each architecture, list the compiler/toolchain, flash method, debugger (if any), and default BSP or core packages.

3. Workflow comparison

Compare side by side: project creation, build, flash, serial monitor, breakpoint debugging (if supported), and common failure modes.

4. Languages and pre-deployment tools

Summarize language choices and tools used before flashing (formatting, static checks, emulation where relevant).