性无码一区二区三区在线观看,少妇被爽到高潮在线观看,午夜精品一区二区三区,无码中文字幕人妻在线一区二区三区,无码精品国产一区二区三区免费

單片機(jī)RTC的中斷剖析

實(shí)時(shí)時(shí)鐘是一個(gè)獨(dú)立的定時(shí)器。RTC模塊擁有一組連續(xù)計(jì)數(shù)的計(jì)數(shù)器,在相應(yīng)軟件配置下,可提供時(shí)鐘日歷的功能。修改計(jì)數(shù)器的值可以重新設(shè)置系統(tǒng)當(dāng)前的時(shí)間和日期。RTC模塊和時(shí)鐘配置系統(tǒng)(RCC_BDCR寄存器)處于后備區(qū)域,即在系統(tǒng)復(fù)位或從待機(jī)模式喚醒后,RTC的設(shè)置和時(shí)間維持不變。系統(tǒng)復(fù)位后,對(duì)后備寄存器和RTC的訪問被禁止,這是為了防止對(duì)后備區(qū)域(BKP)的意外寫操作。執(zhí)行以下操作將使能對(duì)后備寄存器和RTC的訪問:

設(shè)置寄存器RCC_APB1ENR的PWREN和BKPEN位,使能電源和后備接口時(shí)鐘

設(shè)置寄存器PWR_CR的DBP位,使能對(duì)后備寄存器和RTC的訪問。

其供電部分如圖所示,當(dāng)VDD斷點(diǎn)之后,需要VBAT管腳為其供電,才能保證RTC的正常工作。

看一下中斷函數(shù),stm32不同系列的中斷函數(shù)是不一樣的

stm32F和L系列,比如低功耗這塊

1.使用RTC鬧鐘功能:再進(jìn)低功耗前先獲取當(dāng)前RTC的時(shí)間,在當(dāng)前時(shí)間上加10分鐘,算出喚醒時(shí)間,然后設(shè)置RTC鬧鐘喚醒時(shí)間,

設(shè)置函數(shù):HAL_RTC_SetAlarm_IT(&hrtc, &sAlarm, RTC_FORMAT_BCD)

RTC鬧鐘中斷函數(shù):void RTC_Alarm_IRQHandler(void)

2.使用RTC的WakeUp功能,最大計(jì)數(shù)值可以設(shè)置0x1FFFF,根據(jù)時(shí)鐘頻率可以任意調(diào)整延時(shí)喚醒時(shí)間,如果時(shí)1HZ的RTC計(jì)數(shù)頻率,最大延時(shí)喚醒時(shí)間(0x1FFFF+1)*1/60/60=36小時(shí)

設(shè)置函數(shù): HAL_RTCEx_SetWakeUpTimer_IT(&hrtc,600,RTC_WAKEUPCLOCK_CK_SPRE_16BITS);//RTC600秒后喚醒

RTC周期喚醒中斷函數(shù) : void RTC_WKUP_IRQHandler(void)

3.RTC全局中斷函數(shù)          RTC_IRQHandler()

注意事項(xiàng):

4.產(chǎn)生鬧鐘中斷的前一瞬間,一定產(chǎn)生了秒中斷,那么會(huì)先執(zhí)行RTC_IRQHandler() 中斷函數(shù), 在RTC_IRQHandler() 執(zhí)行的過程中,鬧鐘中斷標(biāo)志又被掛起,

由于RTC_IRQHandler()是全局中斷函數(shù),必須清除所有的中斷標(biāo)志,程序才能退出該函數(shù), 假如RTC_IRQHandler() 和RTCAlarm_IRQHandler() 是同樣的優(yōu)先級(jí),

要想讓程序退出RTC_IRQHandler() 函數(shù),那么你必須清除鬧鐘中斷標(biāo)志(如果不清除鬧鐘中斷標(biāo)志,程序會(huì)死在RTC_IRQHandler() ), 這樣問題又出現(xiàn)了,清除鬧鐘中斷標(biāo)志后,程序就不會(huì)進(jìn)入RTCAlarm_IRQHandler(),那么RTCAlarm_IRQHandler()函數(shù)永遠(yuǎn)也不會(huì)被執(zhí)行。

5.STM32F10x有20條中斷線,其中16條用于IO口中斷使用,還有4條用于內(nèi)部中斷事件。EXTI17就是用于內(nèi)部RTC鬧鐘喚醒中斷事件時(shí)使用,所以初始化中除了打開RTC鬧鐘中斷同時(shí)打開了EXTI17中斷線。配置鬧鐘中斷的話,也要開啟EXTI17中斷,特別注意。

6.STM32備份寄存器的配置與使用

嵌入式系統(tǒng)設(shè)計(jì)中,用來存儲(chǔ)系統(tǒng)運(yùn)行過程中的數(shù)據(jù)有很多種方式,而使用STM32的備份寄存器可以實(shí)現(xiàn)對(duì)少量數(shù)據(jù)的頻繁存儲(chǔ)。因?yàn)檫@種方式時(shí)將數(shù)據(jù)存儲(chǔ)在RAM中,掉電則數(shù)據(jù)丟失,所以需要使用備份電源為芯片供電;也由于是在RAM中,理論上可以無限次存取。

代碼如下

u8 RTC_Init()
{
	u8 temp = 0;
	NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP|RCC_APB1Periph_PWR,ENABLE);//電源時(shí)鐘和背部時(shí)鐘
	PWR_BackupAccessCmd(ENABLE);                    //允許背部區(qū)域?qū)?	
	if (BKP_ReadBackupRegister(BKP_DR1) != 0xC0B4)		
		{	 			
 
		BKP_DeInit();	
		RCC_LSEConfig(RCC_LSE_ON);	
		while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET)	
			{
			    temp++;
			    delay_ms(10);
			}
		if(temp>=250)return 1;   
		RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);		   
		RCC_RTCCLKCmd(ENABLE);	 
		RTC_WaitForLastTask();	
		RTC_WaitForSynchro();		
		RTC_ITConfig(RTC_IT_SEC|RTC_IT_ALR, ENABLE);	//打開RTC的秒中斷和鬧鐘中斷	
		RTC_WaitForLastTask();	
		RTC_EnterConfigMode();                        //進(jìn)入配置RTC模式
		RTC_SetPrescaler(32767); 
		
		RTC_SetCounter(0);                            //初始值設(shè)定為0s
	    RTC_WaitForLastTask();
		RTC_SetAlarm(40);	                           //鬧鐘值設(shè)定為40s
		RTC_WaitForLastTask();                        //等待上述配置完成
		RTC_ExitConfigMode();                          //退出配置模式
		BKP_WriteBackupRegister(BKP_DR1, 0XC0B4);
		PWR_BackupAccessCmd(DISABLE);                //不允許背部區(qū)域?qū)懖僮?		}
	else
	{
		PWR_BackupAccessCmd(DISABLE);
		RTC_WaitForSynchro();
		RTC_ITConfig(RTC_IT_SEC|RTC_IT_ALR,ENABLE); //打開RTC的秒中斷和鬧鐘中斷	
		RTC_WaitForLastTask();
	}
  
	NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn;		//RTC全局中斷的中斷配置
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;	
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;	
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;		
	NVIC_Init(&NVIC_InitStructure);		
 
	return 0;
}
//此初始化函數(shù)在主函數(shù)中的用法
while(RTC_Init())
	{
			printf("INIT Programing is ERROR!!\r\n");
		
	}

if (BKP_ReadBackupRegister(BKP_DR1) != 0xC0B4)    的意思就是讓STM32上電后自檢是不是第一次運(yùn)行這個(gè)程序。BKP_ReadBackupRegister(BKP_DR1)代表讀取BKP_DR1的值,如果第一次運(yùn)行這個(gè)程序那這個(gè)值一定是0X0000,值和0XC0B4不相等就進(jìn)入配置初始化程序。BKP_WriteBackupRegister(BKP_DR1, 0XC0B4)代表往BKP_DR1這個(gè)寄存器中寫入0XC0B4,注意BKP_DR1這個(gè)值被寫入之后就算復(fù)位他也不會(huì)被清除成0000。這樣的話就算復(fù)位或者重新上電,初始程序也不會(huì)再執(zhí)行一遍,所以RTC的值就不會(huì)再重新設(shè)置了。如果想要RTC的值重新從0開始計(jì)數(shù),那就可以吧0XC0B4改成一個(gè)新的數(shù)字,重新下載一次程序就可以了。

最后在看STM32G系列的,H系列有喜歡的額可以嘗試一下

只有這一個(gè)RTC中斷函數(shù),RTC_TAMP_IRQHandler

static void MX_RTC_Init(void)
{

  /* USER CODE BEGIN RTC_Init 0 */

  /* USER CODE END RTC_Init 0 */

  RTC_TimeTypeDef sTime = {0};
  RTC_DateTypeDef sDate = {0};
  RTC_AlarmTypeDef sAlarm = {0};

  /* USER CODE BEGIN RTC_Init 1 */

  /* USER CODE END RTC_Init 1 */
  /** 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;
  hrtc.Init.OutPutPullUp = RTC_OUTPUT_PULLUP_NONE;
  if (HAL_RTC_Init(&hrtc) != HAL_OK)
  {
    Error_Handler();
  }

  /* USER CODE BEGIN Check_RTC_BKUP */
//    //重啟后判斷該寄存器是否有值,判定是不是第丿次初始化,是否要裝載初始倿
//    if(HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR1) == 0xAA)
//    {
//        //已經(jīng)初始化過了,直接跳出初始化函
//        return;
//    }
//    //第一次初始化,將任意后備寄存器寫任意值,做個(gè)標(biāo)記,標(biāo)記已經(jīng)初始化過了,下次系統(tǒng)復(fù)位時(shí)不用初始匿
//    HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR1, 0xAA);
  /* USER CODE END Check_RTC_BKUP */

  /** Initialize RTC and set the Time and Date
  */
  sTime.Hours = 14;
  sTime.Minutes = 50;
  sTime.Seconds = 0;
  sTime.SubSeconds = 0;
  sTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
  sTime.StoreOperation = RTC_STOREOPERATION_RESET;
  if (HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BIN) != HAL_OK)
  {
    Error_Handler();
  }
  sDate.WeekDay = RTC_WEEKDAY_THURSDAY;
  sDate.Month = RTC_MONTH_JANUARY;
  sDate.Date = 28;
  sDate.Year = 21;

  if (HAL_RTC_SetDate(&hrtc, &sDate, RTC_FORMAT_BIN) != HAL_OK)
  {
    Error_Handler();
  }
  /** Enable the Alarm A
  */
  sAlarm.AlarmTime.Hours = 14;
  sAlarm.AlarmTime.Minutes = 50;
  sAlarm.AlarmTime.Seconds = 10;	//設(shè)置 10s 后產(chǎn)生鬧鐘中斷
  sAlarm.AlarmTime.SubSeconds = 0;
  sAlarm.AlarmTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
  sAlarm.AlarmTime.StoreOperation = RTC_STOREOPERATION_RESET;
  sAlarm.AlarmMask = RTC_ALARMMASK_NONE;
  sAlarm.AlarmSubSecondMask = RTC_ALARMSUBSECONDMASK_NONE;
  sAlarm.AlarmDateWeekDaySel = RTC_ALARMDATEWEEKDAYSEL_DATE;
  sAlarm.AlarmDateWeekDay = 28;
  sAlarm.Alarm = RTC_ALARM_A;
  if (HAL_RTC_SetAlarm_IT(&hrtc, &sAlarm, RTC_FORMAT_BIN) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN RTC_Init 2 */

  /* USER CODE END RTC_Init 2 */

}

聲明:本內(nèi)容為作者獨(dú)立觀點(diǎn),不代表電子星球立場(chǎng)。未經(jīng)允許不得轉(zhuǎn)載。授權(quán)事宜與稿件投訴,請(qǐng)聯(lián)系:editor@netbroad.com
覺得內(nèi)容不錯(cuò)的朋友,別忘了一鍵三連哦!
贊 2
收藏 3
關(guān)注 210
成為作者 賺取收益
全部留言
0/200
成為第一個(gè)和作者交流的人吧