- 独立看门狗
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;
四、技术应用
- 看门狗
- 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);
}
}