MICHAEL CADIZPaul Rodolf P. Castor
Published

Digital Clock on LCD using RT-SPARK

A precision digital clock built from scratch on an STM32F407 using hardware timers, interrupts, and a PWM-fading LED indicator.

AdvancedFull instructions provided3 hours4
Digital Clock on LCD using RT-SPARK

Things used in this project

Hardware components

Rotary potentiometer (generic)
Rotary potentiometer (generic)
×1
Breadboard (generic)
Breadboard (generic)
×1
Jumper wires (generic)
Jumper wires (generic)
×26
RGB Backlight LCD - 16x2
Adafruit RGB Backlight LCD - 16x2
×1
Resistor 220 ohm
Resistor 220 ohm
×1
LED (generic)
LED (generic)
×1

Story

Read more

Code

Digital Clock

C/C++
/* USER CODE BEGIN Includes */
#include <stdio.h>
#include "lcd.h"
/* USER CODE END Includes */

///////////////////////////////////////////

/* USER CODE BEGIN PV */
volatile uint8_t h = 0;   // hours
volatile uint8_t m = 0;   // minutes
volatile uint8_t s = 0;   // seconds
volatile uint16_t ms = 0; // milliseconds

volatile uint8_t lcd_update_requested = 0; // Flag for main loop
/* USER CODE END PV */

///////////////////////////////////////////

int main(void)
{
  /* MCU Configuration--------------------------------------------------------*/
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_TIM2_Init();
  MX_TIM3_Init();
  
  /* USER CODE BEGIN 2 */
  LCD_Init(); 
  HAL_TIM_Base_Start_IT(&htim2);
  HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1);
  /* USER CODE END 2 */
  
//////////////////////////////////////////////////

/* USER CODE BEGIN WHILE */
  while (1)
  {
      if (lcd_update_requested == 1) {
          lcd_update_requested = 0;

          // Thread-safe copy
          __disable_irq();
          uint8_t disp_h = h;
          uint8_t disp_m = m;
          uint8_t disp_s = s;
          uint16_t disp_ms = ms;
          __enable_irq();

          // Format strings
          char time_str1[16];
          char time_str2[16];
          sprintf(time_str1, "%02d:%02d", disp_h, disp_m);      
          sprintf(time_str2, "%02d.%03d", disp_s, disp_ms);     

          // Send to LCD 
          LCD_SetCursor(0,0);      
          LCD_Print(time_str1);    
          LCD_SetCursor(1,0);      
          LCD_Print(time_str2);    
      }
    /* USER CODE END WHILE */
    
/////////////////////////////////////////////////////

/* USER CODE BEGIN 4 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if (htim->Instance == TIM2) {
        
        // 1. Update Time
        ms++;
        if (ms >= 1000) {
            ms = 0;
            s++;
            if (s >= 60) {
                s = 0;
                m++;
                if (m >= 60) {
                    m = 0;
                    h = (h + 1) % 24;
                }
            }
        }

        // 2. Request LCD Update every 100ms
        if (ms % 100 == 0) {
            lcd_update_requested = 1;
        }

        // 3. LED PWM Fading Logic (100% to 0% over 600ms)
        if (ms < 600) {
            uint32_t duty = 999 - ((ms * 999) / 600);
            __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, duty);
        } else {
            __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, 0);
        }
    }
}
/* USER CODE END 4 */

////////////////////////////////////////////////
lcd.h
#ifndef INC_LCD_H_
#define INC_LCD_H_

#include "main.h" 

// Pin Definitions for Port G
#define RS_PORT LCD_RS_GPIO_Port
#define RS_PIN  LCD_RS_Pin

#define EN_PORT LCD_EN_GPIO_Port
#define EN_PIN  LCD_EN_Pin

#define D4_PORT LCD_D4_GPIO_Port
#define D4_PIN  LCD_D4_Pin

#define D5_PORT LCD_D5_GPIO_Port
#define D5_PIN  LCD_D5_Pin

#define D6_PORT LCD_D6_GPIO_Port
#define D6_PIN  LCD_D6_Pin

#define D7_PORT LCD_D7_GPIO_Port
#define D7_PIN  LCD_D7_Pin

void LCD_Init(void);
void LCD_SetCursor(uint8_t row, uint8_t col);
void LCD_Print(char *str);

#endif /* INC_LCD_H_ */

///////////////////////////////////////////////////////
lcd.c
#include "lcd.h"

void pulse_enable(void) {
    HAL_GPIO_WritePin(EN_PORT, EN_PIN, GPIO_PIN_SET);
    HAL_Delay(1); 
    HAL_GPIO_WritePin(EN_PORT, EN_PIN, GPIO_PIN_RESET);
    HAL_Delay(1);
}

void send_4bits(uint8_t data) {
    HAL_GPIO_WritePin(D4_PORT, D4_PIN, ((data >> 0) & 0x01) ? GPIO_PIN_SET : GPIO_PIN_RESET);
    HAL_GPIO_WritePin(D5_PORT, D5_PIN, ((data >> 1) & 0x01) ? GPIO_PIN_SET : GPIO_PIN_RESET);
    HAL_GPIO_WritePin(D6_PORT, D6_PIN, ((data >> 2) & 0x01) ? GPIO_PIN_SET : GPIO_PIN_RESET);
    HAL_GPIO_WritePin(D7_PORT, D7_PIN, ((data >> 3) & 0x01) ? GPIO_PIN_SET : GPIO_PIN_RESET);
    pulse_enable();
}

void LCD_SendCommand(uint8_t cmd) {
    HAL_GPIO_WritePin(RS_PORT, RS_PIN, GPIO_PIN_RESET); 
    send_4bits(cmd >> 4);   
    send_4bits(cmd & 0x0F); 
}

void LCD_SendData(uint8_t data) {
    HAL_GPIO_WritePin(RS_PORT, RS_PIN, GPIO_PIN_SET); 
    send_4bits(data >> 4);   
    send_4bits(data & 0x0F); 
}

void LCD_Init(void) {
    HAL_Delay(50);  
    HAL_GPIO_WritePin(RS_PORT, RS_PIN, GPIO_PIN_RESET);
    send_4bits(0x03);
    HAL_Delay(5);
    send_4bits(0x03);
    HAL_Delay(1);
    send_4bits(0x03);
    HAL_Delay(1);
    send_4bits(0x02); 

    LCD_SendCommand(0x28); 
    LCD_SendCommand(0x0C); 
    LCD_SendCommand(0x01); 
    HAL_Delay(2);
    LCD_SendCommand(0x06); 
}

void LCD_SetCursor(uint8_t row, uint8_t col) {
    uint8_t address = (row == 0) ? (0x80 + col) : (0xC0 + col);
    LCD_SendCommand(address);
}

void LCD_Print(char *str) {
    while (*str) {
        LCD_SendData((uint8_t)(*str));
        str++;
    }
}

Credits

MICHAEL CADIZ
4 projects • 0 followers
Paul Rodolf P. Castor
21 projects • 9 followers

Comments