STM32G474之TAMPALRM输出

news2024/11/9 9:34:08

TAMPALRM输出源是指“RTC唤醒”、“RTC报警A”和“RTC报警B”输出,可以配置从RTC_OU1(PC13)或RTC_OUT2(PB2)输出,而OUT2EN用来决定从哪个引脚输出。

1、TAMPALRM输出原理见下表:

若不看CALIB输出,可以简化如下表:

2、 “RTC唤醒”测试程序

#include "RTC.h"
#include "stdio.h"  //getchar(),putchar(),scanf(),printf(),puts(),gets(),sprintf()
#include "LED.h"
#include "delay.h"


void RTC_Init(void);
void RTC_Display(void);
void RTC_Set_Date_And_Time(uint16_t syear,uint8_t smon,uint8_t sday,uint8_t week,uint8_t hour,uint8_t min,uint8_t sec,uint32_t Format);
uint8_t RTC_Set_Alarm(uint8_t mode,uint8_t sWeekDay,uint8_t hour,uint8_t min,uint8_t sec,uint8_t subSecond,uint32_t Format);
void RTC_WakeUp_Output_On_RTCOUTx_Pin(RTC_HandleTypeDef *hrtc,uint8_t OutputPin);
void Read_RTC_WakeUp(void);

void RTC_Init(void)
{
	RTC_HandleTypeDef hrtc;
	RCC_OscInitTypeDef        RCC_OscInitStruct;  //配置LSE/LSI时钟
	RCC_PeriphCLKInitTypeDef  PeriphClkInitStruct;//用来为RTC选择时钟源

  __HAL_RCC_PWR_CLK_ENABLE();//Enable write access
	HAL_PWR_EnableBkUpAccess();//Enable the power clock

#ifdef RTC_CLOCK_SOURCE_LSE
  RCC_OscInitStruct.OscillatorType =  RCC_OSCILLATORTYPE_LSI | RCC_OSCILLATORTYPE_LSE;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
  RCC_OscInitStruct.LSEState = RCC_LSE_ON;
  RCC_OscInitStruct.LSIState = RCC_LSI_OFF;
  HAL_RCC_OscConfig(&RCC_OscInitStruct);
	//配置LSE时钟,关闭LSI时钟

  PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_RTC;
  PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSE;
  HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct);
	//选择LSE时钟为RTC时钟源

#elif defined (RTC_CLOCK_SOURCE_LSI)
  RCC_OscInitStruct.OscillatorType =  RCC_OSCILLATORTYPE_LSI;
	RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
  RCC_OscInitStruct.LSIState = RCC_LSI_ON;
	HAL_RCC_OscConfig(&RCC_OscInitStruct);
	//配置LSI时钟

  PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_RTC;
  PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSI;
	HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct);
	//选择LSI时钟为RTC时钟源
#endif /*RTC_CLOCK_SOURCE_LSE*/

  __HAL_RCC_RTCAPB_CLK_ENABLE();//使能RTC APB外部设备时钟,Enable RTC peripheral Clocks
  __HAL_RCC_RTC_ENABLE();//使能RTC时钟,Enable RTC Clock

  hrtc.Instance = RTC;                       //选择RTC
  hrtc.Init.HourFormat = RTC_HOURFORMAT_24;  //指定RTC小时的格式
  hrtc.Init.AsynchPrediv = RTC_ASYNCH_PREDIV;//指定RTC异步预分法器的值。
  hrtc.Init.SynchPrediv = RTC_SYNCH_PREDIV;  //指定RTC同步预分配器的值。

//  RTC_WakeUp_Output_On_RTCOUTx_Pin(&hrtc,1);//“RTC唤醒”输出从RTC_OUT1引脚输出
  RTC_WakeUp_Output_On_RTCOUTx_Pin(&hrtc,2);//“RTC唤醒”输出从RTC_OUT2引脚输出
  HAL_RTC_Init(&hrtc);

  if (HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR0) != 0x32F2)
  {//读TAMP_BKPxR寄存器,因为RTC_BKP_DR0=0,所以是读TAMP_BKP0R寄存器

//		Test_RTC_Set_Date_And_Time();//设置时间为24年2月29日星期四23:59:50:00
//		RTC_Set_Date_And_Time(0x24,0x02,0x29,0x04,0x23,0x59,0x50,RTC_FORMAT_BCD);
		//设置时间为24年2月29日星期四23:59:50:00
		RTC_Set_Date_And_Time(24,2,29,4,23,59,50,RTC_FORMAT_BIN);
		//设置时间为24年2月29日星期四23:59:50:00

		HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR0, 0x32F2);
		//写TAMP_BKPxR寄存器,因为RTC_BKP_DR0=0,所以是写TAMP_BKPxR寄存器
		//将0x32F2写入TAMP_BKP0R寄存器
		//Writes a data in a RTC Backup data Register0
  }

//	HAL_RTCEx_SetWakeUpTimer_IT(&hrtc,0,RTC_WAKEUPCLOCK_CK_SPRE_17BITS);
	//设置“唤醒定时器”65536秒种唤醒一次
	//RTC_WAKEUPCLOCK_CK_SPRE_17BITS,在该模式下,实际的计时时间:“重装载值加上0x10000”,唤醒时间长度范围:0x10000 ~ 0x1FFFF

//	HAL_RTCEx_SetWakeUpTimer_IT(&hrtc,0,RTC_WAKEUPCLOCK_CK_SPRE_16BITS);//设置“唤醒定时器”1秒种唤醒一次
	HAL_RTCEx_SetWakeUpTimer(&hrtc,512,RTC_WAKEUPCLOCK_RTCCLK_DIV16);
	//设置“唤醒定时器”0.5秒种唤醒一次
	//RTC时钟为32768Hz,512/(32768/16)=0.25秒
}

//函数功能:显示“年月日和星期几”以及“时分秒”
void RTC_Display(void)
{
  RTC_DateTypeDef sdatestructureget;//用来保存“年月日和星期几”
  RTC_TimeTypeDef stimestructureget;//用来保存“时分秒”

  printf("RTC_IT_SEC\r\n");
  HAL_RTC_GetTime(NULL, &stimestructureget, RTC_FORMAT_BIN);//读取"RTC时间"
	//读RTC_TR寄存器bit21:20(HT[1:0]),HT[1:0]表示小时的十位数值
	//读RTC_TR寄存器bit19:16(HU[3:0]),HU[3:0]表示小时的个位数值
	//读RTC_TR寄存器bit14:12(MNT[2:0]),MNT[2:0]表示分钟的十位数值
	//读RTC_TR寄存器bit11:8(MNU[3:0]),MNU[3:0]表示分钟的个位数值
	//读RTC_TR寄存器bit6:4(ST[2:0]),ST[2:0]表示秒的十位数值
	//读RTC_TR寄存器bit3:0(SU[3:0]),SU[3:0]表示秒的个位数值
	//HAL库耍牛氓,我也耍牛氓

  HAL_RTC_GetDate(NULL, &sdatestructureget, RTC_FORMAT_BIN);//读取"RTC日期"
	//读RTC_DR寄存器bit23:20(YT[3:0]),YT[3:0]表示年的十位数值
	//读RTC_DR寄存器bit19:16(YU[3:0]),YU[3:0]表示年的个位数值
	//读RTC_DR寄存器bit15:13(WDU[2:0]),WDU[2:0]=001b表示星期1;WDU[2:0]=010b表示星期2......WDU[2:0]=111b表示星期日
	//读RTC_DR寄存器bit12(MT),MT表示月的十位数值
	//读RTC_DR寄存器bit11:8(MU[3:0]),MU[3:0]表示月的个位数值
	//读RTC_DR寄存器bit5:4(DT[1:0]),DT[1:0]表示日的十位数值
	//读RTC_DR寄存器bit3:0(DU[3:0]),DU[3:0]表示日的个位数值
	//HAL库耍牛氓,我也耍牛氓

	printf("%02d-%02d-%02d  day:%02d  ", sdatestructureget.Year,sdatestructureget.Month,sdatestructureget.Date,sdatestructureget.WeekDay);
  printf("%02d:%02d:%02d\r\n", stimestructureget.Hours, stimestructureget.Minutes, stimestructureget.Seconds);
	//显示时间格式为 : YY-MM-DD hh:mm:ss
}

//函数功能:设置时钟,24小时格式
//RTC_FORMAT_BIN:年月日时分秒的格式是十进数
//RTC_FORMAT_BCD:年月日时分秒的格式是BCD码
//RTC_Set_Date_And_Time(0x21,0x02,0x29,0X04,0x23,0x59,0x30,RTC_FORMAT_BCD);
//RTC_Set_Date_And_Time(21,2,29,4,23,59,30,RTC_FORMAT_BIN);
void RTC_Set_Date_And_Time(uint16_t syear,uint8_t smon,uint8_t sday,uint8_t week,uint8_t hour,uint8_t min,uint8_t sec,uint32_t Format)
{
	uint32_t tmpreg;
	uint32_t datetmpreg;
	uint32_t sTimeFormat;

	__HAL_RTC_WRITEPROTECTION_DISABLE(NULL);
	//RTC->WPR = 0xCAU;RTC->WPR = 0x53U;
  //在“备份域”被修改后,一些RTC寄存器会受到写保护,因此,再次配置,需要解锁。
  //解锁受保护的RTC寄存器的步骤:先将0xCA写入RTC_WPR寄存器,然后将0x53RTC_WPR寄存器
	//HAL库耍牛氓,我也耍牛氓

	RTC_EnterInitMode(NULL);
	//进入修改“RTC_TR和RTC_DR”模式
	//HAL库耍牛氓,我也耍牛氓

	CLEAR_BIT(RTC->CR, RTC_CR_FMT);
	//设置当前时间格式为“24小时格式”
  //RTC_CR寄存器bit6(FMT),令FMT=0表示24小时格式,FMT=1表示12小时格式
	sTimeFormat = 0x00U;//记录当前时间格式为“24小时格式”

	if (Format == RTC_FORMAT_BIN)//十进制数据
	{
		tmpreg = (uint32_t)(((uint32_t)RTC_ByteToBcd2(hour) << RTC_TR_HU_Pos) | \
                          ((uint32_t)RTC_ByteToBcd2(min) << RTC_TR_MNU_Pos) | \
                          ((uint32_t)RTC_ByteToBcd2(sec) << RTC_TR_SU_Pos) | \
                          (((uint32_t)sTimeFormat) << RTC_TR_PM_Pos));
		//RTC_ByteToBcd2()将两位十进制数转换成BCD格式的数据
		datetmpreg = (((uint32_t)RTC_ByteToBcd2(syear) << RTC_DR_YU_Pos) | \
                  ((uint32_t)RTC_ByteToBcd2(smon) << RTC_DR_MU_Pos) | \
                  ((uint32_t)RTC_ByteToBcd2(sday) << RTC_DR_DU_Pos) | \
                  ((uint32_t)week << RTC_DR_WDU_Pos));
	}
	else
	{//数据格式为BCD码:RTC_FORMAT_BCD
		tmpreg = (((uint32_t)(hour) << RTC_TR_HU_Pos) | \
                ((uint32_t)(min) << RTC_TR_MNU_Pos) | \
                ((uint32_t)(sec) << RTC_TR_SU_Pos) | \
                ((uint32_t)(sTimeFormat) << RTC_TR_PM_Pos));
		datetmpreg = ((((uint32_t)syear) << RTC_DR_YU_Pos) | \
                  (((uint32_t)smon) << RTC_DR_MU_Pos) | \
                  (((uint32_t)sday) << RTC_DR_DU_Pos) | \
                  (((uint32_t)week) << RTC_DR_WDU_Pos));
	}
	WRITE_REG(RTC->TR, (tmpreg & RTC_TR_RESERVED_MASK));//修改“时分秒”
	WRITE_REG(RTC->DR, (uint32_t)(datetmpreg & RTC_DR_RESERVED_MASK));//修改“年月日和星期几”

	CLEAR_BIT(RTC->CR, RTC_CR_BKP);
	//将RTC_CR寄存器的bit18(BKP),令BKP=0,取消记忆“夏令时被修改过”
	SET_BIT(RTC->CR, (RTC_DAYLIGHTSAVING_NONE | RTC_STOREOPERATION_RESET));
	//RTC_CR寄存器bit16(ADD1H),ADD1H=0,当前时间不增加1小时
	//RTC_CR寄存器bit18(BKP),BKP=0,不使用“夏令时”
		
  CLEAR_BIT(RTC->ICSR, RTC_ICSR_INIT);
	//RTC_ICSR寄存器bit7(INIT),INIT=0进入“自由运行模式”
  if (READ_BIT(RTC->CR, RTC_CR_BYPSHAD) == 0U)
  {//读RTC_CR寄存器bit5(BYPSHAD),BYPSHAD=0表示“日历值从影子寄存器读取”

    if (HAL_RTC_WaitForSynchro(NULL) != HAL_OK)
    {//等待“日历影子寄存器同步”
    }
  }
  else
  {//RTC_CR寄存器bit5(BYPSHAD),若BYPSHAD=1表示“日历值从日历计数器中读取”
    /* Clear BYPSHAD bit */
    CLEAR_BIT(RTC->CR, RTC_CR_BYPSHAD);
		//RTC_CR寄存器bit5(BYPSHAD),令BYPSHAD=0“日历值从影子寄存器读取”
    if (HAL_RTC_WaitForSynchro(NULL) != HAL_OK)
    {//等待“日历影子寄存器同步”
    }
    /* Restore BYPSHAD bit */
    SET_BIT(RTC->CR, RTC_CR_BYPSHAD);
		//RTC_CR寄存器bit5(BYPSHAD),若BYPSHAD=1表示“日历值从日历计数器中读取”
  }

	__HAL_RTC_WRITEPROTECTION_ENABLE(NULL);
	//RTC->WPR = 0xFFU;//RTC寄存器上锁,使能写保护
	//HAL库耍牛氓,我也耍牛氓
}

//在调用HAL_RTC_Init()之前调用RTC_WakeUp_Output_On_RTCOUTx_Pin()
//RTC_WakeUp_Output_On_RTCOUTx_Pin(&hrtc,1);//“RTC唤醒”输出从RTC_OUT1引脚输出
//RTC_WakeUp_Output_On_RTCOUTx_Pin(&hrtc,2);//“RTC唤醒”输出从RTC_OUT2引脚输出
//配置RTC_OUT1输出“RTC唤醒溢出标志”,其电平时间和WUTF的保持时间有关
void RTC_WakeUp_Output_On_RTCOUTx_Pin(RTC_HandleTypeDef *hrtc,uint8_t OutputPin)
{
	GPIO_InitTypeDef GPIO_InitStruct = {0};

	hrtc->Init.OutPutPolarity = RTC_OUTPUT_POLARITY_LOW; //报警TAMPALRM输出低电平;
	hrtc->Init.OutPutType = RTC_OUTPUT_TYPE_PUSHPULL;    //TAMPALRM为推挽输出
	hrtc->Init.OutPutPullUp = RTC_OUTPUT_PULLUP_ON;      //TAMPALRM输出上拉

	if(OutputPin==1)
	{
		__HAL_RCC_GPIOC_CLK_ENABLE();                   //GPIOC时钟使能

    GPIO_InitStruct.Pin = GPIO_PIN_13;              //选择引脚号码为13
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;     //推挽输出模式
//	  GPIO_InitStruct.Pull = GPIO_NOPULL;             //引脚上拉和下拉都没有被激活
	  GPIO_InitStruct.Pull = GPIO_PULLUP;           //设置上拉
	  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;//引脚的输出速度为120MHz
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
	  //根据GPIO_InitStruct结构变量指定的参数初始化GPIOC的外设寄存器

		hrtc->Init.OutPutRemap = RTC_OUTPUT_REMAP_NONE;      //RTC_OUT1输出使能,RTC_OUT2输出不使能;
	}
	else if(OutputPin==2)
	{
		__HAL_RCC_GPIOB_CLK_ENABLE();  //使能GPIOB外设时钟
	  GPIO_InitStruct.Pin = GPIO_PIN_2;//选择引脚编号2
	  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;      //复用功能推挽模式
//	GPIO_InitStruct.Pull = GPIO_NOPULL;          //引脚上拉和下拉都没有被激活
	  GPIO_InitStruct.Pull = GPIO_PULLUP;           //设置上拉
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;//引脚的输出速度为120MHz
    GPIO_InitStruct.Alternate = GPIO_AF0_RTC_50Hz; //将引脚复用为RTC_OUT2
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

		hrtc->Init.OutPutRemap = RTC_OUTPUT_REMAP_POS1; //RTC_OUT1输出不使能,RTC_OUT2输出使能;
	}
	hrtc->Init.OutPut = RTC_OUTPUT_WAKEUP;    //设置“RTC唤醒”输出
}

void Read_RTC_WakeUp(void)
{
//	HAL_RTCEx_WakeUpTimerIRQHandler(&hrtc);

  if (READ_BIT(RTC->SR, RTC_SR_WUTF) != 0U)
  {//读RTC_SR寄存器bit2(WUTF),WUTF=1表示“唤醒定时器中断”
    /* Clear the WAKEUPTIMER interrupt pending bit */
    WRITE_REG(RTC->SCR, RTC_SCR_CWUTF);
		//RTC_SCR寄存器bit2(CWUTF),写入1表示清除“RTC状态寄存器RTC_SR”中的WUTF位,即“唤醒定时器中断标志位”

//    __HAL_RTC_WAKEUPTIMER_EXTI_CLEAR_IT();
//		//EXTI_PR1寄存器bit20PIF20),令PIF20=1用来清除“唤醒定时器事件建立的标志位,使PIF20=0”
		LED1_Toggle();
  }
}

3、“RTC报警A”和“RTC报警B”输出测试程序

#include "RTC.h"
#include "stdio.h"  //getchar(),putchar(),scanf(),printf(),puts(),gets(),sprintf()
#include "LED.h"
#include "delay.h"

void RTC_Init(void);
void RTC_Display(void);
void RTC_Set_Date_And_Time(uint16_t syear,uint8_t smon,uint8_t sday,uint8_t week,uint8_t hour,uint8_t min,uint8_t sec,uint32_t Format);
uint8_t RTC_Set_Alarm(uint8_t mode,uint8_t sWeekDay,uint8_t hour,uint8_t min,uint8_t sec,uint8_t subSecond,uint32_t Format);
void RTC_OUTx_Init(RTC_HandleTypeDef *hrtc,uint32_t OutputSource,uint8_t OutputPin);
void Read_RTC_Alarm(void);

void RTC_Init(void)
{
	RTC_HandleTypeDef hrtc;
	RCC_OscInitTypeDef        RCC_OscInitStruct;  //配置LSE/LSI时钟
	RCC_PeriphCLKInitTypeDef  PeriphClkInitStruct;//用来为RTC选择时钟源

  __HAL_RCC_PWR_CLK_ENABLE();//Enable write access
	HAL_PWR_EnableBkUpAccess();//Enable the power clock

#ifdef RTC_CLOCK_SOURCE_LSE
  RCC_OscInitStruct.OscillatorType =  RCC_OSCILLATORTYPE_LSI | RCC_OSCILLATORTYPE_LSE;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
  RCC_OscInitStruct.LSEState = RCC_LSE_ON;
  RCC_OscInitStruct.LSIState = RCC_LSI_OFF;
  HAL_RCC_OscConfig(&RCC_OscInitStruct);
	//配置LSE时钟,关闭LSI时钟

  PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_RTC;
  PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSE;
  HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct);
	//选择LSE时钟为RTC时钟源

#elif defined (RTC_CLOCK_SOURCE_LSI)
  RCC_OscInitStruct.OscillatorType =  RCC_OSCILLATORTYPE_LSI;
	RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
  RCC_OscInitStruct.LSIState = RCC_LSI_ON;
	HAL_RCC_OscConfig(&RCC_OscInitStruct);
	//配置LSI时钟

  PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_RTC;
  PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSI;
	HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct);
	//选择LSI时钟为RTC时钟源
#endif /*RTC_CLOCK_SOURCE_LSE*/

  __HAL_RCC_RTCAPB_CLK_ENABLE();//使能RTC APB外部设备时钟,Enable RTC peripheral Clocks
  __HAL_RCC_RTC_ENABLE();//使能RTC时钟,Enable RTC Clock

  hrtc.Instance = RTC;                       //选择RTC
  hrtc.Init.HourFormat = RTC_HOURFORMAT_24;  //指定RTC小时的格式
  hrtc.Init.AsynchPrediv = RTC_ASYNCH_PREDIV;//指定RTC异步预分法器的值。
  hrtc.Init.SynchPrediv = RTC_SYNCH_PREDIV;  //指定RTC同步预分配器的值。

   RTC_OUTx_Init(&hrtc,RTC_OUTPUT_ALARMA,1);//RTC报警器A从RTC_OUT1引脚输出
//	 RTC_OUTx_Init(&hrtc,RTC_OUTPUT_ALARMB,1);//RTC报警器B从RTC_OUT1引脚输出
//  RTC_OUTx_Init(&hrtc,RTC_OUTPUT_ALARMA,2);//RTC报警器A从RTC_OUT2引脚输出
//	RTC_OUTx_Init(&hrtc,RTC_OUTPUT_ALARMB,2);//RTC报警器B从RTC_OUT2引脚输出
  HAL_RTC_Init(&hrtc);

  if (HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR0) != 0x32F2)
  {//读TAMP_BKPxR寄存器,因为RTC_BKP_DR0=0,所以是读TAMP_BKP0R寄存器

//		Test_RTC_Set_Date_And_Time();//设置时间为24年2月29日星期四23:59:50:00
//		RTC_Set_Date_And_Time(0x24,0x02,0x29,0x04,0x23,0x59,0x50,RTC_FORMAT_BCD);
		//设置时间为24年2月29日星期四23:59:50:00
		RTC_Set_Date_And_Time(24,2,29,4,23,59,50,RTC_FORMAT_BIN);
		//设置时间为24年2月29日星期四23:59:50:00

		HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR0, 0x32F2);
		//写TAMP_BKPxR寄存器,因为RTC_BKP_DR0=0,所以是写TAMP_BKPxR寄存器
		//将0x32F2写入TAMP_BKP0R寄存器
		//Writes a data in a RTC Backup data Register0
  }

//  RTC_Set_Date_And_Time(0x21,0x02,0x29,0X04,0x23,0x59,0x30,RTC_FORMAT_BCD);
	//设置时间为21年2月29日星期四23:59:30:00
//  RTC_Set_Date_And_Time(21,2,29,4,23,59,30,RTC_FORMAT_BIN);
	//设置时间为21年2月29日星期四23:59:30:00

//  TEST_Hal_RTC_Set_Alarm_A();
//	TEST_Hal_RTC_Set_Alarm_B();

  RTC_Set_Alarm(0x00,0x01,0x00,0x00,0x20,0x56,RTC_FORMAT_BCD);//设置RTC报警器A每秒钟报警一次
	RTC_Set_Alarm(0x80,0x01,0x00,0x00,0x20,0x30,RTC_FORMAT_BCD);//设置RTC报警器B每秒钟报警一次
//	RTC_Set_Alarm(0x01,0x01,0x00,0x00,0x20,0x56,RTC_FORMAT_BCD);//设置RTC报警器A每分钟报警一次
//	RTC_Set_Alarm(0x81,1,0,0,20,50,RTC_FORMAT_BIN);//设置RTC报警器B每分钟报警一次
}

//函数功能:显示“年月日和星期几”以及“时分秒”
void RTC_Display(void)
{
  RTC_DateTypeDef sdatestructureget;//用来保存“年月日和星期几”
  RTC_TimeTypeDef stimestructureget;//用来保存“时分秒”

  printf("RTC_IT_SEC\r\n");
  HAL_RTC_GetTime(NULL, &stimestructureget, RTC_FORMAT_BIN);//读取"RTC时间"
	//读RTC_TR寄存器bit21:20(HT[1:0]),HT[1:0]表示小时的十位数值
	//读RTC_TR寄存器bit19:16(HU[3:0]),HU[3:0]表示小时的个位数值
	//读RTC_TR寄存器bit14:12(MNT[2:0]),MNT[2:0]表示分钟的十位数值
	//读RTC_TR寄存器bit11:8(MNU[3:0]),MNU[3:0]表示分钟的个位数值
	//读RTC_TR寄存器bit6:4(ST[2:0]),ST[2:0]表示秒的十位数值
	//读RTC_TR寄存器bit3:0(SU[3:0]),SU[3:0]表示秒的个位数值
	//HAL库耍牛氓,我也耍牛氓

  HAL_RTC_GetDate(NULL, &sdatestructureget, RTC_FORMAT_BIN);//读取"RTC日期"
	//读RTC_DR寄存器bit23:20(YT[3:0]),YT[3:0]表示年的十位数值
	//读RTC_DR寄存器bit19:16(YU[3:0]),YU[3:0]表示年的个位数值
	//读RTC_DR寄存器bit15:13(WDU[2:0]),WDU[2:0]=001b表示星期1;WDU[2:0]=010b表示星期2......WDU[2:0]=111b表示星期日
	//读RTC_DR寄存器bit12(MT),MT表示月的十位数值
	//读RTC_DR寄存器bit11:8(MU[3:0]),MU[3:0]表示月的个位数值
	//读RTC_DR寄存器bit5:4(DT[1:0]),DT[1:0]表示日的十位数值
	//读RTC_DR寄存器bit3:0(DU[3:0]),DU[3:0]表示日的个位数值
	//HAL库耍牛氓,我也耍牛氓

	printf("%02d-%02d-%02d  day:%02d  ", sdatestructureget.Year,sdatestructureget.Month,sdatestructureget.Date,sdatestructureget.WeekDay);
  printf("%02d:%02d:%02d\r\n", stimestructureget.Hours, stimestructureget.Minutes, stimestructureget.Seconds);
	//显示时间格式为 : YY-MM-DD hh:mm:ss
}


//函数功能:设置时钟,24小时格式
//RTC_FORMAT_BIN:年月日时分秒的格式是十进数
//RTC_FORMAT_BCD:年月日时分秒的格式是BCD码
//RTC_Set_Date_And_Time(0x21,0x02,0x29,0X04,0x23,0x59,0x30,RTC_FORMAT_BCD);
//RTC_Set_Date_And_Time(21,2,29,4,23,59,30,RTC_FORMAT_BIN);
void RTC_Set_Date_And_Time(uint16_t syear,uint8_t smon,uint8_t sday,uint8_t week,uint8_t hour,uint8_t min,uint8_t sec,uint32_t Format)
{
	uint32_t tmpreg;
	uint32_t datetmpreg;
	uint32_t sTimeFormat;

	__HAL_RTC_WRITEPROTECTION_DISABLE(NULL);
	//RTC->WPR = 0xCAU;RTC->WPR = 0x53U;
  //在“备份域”被修改后,一些RTC寄存器会受到写保护,因此,再次配置,需要解锁。
  //解锁受保护的RTC寄存器的步骤:先将0xCA写入RTC_WPR寄存器,然后将0x53RTC_WPR寄存器
	//HAL库耍牛氓,我也耍牛氓

	RTC_EnterInitMode(NULL);
	//进入修改“RTC_TR和RTC_DR”模式
	//HAL库耍牛氓,我也耍牛氓

	CLEAR_BIT(RTC->CR, RTC_CR_FMT);
	//设置当前时间格式为“24小时格式”
  //RTC_CR寄存器bit6(FMT),令FMT=0表示24小时格式,FMT=1表示12小时格式
	sTimeFormat = 0x00U;//记录当前时间格式为“24小时格式”

	if (Format == RTC_FORMAT_BIN)//十进制数据
	{
		tmpreg = (uint32_t)(((uint32_t)RTC_ByteToBcd2(hour) << RTC_TR_HU_Pos) | \
                          ((uint32_t)RTC_ByteToBcd2(min) << RTC_TR_MNU_Pos) | \
                          ((uint32_t)RTC_ByteToBcd2(sec) << RTC_TR_SU_Pos) | \
                          (((uint32_t)sTimeFormat) << RTC_TR_PM_Pos));
		//RTC_ByteToBcd2()将两位十进制数转换成BCD格式的数据
		datetmpreg = (((uint32_t)RTC_ByteToBcd2(syear) << RTC_DR_YU_Pos) | \
                  ((uint32_t)RTC_ByteToBcd2(smon) << RTC_DR_MU_Pos) | \
                  ((uint32_t)RTC_ByteToBcd2(sday) << RTC_DR_DU_Pos) | \
                  ((uint32_t)week << RTC_DR_WDU_Pos));
	}
	else
	{//数据格式为BCD码:RTC_FORMAT_BCD
		tmpreg = (((uint32_t)(hour) << RTC_TR_HU_Pos) | \
                ((uint32_t)(min) << RTC_TR_MNU_Pos) | \
                ((uint32_t)(sec) << RTC_TR_SU_Pos) | \
                ((uint32_t)(sTimeFormat) << RTC_TR_PM_Pos));
		datetmpreg = ((((uint32_t)syear) << RTC_DR_YU_Pos) | \
                  (((uint32_t)smon) << RTC_DR_MU_Pos) | \
                  (((uint32_t)sday) << RTC_DR_DU_Pos) | \
                  (((uint32_t)week) << RTC_DR_WDU_Pos));
	}
	WRITE_REG(RTC->TR, (tmpreg & RTC_TR_RESERVED_MASK));//修改“时分秒”
	WRITE_REG(RTC->DR, (uint32_t)(datetmpreg & RTC_DR_RESERVED_MASK));//修改“年月日和星期几”

	CLEAR_BIT(RTC->CR, RTC_CR_BKP);
	//将RTC_CR寄存器的bit18(BKP),令BKP=0,取消记忆“夏令时被修改过”
	SET_BIT(RTC->CR, (RTC_DAYLIGHTSAVING_NONE | RTC_STOREOPERATION_RESET));
	//RTC_CR寄存器bit16(ADD1H),ADD1H=0,当前时间不增加1小时
	//RTC_CR寄存器bit18(BKP),BKP=0,不使用“夏令时”
		
  CLEAR_BIT(RTC->ICSR, RTC_ICSR_INIT);
	//RTC_ICSR寄存器bit7(INIT),INIT=0进入“自由运行模式”
  if (READ_BIT(RTC->CR, RTC_CR_BYPSHAD) == 0U)
  {//读RTC_CR寄存器bit5(BYPSHAD),BYPSHAD=0表示“日历值从影子寄存器读取”

    if (HAL_RTC_WaitForSynchro(NULL) != HAL_OK)
    {//等待“日历影子寄存器同步”
    }
  }
  else
  {//RTC_CR寄存器bit5(BYPSHAD),若BYPSHAD=1表示“日历值从日历计数器中读取”
    /* Clear BYPSHAD bit */
    CLEAR_BIT(RTC->CR, RTC_CR_BYPSHAD);
		//RTC_CR寄存器bit5(BYPSHAD),令BYPSHAD=0“日历值从影子寄存器读取”
    if (HAL_RTC_WaitForSynchro(NULL) != HAL_OK)
    {//等待“日历影子寄存器同步”
    }
    /* Restore BYPSHAD bit */
    SET_BIT(RTC->CR, RTC_CR_BYPSHAD);
		//RTC_CR寄存器bit5(BYPSHAD),若BYPSHAD=1表示“日历值从日历计数器中读取”
  }

	__HAL_RTC_WRITEPROTECTION_ENABLE(NULL);
	//RTC->WPR = 0xFFU;//RTC寄存器上锁,使能写保护
	//HAL库耍牛氓,我也耍牛氓
}

//alarmType =RTC_ALARM_A
//alarmType =RTC_ALARM_B
//Format=RTC_FORMAT_BIN,数据格式为十进制数
//Format=RTC_FORMAT_BCD,数据格式为BCD码
//mode=0x00设置“RTC报警器A”每秒种报警一次
//mode=0x01设置“RTC报警器A”每分钟报警一次
//mode=0x02设置“RTC报警器A”每小时报警一次
//mode=0x03设置“RTC报警器A”每天报警一次
//mode=0x04设置“RTC报警器A”每月报警一次

//mode=0x80设置“RTC报警器B”每秒种报警一次
//mode=0x81设置“RTC报警器B”每分钟报警一次
//mode=0x82设置“RTC报警器B”每小时报警一次
//mode=0x83设置“RTC报警器B”每天报警一次
//mode=0x84设置“RTC报警器B”每月报警一次
uint8_t RTC_Set_Alarm(uint8_t mode,uint8_t sWeekDay,uint8_t hour,uint8_t min,uint8_t sec,uint8_t subSecond,uint32_t Format)
{
  uint32_t tickstart;
  uint32_t tmpreg;
  uint32_t subsecondtmpreg;
	uint8_t  ret_FLAG;
	uint32_t AlarmDateWeekDaySel;
	uint32_t AlarmMask;

	ret_FLAG=0;
	if( (mode&0x07) ==0 )
    AlarmMask = RTC_ALARMMASK_ALL;
	  //不关注日期,小时,分钟和秒,只关注“子秒”,则每秒种报警一次
	if( (mode&0x07) ==1)
	  AlarmMask = RTC_ALARMMASK_DATEWEEKDAY|RTC_ALARMMASK_HOURS|RTC_ALARMMASK_MINUTES;
	  //不关注日期小时和分钟,只关注“秒和子秒”,则每分钟报警一次
	if( (mode&0x07) ==2)
	  AlarmMask = RTC_ALARMMASK_DATEWEEKDAY|RTC_ALARMMASK_HOURS;
	  //不关注日期和小时,只关注“分、秒和子秒”,则每小时报警一次
	if( (mode&0x07) ==3)
		AlarmMask = RTC_ALARMMASK_DATEWEEKDAY;
	  //不关注日期,只关注“时、分、秒和子秒”,则每天报警一次
	if( (mode&0x07) ==4)
		AlarmMask = RTC_ALARMMASK_NONE;
	  //关注“日期、时、分、秒和子秒”,则每月报警一次

	AlarmDateWeekDaySel = RTC_ALARMDATEWEEKDAYSEL_DATE;//指定RTC警报是按照日期报警
//  AlarmDateWeekDaySel = RTC_ALARMDATEWEEKDAYSEL_WEEKDAY;//指定RTC警报是按照星期报警

  if (Format == RTC_FORMAT_BIN)
  {//数据格式为十进制数:RTC_FORMAT_BIN
    tmpreg = (((uint32_t)RTC_ByteToBcd2(hour) << RTC_ALRMAR_HU_Pos) | \
              ((uint32_t)RTC_ByteToBcd2(min) << RTC_ALRMAR_MNU_Pos) | \
              ((uint32_t)RTC_ByteToBcd2(sec) << RTC_ALRMAR_SU_Pos) | \
              ((uint32_t)(RTC_HOURFORMAT_24) << RTC_ALRMAR_PM_Pos) | \
              ((uint32_t)RTC_ByteToBcd2(sWeekDay) << RTC_ALRMAR_DU_Pos) | \
              ((uint32_t)AlarmDateWeekDaySel) | \
              ((uint32_t)AlarmMask));
  }
  else
  {//数据格式为BCD码:RTC_FORMAT_BCD
    tmpreg = (((uint32_t)(hour) << RTC_ALRMAR_HU_Pos) | \
              ((uint32_t)(min) << RTC_ALRMAR_MNU_Pos) | \
              ((uint32_t)(sec) << RTC_ALRMAR_SU_Pos) | \
              ((uint32_t)(RTC_HOURFORMAT_24) << RTC_ALRMAR_PM_Pos) | \
              ((uint32_t)(sWeekDay) << RTC_ALRMAR_DU_Pos) | \
              ((uint32_t)AlarmDateWeekDaySel) | \
              ((uint32_t)AlarmMask));
  }
  subsecondtmpreg = (uint32_t)((uint32_t)(subSecond) | (uint32_t)(RTC_ALARMSUBSECONDMASK_ALL));
	//Configure the Alarm A or Alarm B Sub Second registers

	__HAL_RTC_WRITEPROTECTION_DISABLE(NULL);
	//RTC->WPR = 0xCAU;RTC->WPR = 0x53U;
  //在“备份域”被修改后,一些RTC寄存器会受到写保护,因此,再次配置,需要解锁。
  //解锁受保护的RTC寄存器的步骤:先将0xCA写入RTC_WPR寄存器,然后将0x53RTC_WPR寄存器
	//HAL库耍牛氓,我也耍牛氓

  if ( (mode&0x80)==0 )
  { //不使能“Alarm A报警”和“Alarm A报警中断”,不选择“RTC报警事件”作为触发源
    CLEAR_BIT(RTC->CR, RTC_CR_ALRAE | RTC_CR_ALRAIE);
		//RTC_CR寄存器的bit8(ALRAE)和bit12(ALRAIE),ALRAIE=0,令不使能“Alarm A报警中断”;ALRAE=0不使能“Alarm A报警”
    __HAL_RTC_ALARM_EXTI_CLEAR_IT();//EXTI_PR1寄存器bit17(PIF17),PIF17=0表示不选择“RTC报警事件”作为触发源
    tickstart = HAL_GetTick();
    while (READ_BIT(RTC->ICSR, RTC_ICSR_ALRAWF) == 0U)
    {//读RTC_ICSR寄存器bit0(ALRAWF),ALRAWF=1表示允许更新“Alarm A”;ALRAWF=0表示不允许更新“Alarm A”
      if ((HAL_GetTick()  - tickstart) > RTC_TIMEOUT_VALUE)
      {
        __HAL_RTC_WRITEPROTECTION_ENABLE(hrtc);//RTC寄存器上锁,使能写保护
        ret_FLAG=1;//超时,出现错误
      }
    }

    if(ret_FLAG==0)
		{
      CLEAR_BIT(RTC->CR, RTC_CR_ALRAIE);
		  //RTC_CR寄存器的bit8(ALRAE)和bit12(ALRAIE),ALRAIE=0,令不使能“Alarm A报警中断”;
      WRITE_REG(RTC->SCR, RTC_SCR_CALRAF);
		  //RTC_SCR寄存器bit0(CALRAF),写入1表示清除“RTC状态寄存器RTC_SR”中的CALRAF位,即“Alarm A报警标志位”
      __HAL_RTC_ALARM_EXTI_CLEAR_IT();//EXTI_PR1寄存器bit17(PIF17),PIF17=0表示不选择“RTC报警事件”作为触发源

      tickstart = HAL_GetTick();
      while (READ_BIT(RTC->ICSR, RTC_ICSR_ALRAWF) == 0U)
      {//读RTC_ICSR寄存器bit0(ALRAWF),ALRAWF=1表示允许更新“Alarm A”;ALRAWF=0表示不允许更新“Alarm A”
        if ((HAL_GetTick() - tickstart) > RTC_TIMEOUT_VALUE) ret_FLAG=1;//超时,出现错误
      }

			if(ret_FLAG==0)
			{
        WRITE_REG(RTC->ALRMAR, tmpreg);//Configure the Alarm A Sub Second register
        WRITE_REG(RTC->ALRMASSR, subsecondtmpreg);//Configure the Alarm interrupt : Enable Alarm
        SET_BIT(RTC->CR, (RTC_CR_ALRAE | RTC_CR_ALRAIE));
				//RTC_CR寄存器的bit8(ALRAE)和bit12(ALRAIE),ALRAIE=1,令使能“Alarm A报警中断”;ALRAE=1使能“Alarm A报警”
			}
	  }
  }
  else
  {
		//不使能“Alarm B报警”和“Alarm B报警中断”,不选择“RTC报警事件”作为触发源
    CLEAR_BIT(RTC->CR, RTC_CR_ALRBE | RTC_CR_ALRBIE);
		//RTC_CR寄存器的bit9(ALRBE)和bit13(ALRBIE),ALRBIE=0,令不使能“Alarm B报警中断”;ALRBE=0不使能“Alarm B报警”
    __HAL_RTC_ALARM_EXTI_CLEAR_IT();//EXTI_PR1寄存器bit17(PIF17),PIF17=0表示不选择“RTC报警事件”作为触发源
    tickstart = HAL_GetTick();
    while (READ_BIT(RTC->ICSR, RTC_ICSR_ALRBWF) == 0U)
    {//读RTC_ICSR寄存器bit1(ALRBWF),ALRBWF=1表示允许更新“Alarm B”;ALRBWF=0表示不允许更新“Alarm B”
      if ((HAL_GetTick() - tickstart) > RTC_TIMEOUT_VALUE)
      {
        __HAL_RTC_WRITEPROTECTION_ENABLE(hrtc);//RTC寄存器上锁,使能写保护
				ret_FLAG=1;//超时,出现错误
      }
    }

		if(ret_FLAG==0)
		{
      CLEAR_BIT(RTC->CR, RTC_CR_ALRBIE);
		  //RTC_CR寄存器的bit9(ALRBE)和bit13(ALRBIE),ALRBIE=0,令不使能“Alarm B报警中断”;
      WRITE_REG(RTC->SCR, RTC_SCR_CALRBF);
		  //RTC_SCR寄存器bitB(CALRBF),写入1表示清除“RTC状态寄存器RTC_SR”中的CALRBF位,清除“Alarm B报警标志位”
      __HAL_RTC_ALARM_EXTI_CLEAR_IT();//EXTI_PR1寄存器bit17(PIF17),PIF17=0表示不选择“RTC报警事件”作为触发源

      tickstart = HAL_GetTick();
      while (READ_BIT(RTC->ICSR, RTC_ICSR_ALRBWF) == 0U)
      {//读RTC_ICSR寄存器bit1(ALRBWF),ALRBWF=1表示允许更新“Alarm B”;ALRBWF=0表示不允许更新“Alarm B”
        if ((HAL_GetTick() - tickstart) > RTC_TIMEOUT_VALUE) ret_FLAG=1;//超时,出现错误
      }

			if(ret_FLAG==0)
			{
        WRITE_REG(RTC->ALRMBR, tmpreg);           //Configure the Alarm B Sub Second register
        WRITE_REG(RTC->ALRMBSSR, subsecondtmpreg);//Configure the Alarm B interrupt : Enable Alarm
        SET_BIT(RTC->CR, (RTC_CR_ALRBE | RTC_CR_ALRBIE));
				//RTC_CR寄存器的bit9(ALRBE)和bit13(ALRBIE),ALRBIE=1,令使能“Alarm B报警中断”;ALRBE=1使能“Alarm B报警”
			}
	  }
  }

/*
  ///RTC Alarm Interrupt Configuration: EXTI configuration
  __HAL_RTC_ALARM_EXTI_ENABLE_IT();//EXTI_IMR1寄存器bit17(IM17),令IM17=1使能中断请求来自“外部中断线17”
  __HAL_RTC_ALARM_EXTI_RISING_IT();//EXTI->RTSR1寄存器bit17(RT17),RT17=1上升沿触发使能

	__HAL_RTC_WRITEPROTECTION_ENABLE(NULL);
	//RTC->WPR = 0xFFU;//RTC寄存器上锁,使能写保护
	//HAL库耍牛氓,我也耍牛氓

  HAL_NVIC_SetPriority(RTC_Alarm_IRQn, 5, 0);
	//设置NVIC中断分组4:4位抢占优先级,0位响应优先级
	//选择中断优先级组4,即抢占优先级为4位,取值为0~15,响应优先级组为0位,取值为0
  HAL_NVIC_EnableIRQ(RTC_Alarm_IRQn);
*/

	return(ret_FLAG);
}

//在调用HAL_RTC_Init()之前调用RTC_OUTx_Init()
//RTC_OUTx_Init(&hrtc,RTC_OUTPUT_ALARMA,1);//RTC报警器A从RTC_OUT1引脚输出
//RTC_OUTx_Init(&hrtc,RTC_OUTPUT_ALARMB,1);//RTC报警器B从RTC_OUT1引脚输出
//RTC_OUTx_Init(&hrtc,RTC_OUTPUT_ALARMA,2);//RTC报警器A从RTC_OUT2引脚输出
//RTC_OUTx_Init(&hrtc,RTC_OUTPUT_ALARMB,2);//RTC报警器B从RTC_OUT2引脚输出
//配置RTC_OUT1输出“RTC报警器A的报警标志”,其电平时间和ALRAF的保持时间有关
//配置RTC_OUT1输出“RTC报警器B的报警标志”,其电平时间和ALRBF的保持时间有关
void RTC_OUTx_Init(RTC_HandleTypeDef *hrtc,uint32_t OutputSource,uint8_t OutputPin)
{
	GPIO_InitTypeDef GPIO_InitStruct = {0};

	hrtc->Init.OutPutPolarity = RTC_OUTPUT_POLARITY_LOW;//报警TAMPALRM输出低电平;
	hrtc->Init.OutPutType = RTC_OUTPUT_TYPE_PUSHPULL;    //TAMPALRM为推挽输出
	hrtc->Init.OutPutPullUp = RTC_OUTPUT_PULLUP_ON;      //TAMPALRM输出上拉

	if(OutputPin==1)
	{
		__HAL_RCC_GPIOC_CLK_ENABLE();                   //GPIOC时钟使能

    GPIO_InitStruct.Pin = GPIO_PIN_13;              //选择引脚号码为13
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;     //推挽输出模式
//	  GPIO_InitStruct.Pull = GPIO_NOPULL;             //引脚上拉和下拉都没有被激活
	  GPIO_InitStruct.Pull = GPIO_PULLUP;           //设置上拉
	  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;//引脚的输出速度为120MHz
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
	  //根据GPIO_InitStruct结构变量指定的参数初始化GPIOC的外设寄存器

		hrtc->Init.OutPutRemap = RTC_OUTPUT_REMAP_NONE;      //RTC_OUT1输出使能,RTC_OUT2输出不使能;
	}
	else if(OutputPin==2)
	{
		__HAL_RCC_GPIOB_CLK_ENABLE();  //使能GPIOB外设时钟
	  GPIO_InitStruct.Pin = GPIO_PIN_2;//选择引脚编号2
	  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;      //复用功能推挽模式
//	GPIO_InitStruct.Pull = GPIO_NOPULL;          //引脚上拉和下拉都没有被激活
	  GPIO_InitStruct.Pull = GPIO_PULLUP;           //设置上拉
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;//引脚的输出速度为120MHz
    GPIO_InitStruct.Alternate = GPIO_AF0_RTC_50Hz; //将引脚复用为RTC_OUT2
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

		hrtc->Init.OutPutRemap = RTC_OUTPUT_REMAP_POS1; //RTC_OUT1输出不使能,RTC_OUT2输出使能;
	}
	if(OutputSource == RTC_OUTPUT_DISABLE) hrtc->Init.OutPut = RTC_OUTPUT_DISABLE;    //“RTC报警器A”和“RTC报警器B”均不输出
	else if(OutputSource == RTC_OUTPUT_ALARMA) hrtc->Init.OutPut = RTC_OUTPUT_ALARMA; //RTC报警器A输出使能
	else if(OutputSource == RTC_OUTPUT_ALARMB) hrtc->Init.OutPut = RTC_OUTPUT_ALARMB;//RTC报警器B输出使能
}

//函数功能:查询RTC报警
void Read_RTC_Alarm(void)
{
  uint32_t tmp = READ_REG(RTC->MISR);//Get interrupt status

//  delay_ms(50);
	//RTC_OUT1输出电平时间和ALRAF的保持时间有关
	//RTC_OUT1输出电平时间和ALRBF的保持时间有关
  if ((tmp & RTC_MISR_ALRAMF) != 0U)//RTC ALARM A报警
  {//当选择“RTC_ALARM_A”时,时间与RTC_ALRMAR相同时报警
//		delay_ms(10);//RTC_OUT1输出电平时间和ALRAF的保持时间有关,所以这里要添加延时10ms
    WRITE_REG(RTC->SCR, RTC_SCR_CALRAF);
		//RTC_SCR寄存器bit0(CALRAF),写入1表示清除“RTC状态寄存器RTC_SR”中的ALRAF位,即“Alarm A报警标志位”
		//Clear the AlarmA interrupt pending bit
		LED1_Toggle();
  }

  if ((tmp & RTC_MISR_ALRBMF) != 0U)//RTC ALARM A报警
  {
		//当选择“RTC_ALARM_B”时,时间与RTC_ALRMBR相同时报警
//		delay_ms(10);//RTC_OUT1输出电平时间和ALRBF的保持时间有关,所以这里要添加延时10ms
    WRITE_REG(RTC->SCR, RTC_SCR_CALRBF);
		LED2_Toggle();
  }

//	__HAL_RTC_ALARM_EXTI_CLEAR_IT();
  delay_ms(500);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2129669.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【API Testing and Development with Postman 2nd_001】关于本书

译者按 今天又淘到一本介绍 Postman 的宝藏级小册子&#xff0c;非常适合想进一步了解 API 接口测试的朋友们。本书最大的特点就是手把手教学。想当年第 1 版问世时&#xff0c;初出茅庐的我随便拣了书中一两招&#xff0c;就能轻松搞定工作中五花八门的 API 疑难杂症。只是当时…

监听键盘事件

问题&#xff1a;点击输入框弹出键盘遮挡文字 需求&#xff1a;点击输入框键盘弹起&#xff0c;点击别处键盘回收&#xff0c;输入框回到原来状态&#xff0c; 解决办法&#xff1a; 1.采用占位的思想&#xff08;隐藏&#xff09;&#xff0c;文本框控制采用焦点控制&#…

多态的概念

多态 所谓的多态其实就是多种形态&#xff0c;它又被分为编译时多态(静态多态) 和 运行时多态(动态多态)。 静态的多态其实就是之前的模版和函数重载&#xff0c;今天我们主要讲动态的多态。所谓的动态多态其实就是相同的函数&#xff0c;完成不同的功能。 这就实现了明明都是…

C#搭建WebApi服务

1&#xff0c;OWIN的介绍 OWIN 的全称是 "Open Web Interface for .NET"&#xff0c; OWIN 在 .NET Web 服务器和 .NET Web 应用之间定义了一套标准的接口&#xff0c; 其目的是为了实现服务器与应用之间的解耦&#xff0c;使得便携式 .NET Web 应用以及跨平台的愿望…

MongoDB事务机制

事务机制 1.事务概念 在对数据的操作的过程中&#xff0c;涉及到一连串的操作&#xff0c;这些操作如果失败&#xff0c;会导致我们的数据部分变化了&#xff0c;部分没变化。这个过程就好比如你去吃早餐&#xff0c;你点完餐了&#xff0c;并且吃完早餐了&#xff0c;没付钱你…

ES6标准---【五】【看这一篇就够了!!!】

目录 ES6以往文章 箭头函数的基本用法 箭头函数的用处 简化回调函数 rest参数与箭头函数结合 箭头函数使用注意点 this指向的问题 其它不存在的变量 不能使用call()、apply()、bind()方法改变this的指向 箭头函数不适用场合 定义对象时&#xff0c;对象方法内部包含…

信创环境下源代码防泄露解决方案

在当今数字化时代&#xff0c;信息安全已成为企业生存与发展的基石&#xff0c;尤其是在信息技术应用创新&#xff08;信创&#xff09;环境下&#xff0c;数据保护更是被提升至前所未有的高度。SDC沙盒防泄露系统以其独特的技术架构和卓越的安全性能&#xff0c;在信创环境中构…

ES6标准---【六】【学习ES6标准看这一篇就够了!!!】

目录 以往ES6文章 前言 对象属性的简洁表示法 一个实际例子 简介写法在打印对象时也很有用 注意 对象属性名表达式 用表达式做属性名 用表达式定义方法名 注意 对象方法的name属性 对象属性的可枚举性和遍历 可枚举性 属性的遍历 属性比那里次序规则 super关键…

图片生成PPT!首推这款一站式AI制作PPT工具!

在当今快节奏的工作中&#xff0c;制作一份精美的PPT演示文稿往往是一项费时费力的工作&#xff0c;特别是当我们需要将大量的图片转化为PPT时&#xff0c;传统的方法显得尤为繁琐。幸运的是&#xff0c;随着AI人工智能技术的飞速发展&#xff0c;一种更便捷地将图片转为ppt的解…

计算机毕业设计 《计算机基础》网上考试系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…

Java之线程篇三

​​​​​​​ 目录 线程状态 观察线程的所有状态 线程状态及其描述 线程状态转换 代码示例1 代码示例2 线程安全 概念 线程不安全的代码示例 线程不安全的原因 线程安全的代码示例-加锁 synchronized关键字 synchronized的特性 小结 形成死锁的四个必要条件 …

Java设计模式之命令模式介绍和案例示范

一、命令模式简介 命令模式&#xff08;Command Pattern&#xff09;是一种行为型设计模式&#xff0c;它将请求封装为一个对象&#xff0c;从而使你可以用不同的请求对客户端进行参数化、对请求排队或记录日志&#xff0c;以及支持可撤销的操作。命令模式的核心思想是将发出请…

kvm 虚拟机命令行虚拟机操作、制作快照和恢复快照以及工作常用总结

文章目录 kvm 虚拟机命令行虚拟机操作、制作快照和恢复快照一、kvm 虚拟机命令行虚拟机操作(创建和删除)查看虚拟机virt-install创建一个虚拟机关闭虚拟机重启虚拟机销毁虚拟机 二、kvm 制作快照和恢复快照**创建快照**工作常见问题创建快照报错&#xff1a;&#xff1a;intern…

超详细、史上最全pytorch安装教程

一、anaconda安装 1.下载 Index of /anaconda/archive/ | 清华大学开源软件镜像站 | Tsinghua Open Source Mirrorhttps://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/ 这里划到最下面选择5.3.1最新版&#xff1a; 2.下载完成后安装 点击next 点击 I agree 选择All Us…

ignav的INS的状态更新

ignav的代码 static void updstat(const insopt_t *opt,insstate_t *ins,const double dt,const double *x0,const double *P0,double *phi,double *P,double *x,double *Q) {opt->exprn?getprn(ins,opt,dt,Q): getQ(opt,dt,Q); // //phi 状态转移矩阵 &#xff0c;离散化…

算法学习攻略总结 : 入门至进阶,通关之路指南

❃博主首页 &#xff1a; <码到三十五> ☠博主专栏 &#xff1a; <mysql高手> <elasticsearch高手> <源码解读> <java核心> <面试攻关> ♝博主的话 &#xff1a; <搬的每块砖&#xff0c;皆为峰峦之基&#xff1b;公众号搜索(码到…

CircleProgressView 鸿蒙ArkTS自定义View实现圆形进度条

上篇的截图中除了一个上下的箭头&#xff0c;还有一个圆形进度条&#xff0c;今天我们来讲讲这个如何进行实现 我们看这个图形的构造&#xff0c;其实很简单&#xff1a;一个圆形图形&#xff0c;以及一个文本来显示进度 所以我们用一个层叠布局 绘制一个带颜色的圆形&#xff…

『功能项目』播放动画时禁止点击移动【40】

我们打开上一篇39GameObject对象池 - 第三职业的项目&#xff0c; 本章要做的事情是在第三职业播放续航攻击动画时禁止点击时触发的移动函数&#xff0c;换句话说是在播放攻击动画时禁止移动 修改脚本&#xff1a;PlayerRayClickNavigation.cs 运行项目 - 播放第三职业续航技能…

2-92 基于matlab的KPCA的TE过程的故障监测

基于matlab的KPCA的TE过程的故障监测&#xff0c;利用核主元分析法(KPCA)来进行故障检测的思想,将输入空间中复杂的非线性问题转化为特征空间中的线性问题&#xff0c;计算步骤&#xff1a;&#xff08;1&#xff09; 选择监控变量&#xff0c;收集正常工况下的各变量的样本&am…

【警告 C6031:返回值被忽略:scanf】

警告 C6031 返回值被忽略: “scanf”。 错误 C4996 scanf: This function or variable may be unsafe. Consider using scanf_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details. #include <stdio.h> int max(int x, int y…