上次實驗完成了對實時時鐘的基本功能——計時的實驗,這次在計時的基礎上對RTC的可編程鬧鐘的功能進行測試。
RTC 單元提供兩個可編程鬧鐘,即鬧鐘 A 和鬧鐘 B。
可通過將 RTC_CR 寄存器中的 ALRAE 和 ALRBE 位置 1 來使能可編程鬧鐘功能。如果日歷亞秒、秒、分鐘、小時、日期或日分別與鬧鐘寄存器RTC_ALRMASSR/RTC_ALRMAR 和RTC_ALRMBSSR/RTC_ALRMBR 中編程的值相匹配,則 ALRAF 和 ALRBF 標志會被置為1??赏ㄟ^ RTC_ALRMAR 和 RTC_ALRMBR 寄存器的 MSKx 位以及 RTC_ALRMASSR 和RTC_ALRMBSSR 寄存器的 MASKSSx 位單獨選擇各日歷字段??赏ㄟ^ RTC_CR 寄存器中的 ALRAIE 和 ALRBIE 位使能鬧鐘中斷。
鬧鐘 A 和鬧鐘 B(如果已通過 RTC_CR 寄存器中的位 OSEL[0:1] 使能)可連接到 RTC_ALARM輸出??赏ㄟ^ RTC_CR 寄存器的 POL 位配置 RTC_ALARM 極性。
要對可編程的鬧鐘(鬧鐘 A 或鬧鐘 B)進行編程或更新,必須執(zhí)行類似的步驟:
- 將 RTC_CR 寄存器中的 ALRAE 或 ALRBE 位清零以禁止鬧鐘 A 或鬧鐘 B。
- 輪詢 RTC_ISR 寄存器中的 ALRAWF 或 ALRBWF 位,直到其中一個置 1,以確保鬧鐘寄存器可以訪問。大約需要 2 個 RTCCLK 時鐘周期(由于時鐘同步)。
- 編程鬧鐘 A 或鬧鐘 B 寄存器(RTC_ALRMASSR/RTC_ALRMAR 或 RTC_ALRMBSSR/RTC_ALRMBR)。
- 將 RTC_CR 寄存器中的 ALRAE 或 ALRBE 位置 1 以再次使能鬧鐘 A 或鬧鐘 B。
注意:約 2 個 RTCCLK 時鐘周期(由于時鐘同步)后,將執(zhí)行對 RTC_CR 寄存器的更改。
寫程序前先簡單了解下鬧鐘相關的寄存器:
RTC鬧鐘A寄存器 (RTC_ALRMAR)
位 31 MSK4:鬧鐘 A 日期掩碼 (Alarm A date mask)
0:如果日期/日匹配,則鬧鐘 A 置 1
1:在鬧鐘 A 比較中,日期/日無關
位 30 WDSEL:星期幾選擇 (Week day selection)
0:DU[3:0] 代表日期的個位
1:DU[3:0] 代表星期幾。DT[1:0] 為無關位。
位 29:28 DT[1:0]:日期的十位(BCD 格式)
位 27:24 DU[3:0]:日期的個位或日(BCD 格式)
位 23 MSK3:鬧鐘 A 小時掩碼 (Alarm A hours mask)
0:如果小時匹配,則鬧鐘 A 置 1?
1:在鬧鐘 A 比較中,小時無關
位 22 PM :AM/PM 符號 (AM/PM notation)
0:AM 或 24 小時制
1:PM
位 21:20 HT[1:0]:小時的十位(BCD 格式)
位 19:16 HU[3:0]:小時的個位(BCD 格式)
位 15 MSK2:鬧鐘 A 分鐘掩碼 (Alarm A minutes mask)
0:如果分鐘匹配,則鬧鐘 A 置 1
1:在鬧鐘 A 比較中,分鐘無關
位 14:12 MNT[2:0]:分鐘的十位(BCD 格式)
位 11:8 MNU[3:0]:分鐘的個位(BCD 格式)
位 7 MSK1:鬧鐘 A 秒掩碼 (Alarm A seconds mask)
0:如果秒匹配,則鬧鐘 A 置 1
1:在鬧鐘 A 比較中,秒無關
位 6:4 ST[2:0]:秒的十位(BCD 格式)
位 3:0 SU[3:0]:秒的個位(BCD 格式)
鬧鐘B寄存器RTC_ALRMBR與鬧鐘A寄存器RTC_ALRMAR的寄存器功能一樣,這里不再進行介紹。
RTC鬧鐘配置函數(shù)和中斷處理函數(shù)
void RTC_AlarmConfig(u8 Alarm_sel,u8 Alarm_set,u8 Alarm_day,u8 Alarm_hour,u8 Alarm_minute)
{
u32 prigroup = 0;
u32 priority = 0;
u32 temp = 0;
//1.解除保護
//寫密鑰:先寫0xca,再寫0x53
RTC- >WPR = 0XCA;
RTC- >WPR = 0X53;
switch(Alarm_set)
{
case SPECIAL_DAY:
temp |= Alarm_day< 24; //設置具體星期
break;
case WORK_DAY:
case ALL_DAY:
temp |= (u32)(1< 31);
break;
case DISABLE_DAY:
break;
}
temp |= 1< 30; //用星期來匹配
temp |= ((Alarm_hour/10)< 4 | (Alarm_hour%10))< 16 | 1< 23;
temp |= ((Alarm_minute/10)< 4 | (Alarm_minute%10))< 8 | 1< 15;
temp |= 1< 7;
//關閉鬧鐘,等待鬧鐘可寫入
if(Alarm_sel == ALARM_A)
{
RTC- >CR &= ~(1< 8);
while((RTC- >ISR & (1< 0)) == 0){}
RTC- >ALRMAR = temp;
RTC- >CR |= 1< 8; //開啟鬧鐘A
//開鬧鐘A的中斷
RTC- >CR |= 1< 12;
//清中斷標記
RTC- >ISR &= ~(1< 8);
}
else if(Alarm_sel == ALARM_B)
{
RTC- >CR &= ~(1< 9);
while((RTC- >ISR & (1< 1)) == 0){}
RTC- >ALRMBR = temp;
RTC- >CR |= 1< 9; //開啟鬧鐘B
//開鬧鐘B的中斷
RTC- >CR |= 1< 13;
//清中斷標記
RTC- >ISR &= ~(1< 9);
}
//鬧鐘中斷對應于外部中斷線,因此要設置外部中斷線(17)
EXTI- >IMR |= 1< 17;
EXTI- >RTSR |= 1< 17; //鬧鐘中斷需設置為上升沿
//清中斷標記
EXTI- >PR |= 1< 17;
prigroup = NVIC_GetPriorityGrouping();
priority = NVIC_EncodePriority(prigroup,1,2);
NVIC_SetPriority(RTC_Alarm_IRQn,priority);
NVIC_EnableIRQ(RTC_Alarm_IRQn);
switch(Alarm_set)
{
case SPECIAL_DAY:
break;
case WORK_DAY:
temp = (RTC- >DR & 0x0000e000) >>13;
if(temp >5)
{
if(Alarm_sel == ALARM_A)
RTC- >CR &= ~(1< 8);
else if(Alarm_sel == ALARM_B)
RTC- >CR &= ~(1< 9);
}
else
{
if(Alarm_sel == ALARM_A)
RTC- >CR |= 1< 8;
else if(Alarm_sel == ALARM_B)
RTC- >CR |= 1< 9;
}
break;
case ALL_DAY:
break;
case DISABLE_DAY:
if(Alarm_sel == ALARM_A)
RTC- >CR &= ~(1< 8);
else if(Alarm_sel == ALARM_B)
RTC- >CR &= ~(1< 9);
break;
}
//2. 再次保護
RTC- >WPR = 0XFF; //寫任意值,再次保護
}
//中斷處理
void RTC_Alarm_IRQHandler()
{
EXTI- >PR |= 1< 17;
//中斷處理
if(RTC- >ISR & (1< 8))
{
RTC- >ISR &= ~(1< 8);
//鬧鐘A中斷處理
LED_Toggle(DS1);
}
else if(RTC- >ISR & (1< 9))
{
RTC- >ISR &= ~(1< 9);
//鬧鐘B中斷處理
}
}
由于鬧鐘的編寫比較簡單,這里就不多加描述了,接下來編寫主函數(shù)進行測試。
#include "stm32f4xx.h"
#include "usart.h"
#include "delay.h"
#include "stdio.h"
#include "RTC.h"
#include "led.h"
typedef struct
{
u8 shi;
u8 fen;
u8 miao;
u8 nian;
u8 yue;
u8 ri;
u8 xingqi;
}TIME_Typedef;
TIME_Typedef time = {1};
int main()
{
LED_Init();
Usart1_Init(115200);
RTC_Init(23,59,50,19,7,9,2);
RTC_AlarmConfig(ALARM_A,SPECIAL_DAY,3,0,0);
while(1)
{
time.shi = ((RTC- >TR & 0x300000) >>20)*10 + ((RTC- >TR & 0xf0000) >>16);
time.fen = ((RTC- >TR & 0x7000) >>12)*10 + ((RTC- >TR & 0xf00) >>8);
time.miao = ((RTC- >TR & 0x70) >>4)*10 + (RTC- >TR & 0xf);
printf("%d:%d:%drn",time.shi,time.fen,time.miao);
Delay_ms(1000);
}
}
初始時間設為23:59:50,鬧鐘時間設為0:0:0。運行程序,經(jīng)過10秒鐘后,鬧鐘進入中斷,LED燈實現(xiàn)翻轉(zhuǎn),RTC鬧鐘實驗測試成功。
-
寄存器
+關注
關注
31文章
5358瀏覽量
120775 -
計時器
+關注
關注
1文章
426瀏覽量
32771 -
中斷處理
+關注
關注
0文章
94瀏覽量
10988 -
BCD編碼
+關注
關注
0文章
9瀏覽量
6037 -
RTC
+關注
關注
2文章
542瀏覽量
66772
發(fā)布評論請先 登錄
相關推薦
評論