Obsługa RTC w STM32
List. 2
void Configuration_RTC(void) { //włączenie dostępu do BKP PWR_BackupAccessCmd(ENABLE); //deinicjalizacja BPK BKP_DeInit(); //wejście do trybu edycji RTC RTC_EnterConfigMode(); //włączenie LSE RCC_LSEConfig(RCC_LSE_ON); //odczekanie na poprawne włączenie LSE while(RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET){}; //RTCCLK = LSE = 32768 Hz RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); //włączenie zegara RTC RCC_RTCCLKCmd(ENABLE); //dczekanie na synchronizacje RTC_WaitForSynchro(); //odczekanie na zakończenie operacji RTC_WaitForLastTask(); //ustawienie preskalera na 32768 taktów RTC_SetPrescaler(32767); //odczekanie na zakończenie operacji RTC_WaitForLastTask(); //wyjscie z trybu edycji RTC_ExitConfigMode(); //ustawienie licznika RTC na 12h00m00s RTC_SetCounter(43200); //zresetowanie flagi SECF rejestru RTC->CRL, wymagane do poprawnego zapisu rejestru alarmu RTC_ClearFlag(RTC_FLAG_SEC); while(RTC_GetFlagStatus(RTC_FLAG_SEC) == RESET){}; //odczekanie na zakończenie operacji na RTC RTC_WaitForLastTask(); //ustawienie rejestru alarmu RTC na 12h00m00s RTC_SetAlarm(43200); //odczekanie na zakończenie operacji na RTC RTC_WaitForLastTask(); }
Funkcja Configuration_RTC przedstawia klasyczną inicjalizację zegara czasu rzeczywistego przy wykorzystaniu biblioteki dostarczonej przez firmę STMicroelectronics – STM32F10x_StdPeriph_Lib_V3.3.0. Dodatkowo funkcją void RTC_SetCounter(uint32_t CounterValue) są wprowadzane dane do licznika odpowiadającego za przechowywanie wartości odmierzanego czasu. Natomiast za pomocą funkcji void RTC_SetAlarm(uint32_t AlarmValue) są wprowadzane dane porównywane z licznikiem w celu wywołania alarmu. Wprowadzenie czasu alarmu jest realizowane, analogicznie do zmiany wartości licznika RTC. Operacja ta jest musi być poprzedzona wyczyszczeniem flagi SECF rejestru RTC->CRL.
W działaniu zegarka są wykorzystywane przerwania. W związku z tym należy je odpowiednio skonfigurować i zaimplementować funkcje obsługi przerwań. Na listingu 3 pokazano skróconą funkcję (o mniej istotne elementy) konfigurującą system przerwań.
List. 3
void Configuration_Interrupts(void) { //zdefiniowanie struktury wykorzystywanej do konfiguracji przerwani NVIC_InitTypeDef NVIC_InitStructure; EXTI_InitTypeDef EXTI_InitStructure; //skonfigurowanie miejsca przechowywania tablicy wektorów przerwań NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0); //konfiguracja podziału priorytetów przerwań NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //włączenie obsługi alarmu if(alarm_state == 1) { //konfiguracja przerwań pochodzących od RTC Alarm EXTI_ClearITPendingBit(EXTI_Line17); EXTI_InitStructure.EXTI_Line = EXTI_Line17; EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; EXTI_InitStructure.EXTI_LineCmd = ENABLE; EXTI_Init(&EXTI_InitStructure); //generowanie przerwania przez RTC Alarm RTC_ITConfig(RTC_IT_ALR, ENABLE); //odczekanie na zakończenie operacji RTC_WaitForLastTask(); } //wyłączenie obsługi alarmu else { //konfiguracja przerwań pochodzących od RTC Alarm EXTI_ClearITPendingBit(EXTI_Line17); EXTI_InitStructure.EXTI_Line = EXTI_Line17; EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; EXTI_InitStructure.EXTI_LineCmd = DISABLE; EXTI_Init(&EXTI_InitStructure); //generowanie przerwania przez RTC Alarm RTC_ITConfig(RTC_IT_ALR, ENABLE); //odczekanie na zakończenie operacji RTC_WaitForLastTask(); } //konfiguracja przerwań pochodzących od RTC NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); //generowanie przerwania przez RTC co 1s RTC_ITConfig(RTC_IT_SEC, ENABLE); //odczekanie na zakończenie operacji RTC_WaitForLastTask(); //konfiguracja przerwań pochodzących od RTC Alarm NVIC_InitStructure.NVIC_IRQChannel = RTCAlarm_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); //konfiguracja obsługi przerwań od joysticka //. . . //konfiguracja obsługi przerwań od SysTick //. . . }
W programie są wykorzystywane dwa przerwania pochodzące od RTC. Pierwsze z nich to RTC_IT_SEC wywoływane przy każdej inkrementacji licznika RTC (w zależności od konfiguracji odpowiada to cyklicznemu wywołaniu co 1 sekundę). Drugie wykorzystywane przerwanie (RTC_IT_ALR) jest wywoływane, gdy następuje zgodność licznika z rejestrem przechowującym wartość do porównania, przerwanie określane jest jako alarm.
Konfiguracja przerwania RTC_IT_SEC polega na określeniu priorytetu i włączeniu obsługi przy wykorzystaniu funkcji z określonymi parametrami RTC_ITConfig(RTC_IT_SEC, ENABLE). W przypadku ustawień przerwania RTC_IT_ALR poza elementami analogicznymi do przerwania wywoływanego zmianą zawartości licznika RTC do poprawnej pracy należy dodatkowo skonfigurować linie przerwania. W dokumentacji Reference manual RM0008 można znaleźć informację, że zdarzenie alarmu RTC jest dołączone do linii 17 EXTI, tak więc musimy dokonać konfiguracji tego elementu. W funkcji jest to realizowane warunkowo w zależności od wartości zmiennej alarm_state (zmienna informująca czy alarm jest włączony – 1, czy może jest wyłączony – 0).
W programie są obsługiwane przerwania pochodzące od różnych układów peryferyjnych. Są to przerwania wywoływane zmianą położenia joysticka, przerwania pochodzące od RTC (inkrementacja licznika oraz alarm) oraz przerwanie SysTick.
W przypadku obsługi przerwania od zmiany położenia joysticka, funkcja obsługi przerwania ma za zadanie zmienić aktualnie edytowany element oraz odpowiednio inkrementować lub dekrementować jego wartość – są to operacje typowo „matematyczne”.
Przerwanie SysTick wykorzystano do generowania dźwięku. Podyktowane to było tym, iż generowany sygnał nie musi być zbyt skomplikowany, a jedynie „drażniący”, by wymusić zauważenie włączenie alarmu. Operacje realizowane w przerwaniu przedstawiono na listingu 4. Można zauważyć, że jest to tylko przełączanie sygnału wyprowadzonego na przetwornik piezoceramiczny z odpowiednią częstotliwością (ustawioną w konfiguracji przerwania SysTick) realizowane warunkowo, gdy nastąpi włączenie się alarmu.