41a RTCをバッテリバックアップで動かしてみる (NVIC,RTC,BKP,GPIO,UART,LEDチカチカ)
わたしはRTC(real-time clock)を使うのは初めてです.
RTCって何?
Q: 一口で言うとRTCってなに?
A: バッテリバックアップされたタイマ
Q: リアルタイムクロックというからには年月日とかうるう年も識別してくれるの?
A: ちがいます.STM32-DISCOVERYのCPUではカレンダーは搭載してません.カウンタはただのストレートなカウンタです.
Q: 最大でどれだけカウントできるの?
A: カウンタは32bitですので、1秒毎にカウントすると130年ぐらい持ちます.何秒毎にカウントするかはプログラムできます.
Q: 23:59:59になったら自動的に00:00:00に戻るの?
A: ちがいます.ユーザーがプログラミングして戻します.
Q: 時間精度は?
A: 最大120ppmの微調整機能がついてます.調整機能はついてるけれどどうやって調整するのかはいまのところ不明です.
Q: clockは?
A: STM32-DISCOVERYでは外付けの32kHzのRTC専用Xtalがついてます.その他にCPU系のclockも使えます.
Q: 割り込みは?
A: アラーム割り込み、毎秒割り込み、32bitカウンタオーバーフロー割り込み
RTCのハードウエア仕様を読むと、むやみにRTCレジスタを変更しちゃまずいらしくて、手続きが必要らしいです.
そこら辺をレジスタベースで解説するとかったるいことになるので割愛します.
レジスタなんか知らなくてもライブラリ関数を使いこなせればよろしかろう.
バッテリバックアップの仕組みを知る必要がある
RTCはいきなりライブラリ関数を使えばよいとしたものの、バッテリバックアップはhardwareの仕組みを知っておく必要があります.
なので、RTCの話題から逸れますけど、以下しばらくBACKUPについて解説します.
====パワー系統ブロック図====
●メイン電源VDDは2~3.6V
●ただしCPU coreは1.8Vで動きます.そのためのLDOを内蔵しています.
●VDDA/VSSAはアナログ回路専用電源です.ADC+DAC+温度センサ+リセット+PLLがアナログ回路です.リセットがアナログ回路なのはコンパレータを含むからでしょうか? 下図によるとVREF+は2.4V以上となっているので、もしかしたらVDD<2.4VだとADCやDACが動かないのかもしれませんが、仕様は未確認です.
●STM32-DISCOVERYのCPUではVREF+はVDDAに、VREF-はVSSAに内部接続されており、pinは存在しない.
●VBATはバッテリーの接続端子です.バッテリーで駆動されるのは、内部32kHz発振器+Backup+clock+RTC です.Low Voltage detectorが作動すると、それまでVDDから電源をもらって動いていたこれらの回路がVBATから電源をもらうように切り替わります.
====VBATの注意====
VBATにはbatteryを接続しますが、データシートによると、battery-VBAT間にシリーズにshotkey diodeを挿入することがオススメされているようです.なぜか? VDDが低下するとVBATに切り替わりますが、一瞬VDDとVBATがshortするタイミングがあるそうです.その瞬間にVDD→VBATへ電流が流れ、batteryにその電流が流入します.その電流を回避するためにdiodeを挿入しておくのがよいそうです.
batterを使わないときはVBAT=VDDに接続すればOKです.
====VBATで駆動される回路の外部pinのアサイン====
●VDDが生きているとき
- PC14 と PC15 は GPIO または LSE として使える
- PC13 は GPIO, TAMPER, RTC Calibration Clock, RTC Alarm or second output として使える
●VDDが落ちているとき(VBATで動いているとき)
- PC14 と PC15 は LSE としてのみ使える
- PC13 は TAMPER, RTC Alarm or Second output として使える
====謎の機能TAMPER====
製品をハッキングしようとした人が、ネジを開けてしまったらその製品が自殺するという機能のことだそうです.
ソフトを動かすために必要なパスワードをbackup registerに記憶しておき、バッテリでbackupしておきます.
そしてTAMPERピンには、製品のフタに取りつけたSWを接続しておき、フタが開くとTAMPERがオンになって、パスワードを消してしまいます.
そんな実装をするための機能です.知ってました? わたしは初めて知りました.
====RTCキャリブレーション====
RTCの精度を向上させるためのキャリブレーション.
XtalをVXO的にキャリブレするのではなくて、たまにRTC clockを間引くことによって、時計を遅らせる方向に最大121ppmまで調節できます.そのキャリブレ設定をバッテリbackupできます.
====backupレジスタ====
●BKP_DR1[15:0] ~ BKP_DR10[15:0]
全部合わせて22BYTEのユーザーデータ置き場.
backup機能の主なところは、ここへ書いたユーザーデータがbattery backupされるっていうことのようです.
ここがクリアされる条件は特殊なので注意が必要です.
1)CPU resetではクリアされません
2)standbyからの復帰ではクリアされません
3)backup resetでクリアされる
4)TAMPERでクリアされる (TAMPER disableは可能)
●BKP_RTCCR[9:0]
ASOS[9] TAMPERピン出力選択 0:RTCアラームパルス出力 1:RTC秒パルス出力
ASOE[8] 1:TAMPERピン出力enable
CCO[7] 1:TAMPERピンにRTC clock ÷ 64 を出力する
CAL[6:0] フルビット1:RTC clockを間引いて121ppm遅くできる 範囲は0~7F
●BKP_CR[1:0]
TPAL[1] 1:TAMPERピン=1でTAMPERが働く 0:TAMPERピン=0でTAMPERが働く
●BKP_CSR[9:0]
TIF[9] 1:TAMPER割り込みあり (readのみ)
TEF[8] 1:TAMPER発生 (readのみ)
TPIE[2] 1:TAMPER割り込みenable
CTI[1] 1:TIFをクリアする
CTE[0] 1:TEFをクリアする
====バッテリバックアップするには?====
STM32-DISCOVERYは、defaultでVBAT=VDDに接続されていますので、まずはそれを外します.
外すには、SB1に載っているchip抵抗をハンダごてて外します.
それでリチウムバッテリー(3V)を下図のようにつなげばOKです.SWを取りつけるかどうかはお好みでどうぞ.
====バッテリ消費電流は?====
VDD=0VのときにテスターでLi電池の電流を測定してみましたが、とても微弱だとみえて、テスターの測定限界以下でした.
なので何uAなのかは実測では不明です.
サンプルプログラムでどんなものを作るか?
PC上のterminal softを起動し、115200bps+parityなし+8bit+stop1bit+フロー制御なし で接続します.
あと、バッテリSWはオンにしておくこと.
●STM32-DISCOVERYを起動すると、下記のように1秒毎に表示されます.
TIM3割り込みはCPU系のclockソース(8MHz xtal)で駆動されています.
時刻表示はRTC割り込みです.RTCのclockソースは32kHz xtalです.
===starting RTC test program
TIM3 interrupted 1
RTC 00:00:26 (not configured)
TIM3 interrupted 2
RTC 00:00:27 (not configured)
TIM3 interrupted 3
RTC 00:00:28 (not configured)
TIM3 interrupted 4
RTC 00:00:29 (not configured)
●TIM3割り込みでブルーLEDがチカチカしますので、LEDは1秒毎にチカチカします.
●terminal softでenter keyを入力すると、次のmenu表示がでます.
-----RTC TEST MENU-----
int 10 : LED flash 10 Hz LEDの点滅周期を10Hzにします
off : LED off LEDをオフします
on : LED on LEDの点滅をオンします
set 14 22 49 : set time 14:22:49 RTCに現在時刻14時22分49秒を設定します
-----------------------
●現在時刻を設定すると、表示が変わります.
RTC 11:08:36 (configured)
●STM32-DISCOVERYをリセットします.
===starting RTC test program 再起動メッセージ
TIM3 interrupted 1
===External Reset occurred 外部リセットされたメッセージ
===No need to configure RTC RTCを再設定する必要なしメッセージ
RTC 11:15:05 (configured) RTCはリセット前の時刻が保存されていることを確認
●USBケーブルをPCから引っこ抜いて電源をオフします.その後USBケーブルを接続し、terminal softを再接続します.
すると、RTCは電源がオフられてもバッテリバックアップされていたので電源オフ前の時刻が保存されています.
RTC 11:25:34 (configured)
サンプルプログラムのperipheral利用状況
UARTをUSBにつなぐ回路は?
UARTをUSBに変換する回路を使ってUSB経由でPCに接続します.
つかうのは秋月電子で売られているこの回路です. http://akizukidenshi.com/catalog/g/gK-01977/
STM32-DISCOVERYとの実体配線図はこのようになります.
ここではUSART3 defaultを使うので、下辺のPB10(TX),PB11(RX)から配線を取り出します.
他のUSARTを使いたい場合は下図の各所から配線を取り出します.
terminal softは別途用意してPCにインストールしてください.
XPとかの古いwindowsではhyper-terminalというのが最初からインストールされていましたが、vista以降は無くなってしまったと思います.
下記の写真の上のUSBケーブルは焼き用です.下のUSBケーブルはUSB-COM-PORTによる通信用です.
都合PCのUSB portを2ヶ占有します.
サンプルプログラム解説
サンプルプログラムはこのページの末尾からDLできます.projectの組み込み方法はこちらを参照してください.
重要な注意: 当初compile errorが出ました.エラー回避のために、syscalls.cというファイルを追加してあります.これはyagartからDLしたファイルですが、これがないとcompileできません.トラブルシュートの詳細はこちらのページを参照してください.
main.c
#include "stdio.h" このC標準関数3兄弟を使おうとするとsyscalls.cが必要になります.詳しくはこちらを参照.
#include "string.h"
#include "stdlib.h"
#include "stm32f10x.h" STM32のhardwareに根ざした設定を多数やってます
#include "usrlib-uart3d.h" UART3を使う自作ライブラリ
#include "usrlib-gpio.h" GPIOを使う自作ライブラリ
#include "usrlib-rtc.h" RTCを使う自作ライブラリ
NVIC_InitTypeDef NVIC_InitStructure; 割込優先度コントローラNVIC設定用構造体
GPIO_InitTypeDef GPIO_InitStructure; GPIO設定用構造体
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM設定用構造体
void Menu(void); UARTのメニュー処理ルーチン
int main(void) メインルーチン始まり
{
↓つかうperipheralのclockをenableしています.
clock周波数を変更するようなことは特にしてないので24MHzが供給されます.
RTCはRTC専用の初期設定ルーチンでclockをenableしてるのでここにはないです.
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE); // power for RTC
RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP, ENABLE); // backup for RTC
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); // USART1 TX/RX (default)
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); // LED
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
第一引数の選択肢は下記です.
RCC_APB1PeriphClockCmd()
RCC_APB1Periph_TIM2, RCC_APB1Periph_TIM3, RCC_APB1Periph_TIM4, RCC_APB1Periph_TIM6, RCC_APB1Periph_TIM7, RCC_APB1Periph_WWDG, RCC_APB1Periph_SPI2, RCC_APB1Periph_USART2, RCC_APB1Periph_USART3, RCC_APB1Periph_I2C1, RCC_APB1Periph_I2C2, RCC_APB1Periph_PWR, RCC_APB1Periph_DAC, RCC_APB1Periph_CEC
RCC_APB2PeriphClockCmd()
RCC_APB2Periph_AFIO, RCC_APB2Periph_GPIOA, RCC_APB2Periph_GPIOB, RCC_APB2Periph_GPIOC, RCC_APB2Periph_GPIOD, RCC_APB2Periph_GPIOE, RCC_APB2Periph_GPIOF, RCC_APB2Periph_GPIOG, RCC_APB2Periph_ADC1, RCC_APB2Periph_TIM1, RCC_APB2Periph_SPI1, RCC_APB2Periph_USART1, RCC_APB2Periph_TIM15, RCC_APB2Periph_TIM16, RCC_APB2Periph_TIM17
↓割込優先度コントローラの設定
NVIC割り込みコントローラは4bitの優先度を持っていて、つまり最大で16個の割り込み優先度設定が出来るようです、
割り込み優先度には、PreemptionPriority とSubPriority にカテゴライズされています.
前者が大分類、後者が小分類というような階層になっています.
大分類に3bitを割り当て、小分類に1bitを割り当てるような階層作りができます.
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
それをやるのがこの↑関数です.引数によって、大分類と小分類のbitアサインを決めます.
| PreemptionPriority | SubPriority |
---------------------------------------------------------
NVIC_PriorityGroup_0 | 0 (0bit) | 0-15 (4bit) |
NVIC_PriorityGroup_1 | 0-1 (1bit) | 0-7 (3bit) |
NVIC_PriorityGroup_2 | 0-3 (2bit) | 0-3 (2bit) |
NVIC_PriorityGroup_3 | 0-7 (3bit) | 0-1 (1bit) |
NVIC_PriorityGroup_4 | 0-15(4bit) | 0 (0bit) |
ここでは、RTCとTIM3とUSART3の3つの割り込みを使うので NVIC_PriorityGroup_2 にしました.
NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn; RTC割込
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; 最高優先度
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; TIM3割込
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; 2番目優先度
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn; USART2割込
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; 3番目優先度
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
↓UARTの設定
UART_Init(); 自作ライブラリの初期設定をコール
UART_PutString("===starting RTC test program\r\n"); 起動メッセージをUARTへ送信
↓LEDチカチカの設定
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9; PC8とPC9がLEDのポート.そこを出力に設定する.
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; 出力ドライブ能力は最低でよい
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; フツーの出力ポートに設定
GPIO_Init(GPIOC, &GPIO_InitStructure);
↓タイマの設定 24MHz÷24000÷1000=1Hz
TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
TIM_TimeBaseStructure.TIM_Period = 24000;
TIM_TimeBaseStructure.TIM_Prescaler = 1000;
TIM_TimeBaseStructure.TIM_ClockDivision = 0x0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);
TIM_Cmd(TIM3, ENABLE);
↓RTCの設定
RTC_Configuration(); 自作ライブラリのRTC初期設定ルーチン.あとで説明します.
↓power on resetフラグをチェック、YESならメッセージを表示
if (RCC_GetFlagStatus(RCC_FLAG_PORRST) != RESET) UART_PutString("===Power On Reset occurred\r\n");
↓resetボタンを押されたフラグをチェック、YESならメッセージを表示
if (RCC_GetFlagStatus(RCC_FLAG_PINRST) != RESET) UART_PutString("===External Reset occurred\r\n");
この関数の引数は次のようにいろいろあります.
RCC_FLAG_HSIRDY: HSI oscillator clock ready
RCC_FLAG_HSERDY: HSE oscillator clock ready
RCC_FLAG_PLLRDY: PLL clock ready
RCC_FLAG_LSERDY: LSE oscillator clock ready
RCC_FLAG_LSIRDY: LSI oscillator clock ready
RCC_FLAG_PINRST: Pin reset
RCC_FLAG_PORRST: POR/PDR reset
RCC_FLAG_SFTRST: Software reset
RCC_FLAG_IWDGRST: Independent Watchdog reset
RCC_FLAG_WWDGRST: Window Watchdog reset
RCC_FLAG_LPWRRST: Low Power reset
↓以下では、ここでのBACKUP registerの活用方法を知っておく必要があります.
最初に起動されたときには、BACKUP register 1 (BKP_DR1)は0000Hになっています.
この状態ですと、このプログラムは、時刻が未設定だと判断します.
そして、時刻が設定されたらBKP_DR1=A5A5Hに設定されます.
この状態ですと、このプログラムは、時刻設定済みだと判断します.
このように、RTCとBACKUP registerは密接な関係にあります.
↓BKP_DR1==0000ならまだ時刻が設定されていませんので、メッセージ表示
if (BKP_ReadBackupRegister(BKP_DR1) != 0xA5A5) UART_PutString("===Need to configure RTC\r\n");
↓BKP_DR1=A5A5なら時刻設定済みなので、メッセージ表示
else UART_PutString("===No need to configure RTC\r\n");
RCC_ClearFlag(); よくわからないけど、元のサンプルプログラムにあったのを踏襲.
while(1) { Menu(); } メニューを無限ループする
} メインルーチンおしまい
↓debug用関数
#ifdef USE_FULL_ASSERT
void assert_failed(uint8_t* file, uint32_t line){ while (1) { } }
#endif
↓TIM3の割り込みルーチン
char UARTbuf[100]; UART表示文字列バッファ
int times = 1; TIM3割り込みカウンタ
void TIM3_IRQHandler(void) TIM3でLEDを点滅させます
{
TIM_ClearITPendingBit(TIM3, TIM_IT_Update ); 割り込みフラグをクリア.これを怠ると次回の割り込みがかかりません.
LedBlueToggle(); ブルーLEDを点滅させる自作関数 usrlib-gpio.h の中に定義されています
sprintf(UARTbuf,"TIM3 interrupted %d\r\n",times++); UARTへメッセージを表示
UART_PutString(UARTbuf); UARTへメッセージを表示
}
↓RTC割り込みルーチン
割り込みルーチン名は、ひょんなところに明示されています.
project_top\Libraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x\startup\gcc_ride7\startup_stm32f10x_md_vl.s
もしも他の割り込みハンドラを書きたいときにはこのファイルを参照しましょう.
void RTC_IRQHandler(void)
{
if (RTC_GetITStatus(RTC_IT_SEC) != RESET) 毎秒割り込みフラグなら以下を処理
{
RTC_ClearITPendingBit(RTC_IT_SEC); 毎秒割り込みフラグをクリア
RTC_TimeDisplay(); RTCの時刻をUARTへ表示
if (RTC_GetCounter() == 0x0001517F) RTC_SetCounter(0x0); RTCが23:59:59ならば00:00:00に戻す
RTC_WaitForLastTask(); RTCのレジスタを書き換えたら必ずこの関数でwaitする
}
}
↓UARTメニュー処理ルーチン
void Menu(void)
{
int n,i;
char tmp[30];
↓UARTからコマンドラインを受信したらUART_STR_EXIST=1になる
if(UART_STR_EXIST==0) return; // there is not any command line
↓コマンドラインを単語毎にブツ切りにする
n=separate_line(command); // divide a line into words
↓コマンドを表示
strcpy(UARTbuf,"\r\ncommand: ");
for(i=0;i<n;i++)
{
sprintf(tmp,"(%d)%s/ ",i,Field[i]);
strcat(UARTbuf,tmp);
}
strcat(UARTbuf,"\r\n");
UART_PutString(UARTbuf);
if(strcmp(Field[0],"int")==0) intコマンド処理
{
float f;
f = atof(Field[1]);
TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
TIM_TimeBaseStructure.TIM_Period = 24000; // 24MHz / 24000 / 1000 = 1Hz
TIM_TimeBaseStructure.TIM_Prescaler = (uint16_t)(1000.0/f); プリスケーラ値を変えます
TIM_TimeBaseStructure.TIM_ClockDivision = 0x0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
}
else if(strcmp(Field[0],"off")==0) offコマンド処理
{
GPIO_ResetBits(GPIOC, GPIO_Pin_8); LEDオフ
TIM_Cmd(TIM3, DISABLE); TIM3オフ
}
else if(strcmp(Field[0],"on")==0) onコマンド処理
{
TIM_Cmd(TIM3, ENABLE); TIM3オン
}
else if(strcmp(Field[0],"set")==0) setコマンド処理
{
uint32_t hour, min, sec;
hour = (uint32_t)atof(Field[1]); 引数1は時
min = (uint32_t)atof(Field[2]); 引数2は分
sec = (uint32_t)atof(Field[3]); 引数3は秒
RTC_SetTime(hour,min,sec); RTCに時分秒をセットする自作ライブラリ関数
BKP_WriteBackupRegister(BKP_DR1, 0xA5A5); 時刻設定済みの印であるBKP_DR1=A5A5に設定
}
else UART_PutString("command error\r\n"); 該当コマンドなしならエラー
↓コマンドメニュー表示
UART_PutString("\r\n");
UART_PutString("-----RTC TEST MENU-----\r\n");
UART_PutString("int 10 : LED flash 10 Hz\r\n");
UART_PutString("off : LED off\r\n");
UART_PutString("on : LED on\r\n");
UART_PutString("set 14 22 49 : set time 14:22:49\r\n");
UART_PutString("-----------------------\r\n\n");
UART_STR_EXIST=0;
return;
}
usrlib-rtc.c
RTCの設定にはおまじない要素が多いです.waitとか.
#include "stm32f10x.h"
#include "stdio.h"
#include "usrlib-uart3d.h"
↓RTC初期設定.どうしてこうしなくちゃいけないんだ?と思うことが多々ありますが、考えるのもめんどくさいのでこのままで使います.
void RTC_Configuration(void)
{
PWR_BackupAccessCmd(ENABLE); BACKUP回路へのアクセスをenableする
//BKP_DeInit(); BACKUP registerをresetする.ただしコメントアウトしてあるのはバッテリバックアップされた時刻を消させないため
RCC_LSEConfig(RCC_LSE_ON); LSEとは外付け32kHzのことだと思う.
この関数の引数には次の選択肢があります.
RCC_LSE_OFF: LSE oscillator OFF
RCC_LSE_ON: LSE oscillator ON
RCC_LSE_Bypass: LSE oscillator bypassed with external clock 外部clockをLSEに流し込むと言ってますがよくわかりません
while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET){} LSEが起動するまでwait.
この関数の引数は次のようにいろいろあります.
RCC_FLAG_HSIRDY: HSI oscillator clock ready
RCC_FLAG_HSERDY: HSE oscillator clock ready
RCC_FLAG_PLLRDY: PLL clock ready
RCC_FLAG_LSERDY: LSE oscillator clock ready
RCC_FLAG_LSIRDY: LSI oscillator clock ready
RCC_FLAG_PINRST: Pin reset
RCC_FLAG_PORRST: POR/PDR reset
RCC_FLAG_SFTRST: Software reset
RCC_FLAG_IWDGRST: Independent Watchdog reset
RCC_FLAG_WWDGRST: Window Watchdog reset
RCC_FLAG_LPWRRST: Low Power reset
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); LSEをRTC clockにする
この関数の引数には次の選択肢があります.
RCC_RTCCLKSource_LSE: 外部XTAL 32.768kHz(LSE)をRTCのclockとしてつかう
RCC_RTCCLKSource_LSI: 内部RC発振器の40kHz(LSI)をRTCのclockとしてつかう
RCC_RTCCLKSource_HSE_Div128: 外部XTAL(HSE)を128分周したclockをRCCでつかう
RCC_RTCCLKCmd(ENABLE); RTC clock enable
RTC_WaitForSynchro(); 謎のwait
RTC_WaitForLastTask(); RTC registerをいじったらwaitせよ
RTC_ITConfig(RTC_IT_SEC, ENABLE); 毎秒割り込みをenable
この関数の引数には次の選択肢があります.
RTC_IT_OW: Overflow interrupt 32bitカウンタがオーバーフローしたら割り込み
RTC_IT_ALR: Alarm interrupt 特定のカウント値で割り込み 特定値の設定にはこの関数→void RTC_SetAlarm(uint32_t AlarmValue)
RTC_IT_SEC: Second interrupt 毎秒割り込み
RTC_WaitForLastTask(); RTC registerをいじったらwaitせよ
RTC_SetPrescaler(32767); プリスケを32767にすると、32.768kHz÷32768=1Hzになる.32bit値です.
RTC_WaitForLastTask(); RTC registerをいじったらwaitせよ
}
↓時分秒をRTCに設定します
void RTC_SetTime(uint32_t hour, uint32_t min, uint32_t sec)
{
uint32_t timevalue;
timevalue = hour*3600 + min*60 + sec;
RTC_WaitForLastTask(); RTC registerをいじる前に念のためwaitせよ
RTC_SetCounter(timevalue); 時刻設定
RTC_WaitForLastTask(); RTC registerをいじったらwaitせよ
}
↓UARTに時刻を表示します
void RTC_TimeDisplay(void)
{
uint32_t hour, min, sec, TimeVar;
char UARTbuf[20];
TimeVar = RTC_GetCounter();
hour = TimeVar / 3600; // hour
min = (TimeVar % 3600) / 60; // minutes
sec = (TimeVar % 3600) % 60; // second
if (BKP_ReadBackupRegister(BKP_DR1)==0xA5A5) 時刻設定済みならA5A5になってる 時刻未設定なら0000になってる
sprintf(UARTbuf,"RTC %02d:%02d:%02d (configured)\r\n", (int)hour, (int)min, (int)sec);
else sprintf(UARTbuf,"RTC %02d:%02d:%02d (not configured)\r\n", (int)hour, (int)min, (int)sec);
UART_PutString(UARTbuf);
}