Bootstrap

stm32独立看门狗和rtc闹钟

  • 独立看门狗

1、独立看门狗概述

      在由单片机构成的微型计算机系统中,由于单片机的工作常常会受到来自外界电磁场的干扰,造成程序的跑飞,而陷入死循环,程序的正常运行被打断,由单片机控制的系统无法继续工作,会造成整个系统的陷入停滞状态,发生不可预料的后果,所以出于对单片机运行状态进行实时监测的考虑,便产生了一种专门用于监测单片机程序运行状态的模块或者芯片,俗称“看门狗”(watchdog) 。

    看门狗( watchdog timer),是一个定时器(12位)电路, 一般有一个输入,叫喂狗(kicking the dog or service the dog),一个输出到MCU的RST端,MCU正常工作的时候,每隔一段时间输出一个信号到喂狗端,给WDT清零,如果超过规定的时间不喂狗,(一般在程序跑飞时,不在程序正常的状态),WDT 定时超过,就会给出一个复位信号到MCU,使MCU复位. 防止MCU死机. 看门狗的作用就是防止程序发生死循环,或者说程序跑飞。

2、STM32独立看门狗

独立看门狗(IWDG)由专用的低速时钟(LSI)驱动,即使主时钟发生故障它仍有效。

   独立看门狗适合应用于需要看门狗作为一个在主程序之外 能够完全独立工作,并且对时间精度要求低的场合。

STM32F4 的独立看门狗由内部专门的 32Khz 低速时钟 (LSI) 驱动,即使主时钟发生故障,它也仍然有效。这里需要注意独立看门狗的时钟是一个内部RC时钟,所以并不是准确的32Khz,而是在15~47Khz 之间的一个可变化的时钟,只是我们在估算的时候,以 32Khz 的频率来计算,独立看门狗对时间的要求不是很精确,所以,时钟有些偏差都是接受的范围。

 

3、独立看门狗操作步骤

独立看门狗操作步骤需要添加的库函数文件:stm32f4xx_iwdg.c

1、 取消寄存器写保护:

      IWDG_WriteAccessCmd();

2、设置独立看门狗的预分频系数,确定时钟:

     IWDG_SetPrescaler();

3、设置看门狗重装载值,确定溢出时间:

    IWDG_SetReload();

4、使能看门狗

    IWDG_Enable();

5、应用程序喂狗:

   IWDG_ReloadCounter();

  • RTC

1、RTC时间

RTC (Real Time Clock):实时时钟

    STM32 的 RTC 外设,实质是一个掉电后还继续运行的定时器。RTC是个独立的BCD定时器/计数器。提供一个日历时钟,两个可编程闹钟中断,以及一个具有中断功能的周期性可编程唤醒标志。RTC还包含用于管理低功耗模式的自动唤醒单元。

两个32位寄存器包含二进码十进制格式(BCD)的秒,分钟,小时(12或24小时制),星期几,日期,月份和年份。此外,还可以提供二进制的亚秒值。系统可以自动将月份的天数补偿为28,29(闰年),30,31天。并且还可以进行夏令时补偿。

选择外部时钟源,当主时钟发生故障时,RTC还能正常运行;且当主电源发生故障,RTC由钮扣电池进行独立供电

RTC时间与日期配置流程:

RTC时间与日期配置流程所需要的库函数文件:stm32f4xx_rtc.c与stm32f4xx_pwr.c

1、使能PWR时钟:RCC_APB1PeriphClockCmd();

2、使能后备寄存器访问:   PWR_BackupAccessCmd();

3、配置RTC时钟源,使能RTC时钟:

      RCC_RTCCLKConfig();

      RCC_RTCCLKCmd();

      如果使用LSE,要打开LSE:RCC_LSEConfig(RCC_LSE_ON);

4、 初始化RTC(同步/异步分频系数和时钟格式):RTC_Init ();

5、 设置时间:RTC_SetTime ();

6、设置日期:RTC_SetDate();

2、RTC闹钟

RTC 中断
所有 RTC 中断均与 EXTI(外部中断控制) 控制器相连。
要使能 RTC 闹钟中断,需按照以下顺序操作:
1. 将 EXTI 线 17 配置为中断模式并将其使能,然后选择上升沿有效。
2. 配置 NVIC 中的 RTC_Alarm IRQ 通道并将其使能。
3. 配置 RTC 以生成 RTC 闹钟(闹钟 A 或闹钟 B)。 

闹钟A配置流程

1、RTC已经初始化好相关参数。

2、关闭闹钟:RTC_AlarmCmd(RTC_Alarm_A,DISABLE);

3、配置闹钟参数:RTC_SetAlarm();

4、开启闹钟:RTC_AlarmCmd(RTC_Alarm_A,ENABLE);

5、开启配置闹钟中断:

     RTC_ITConfig();

     EXTI_Init();

     NVIC_Init();

6、编写中断服务函数:RTC_Alarm_IRQHandler();

三、函数说明

void IWDG_WriteAccessCmd(uint16_t IWDG_WriteAccess);

函数功能:是否使能 IWDG_PR and IWDG_RLR寄存器

返回值:无

uint16_t IWDG_WriteAccess:是否使能

IWDG_WriteAccess_Enable

IWDG_WriteAccess_Disable

void IWDG_SetPrescaler(uint8_t IWDG_Prescaler)

函数功能:设置看门预分频器

返回值:无

uint8_t IWDG_Prescaler:分频系数

IWDG_Prescaler_4   

IWDG_Prescaler_8   

IWDG_Prescaler_16  

IWDG_Prescaler_32  

IWDG_Prescaler_64  

IWDG_Prescaler_128

IWDG_Prescaler_256

void RCC_RTCCLKConfig(uint32_t RCC_RTCCLKSource)

void IWDG_SetReload(uint16_t Reload)

函数功能:设置重载值

返回值:无

uint16_t Reload:重载值寄存器的值,范围:0~0xFFF

void RCC_RTCCLKConfig(uint32_t RCC_RTCCLKSource)

函数功能:RTC时钟源配置

返回值:无

uint32_t RCC_RTCCLKSource:时钟源选择

RCC_RTCCLKSource_LSE      

RCC_RTCCLKSource_LSI      

RCC_RTCCLKSource_HSE_Div2

RCC_RTCCLKSource_HSE_Div3

RCC_RTCCLKSource_HSE_Div4

RCC_RTCCLKSource_HSE_Div5

RCC_RTCCLKSource_HSE_Div6

RCC_RTCCLKSource_HSE_Div7

RCC_RTCCLKSource_HSE_Div8

RCC_RTCCLKSource_HSE_Div9

RCC_RTCCLKSource_HSE_Div10

RCC_RTCCLKSource_HSE_Div11

RCC_RTCCLKSource_HSE_Div12

RCC_RTCCLKSource_HSE_Div13

RCC_RTCCLKSource_HSE_Div14

RCC_RTCCLKSource_HSE_Div15

RCC_RTCCLKSource_HSE_Div16

RCC_RTCCLKSource_HSE_Div17

RCC_RTCCLKSource_HSE_Div18

RCC_RTCCLKSource_HSE_Div19

RCC_RTCCLKSource_HSE_Div20

RCC_RTCCLKSource_HSE_Div21

RCC_RTCCLKSource_HSE_Div22

RCC_RTCCLKSource_HSE_Div23

RCC_RTCCLKSource_HSE_Div24

RCC_RTCCLKSource_HSE_Div25

RCC_RTCCLKSource_HSE_Div26

RCC_RTCCLKSource_HSE_Div27

RCC_RTCCLKSource_HSE_Div28

RCC_RTCCLKSource_HSE_Div29

RCC_RTCCLKSource_HSE_Div30

RCC_RTCCLKSource_HSE_Div31

ErrorStatus RTC_Init(RTC_InitTypeDef* RTC_InitStruct);

函数功能:RTC设置

返回值

成功:SUCCESS

失败:ERROR

RTC_InitTypeDef* RTC_InitStruct:RTC结构体

typedef struct

{

  uint32_t RTC_HourFormat;   //小时制选择

  

  uint32_t RTC_AsynchPrediv; //异步通道分频器

  

  uint32_t RTC_SynchPrediv;  //同步通道分频器

}RTC_InitTypeDef;

ErrorStatus RTC_SetTime(uint32_t RTC_Format, RTC_TimeTypeDef* RTC_TimeStruct);

函数功能:RTC时间设置

返回值

成功:SUCCESS

失败:ERROR

uint32_t RTC_Format:存储格式

RTC_Format_BIN:二进制存储

RTC_Format_BCD:BCD编码存储

RTC_TimeTypeDef* RTC_TimeStruct:时间结构体

typedef struct

{

  uint8_t RTC_Hours;    //时

  uint8_t RTC_Minutes;  //分

  

  uint8_t RTC_Seconds;  //秒

  uint8_t RTC_H12;      //上/下午

}RTC_TimeTypeDef;

ErrorStatus RTC_SetDate(uint32_t RTC_Format, RTC_DateTypeDef* RTC_DateStruct);

函数功能:RTC日期设置

返回值

成功:SUCCESS

失败:ERROR

uint32_t RTC_Format:存储格式

RTC_Format_BIN:二进制存储

RTC_Format_BCD:BCD编码存储

RTC_DateTypeDef* RTC_DateStruct:日期结构体

typedef struct

{

  uint8_t RTC_WeekDay; //星期

  

  uint8_t RTC_Month;   //月

  uint8_t RTC_Date;     //日

  

  uint8_t RTC_Year;     //年

}RTC_DateTypeDef;

/**

  * @brief  Set the specified RTC Alarm.

  * @note   The Alarm register can only be written when the corresponding Alarm

  *         is disabled (Use the RTC_AlarmCmd(DISABLE)).    

  * @param  RTC_Format: specifies the format of the returned parameters.

  *          This parameter can be one of the following values:

  *            @arg RTC_Format_BIN: Binary data format

  *            @arg RTC_Format_BCD: BCD data format

  * @param  RTC_Alarm: specifies the alarm to be configured.

  *          This parameter can be one of the following values:

  *            @arg RTC_Alarm_A: to select Alarm A

  *            @arg RTC_Alarm_B: to select Alarm B  

  * @param  RTC_AlarmStruct: pointer to a RTC_AlarmTypeDef structure that

  *                          contains the alarm configuration parameters.     

  * @retval None

  */

void RTC_SetAlarm(uint32_t RTC_Format, uint32_t RTC_Alarm, RTC_AlarmTypeDef* RTC_AlarmStruct)

函数说明:闹钟设置

返回值:无

uint32_t RTC_Format:存储格式

RTC_Format_BIN:二进制存储

RTC_Format_BCD:BCD编码存储

uint32_t RTC_Alarm:选择闹钟

RTC_Alarm_A:闹钟A

RTC_Alarm_B:闹钟B

RTC_AlarmTypeDef* RTC_AlarmStruct:闹钟结构体

typedef struct

{

  RTC_TimeTypeDef RTC_AlarmTime;     //时间设置

  uint32_t RTC_AlarmMask;            //掩码位

  uint32_t RTC_AlarmDateWeekDaySel;  //选择日期还是星期设置闹钟

  

  uint8_t RTC_AlarmDateWeekDay;      //日期还是星期

}RTC_AlarmTypeDef;

typedef struct

{

  uint8_t RTC_Hours;    //时

  uint8_t RTC_Minutes;  //分

  

  uint8_t RTC_Seconds;  //秒

  uint8_t RTC_H12;      //上/下午

}RTC_TimeTypeDef;

四、技术应用

  1. 看门狗

  1. RTC

小天才手表

公交刷卡机

 看门狗

#include "iwdg.h"

void Iwdg_Init(void)
{
	//1、 取消寄存器写保护:
	IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
	//2、设置独立看门狗的预分频系数,确定时钟; 在32KHZ,分频128,得频率:250HZ
	IWDG_SetPrescaler(IWDG_Prescaler_128);
	//3、设置看门狗重装载值,确定溢出时间:2S
	IWDG_SetReload(500);
	//4、使能看门狗
	IWDG_Enable();

	//应用程序喂狗:
    IWDG_ReloadCounter();
}
#ifndef __IWDG_H
#define __IWDG_H

#include "stm32f4xx.h"


void Iwdg_Init(void);

#endif

#include "stm32f4xx.h"
#include "led.h"
#include "key.h"
#include "exti.h"
#include "delay.h"
#include "tim.h"
#include "pwm.h"
#include "usart.h"
#include "sys.h"
#include "dht11.h"
#include "infrared.h"
#include "iwdg.h"


u8  buffer[64] = {0};
u8  rx_buffer[64] = {0};
u8  count = 0, rx_i = 0;
u8  rx_flag = 0; //接受标志位,rx_flag = 表示数据帧完毕


void USART1_IRQHandler(void)
{
	


	//判断接收标志位是否为1
	if(USART_GetITStatus(USART1, USART_IT_RXNE) == SET)
	{
		//清空接受标志位
		USART_ClearITPendingBit(USART1, USART_IT_RXNE);	
		//接受数据 
		buffer[count++] = USART_ReceiveData(USART1);
		//判断数据是否为':',如果是':'数据帧结束
		if(buffer[count-1] == ':')
		{
			//数据赋值到rx_buffer,并过滤帧尾
			for(rx_i=0; rx_i<(count-1); rx_i++)
			{
				rx_buffer[rx_i] = buffer[rx_i];
			}
		
			//清空数组
			memset(buffer, 0, sizeof(buffer));
			
			//标志位置1
			rx_flag = 1;
			//下一帧数据从buffer[0]开始接受
			count = 0; 
					
		
		}
		
	}
}




void USART2_IRQHandler(void)
{
	
	u8 data;

	//判断接收标志位是否为1
	if(USART_GetITStatus(USART2, USART_IT_RXNE) == SET)
	{
		//清空接受标志位
		USART_ClearITPendingBit(USART2, USART_IT_RXNE);	
		//接受数据 
		buffer[count++] = USART_ReceiveData(USART2);
		//判断数据是否为':',如果是':'数据帧结束
		if(buffer[count-1] == ':')
		{
			//数据赋值到rx_buffer,并过滤帧尾
			for(rx_i=0; rx_i<(count-1); rx_i++)
			{
				rx_buffer[rx_i] = buffer[rx_i];
			}
		
			//清空数组
			memset(buffer, 0, sizeof(buffer));
			
			//标志位置1
			rx_flag = 1;
			//下一帧数据从buffer[0]开始接受
			count = 0; 
					
		}
		
	}


}


void USART3_IRQHandler(void)
{
	
	u8 data;

	//判断接收标志位是否为1
	if(USART_GetITStatus(USART3, USART_IT_RXNE) == SET)
	{
		//清空接受标志位
		USART_ClearITPendingBit(USART3, USART_IT_RXNE);	
		//接受数据 
		buffer[count++] = USART_ReceiveData(USART3);
		//判断数据是否为':',如果是':'数据帧结束
		if(buffer[count-1] == ':')
		{
			//数据赋值到rx_buffer,并过滤帧尾
			for(rx_i=0; rx_i<(count-1); rx_i++)
			{
				rx_buffer[rx_i] = buffer[rx_i];
			}
		
			//清空数组
			memset(buffer, 0, sizeof(buffer));
			
			//标志位置1
			rx_flag = 1;
			//下一帧数据从buffer[0]开始接受
			count = 0; 
					
		}
		
	}


}




int main(void)
{
	int ret;
	u8 data[5] = {0};
	//设置NVIC分组(一个工程只能设置一个分组) 
	//第二分组;抢占优先组取值范围:0~3 响应先组取值范围:0~3
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	Led_Init();
	Delay_Init();
	Tim7_Init();	//初始化定时器7
	Usart1_Init(115200);
	Iwdg_Init();
	printf("iwdg test\r\n");
	
	while(1)
	{
		
		
		if(GPIO_ReadInputDataBit(GPIOA,  GPIO_Pin_0) == Bit_RESET)
		{
			//延时消抖 20ms
			delay_ms(20); 
			//判断按键是否按下
			if(GPIO_ReadInputDataBit(GPIOA,  GPIO_Pin_0) == Bit_RESET)
			{
				printf("key up\r\n");
				
				//往一个非法地址写入一个值,模拟程序跑飞
				*((unsigned int *)0xC0000000) = 0x666;
			}

		}		
		
		//这里的循环相当应用程序的时间
		delay_s(4);


	}
}

RTC_TIM

#include "rtc.h"

#define  BKP_DR  0x2162


void Rtc_Tim_Init(void)
{

	RTC_InitTypeDef  RTC_InitStruct;
	RTC_TimeTypeDef  RTC_TimeStruct;
	RTC_DateTypeDef  RTC_DateStruct;
	
	//1、使能PWR时钟,与电源寄存器有关
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
	//2、使能后备寄存器访问,是一种掉电保存数据的寄存器  
	PWR_BackupAccessCmd(ENABLE);
	
	//判断后备寄存器的值
	if(RTC_ReadBackupRegister(RTC_BKP_DR0) != BKP_DR)
	{
		//3、配置RTC时钟源,使能RTC时钟:
		RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
		RCC_RTCCLKCmd(ENABLE);
		//如果使用LSE,要打开LSE:
		RCC_LSEConfig(RCC_LSE_ON);
		//延时一段时间,等待时钟源稳定
		delay_ms(50);
		
		RTC_InitStruct.RTC_HourFormat	= RTC_HourFormat_24;	//24小时制
		RTC_InitStruct.RTC_AsynchPrediv	= 0x7F;					//异步分频 128分频
		RTC_InitStruct.RTC_SynchPrediv	= 0xFF;					//同频分频 255分频
		//4、初始化RTC(同步/异步分频系数和时钟格式):
		RTC_Init(&RTC_InitStruct);


		RTC_TimeStruct.RTC_H12		= RTC_H12_PM;		//下午 24小时制,可写可不写
		RTC_TimeStruct.RTC_Hours	= 15;				//小时
		RTC_TimeStruct.RTC_Minutes	= 30;				//分
		RTC_TimeStruct.RTC_Seconds	= 10;				//ADC+
		RTC_SetTime(RTC_Format_BIN, &RTC_TimeStruct);	
		
		RTC_DateStruct.RTC_Year	   	= 21;					//年份
		RTC_DateStruct.RTC_Month	= 11;					//月份
		RTC_DateStruct.RTC_Date		= 16;					//日
		RTC_DateStruct.RTC_WeekDay  = RTC_Weekday_Tuesday;	//星期二
		RTC_SetDate(RTC_Format_BIN, &RTC_DateStruct);
	
		//将值写入后备寄存器
		RTC_WriteBackupRegister(RTC_BKP_DR0, BKP_DR);
	
	}
}
#ifndef __RTC_H
#define __RTC_H

#include "stm32f4xx.h"
#include "delay.h"

void Rtc_Tim_Init(void);

#endif
#include "stm32f4xx.h"
#include "led.h"
#include "key.h"
#include "exti.h"
#include "delay.h"
#include "tim.h"
#include "pwm.h"
#include "usart.h"
#include "sys.h"
#include "dht11.h"
#include "infrared.h"
#include "iwdg.h"
#include "rtc.h"


u8  buffer[64] = {0};
u8  rx_buffer[64] = {0};
u8  count = 0, rx_i = 0;
u8  rx_flag = 0; //接受标志位,rx_flag = 表示数据帧完毕


void USART1_IRQHandler(void)
{
	


	//判断接收标志位是否为1
	if(USART_GetITStatus(USART1, USART_IT_RXNE) == SET)
	{
		//清空接受标志位
		USART_ClearITPendingBit(USART1, USART_IT_RXNE);	
		//接受数据 
		buffer[count++] = USART_ReceiveData(USART1);
		//判断数据是否为':',如果是':'数据帧结束
		if(buffer[count-1] == ':')
		{
			//数据赋值到rx_buffer,并过滤帧尾
			for(rx_i=0; rx_i<(count-1); rx_i++)
			{
				rx_buffer[rx_i] = buffer[rx_i];
			}
		
			//清空数组
			memset(buffer, 0, sizeof(buffer));
			
			//标志位置1
			rx_flag = 1;
			//下一帧数据从buffer[0]开始接受
			count = 0; 
					
		
		}
		
	}
}




void USART2_IRQHandler(void)
{
	
	u8 data;

	//判断接收标志位是否为1
	if(USART_GetITStatus(USART2, USART_IT_RXNE) == SET)
	{
		//清空接受标志位
		USART_ClearITPendingBit(USART2, USART_IT_RXNE);	
		//接受数据 
		buffer[count++] = USART_ReceiveData(USART2);
		//判断数据是否为':',如果是':'数据帧结束
		if(buffer[count-1] == ':')
		{
			//数据赋值到rx_buffer,并过滤帧尾
			for(rx_i=0; rx_i<(count-1); rx_i++)
			{
				rx_buffer[rx_i] = buffer[rx_i];
			}
		
			//清空数组
			memset(buffer, 0, sizeof(buffer));
			
			//标志位置1
			rx_flag = 1;
			//下一帧数据从buffer[0]开始接受
			count = 0; 
					
		}
		
	}


}


void USART3_IRQHandler(void)
{
	
	u8 data;

	//判断接收标志位是否为1
	if(USART_GetITStatus(USART3, USART_IT_RXNE) == SET)
	{
		//清空接受标志位
		USART_ClearITPendingBit(USART3, USART_IT_RXNE);	
		//接受数据 
		buffer[count++] = USART_ReceiveData(USART3);
		//判断数据是否为':',如果是':'数据帧结束
		if(buffer[count-1] == ':')
		{
			//数据赋值到rx_buffer,并过滤帧尾
			for(rx_i=0; rx_i<(count-1); rx_i++)
			{
				rx_buffer[rx_i] = buffer[rx_i];
			}
		
			//清空数组
			memset(buffer, 0, sizeof(buffer));
			
			//标志位置1
			rx_flag = 1;
			//下一帧数据从buffer[0]开始接受
			count = 0; 
					
		}
		
	}


}





int main(void)
{
	RTC_TimeTypeDef  RTC_TimeStruct;
	RTC_DateTypeDef  RTC_DateStruct;	
	
	
	//设置NVIC分组(一个工程只能设置一个分组) 
	//第二分组;抢占优先组取值范围:0~3 响应先组取值范围:0~3
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
//	Led_Init();
	Delay_Init();

	Usart1_Init(115200);

	Rtc_Tim_Init();
	

	
	while(1)
	{
		//获取日期
		RTC_GetDate(RTC_Format_BIN, &RTC_DateStruct);
		printf("日期:%d-%d-%d 星期:%d\r\n",RTC_DateStruct.RTC_Year,
		RTC_DateStruct.RTC_Month,RTC_DateStruct.RTC_Date,RTC_DateStruct.RTC_WeekDay);
		//获取时间
		RTC_GetTime(RTC_Format_BIN,&RTC_TimeStruct);
		printf("时间:%d:%d:%d\r\n",RTC_TimeStruct.RTC_Hours,
		RTC_TimeStruct.RTC_Minutes,RTC_TimeStruct.RTC_Seconds);
		delay_s(1);
	}
}

RTC_ALARM

#include "rtc.h"

#define  BKP_DR  0x2162


void Rtc_Tim_Init(void)
{

	RTC_InitTypeDef  RTC_InitStruct;
	RTC_TimeTypeDef  RTC_TimeStruct;
	RTC_DateTypeDef  RTC_DateStruct;
	
	//1、使能PWR时钟,与电源寄存器有关
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
	//2、使能后备寄存器访问,是一种掉电保存数据的寄存器  
	PWR_BackupAccessCmd(ENABLE);
	
	//判断后备寄存器的值
	if(RTC_ReadBackupRegister(RTC_BKP_DR0) != BKP_DR)
	{
		//3、配置RTC时钟源,使能RTC时钟:
		RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
		RCC_RTCCLKCmd(ENABLE);
		//如果使用LSE,要打开LSE:
		RCC_LSEConfig(RCC_LSE_ON);
		//延时一段时间,等待时钟源稳定
		delay_ms(50);
		
		RTC_InitStruct.RTC_HourFormat	= RTC_HourFormat_24;	//24小时制
		RTC_InitStruct.RTC_AsynchPrediv	= 0x7F;					//异步分频 128分频
		RTC_InitStruct.RTC_SynchPrediv	= 0xFF;					//同频分频 255分频
		//4、初始化RTC(同步/异步分频系数和时钟格式):
		RTC_Init(&RTC_InitStruct);


		RTC_TimeStruct.RTC_H12		= RTC_H12_PM;		//下午 24小时制,可写可不写
		RTC_TimeStruct.RTC_Hours	= 15;				//小时
		RTC_TimeStruct.RTC_Minutes	= 30;				//分
		RTC_TimeStruct.RTC_Seconds	= 10;				//ADC+
		RTC_SetTime(RTC_Format_BIN, &RTC_TimeStruct);	
		
		RTC_DateStruct.RTC_Year	   	= 21;					//年份
		RTC_DateStruct.RTC_Month	= 11;					//月份
		RTC_DateStruct.RTC_Date		= 16;					//日
		RTC_DateStruct.RTC_WeekDay  = RTC_Weekday_Tuesday;	//星期二
		RTC_SetDate(RTC_Format_BIN, &RTC_DateStruct);
	
		//将值写入后备寄存器
		RTC_WriteBackupRegister(RTC_BKP_DR0, BKP_DR);
	
	}
}

//闹钟A初始化
void RTC_Alarm_AInit(void)
{
	RTC_AlarmTypeDef  RTC_AlarmStruct;
	RTC_TimeTypeDef   RTC_AlarmTime;
	EXTI_InitTypeDef  EXTI_InitStruct;
	NVIC_InitTypeDef  NVIC_InitStruct;
	
	
	//关闭闹钟:
	RTC_AlarmCmd(RTC_Alarm_A,DISABLE); 
	
	RTC_AlarmTime.RTC_H12		= RTC_H12_PM;		//下午 24小时制,可写可不写
	RTC_AlarmTime.RTC_Hours		= 15;				//小时
	RTC_AlarmTime.RTC_Minutes	= 30;				//分
	RTC_AlarmTime.RTC_Seconds	= 30;				//ADC+
	
	
	RTC_AlarmStruct.RTC_AlarmTime			= RTC_AlarmTime;				//设置时间
	RTC_AlarmStruct.RTC_AlarmMask			= RTC_AlarmMask_None;			//无掩码,按实际设置的时间响应闹钟
	RTC_AlarmStruct.RTC_AlarmDateWeekDaySel	= RTC_AlarmDateWeekDaySel_Date; //按日期响应闹钟
	RTC_AlarmStruct.RTC_AlarmDateWeekDay	= 16;							//16号
	//配置闹钟参数:
	RTC_SetAlarm(RTC_Format_BIN, RTC_Alarm_A, &RTC_AlarmStruct);
	
	//开启闹钟:
	RTC_AlarmCmd(RTC_Alarm_A,ENABLE);
	//开启配置闹钟中断:
	RTC_ITConfig(RTC_IT_ALRA, ENABLE);
	
	EXTI_InitStruct.EXTI_Line	= EXTI_Line17;			//中断线17
	EXTI_InitStruct.EXTI_Mode	= EXTI_Mode_Interrupt; 	//中断模式
	EXTI_InitStruct.EXTI_Trigger= EXTI_Trigger_Rising;	//上升沿触发
	EXTI_InitStruct.EXTI_LineCmd= ENABLE;				//中断线使能
	//初始化线上中断,设置触发条件等。 
    EXTI_Init(&EXTI_InitStruct);
	
	NVIC_InitStruct.NVIC_IRQChannel						= RTC_Alarm_IRQn;//中断通道,中断通道在stm32f4xx.h文件当中查找
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority	= 2;		 //抢占优先级			
	NVIC_InitStruct.NVIC_IRQChannelSubPriority			= 2;		 //响应优先级
	NVIC_InitStruct.NVIC_IRQChannelCmd					= ENABLE;	 //使能通道
	//配置中断分组(NVIC),并使能中断。
    NVIC_Init(&NVIC_InitStruct);	

}
//闹钟B初始化
void RTC_Alarm_BInit(void)
{
	RTC_AlarmTypeDef  RTC_AlarmStruct;
	RTC_TimeTypeDef   RTC_AlarmTime;
	EXTI_InitTypeDef  EXTI_InitStruct;
	NVIC_InitTypeDef  NVIC_InitStruct;
	
	
	//关闭闹钟:
	RTC_AlarmCmd(RTC_Alarm_B,DISABLE); 
	
	RTC_AlarmTime.RTC_H12		= RTC_H12_PM;		//下午 24小时制,可写可不写
	RTC_AlarmTime.RTC_Hours		= 15;				//小时
	RTC_AlarmTime.RTC_Minutes	= 30;				//分
	RTC_AlarmTime.RTC_Seconds	= 40;				//ADC+
	
	
	RTC_AlarmStruct.RTC_AlarmTime			= RTC_AlarmTime;				//设置时间
	RTC_AlarmStruct.RTC_AlarmMask			= RTC_AlarmMask_None;			//无掩码,按实际设置的时间响应闹钟
	RTC_AlarmStruct.RTC_AlarmDateWeekDaySel	= RTC_AlarmDateWeekDaySel_Date; //按日期响应闹钟
	RTC_AlarmStruct.RTC_AlarmDateWeekDay	= 16;							//16号
	//配置闹钟参数:
	RTC_SetAlarm(RTC_Format_BIN, RTC_Alarm_B, &RTC_AlarmStruct);
	
	//开启闹钟:
	RTC_AlarmCmd(RTC_Alarm_B,ENABLE);
	//开启配置闹钟中断:
	RTC_ITConfig(RTC_IT_ALRB, ENABLE);
	
	EXTI_InitStruct.EXTI_Line	= EXTI_Line17;			//中断线17
	EXTI_InitStruct.EXTI_Mode	= EXTI_Mode_Interrupt; 	//中断模式
	EXTI_InitStruct.EXTI_Trigger= EXTI_Trigger_Rising;	//上升沿触发
	EXTI_InitStruct.EXTI_LineCmd= ENABLE;				//中断线使能
	//初始化线上中断,设置触发条件等。 
    EXTI_Init(&EXTI_InitStruct);
	
	NVIC_InitStruct.NVIC_IRQChannel						= RTC_Alarm_IRQn;//中断通道,中断通道在stm32f4xx.h文件当中查找
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority	= 2;		 //抢占优先级			
	NVIC_InitStruct.NVIC_IRQChannelSubPriority			= 2;		 //响应优先级
	NVIC_InitStruct.NVIC_IRQChannelCmd					= ENABLE;	 //使能通道
	//配置中断分组(NVIC),并使能中断。
    NVIC_Init(&NVIC_InitStruct);	

}
//闹钟中断服务函数
void RTC_Alarm_IRQHandler(void)
{
	if(EXTI_GetITStatus(EXTI_Line17) == SET)
	{
		
		//判断是否为闹钟A
		if(RTC_GetFlagStatus(RTC_FLAG_ALRAF) == SET)
		{
			LED0_ON;
		}
		//判断是否为闹钟B
		if(RTC_GetFlagStatus(RTC_FLAG_ALRBF) == SET)
		{
			LED0_OFF;
			LED1_ON;
		}
		
		RTC_ClearFlag(RTC_FLAG_ALRAF);
		RTC_ClearFlag(RTC_FLAG_ALRBF);
		
	}
	//清空标志位
	EXTI_ClearITPendingBit(EXTI_Line17);
}

#ifndef __RTC_H
#define __RTC_H

#include "stm32f4xx.h"
#include "delay.h"
#include "led.h"

void Rtc_Tim_Init(void);
void RTC_Alarm_AInit(void);
void RTC_Alarm_BInit(void);
#endif
#include "stm32f4xx.h"
#include "led.h"
#include "key.h"
#include "exti.h"
#include "delay.h"
#include "tim.h"
#include "pwm.h"
#include "usart.h"
#include "sys.h"
#include "dht11.h"
#include "infrared.h"
#include "iwdg.h"
#include "rtc.h"


u8  buffer[64] = {0};
u8  rx_buffer[64] = {0};
u8  count = 0, rx_i = 0;
u8  rx_flag = 0; //接受标志位,rx_flag = 表示数据帧完毕


void USART1_IRQHandler(void)
{
	


	//判断接收标志位是否为1
	if(USART_GetITStatus(USART1, USART_IT_RXNE) == SET)
	{
		//清空接受标志位
		USART_ClearITPendingBit(USART1, USART_IT_RXNE);	
		//接受数据 
		buffer[count++] = USART_ReceiveData(USART1);
		//判断数据是否为':',如果是':'数据帧结束
		if(buffer[count-1] == ':')
		{
			//数据赋值到rx_buffer,并过滤帧尾
			for(rx_i=0; rx_i<(count-1); rx_i++)
			{
				rx_buffer[rx_i] = buffer[rx_i];
			}
		
			//清空数组
			memset(buffer, 0, sizeof(buffer));
			
			//标志位置1
			rx_flag = 1;
			//下一帧数据从buffer[0]开始接受
			count = 0; 
					
		
		}
		
	}
}




void USART2_IRQHandler(void)
{
	
	u8 data;

	//判断接收标志位是否为1
	if(USART_GetITStatus(USART2, USART_IT_RXNE) == SET)
	{
		//清空接受标志位
		USART_ClearITPendingBit(USART2, USART_IT_RXNE);	
		//接受数据 
		buffer[count++] = USART_ReceiveData(USART2);
		//判断数据是否为':',如果是':'数据帧结束
		if(buffer[count-1] == ':')
		{
			//数据赋值到rx_buffer,并过滤帧尾
			for(rx_i=0; rx_i<(count-1); rx_i++)
			{
				rx_buffer[rx_i] = buffer[rx_i];
			}
		
			//清空数组
			memset(buffer, 0, sizeof(buffer));
			
			//标志位置1
			rx_flag = 1;
			//下一帧数据从buffer[0]开始接受
			count = 0; 
					
		}
		
	}


}


void USART3_IRQHandler(void)
{
	
	u8 data;

	//判断接收标志位是否为1
	if(USART_GetITStatus(USART3, USART_IT_RXNE) == SET)
	{
		//清空接受标志位
		USART_ClearITPendingBit(USART3, USART_IT_RXNE);	
		//接受数据 
		buffer[count++] = USART_ReceiveData(USART3);
		//判断数据是否为':',如果是':'数据帧结束
		if(buffer[count-1] == ':')
		{
			//数据赋值到rx_buffer,并过滤帧尾
			for(rx_i=0; rx_i<(count-1); rx_i++)
			{
				rx_buffer[rx_i] = buffer[rx_i];
			}
		
			//清空数组
			memset(buffer, 0, sizeof(buffer));
			
			//标志位置1
			rx_flag = 1;
			//下一帧数据从buffer[0]开始接受
			count = 0; 
					
		}
		
	}


}





int main(void)
{
	RTC_TimeTypeDef  RTC_TimeStruct;
	RTC_DateTypeDef  RTC_DateStruct;	
	
	
	//设置NVIC分组(一个工程只能设置一个分组) 
	//第二分组;抢占优先组取值范围:0~3 响应先组取值范围:0~3
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	Led_Init();
	Delay_Init();

	Usart1_Init(115200);

	Rtc_Tim_Init();
	RTC_Alarm_AInit();
	RTC_Alarm_BInit();
	
	while(1)
	{
		//获取日期
		RTC_GetDate(RTC_Format_BIN, &RTC_DateStruct);
		printf("日期:%d-%d-%d 星期:%d\r\n",RTC_DateStruct.RTC_Year,
		RTC_DateStruct.RTC_Month,RTC_DateStruct.RTC_Date,RTC_DateStruct.RTC_WeekDay);
		//获取时间
		RTC_GetTime(RTC_Format_BIN,&RTC_TimeStruct);
		printf("时间:%d:%d:%d\r\n",RTC_TimeStruct.RTC_Hours,
		RTC_TimeStruct.RTC_Minutes,RTC_TimeStruct.RTC_Seconds);
		delay_s(1);
	}
}

;