GD32入门到实战24--RTC实时时钟
我们引用时间戳相关的库:
#include <time.h>
#include <stdint.h>
#include <stdio.h>
#include "led_drv.h"
#include "key_drv.h"
#include "systick.h"
#include "usart_drv.h"
#include "delay.h"
#include "usb2com_app.h"
#include "hmi_app.h"typedef struct
{uint8_t run; // 调度标志,1:调度,0:挂起uint16_t timCount; // 时间片计数值uint16_t timRload; // 时间片重载值void (*pTaskFuncCb)(void); // 函数指针变量,用来保存业务功能模块函数地址
} TaskComps_t;/*任务调度结构体*/static TaskComps_t g_taskComps[] = /*任务调度结构体数组,存放各个业务功能模块调度参数*/
{/*填入各个业务功能模块*/{0, 5, 5, HmiTask},{0, 200, 200, usartTask},/* 添加业务功能模块 */
};#define TASK_NUM_MAX (sizeof(g_taskComps) / sizeof(g_taskComps[0]))
/*用宏定义计算结构体数组的个数*///sizeof(g_taskComps):计算整个数组 g_taskComps 的大小(以字节为单位)。
//sizeof(g_taskComps[0]):计算数组中单个元素的大小(以字节为单位)。
//通过整个数组的大小除以单个元素的大小,得到数组中元素的数量/*
******************************************
* @brief 任务调度函数(判断所有业务模块的标志位)
* @param
* @return
********************************************
*/
static void TaskHandler(void)
{for (uint8_t i = 0; i < TASK_NUM_MAX; i++){if (g_taskComps[i].run) // 判断时间片标志{g_taskComps[i].run = 0; // 标志清零g_taskComps[i].pTaskFuncCb(); // 执行调度业务功能模块}}
}/*
******************************************
* @brief 时间片递减函数 1ms-1时间片
* @param
* @return
********************************************
*/
static void TaskScheduleCb(void)
{for (uint8_t i = 0; i < TASK_NUM_MAX; i++){if (g_taskComps[i].timCount){g_taskComps[i].timCount--;if (g_taskComps[i].timCount == 0){g_taskComps[i].run = 1;g_taskComps[i].timCount = g_taskComps[i].timRload;}}}
}static void DrvInit(void)
{SystickInit();LedDrvInit();KeyDrvInit();DelayInit();UsartDrv_Init();
}
static void AppInit(void)
{Usb2ComAppInit();TaskScheduleCbReg(TaskScheduleCb);
}#include <time.h>
int main(void)
{ DrvInit();AppInit();time_t timeStamp = 1000000000;struct tm *timeInfo = NULL;//struct tm 是C标准库中定义的一个结构体//struct tm *timeInfo:定义了一个指向 struct tm 的指针 timeInfotimeInfo = localtime(&timeStamp);//localtime()将time_t类型的时间转换为本地时间,并返回一个指向struct tm的指针printf("localtime, %d-%d-%d % d:%d:%d\n",timeInfo->tm_year + 1900, timeInfo->tm_mon+1,timeInfo->tm_mday, timeInfo->tm_hour, timeInfo->tm_min, timeInfo->tm_sec);printf("%s\n",asctime(timeInfo)); //asctime()将struct tm指针指向的timeStamp(时间)转换为字符串形式,并返回一个指向静态存储区的指针char timeArr[80];strftime(timeArr, 80,"%Y-%m-%d.%H:%M:%S",timeInfo);//strftime()用于将时间格式化为指定的字符串格式. 存储位置,最大长度,格式化字符串,指向struct tm的指针printf("%s\n",timeArr); while (1){TaskHandler();}
}
主电源掉电由纽扣电池给RTC和BKP(掉电易失)供电
我们添加这几个.c文件到gd32_hal
我们新建rtc_drv.c
#include <stdint.h>
#include <stdio.h>
#include "gd32f30x.h"
#include "rtc_drv.h"
#include <time.h>
#define MAGIC_CODE 0x5A5A //摩码用来判断是不是第一次初始化,防止重复参数导致时间有问题
/**
***********************************************************
* @brief RTC硬件初始化
* @param
* @return
***********************************************************
*/
void RtcDrvInit()
{if(bkp_read_data(BKP_DATA0) != MAGIC_CODE)//判断是不是第一次初始化{//第一次/*使能对RTC的访问,使能PMU和BKP时钟*/rcu_periph_clock_enable(RCU_PMU);rcu_periph_clock_enable(RCU_BKPI);/*使能对后备寄存器和RTC的写权限*/pmu_backup_write_enable();/*复位后备寄存器*/bkp_deinit();/*使能LXTAL,并等待其稳定 */rcu_osci_on(RCU_LXTAL);rcu_osci_stab_wait(RCU_LXTAL);/*设置RTC时钟源为LXTAL */rcu_rtc_clock_config(RCU_RTCSRC_LXTAL);/*使能RTC时钟*/rcu_periph_clock_enable(RCU_RTC);/*等待APB1接口时钟和RTC时钟同步 */rtc_register_sync_wait();/*等待上次对 RTC 寄存器写操作完成 */rtc_lwoff_wait();/*设置分频值32767*/rtc_prescaler_set(32767);/*等待上次对 RTC 寄存器写操作完成 */rtc_lwoff_wait();/*设置时间1970-01-01 0:0:0 */rtc_counter_set(0);bkp_write_data(BKP_DATA0,MAGIC_CODE);//写入摩码return;}/*使能对RTC的访问,使能PMU和BKP时钟*/rcu_periph_clock_enable(RCU_PMU);rcu_periph_clock_enable(RCU_BKPI);/*使能对后备寄存器和RTC的写权限*/pmu_backup_write_enable();/*等待APB1接口时钟和RTC时钟同步 */rtc_register_sync_wait();/*等待上次对 RTC 寄存器写操作完成 */rtc_lwoff_wait();
}/**
***********************************************************
* @brief 设置时间
* @param time,输入,日历时间
* @return
***********************************************************
*/
void SetRtcTime(RtcTime_t *time)
{time_t timeStamp;struct tm tmInfo;tmInfo.tm_year = time->year - 1900;tmInfo.tm_mon = time->month - 1;tmInfo.tm_mday = time->day;tmInfo.tm_hour = time->hour;tmInfo.tm_min = time->minute;tmInfo.tm_sec = time->second;timeStamp = mktime(&tmInfo) - 8 * 60 *60;rtc_lwoff_wait();rtc_counter_set(timeStamp);
}/**
***********************************************************
* @brief 获取时间
* @param
* @return
***********************************************************
*/
void GetRtcTime(RtcTime_t *time)
{time_t timeStamp;struct tm *tmInfo;timeStamp = rtc_counter_get() + 8 * 60 *60;tmInfo = localtime(&timeStamp);time->year = tmInfo->tm_year + 1900;time->month = tmInfo->tm_mon + 1;time->day = tmInfo->tm_mday;time->hour = tmInfo->tm_hour;time->minute = tmInfo->tm_min;time->second = tmInfo->tm_sec;
}
rtc_drv.h
#ifndef _RTC_DRV_H_
#define _RTC_DRV_H_
#include <stdint.h>typedef struct {uint16_t year;uint8_t month;uint8_t day;uint8_t hour;uint8_t minute;uint8_t second;
}RtcTime_t;/**
***********************************************************
* @brief RTC硬件初始化
* @param
* @return
***********************************************************
*/
void RtcDrvInit();/**
***********************************************************
* @brief 设置时间
* @param time,输入,日历时间
* @return
***********************************************************
*/
void SetRtcTime(RtcTime_t *time);/**
***********************************************************
* @brief 获取时间
* @param
* @return
***********************************************************
*/
void GetRtcTime(RtcTime_t *time);#endif
hmi_app.c
#include <stdint.h>
#include <stdio.h>
#include "rtc_drv.h"/**
***********************************************************
* @brief 人机交互任务处理函数
* @param
* @return
***********************************************************
*/
void HmiTask(void)
{RtcTime_t rtcTime;GetRtcTime(&rtcTime);printf("%d-%02d-%02d %02d:%02d:%02d\n",rtcTime.year,rtcTime.month,rtcTime.day,rtcTime.hour, rtcTime.minute, rtcTime.second);
}