STM32 マイコン(STM32F334R8)に内蔵されている RTC(リアルタイム・クロック)を使って時計を作ってみます。
マイコンボードは STMicroelectronics 社の NUCLEO-F334R8 を使いました。 時刻の表示には「有機 EL ディスプレイ(OLED) SO1602A を使う」で紹介した有機 EL ディスプレイ SO1602A を使いました。
STM32CubeMX を使ってプロジェクトを作ります。
STM32CubeMX のメイン画面,Pinout タブの Configuration → Peripherals → RTC で設定を行います。
今回使用したマイコンボード NUCLEO-F334R8 には RTC 用の 32.768 kHz 水晶発振子が搭載されているので,これを使うようにします。
1 秒ごとに割り込みを発生させるための設定を行います。
以上で,1 秒ごとに割り込みがかかるようになりますが,HAL_Delay 関数を使うときの問題を回避するため,"RTC wake-up" 割り込みの優先順位を下げておきます。
以上で,STM32CubeMX での設定は終わりです。"Project" メニューの "Generate Code" でコードを生成し,お好みの統合開発環境で,コードを追加していきます。ちなみに私は,Atllic の TrueStudio を使っています。
STM32CubeMX で生成されたコードを読んでみます。 RTC wake-up 割り込みが発生すると,RTC_WKUP_IRQHandler 関数が呼ばれます。 そこから,HAL_RTCEx_WakeUpTimerIRQHandler が呼ばれます。 その中で,HAL_RTCEx_WakeUpTimerEventCallback が呼ばれます。
HAL_RTCEx_WakeUpTimerEventCallback は __weak 属性で定義されているので,この関数を再定義して処理するのが良さそうです。
void HAL_RTCEx_WakeUpTimerEventCallback(RTC_HandleTypeDef *hrtc)
{
// ここに 1 秒ごとの処理を書く
}
時刻の取得は HAL_RTC_GetTime 関数で行なえます。
ただし,HAL_RTC_GetTime を読んだあとは,(日付が必要なくても),HAL_RTC_GetDate を呼ばないといけないようです。そうしないと処理が止まります。
ソースコードは以下のようになります。
void HAL_RTCEx_WakeUpTimerEventCallback(RTC_HandleTypeDef *hrtc)
{
RTC_DateTypeDef date;
RTC_TimeTypeDef time;
HAL_RTC_GetTime(hrtc, &time, RTC_FORMAT_BCD);
HAL_RTC_GetDate(hrtc, &date, RTC_FORMAT_BCD);
OLED_WriteInstraction(0x02); // Return Home
PrintTime(&time);
}
上で使っている PrintTime 関数は以下のように定義しました。
// 1 文字表示
void PutChar(int c)
{
OLED_WriteData(c);
}
// BCD(2 進化 10 進数) の表示
void PrintBCD(uint8_t n)
{
PutChar(((n >> 4) & 0xf) + '0');
PutChar((n & 0xf) + '0');
}
// 時刻の表示
void PrintTime(RTC_TimeTypeDef *time)
{
PrintBCD(time->Hours);
PutChar(':');
PrintBCD(time->Minutes);
PutChar(':');
PrintBCD(time->Seconds);
}
OLED_WriteData,OLED_WriteInstraction 関数は,「有機 EL ディスプレイ(OLED) SO1602A を使う」で定義したものです。
以上で 1 秒ごとに(起動からの)時刻を表示できるようになりました。
実際に時計として使うには,時刻や日付を設定する仕組みが必要です。時刻の設定は HAL_RTC_SetTime 関数,日付の設定は HAL_RTC_SetDate 関数で行なえます。