CH32的RTC闹钟中断

都是外部事件,所以是需要开启EXTI映射功能,停止模式用事件中断都可以唤醒,而待机只能用事件唤醒。
一、配置
1.停止模式下配置。
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);//开启PWR时钟
if(PWR_GetFlagStatus(PWR_FLAG_WU) == SET)//判断是不是wake up复位
{
printf("\r\n Standby wake up reset \r\n");
}
else
{
printf("\r\n Power on reset \r\n");
PWR_WakeUpPinCmd(ENABLE);//使能wake up引脚唤醒
PWR_EnterSTOPMode_RAM_LV(PWR_Regulator_LowPower,PWR_STOPEntry_WFI);;//进入停止模式,第二个参数与外部中断唤醒与事件唤醒相匹配。
}
EXTI配置:
/* GPIOA ----> EXTI_Line0 */
EXTI_InitStructure.EXTI_Line = EXTI_Line17;//此处为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);
//EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Event;上述是这个事件,下面的中断函数与中断配置皆可不要。
NVIC_InitStructure.NVIC_IRQChannel = RTCAlarm_IRQn;//开启闹钟外部中断,其实是EXTI17 RTC
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
//编写中断函数
void RTCAlarm_IRQHandler(void)
{
...
}
2.待机模式下配置:
//由于待机模式唤醒后会复位,不执行中断函数,中断配置都不需要,待机模式配置比较简单
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
if(PWR_GetFlagStatus(PWR_FLAG_WU) == SET)
{
printf("\r\n Standby wake up reset \r\n");
}
else
{
printf("\r\n Power on reset \r\n");
PWR_WakeUpPinCmd(ENABLE);
PWR_EnterSTANDBYMode();
}
EXTI_InitStructure.EXTI_Line = EXTI_Line17;//此处为EXTI_Line17
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Event;此处只能为事件
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
二、与RTC中断的共同处理
CH32的中断函数RTCAlarm_IRQHandler() 唤醒,并没有用到RTC全局中断RTC_IRQHandler()
如果两个中断函数同时使用的话,我们必须这样设置才不会有漏洞 RTCAlarm_IRQHandler() 函数的优先级一定要高于RTC_IRQHandler()
原因如下:
产生闹钟中断的前一瞬间,一定产生了秒中断,那么会先执行RTC_IRQHandler() 中断函数, 在RTC_IRQHandler() 执行的过程中,闹钟中断标志又被挂起,
由于RTC_IRQHandler()是全局中断函数,必须清除所有的中断标志,程序才能退出该函数, 假如RTC_IRQHandler() 和RTCAlarm_IRQHandler() 是同样的优先级,
要想让程序退出RTC_IRQHandler() 函数,那么你必须清除闹钟中断标志(如果不清除闹钟中断标志,程序会死在RTC_IRQHandler() ), 这样问题又出现了,清除闹钟中断标志后,程序就不会进入RTCAlarm_IRQHandler(),那么RTCAlarm_IRQHandler()函数永远也不会被执行。
设置闹钟中断函数RTCAlarm_IRQHandler() 的优先级高于全局中断函数RTC_IRQHandler(),
在执行全局中断函数RTC_IRQHandler() 的时候,如果产生闹钟中断,那么中断嵌套去执行RTCAlarm_IRQHandler(),执行完毕RTCAlarm_IRQHandler()后,再去执行RTC_IRQHandler() 。
typedef struct
{
vu8 hour;
vu8 min;
vu8 sec;
vu16 w_year;
vu8 w_month;
vu8 w_date;
vu8 week;
} _calendar_obj;
_calendar_obj calendar;
u8 const table_week[12] = {0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5};
const u8 mon_table[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
volatile u8 flag=0;
/* Exported_Functions */
u8 RTC_Init(void);
u8 Is_Leap_Year(u16 year);
u8 RTC_Alarm_Set(u16 syear, u8 smon, u8 sday, u8 hour, u8 min, u8 sec);
u8 RTC_Get(void);
u8 RTC_Get_Week(u16 year, u8 month, u8 day);
u8 RTC_Set(u16 syear, u8 smon, u8 sday, u8 hour, u8 min, u8 sec);
/*********************************************************************
* @fn RTC_NVIC_Config
*
* @brief Initializes RTC Int.
*
* @return none
*/
static void RTC_NVIC_Config(void)
{
NVIC_InitTypeDef NVIC_InitStructure = {0};
NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
/*********************************************************************
* @fn RTC_Init
*
* @brief Initializes RTC collection.
*
* @return 1 - Init Fail
* 0 - Init Success
*/
u8 RTC_Init(void)
{
u8 temp = 0;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
PWR_BackupAccessCmd(ENABLE);
/* Is it the first configuration */
if(BKP_ReadBackupRegister(BKP_DR1) != 0xA1A1)
{
BKP_DeInit();
RCC_LSEConfig(RCC_LSE_OFF);
RCC_LSICmd(ENABLE);
while(RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET && temp < 250)
{
temp++;
Delay_Ms(20);
}
if(temp >= 250)
return 1;
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);
RCC_RTCCLKCmd(ENABLE);
RTC_WaitForLastTask();
RTC_WaitForSynchro();
RTC_ITConfig(RTC_IT_ALR, ENABLE);
RTC_ITConfig(RTC_IT_SEC, ENABLE);
RTC_WaitForLastTask();
RTC_EnterConfigMode();
RTC_SetPrescaler(32767);
RTC_WaitForLastTask();
RTC_Set(2019, 10, 8, 13, 58, 55); /* Setup Time */
RTC_ExitConfigMode();
BKP_WriteBackupRegister(BKP_DR1, 0XA1A1);
}
else
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
RCC_LSEConfig(RCC_LSE_OFF);
RCC_LSICmd(ENABLE);
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);
RCC_RTCCLKCmd(ENABLE);
PWR_WakeUpPinCmd(DISABLE);
RTC_WaitForSynchro();
RTC_ITConfig(RTC_IT_ALR, ENABLE);
RTC_ITConfig(RTC_IT_SEC, ENABLE);
RTC_WaitForLastTask();
}
RTC_NVIC_Config();
RTC_Get();
return 0;
}
/*********************************************************************
* @fn Is_Leap_Year
*
* @brief Judging whether it is a leap year.
*
* @param year
*
* @return 1 - Yes
* 0 - No
*/
u8 Is_Leap_Year(u16 year)
{
if(year % 4 == 0)
{
if(year % 100 == 0)
{
if(year % 400 == 0)
return 1;
else
return 0;
}
else
return 1;
}
else
return 0;
}
/*********************************************************************
* @fn RTC_Set
*
* @brief Set Time.
*
* @param Struct of _calendar_obj
*
* @return 1 - error
* 0 - success
*/
u8 RTC_Set(u16 syear, u8 smon, u8 sday, u8 hour, u8 min, u8 sec)
{
u16 t;
u32 seccount = 0;
if(syear < 1970 || syear > 2099)
return 1;
for(t = 1970; t < syear; t++){
if(Is_Leap_Year(t))
seccount += 31622400;
else
seccount += 31536000;
}
smon -= 1;
for(t = 0; t < smon; t++){
seccount += (u32)mon_table[t] * 86400;
if(Is_Leap_Year(syear) && t == 1)
seccount += 86400;
}
seccount += (u32)(sday - 1) * 86400;
seccount += (u32)hour * 3600;
seccount += (u32)min * 60;
seccount += sec;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
PWR_BackupAccessCmd(ENABLE);
RTC_SetCounter(seccount);
RTC_WaitForLastTask();
return 0;
}
/*********************************************************************
* @fn RTC_Alarm_Set
*
* @brief Set Alarm Time.
*
* @param Struct of _calendar_obj
*
* @return 1 - error
* 0 - success
*/
u8 RTC_Alarm_Set(u16 syear, u8 smon, u8 sday, u8 hour, u8 min, u8 sec)
{
u16 t;
u32 seccount = 0;
if(syear < 1970 || syear > 2099)
return 1;
for(t = 1970; t < syear; t++) {
if(Is_Leap_Year(t))
seccount += 31622400;
else
seccount += 31536000;
}
smon -= 1;
for(t = 0; t < smon; t++){
seccount += (u32)mon_table[t] * 86400;
if(Is_Leap_Year(syear) && t == 1)
seccount += 86400;
}
seccount += (u32)(sday - 1) * 86400;
seccount += (u32)hour * 3600;
seccount += (u32)min * 60;
seccount += sec;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
PWR_BackupAccessCmd(ENABLE);
RTC_SetAlarm(seccount);
RTC_WaitForLastTask();
return 0;
}
/*********************************************************************
* @fn RTC_Get
*
* @brief Get current time.
*
* @return 1 - error
* 0 - success
*/
u8 RTC_Get(void)
{
static u16 daycnt = 0;
u32 timecount = 0;
u32 temp = 0;
u16 temp1 = 0;
timecount = RTC_GetCounter();
temp = timecount / 86400;
if(daycnt != temp)
{
daycnt = temp;
temp1 = 1970;
while(temp >= 365)
{
if(Is_Leap_Year(temp1))
{
if(temp >= 366)
temp -= 366;
else
{
temp1++;
break;
}
}
else
temp -= 365;
temp1++;
}
calendar.w_year = temp1;
temp1 = 0;
while(temp >= 28)
{
if(Is_Leap_Year(calendar.w_year) && temp1 == 1)
{
if(temp >= 29)
temp -= 29;
else
break;
}
else
{
if(temp >= mon_table[temp1])
temp -= mon_table[temp1];
else
break;
}
temp1++;
}
calendar.w_month = temp1 + 1;
calendar.w_date = temp + 1;
}
temp = timecount % 86400;
calendar.hour = temp / 3600;
calendar.min = (temp % 3600) / 60;
calendar.sec = (temp % 3600) % 60;
calendar.week = RTC_Get_Week(calendar.w_year, calendar.w_month, calendar.w_date);
return 0;
}
/*********************************************************************
* @fn RTC_Get_Week
*
* @brief Get the current day of the week.
*
* @param year/month/day
*
* @return week
*/
void SET_ALARM(u8 Value)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
PWR_BackupAccessCmd(ENABLE);
RTC_SetAlarm(RTC_GetCounter()+Value);
RTC_WaitForLastTask();
}
u8 RTC_Get_Week(u16 year, u8 month, u8 day)
{
u16 temp2;
u8 yearH, yearL;
yearH = year / 100;
yearL = year % 100;
if(yearH > 19)
yearL += 100;
temp2 = yearL + yearL / 4;
temp2 = temp2 % 7;
temp2 = temp2 + day + table_week[month - 1];
if(yearL % 4 == 0 && month < 3)
temp2--;
return (temp2 % 7);
}
//void EXTI17_Init(void)
//{
// EXTI_InitTypeDef EXTI_InitStructure;
// NVIC_InitTypeDef NVIC_InitStructure;
// RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
//
//
// EXTI_InitStructure.EXTI_Line=EXTI_Line17;
// EXTI_InitStructure.EXTI_LineCmd=ENABLE;
// EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;
// EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Rising;
// EXTI_Init(&EXTI_InitStructure);
//
// NVIC_InitStructure.NVIC_IRQChannel=RTCAlarm_IRQn;
// NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
// NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;
// NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;
// NVIC_Init(&NVIC_InitStructure);
//}
void Intwake_Init(void)
{
EXTI_InitTypeDef EXTI_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
GPIO_InitTypeDef GPIO_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOC|RCC_APB2Periph_AFIO, ENABLE);
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_1;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_ResetBits(GPIOA, GPIO_Pin_1);
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IPD;
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_0;
// GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &GPIO_InitStruct);
EXTI_InitStructure.EXTI_Line=EXTI_Line17;
EXTI_InitStructure.EXTI_LineCmd=ENABLE;
EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Rising;
EXTI_Init(&EXTI_InitStructure);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOC, GPIO_PinSource0);
EXTI_InitStructure.EXTI_Line=EXTI_Line0;
EXTI_InitStructure.EXTI_LineCmd=ENABLE;
EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Rising;
EXTI_Init(&EXTI_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel=RTCAlarm_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;
NVIC_Init(&NVIC_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel=EXTI0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;
NVIC_Init(&NVIC_InitStructure);
}
/*********************************************************************
* @fn main
*
* @brief Main program.
*
* @return none
*/
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
Delay_Init();
USART_Printf_Init(115200);
Delay_Ms(2000);
printf("SystemClk:%d\r\n", SystemCoreClock);
printf("RTC Test\r\n");
RTC_Init();
// EXTI17_Init();
Intwake_Init();
SET_ALARM(5);
Delay_Ms(2000);
printf("sleep\r\n");
PWR_EnterSTOPMode(PWR_Regulator_LowPower, PWR_STOPEntry_WFI);
while(1)
{
Delay_Ms(1000);
printf("year/month/day/week/hour/min/sec:\r\n");
printf("%d-%d-%d %d %d:%d:%d\r\n", calendar.w_year, calendar.w_month, calendar.w_date,
calendar.week, calendar.hour, calendar.min, calendar.sec);
}
}
void EXTI0_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
/*********************************************************************
* @fn EXTI0_IRQHandler
*
* @brief This function handles EXTI0 Handler.
*
* @return none
*/
void EXTI0_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line0)!=RESET)
{
printf("Run at EXTI\r\n");
GPIO_SetBits(GPIOA, GPIO_Pin_1);
EXTI_ClearITPendingBit(EXTI_Line0); /* Clear Flag */
}
}
void RTC_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
void RTCAlarm_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
void RTC_IRQHandler(void)
{
if(RTC_GetITStatus(RTC_IT_SEC) != RESET) /* Seconds interrupt */
{
RTC_Get();
}
if(RTC_GetITStatus(RTC_IT_ALR) != RESET) /* Alarm clock interrupt */
{
RTC_ClearITPendingBit(RTC_IT_ALR);
}
RTC_ClearITPendingBit(RTC_IT_SEC | RTC_IT_OW);
RTC_WaitForLastTask();
}
void RTCAlarm_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line17) != RESET)
{
SystemInit();
printf("enter EXTI_Line17 int\r\n");
EXTI_ClearITPendingBit(EXTI_Line17);
}
}
Intwake
浙公网安备 33010602011771号