STM32マイコンによる電子時計の実装

システム設計と構成

ハードウェア構成

本システムはSTM32F103C8T6マイコンをコアとして、以下の周辺デバイスと接続されています:

  • OLEDディスプレイ(SSD1306ドライバ) - I2Cバス経由
  • 4x4マトリクスキーパッド - 外部割込み(EXTI)
  • ブザー(アラーム出力用)

ソフトウェア構成

  • システムティックタイマ(SysTick)による1ms精度の時間管理
  • SSD1306ドライバによるOLED表示制御
  • キーマトリクススキャンと外部割込み処理
  • 低消費電力モードの実装

ハードウェア初期化

システムクロック設定


void ConfigureSystemClock(void)
{
    RCC_OscInitTypeDef osc_init = {0};
    RCC_ClkInitTypeDef clk_init = {0};

    // HSE発振器とPLLの設定
    osc_init.OscillatorType = RCC_OSCILLATORTYPE_HSE;
    osc_init.HSEState = RCC_HSE_ON;
    osc_init.PLL.PLLState = RCC_PLL_ON;
    osc_init.PLL.PLLSource = RCC_PLLSOURCE_HSE;
    osc_init.PLL.PLLMUL = RCC_PLL_MUL9;
    HAL_RCC_OscConfig(&osc_init);

    // クロックドメインの構成
    clk_init.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK
                       | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
    clk_init.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
    clk_init.AHBCLKDivider = RCC_SYSCLK_DIV1;
    clk_init.APB1CLKDivider = RCC_HCLK_DIV2;
    clk_init.APB2CLKDivider = RCC_HCLK_DIV1;
    HAL_RCC_ClockConfig(&clk_init, FLASH_LATENCY_2);
}

OLEDディスプレイ初期化


void InitializeSSD1306(void)
{
    // 基本設定コマンド
    SSD1306_WriteCommand(0xAE); // ディスプレイオフ
    SSD1306_WriteCommand(0x20); // アドレスモード設定
    SSD1306_WriteCommand(0x00); // 水平アドレスモード
    SSD1306_WriteCommand(0xB0); // ページアドレス設定
    SSD1306_WriteCommand(0xC8); // COMスキャン方向設定
    SSD1306_WriteCommand(0x00); // 列アドレス低位
    SSD1306_WriteCommand(0x10); // 列アドレス高位
    SSD1306_WriteCommand(0x40); // 開始行設定
    SSD1306_WriteCommand(0x81); // コントラスト設定
    SSD1306_WriteCommand(0xFF); // 最大コントラスト
    SSD1306_WriteCommand(0xA1); // セグメントマッピング
    SSD1306_WriteCommand(0xA6); // 正常表示モード
    SSD1306_WriteCommand(0xA8); // 多重化比率設定
    SSD1306_WriteCommand(0x3F); // 1/64 duty
    SSD1306_WriteCommand(0xD3); // 表示オフセット
    SSD1306_WriteCommand(0x00); // オフセットなし
    SSD1306_WriteCommand(0xD5); // クロック設定
    SSD1306_WriteCommand(0x80); // 基準値
    SSD1306_WriteCommand(0xD9); // 預充電周期
    SSD1306_WriteCommand(0xF1); // 設定値
    SSD1306_WriteCommand(0xDA); // COMピン構成
    SSD1306_WriteCommand(0x12); // 設定値
    SSD1306_WriteCommand(0xDB); // VCOMH設定
    SSD1306_WriteCommand(0x40); // 電圧レベル
    SSD1306_WriteCommand(0x8D); // チャージポンプ
    SSD1306_WriteCommand(0x14); // 有効化
    SSD1306_WriteCommand(0xAF); // ディスプレイオン
}

時間管理システム

SysTick割込み処理


volatile uint32_t tick_counter = 0;

void SysTick_Handler(void)
{
    HAL_IncTick();
    tick_counter++;
}

// 時間構造体
typedef struct {
    uint8_t hour;
    uint8_t minute;
    uint8_t second;
} TimeData;

TimeData current_time = {0, 0, 0};

// 時間更新関数
void UpdateTime(void)
{
    if(tick_counter >= 1000) {
        tick_counter = 0;
        current_time.second++;
        
        if(current_time.second >= 60) {
            current_time.second = 0;
            current_time.minute++;
            
            if(current_time.minute >= 60) {
                current_time.minute = 0;
                current_time.hour++;
                
                if(current_time.hour >= 24) {
                    current_time.hour = 0;
                }
            }
        }
    }
}

ユーザーインターフェース実装

マトリクスキーパッドスキャン


#define ROW_COUNT 4
#define COL_COUNT 4

GPIO_TypeDef* row_ports[ROW_COUNT] = {GPIOA, GPIOA, GPIOA, GPIOA};
uint16_t row_pins[ROW_COUNT] = {GPIO_PIN_0, GPIO_PIN_1, GPIO_PIN_2, GPIO_PIN_3};

GPIO_TypeDef* col_ports[COL_COUNT] = {GPIOB, GPIOB, GPIOB, GPIOB};
uint16_t col_pins[COL_COUNT] = {GPIO_PIN_0, GPIO_PIN_1, GPIO_PIN_2, GPIO_PIN_3};

char ScanKeyMatrix(void)
{
    for(uint8_t col=0; col

メイン制御ループ


int main(void)
{
    HAL_Init();
    ConfigureSystemClock();
    InitializeGPIO();
    InitializeI2C();
    InitializeSSD1306();
    
    // 時間初期化
    current_time.hour = 12;
    current_time.minute = 0;
    current_time.second = 0;
    
    while(1)
    {
        UpdateTime();
        
        OLED_Clear();
        OLED_ShowString(0, 0, "時刻:");
        OLED_DisplayTime(32, 0);
        OLED_ShowString(0, 2, "現在:");
        OLED_DisplayTime(32, 2);
        
        char key = ScanKeyMatrix();
        if(key != 0xFF) {
            ProcessKeyInput(key);
        }
    }
}

拡張機能の実装

アラーム機能


typedef struct {
    uint8_t active;
    uint8_t hour;
    uint8_t minute;
} AlarmData;

AlarmData alarm = {0, 7, 30}; // 7:30にアラーム

void CheckAlarm(void)
{
    if(!alarm.active) return;
    
    if(current_time.hour == alarm.hour &&
       current_time.minute == alarm.minute &&
       current_time.second == 0) {
        ActivateBuzzer(); // ブザー作動
        HAL_Delay(30000); // 30秒間
        DeactivateBuzzer();
    }
}

タグ: STM32 ssd1306 OLED I2C SysTick

8月4日 12:56 投稿