STM32的闹钟真是闹心啊......
因为方案变化,这个星期要用到STM32的闹钟,就是让程序每天固定时间醒来,完成任务后继续睡眠,也可以根据情况任务的完成情况定下一次的醒来时间。
根本点:
1、闹钟固定时间醒;
2、指定下一次醒来的时间(不指定就是明天的同一时间醒来执行任务)。
看似很简单,我想肯定就是半天的功夫了。
星期一开始干,在网上查看教程,结果全部是标准库的,方法繁琐,我的工程文件是HAL库的,是同事帮我生成的,我只负责写代码。
结果可想而知,无功而返,折腾到星期二晚上依然不见起闹,转念一想,还是看系统的HAL代码,这样很见效果,闹钟可以按时起闹了。
星期三和星期四做其他工作就没写,星期五要完成指定下一次的醒来时间,想也简单,把上次的代码写成函数直接调用就行了,结果因为一行代码的顺序错误调试了大半天,最后才找到原因。
闹钟起闹。
/ RTC init function /
void MX_RTC_Init(void)
{
RTC_TimeTypeDef sTime;
RTC_DateTypeDef sDate;
RTC_AlarmTypeDef sAlarm;
/*Initialize RTC Only
/
hrtc.Instance = RTC;//全局的实例
hrtc.Init.HourFormat = RTC_HOURFORMAT_24;
hrtc.Init.AsynchPrediv = 127;
hrtc.Init.SynchPrediv = 255;
hrtc.Init.OutPut = RTC_OUTPUT_DISABLE;
hrtc.Init.OutPutRemap = RTC_OUTPUT_REMAP_NONE;
hrtc.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;
hrtc.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN;
if (HAL_RTC_Init(&hrtc) != HAL_OK)
{
_Error_Handler(FILE, LINE);
}
/*Initialize RTC and set the Time and Date
/
sTime.Hours = 0x12;
sTime.Minutes = 0x13;
sTime.Seconds = 0x03;
sTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
sTime.StoreOperation = RTC_STOREOPERATION_RESET;
if (HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BCD) != HAL_OK)
{
_Error_Handler(FILE, LINE);
}
sDate.WeekDay = RTC_WEEKDAY_FRIDAY;
sDate.Month = RTC_MONTH_MAY;
sDate.Date = 0x05;
sDate.Year = 0x13;
if (HAL_RTC_SetDate(&hrtc, &sDate, RTC_FORMAT_BCD) != HAL_OK)
{
_Error_Handler(FILE, LINE);
}
/**Enable the Alarm A
*/
sAlarm.AlarmTime.Hours = 0x12;
sAlarm.AlarmTime.Minutes = 0x14;
sAlarm.AlarmTime.Seconds = 0x0;
sAlarm.AlarmTime.SubSeconds = 0x0;
sAlarm.AlarmTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
sAlarm.AlarmTime.StoreOperation = RTC_STOREOPERATION_RESET;
sAlarm.AlarmMask = RTC_ALARMMASK_DATEWEEKDAY|RTC_ALARMMASK_HOURS
|RTC_ALARMMASK_MINUTES;
sAlarm.AlarmSubSecondMask = RTC_ALARMSUBSECONDMASK_ALL;
sAlarm.AlarmDateWeekDaySel = RTC_ALARMDATEWEEKDAYSEL_DATE;
sAlarm.AlarmDateWeekDay = 0x1;
sAlarm.Alarm = RTC_ALARM_A;
if (HAL_RTC_SetAlarm_IT(&hrtc, &sAlarm, RTC_FORMAT_BCD) != HAL_OK)
{
_Error_Handler(FILE, LINE);
}
/**Enable the WakeUp
*/
if (HAL_RTCEx_SetWakeUpTimer_IT(&hrtc, 0, RTC_WAKEUPCLOCK_RTCCLK_DIV16) != HAL_OK)
{
_Error_Handler(FILE, LINE);
}
}
我把起闹时间在系统初始化就指定了。
上面代码在RTC.c文件中。
void HAL_RTC_AlarmIRQHandler(RTC_HandleTypeDef hrtc)
{
/ Get the AlarmA interrupt source enable status /
if(__HAL_RTC_ALARM_GET_IT_SOURCE(hrtc, RTC_IT_ALRA) != RESET)
{
/ Get the pending status of the AlarmA Interrupt /
if(__HAL_RTC_ALARM_GET_FLAG(hrtc, RTC_FLAG_ALRAF) != RESET)
{
/ AlarmA callback */
HAL_RTC_AlarmAEventCallback(hrtc);
RTC_Alarm_IRQHandler();
/* Clear the AlarmA interrupt pending bit */
__HAL_RTC_ALARM_CLEAR_FLAG(hrtc, RTC_FLAG_ALRAF);
}
}
/ Get the AlarmB interrupt source enable status /
if(__HAL_RTC_ALARM_GET_IT_SOURCE(hrtc, RTC_IT_ALRB) != RESET)
{
/ Get the pending status of the AlarmB Interrupt /
if(__HAL_RTC_ALARM_GET_FLAG(hrtc, RTC_FLAG_ALRBF) != RESET)
{
/ AlarmB callback /
HAL_RTCEx_AlarmBEventCallback(hrtc);
/* Clear the AlarmB interrupt pending bit */
__HAL_RTC_ALARM_CLEAR_FLAG(hrtc, RTC_FLAG_ALRBF);
}
}
/ Clear the EXTI's line Flag for RTC Alarm /
__HAL_RTC_ALARM_EXTI_CLEAR_FLAG();
/ Change RTC state /
hrtc->State = HAL_RTC_STATE_READY;
}
上面我写了中断函数
RTC_Alarm_IRQHandler();
里面是执行我写的任务代码。
中断代码:
//RTC闹钟中断事件
void RTC_Alarm_IRQHandler(void)
{
RTC_HandleTypeDef *hrtcTMP;
hrtcTMP=&hrtc//获取当前的RTC实例
switch(YCWorkStatus){
case 0://没有开始
break;
case 1://进行中
SendBuffer[20]=0x11;
SendBuffer[21]=0x11;
SendBuffer[22]=0x11;
SendBuffer[23]=0x11;
SendBuffer[24]=0x11;
SendBuffer[25]=0x11;
IRQHandlerCount=IRQHandlerCount+1;
SendBuffer[26]=IRQHandlerCount;
break;
case 2://完成
__HAL_RTC_ALARMA_DISABLE(hrtcTMP);//使闹钟A不能
__HAL_RTC_ALARM_CLEAR_FLAG(hrtcTMP, RTC_FLAG_ALRAF);//清理标志
break;
default: //不支持的命令
break;
}
}
下面就是main里面的主要代码:
int main(void)
{
HAL_Init();//初始化HAL库
SystemClock_Config();//配置系统时钟
/ 初始化外围设置 /
MX_GPIO_Init();
MX_DMA_Init();
MX_ADC_Init();
MX_LPUART1_UART_Init();
MX_USART1_UART_Init();
MX_RTC_Init();
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_3, GPIO_PIN_SET); //打开LORA电源PB3(1)
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_4, GPIO_PIN_RESET); //M0 M1同时配置0处于工作状态(M0)
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_5, GPIO_PIN_RESET); //(M1)
HAL_Delay (1000);//延时10毫秒
HAL_UART_Transmit(&hlpuart1,SendBuffer,sizeof(SendBuffer),10); //串口1向LORA发送整个缓冲区
YCWorkStatus=1;
RTC_HandleTypeDef *hrtcTMP;
hrtcTMP=&hrtc;//获取当前的RTC实例
while (1)
{
GetCurrentDateTime();
MainSendCount=MainSendCount+1;
HAL_UART_Transmit(&hlpuart1,SendBuffer,sizeof(SendBuffer),10); //串口1向LORA发送整个缓冲区
HAL_Delay (200);
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_15, GPIO_PIN_SET);HAL_Delay (200); //P15闪烁
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_15, GPIO_PIN_RESET);HAL_Delay (200); //P15闪烁
SendBuffer[40]=MainSendCount;
if(MainSendCount>=255){
MainSendCount=0;
}
if(IRQHandlerCount>=2){
HAL_NVIC_DisableIRQ(RTC_IRQn);
IRQHandlerCount=0;
SendBuffer[20]=0x99;
SendBuffer[21]=0x99;
SendBuffer[22]=0x99;
SendBuffer[23]=0x99;
SendBuffer[24]=0x99;
SendBuffer[25]=0x99;
GetCurrentDateTime();//得到当前的时间和日期
ITMP=(uint8_t)CurrentTime.Minutes+2;
RTC_Set_AlarmA(CurrentTime.Hours,ITMP,0);
SendBuffer[51]=CurrentTime.Minutes;
SendBuffer[52]=ITMP;
//__HAL_RCC_APB1_RELEASE_RESET();
//__HAL_RCC_APB2_RELEASE_RESET();
//__HAL_RTC_ALARMA_DISABLE(hrtcTMP);//使闹钟A不能
//__HAL_RTC_ALARM_DISABLE_IT(hrtcTMP,RTC_IT_ALRA);//使闹钟A中断不能
//__HAL_RTC_ALARM_CLEAR_FLAG(hrtcTMP, RTC_FLAG_ALRAF);//清理标志
//__HAL_RTC_WAKEUPTIMER_DISABLE(hrtcTMP);
//__HAL_RTC_ALARM_ENABLE_IT
//
//HAL_NVIC_EnableIRQ(RTC_IRQn);
//__HAL_RCC_RTC_DISABLE();
//HAL_NVIC_DisableIRQ(RTC_IRQn);
//__HAL_RTC_ALARM_EXTI_DISABLE_IT();
//__HAL_RTC_ALARM_EXTI_CLEAR_FLAG();
//__HAL_RTC_ALARM_EXTI_DISABLE_IT();
}
}
}
程序执行正确,按时醒来,根据指定时间下一次再醒来。