システム設計と構成
ハードウェア構成
本システムは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();
}
}