--WDOG
-介绍
WatchDog是为了能够防止程序跑飞而使用的一种硬件模块,如果你的程序没有跑飞,那么你的程序会定时的去喂看门狗;如果你的程序跑飞了,那么就不会再去喂狗了,如果超过了喂狗时间,那么狗就会自己生成一个信号来重新reset你的CPU让程序重新开始。这是一种在很重要的情况下防止系统跑飞的一种方式
-编程思路
1.设置复位信号产生后以冷启动方式复位
2.关闭看门狗控制器
3.设置看门狗定时器定时时间
4.使能看门狗
5.进行喂狗服务,重置看门狗定时器
6.不喂狗看门狗定时器超时,产生复位信号,复位开发板
--RTC
-介绍
实时时钟的缩写是RTC(Real_Time Clock).RTC是集成电路,通常称为时钟芯片
实时时钟芯片是日常生活中应用最广泛的消费类电子产品之一。它为人们提供精确的实际时间,或者为电子系统提供精确的时间基准,实时时钟芯片大多数采用精度较高的晶体振荡器作为时钟源。有些时钟芯片为了在主电源掉电时,还可以工作,需要外加电池供电。
为什么我们需要一个单独的RTC?
答:原因是CPU的定时器时钟功能只在通电时运行,断电时停止,当然,如果时钟不能连续跟踪时间,则必须手动设置时间,如今,通过接收标准电波(传输各国标准时间的电波)来自动调整时间手表越来越多,但它是一种不应该在室内携带的电子设备
RTC有一个与CPU单独分离的电源,如纽扣电池(备用电池),即使主机电源关闭,它也保持滴答作响随时可以实时显示时间。然后,当计算机再次打开时,计算机内置的定时器时钟从RTC读取当前时间,并在此基础上供电的同时,时间在其自身机制下显示
同时RTC单元外接32.768KHZ晶振,具有定时报警功能
-编程思路
1.设置寄存器访问不受限制
2.使能SNVS时钟
3.停止RTC计数器,等待RTC计数器停止成功
4.设置日期
5.开启RTC计数器,等待RTC计数器开启成功
6.每隔一秒读取RTC数据,然后输出
-代码实现
rtc_datetime.h
stdint.h( /usr/include )
#ifndef __DATETIME_HEAD_H__
#define __DATETIME_HEAD_H__
#include <stdint.h>
/*stdint.h头文件中定义了int16_t、uint32_t、int64_t等整型,在
需要确定大小的整型时可以使用它们代替short、unsigned long long
等*/
#define SECONDS_IN_A_DAY (86400U)
#define SECONDS_IN_A_HOUR (3600U)
#define SECONDS_IN_A_MINUTE (60U)
#define DAYS_IN_A_YEAR (365U)
#define YEAR_RANGE_START (1970U)
/*! @brief Structure is used to hold the date and time */
typedef struct rtc_datetime
{
uint_fast16_t year; /*!< Range from 1970.*/
uint_fast16_t month; /*!< Range from 1 to 12.*/
uint_fast16_t day; /*!< Range from 1 to 31
(depending on month).*/
uint_fast16_t hour; /*!< Range from 0 to 23.*/
uint_fast16_t minute; /*!< Range from 0 to 59.*/
uint_fast16_t second; /*!< Range from 0 to 59.*/
}rtc_datetime_t;
extern uint_fast32_t convert_datetime_to_seconds(const
rtc_datetime_t *datetime);
extern void convert_seconds_to_datetime(uint_fast32_t
seconds, rtc_datetime_t *datetime);
#endif
rtc_datetime.c
#include "rtc_datetime.h"
uint_fast32_t convert_datetime_to_seconds(const
rtc_datetime_t *datetime)
{
/* Number of days from begin of the non Leap-year*/
uint_fast16_t monthDays[] = {0U, 31U, 59U, 90U,
120U, 151U, 181U, 212U, 243U, 273U, 304U, 334U};
uint_fast32_t seconds;
/* Compute number of days from 1970 till given
year*/
seconds = (datetime->year - 1970U) * DAYS_IN_A_YEAR;
/* Add leap year days */
seconds += ((datetime->year / 4) - (1970U / 4));
/* Add number of days till given month*/
seconds += monthDays[datetime->month-1];
/* Add days in given month. We subtract the current
day as it is
* represented in the hours, minutes and seconds
field*/
seconds += (datetime->day - 1);
// 前面计算出共多少天
/* For leap year if month less than or equal to
Febraury, decrement day counter*/
if ((!(datetime->year & 3U)) && (datetime->month <=
2U))
{
seconds--;
}
seconds = (seconds * SECONDS_IN_A_DAY) + (datetime-
>hour * SECONDS_IN_A_HOUR) +
(datetime->minute *
SECONDS_IN_A_MINUTE) + datetime->second;
return seconds;
} v
oid convert_seconds_to_datetime(uint_fast32_t seconds,
rtc_datetime_t *datetime)
{
uint_fast32_t x;
uint_fast32_t secondsRemaining, days;
uint_fast16_t daysInYear;
/* Table of days in a month for a non leap year.
First entry in the table is not used,
* valid months start from 1
*/
uint_fast8_t daysPerMonth[] = {31U, 28U, 31U, 30U,
31U, 30U, 31U, 31U, 30U, 31U, 30U, 31U};
/* Start with the seconds value that is passed in to
be converted to
date time format*/
secondsRemaining = seconds;
/* Calcuate the number of days, we add 1 for the
current day which is represented in
the hours and seconds field
*/
days = secondsRemaining / SECONDS_IN_A_DAY + 1;
/* Update seconds left*/
secondsRemaining = secondsRemaining %
SECONDS_IN_A_DAY;
/* Calculate the datetime hour, minute and second
fields */
datetime->hour = secondsRemaining /
SECONDS_IN_A_HOUR;
secondsRemaining = secondsRemaining %
SECONDS_IN_A_HOUR;
datetime->minute = secondsRemaining /
SECONDS_IN_A_MINUTE;
datetime->second = secondsRemaining %
SECONDS_IN_A_MINUTE;
/* Calculate year */
daysInYear = DAYS_IN_A_YEAR;
datetime->year = YEAR_RANGE_START;// 默认从1970年开始
while (days > daysInYear)
{
/* Decrease day count by a year and increment
year by 1 */
days -= daysInYear;
datetime->year++;
/* Adjust the number of days for a leap year */
if (datetime->year & 3U)
{
daysInYear = DAYS_IN_A_YEAR;
}
else
{
daysInYear = DAYS_IN_A_YEAR + 1;
}
}
/* Adjust the days in February for a leap year */
if (!(datetime->year & 3U))
{
daysPerMonth[1] = 29U;
}
for (x = 1U; x <= 12U; x++)
{
if (days <= daysPerMonth[x-1])
{
datetime->month = x;
break;
}
else
{
days -= daysPerMonth[x-1];
}
}
datetime->day = days;
return;
rtc.c
#include "rtc.h"
// RTC_EN = 0
void disable_rtc_counter(){
SNVS->HPCR &=~(0x1 << 0);
while((SNVS->HPCR & 1));
} /
/ RTC_EN = 1
void enable_rtc_counter(){
SNVS->HPCR |=(0x1<<0);
while(!(SNVS->HPCR & 1));
} v
oid rtc_set_datetime(const rtc_datetime_t* p_curtime){
// 停止RTC计数器,等待RTC计数器停止成功
disable_rtc_counter();
uint_fast32_t seconds;
seconds = convert_datetime_to_seconds(p_curtime);
// [14:0]存放高15位
SNVS->HPRTCMR = seconds >> 17;
// [31:15]存放低17位
SNVS->HPRTCLR = seconds << 15;
// 开启RTC计数器,等待RTC计数器开启成功
enable_rtc_counter();
} /
/ 获取时间
void rtc_get_datetime(rtc_datetime_t* p_curtime){
uint_fast32_t seconds = 0;
uint_fast32_t compareVal = 0;
do{
compareVal = seconds;
seconds = (SNVS->HPRTCMR << 17) | (SNVS-
>HPRTCLR >> 15);
}while(compareVal!=seconds);
convert_seconds_to_datetime(seconds, p_curtime);
} v
oid rtc_init(){
/*
设置寄存器访问不受权限限制
any software can access the privileged registers.
*/
SNVS->HPCOMR |=(0x1 << 31);
/*
使能SNVS时钟
*/
CCM_CCGR5 |=(0x3 << 18);
}
void rtc_test(){
rtc_init();
rtc_datetime_t curtime;
curtime.year = 2024;
curtime.month = 9;
curtime.day = 25;
curtime.hour = 10;
curtime.minute = 35;
curtime.second = 40;
rtc_set_datetime(&curtime);
while(1){
rtc_get_datetime(&curtime);
uart_printf("%d-%d-%d
%d:%d:%d\r\n",curtime.year,curtime.month,curtime.day,curtim
e.hour,curtime.minute,curtime.second);
gpt_delay_seconds(1); // 延迟1秒
}
}
--Alarm中断
-编程思路
1.注册RTC中断
2.设置RTC alarm日期
1>Disable RTC alarm
2>设置日期
3>Enable RTC alarm
3.在中断处理函数判断是否时RTC alarm中断,如果时则输出信息提醒闹钟时间到达
4.在中断处理函数中清除RTC alarm中断标志,写1清0