Greenhouse Climate Monitor

The HS3001 is a small temperature and humidity sensor that talks over I2C. Your job is to wire it up (including the pull-up resistors on the I2C lines), read its 4 byte measurement, work out the temperature and humidity from those bytes, and send the results out over UART. It's the sort of code you'd write for any board that needs to keep track of its surroundings.

Board
STM32 · HAL
Difficulty
Medium
Topic
Timers & Interrupts
Access
Free

The task

Greenhouse Climate Monitor

You've just joined the firmware team at VerdeGrow, a startup building smart greenhouses. Each grow-pod has an STM32 controller wired to an HS3001 temperature & humidity sensor over I2C. The cloud dashboard expects a steady stream of climate readings over the controller's UART link.

The hardware team finished the board. The sensor is connected and powered. The only thing missing is the firmware that actually talks to the sensor and reports the climate — that's your job.

Your Task

Complete userCode() in Core/Src/userCode.c so that it:

  1. Reads the HS3001 sensor over I2C1.
  2. Decodes the raw bytes into temperature (°C) and relative humidity (%RH).
  3. Prints both values over UART4.
  4. Takes 10 readings, waiting 100 ms between each.
  5. Returns once all 10 readings are done.

Expected output (your exact decimals may differ slightly):

Temp: 25.01 C  Humidity: 60.02 %RH
Temp: 25.01 C  Humidity: 60.02 %RH
Temp: 25.01 C  Humidity: 60.02 %RH
...

Printing Over UART

Format each reading with snprintf() and send it with HAL_UART_Transmit():

char message[48];
snprintf(message, sizeof(message),
         "Temp: %.2f C  Humidity: %.2f %%RH\r\n", tempC, humidityRH);
HAL_UART_Transmit(&huart4, (uint8_t *)message, strlen(message), 100);
Handles are already provided

The handles you need are already provided from main.c:

extern I2C_HandleTypeDef hi2c1;
extern UART_HandleTypeDef huart4;
Printing a literal % sign

%% prints a literal % sign inside a format string.


Timing & Loop

Take exactly 10 readings with a 100 ms pause between them:

for (int i = 0; i < 10; i++)
{
    // 1. read 4 bytes from the sensor
    // 2. decode raw humidity + temperature
    // 3. convert to %RH and °C
    // 4. print over UART4
    HAL_Delay(100);
}
Watch the byte order

Do the math in float, but watch the byte order: temperature lives in bytes 2–3, humidity in bytes 0–1.


Success Criteria

Your solution is complete when:

  1. The firmware builds.
  2. userCode() runs and reads the sensor.
  3. UART prints 10 lines, each with a temperature and a humidity value.
  4. There is a 100 ms gap between readings.
  5. userCode() returns after the 10th reading.

What you get

  • Your firmware is built and run on an emulated board and checked by hardware-level tests.
  • A video walkthrough of the solution.
  • No development board or local toolchain needed.

New to embedded? Start with the roadmap: How to learn embedded systems