Panel For Example Panel For Example Panel For Example

Embedded STM32 Smartwatch Implementation

Author : Adrian October 02, 2025

Embedded STM32 Smartwatch

Overview

This project implements a multi-level menu UI on an OLED driven by an embedded STM32. It is a compact STM32 project that integrates multiple sensors and an OLED display to realize a simple smart terminal. The multi-level menu UI uses a common struct-index approach to switch between functions, combined with DHT11, RTC, LED, and key inputs to provide integrated operation.

1. Introduction

The hardware can be adapted into a custom board for devices such as a smartwatch. At present the project runs bare-metal with CPU usage at 100%. Future work may add an RTOS.

2. Hardware Photo

Hardware photo

3. Hardware Pinout

OLED module: VCC --> 3.3V GND --> GND SCL --> PB10 SDA --> PB11 DHT11 module: DATA --> PB9 VCC --> 3.3V GND --> GND KEY module (this section uses pins from the development board): KEY0 --> PE4 KEY1 --> PE3 KEY_UP --> PA0

4. Multi-level Menu

With industrial automation, almost all projects require a display terminal. Multi-level menus are a common part of display projects. On larger TFT-LCD screens many open-source GUIs can be ported, for example LVGL. On a 0.96-inch OLED, the multi-level menu usually needs to be adapted and implemented manually.

5. CubeMX Configuration

  1. RCC: configure external high-speed crystal oscillator (HSE) for higher accuracy.
  2. SYS: set Debug to Serial Wire to avoid potential chip lockup.
  3. I2C2: instead of using CubeMX I2C2 peripheral, this project simulates I2C with GPIOs (PB10: CLK; PB11: SDA).
  4. RTC: configure year, month, day, hour, minute, second.
  5. TIM2: DHT11 requires microsecond-level delays, while HAL provides only millisecond delays, so a timer-based microsecond delay is implemented.
  6. KEY inputs: configure PE3, PE4, and PA0 as GPIO inputs according to the development board schematic.

6. Code

6.1 OLED Driver Header

#ifndef __OLED_H #define __OLED_H #include "main.h" #define u8 uint8_t #define u32 uint32_t #define OLED_CMD 0 // write command #define OLED_DATA 1 // write data #define OLED0561_AD 0x78 // OLED I2C address #define COM 0x00 // OLED #define DAT 0x40 // OLED #define OLED_MODE 0 #define SIZE 8 #define XLevelL 0x00 #define XLevelH 0x10 #define Max_Column 128 #define Max_Row 64 #define Brightness 0xFF #define X_WIDTH 128 #define Y_WIDTH 64 // -----------------OLED IIC GPIO emulation---------------- #define OLED_SCLK_Clr() HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_RESET) // SCL #define OLED_SCLK_Set() HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_SET) #define OLED_SDIN_Clr() HAL_GPIO_WritePin(GPIOB, GPIO_PIN_11, GPIO_PIN_RESET) // SDA #define OLED_SDIN_Set() HAL_GPIO_WritePin(GPIOB, GPIO_PIN_11, GPIO_PIN_SET) // I2C GPIO emulation void IIC_Start(); void IIC_Stop(); void IIC_WaitAck(); void IIC_WriteByte(unsigned char IIC_Byte); void IIC_WriteCommand(unsigned char IIC_Command); void IIC_WriteData(unsigned char IIC_Data); void OLED_WR_Byte(unsigned dat,unsigned cmd); // Function prototypes void OLED_Init(void); void OLED_WR_Byte(unsigned dat,unsigned cmd); void OLED_FillPicture(unsigned char fill_Data); void OLED_SetPos(unsigned char x, unsigned char y); void OLED_DisplayOn(void); void OLED_DisplayOff(void); void OLED_Clear(void); void OLED_On(void); void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 Char_Size); u32 oled_pow(u8 m,u8 n); void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 size2); void OLED_ShowString(u8 x,u8 y,u8 *chr,u8 Char_Size); #endif

6.2 Dino Game Graphics Header

#ifndef __DINOGAME_H #define __DINOGAME_H void OLED_DrawBMP(unsigned char x0, unsigned char y0,unsigned char x1, unsigned char y1,unsigned char BMP[]); void OLED_DrawBMPFast(const unsigned char BMP[]); void oled_drawbmp_block_clear(int bx, int by, int clear_size); void OLED_DrawGround(); void OLED_DrawCloud(); void OLED_DrawDino(); void OLED_DrawCactus(); int OLED_DrawCactusRandom(unsigned char ver, unsigned char reset); int OLED_DrawDinoJump(char reset); void OLED_DrawRestart(); void OLED_DrawCover(); #endif

6.3 Dino Game Control Code

#include "control.h" #include "oled.h" #include "dinogame.h" #include "stdlib.h" unsigned char key_num = 0; unsigned char cactus_category = 0; unsigned char cactus_length = 8; unsigned int score = 0; unsigned int highest_score = 0; int height = 0; int cactus_pos = 128; unsigned char cur_speed = 30; char failed = 0; char reset = 0; int get_key(){ if(HAL_GPIO_ReadPin(GPIOE, GPIO_PIN_4)==0) { HAL_Delay(10); // Delay if(HAL_GPIO_ReadPin(GPIOE, GPIO_PIN_4)==0) { return 2; } } if(HAL_GPIO_ReadPin(GPIOE, GPIO_PIN_3)==0) { HAL_Delay(10); // Delay if(HAL_GPIO_ReadPin(GPIOE, GPIO_PIN_3)==0) { return 1; } } if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0)==1) { HAL_Delay(10); // Delay if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0)==1) { return 3; } } return 0; } void Game_control(){ while(1) { if(get_key() == 3) // If WK_UP key is pressed, force exit one loop { break; } if (failed == 1) { OLED_DrawRestart(); key_num = get_key(); if (key_num == 2) { if(score > highest_score) highest_score = score; score = 0; failed = 0; height = 0; reset = 1; OLED_DrawDinoJump(reset); OLED_DrawCactusRandom(cactus_category, reset); OLED_Clear(); } continue; } score++; if (height <= 0) key_num = get_key(); OLED_DrawGround(); OLED_DrawCloud(); if (height>0 || key_num == 1) height = OLED_DrawDinoJump(reset); else OLED_DrawDino(); cactus_pos = OLED_DrawCactusRandom(cactus_category, reset); if(cactus_category == 0) cactus_length = 8; else if(cactus_category == 1) cactus_length = 16; else cactus_length = 24; if (cactus_pos + cactus_length < 0) { cactus_category = rand()%4; OLED_DrawCactusRandom(cactus_category, 1); } if ((height < 16) && (cactus_pos>=16 && cactus_pos <=32) || (cactus_pos + cactus_length>=16 && cactus_pos + cactus_length <=32)) { failed = 1; } OLED_ShowString(35, 0, "HI:", 12); OLED_ShowNum(58, 0, highest_score, 5, 12); OLED_ShowNum(98, 0, score, 5, 12); reset = 0; cur_speed = score/20; if (cur_speed > 29) cur_speed = 29; HAL_Delay(30 - cur_speed); key_num = 0; } }

6.4 Multi-level Menu Core Header

#ifndef __MENU_H #define __MENU_H #include "main.h" #define u8 unsigned char // Key definitions #define KEY0 HAL_GPIO_ReadPin(GPIOE, GPIO_PIN_4) // active low #define KEY1 HAL_GPIO_ReadPin(GPIOE, GPIO_PIN_3) // active low #define WK_UP HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) // active high typedef struct{ u8 current; // current state index u8 next; // next state u8 enter; // enter u8 back; // back void (*current_operation)(void); // operation to execute for current state } Menu_table; // UI screens void home(); void Temperature(); void Palygame(); void Setting(); void Info(); void Menu_key_set(void); u8 KEY_Scan(u8 mode); void TestTemperature(); void ConrtolGame(); void Set(); void Information(); void LED(); void RTC_display(); #endif

7. Summary

This project is an initial, simple implementation of a multi-level menu UI on an OLED with an STM32. The UI currently uses static icons for battery and signal; future development may add battery coulomb counting to measure battery capacity. The article highlights areas to note and possible improvements for further development.

Recommended Reading
How Smartwatches Monitor Sleep

How Smartwatches Monitor Sleep

October 31, 2025

Overview of how wearables use actigraphy and cardiopulmonary coupling (CPC) to infer sleep stages, assess deep sleep accuracy, and enable at-home physiological sleep monitoring.

Article
Smartwatch and Patch Using a Piezoelectric Blood Pressure Sensor

Smartwatch and Patch Using a Piezoelectric Blood Pressure Sensor

October 31, 2025

KAIST-developed wearable piezoelectric blood pressure sensor validated in clinical trials, meeting accuracy standards and integrated into smartwatch and patch prototypes.

Article
Wearable Sensor for Detecting and Monitoring Muscle Atrophy

Wearable Sensor for Detecting and Monitoring Muscle Atrophy

October 31, 2025

Ohio State researchers developed a wearable sensor to detect and monitor muscle atrophy using conductive e-threads and coil-based sensing for volumetric limb tracking.

Article
Wearable Bistable Triboelectric Generator for Low-Frequency Harvesting

Wearable Bistable Triboelectric Generator for Low-Frequency Harvesting

October 31, 2025

Wearable bistable triboelectric nanogenerator using a flexible negative-stiffness mechanism to harvest low-frequency torsional energy from human motion and power low-power sensors.

Article
Skin-Integrated PPG-ECG Multimodal Sensing Patch Design

Skin-Integrated PPG-ECG Multimodal Sensing Patch Design

October 02, 2025

Skin-integrated PPG-ECG patch using ultraflexible organic photodetectors and hydrogel electrodes to monitor HR, RR, cuffless BP and SpO2 with high NIR responsivity.

Article
Multimodal Wearable Sensor Patch for Continuous Plant Monitoring

Multimodal Wearable Sensor Patch for Continuous Plant Monitoring

October 02, 2025

Multimodal wearable sensor patch for continuous plant physiology monitoring detects leaf VOCs, temperature and humidity; PCA-based ML enables earlier disease and stress detection.

Article