RT-Thread:STM32实时时钟 RTC开启及应用

**说明:**STM32F103/407系列基于 RT-Thread 系统的 RTC 开启及应用 应用流程介绍。

1. RTC功能开启

1.1 开启系统RTC驱动

1.2 打开系统RTC相关的宏

1.3 打开库函数 RTC 相关的宏

完成以上系统配置,编译无误情况下RTC 就已经开启了。

2. RTC 应用

官方 API 查询地址:https://www.rt-thread.org/document/api/rtc_sample_8c-example.html#a3

2.1 相关函数

1.设置日期:设置系统日期但不修改时间

cpp 复制代码
rt_err_t 	set_date (rt_uint32_t year, rt_uint32_t month, rt_uint32_t day)

2.设置时间:设置系统时间但不修改日期

cpp 复制代码
rt_err_t 	set_time (rt_uint32_t hour, rt_uint32_t minute, rt_uint32_t second)

3.获取时间:

这里 time_t 是 long 型变量,这个变量接受 time()函数返回的 RTC 系统时间,系统返回的是 秒,从1900年开始总计运行了多少秒。

cpp 复制代码
 time_t now;
 now = time(RT_NULL);

4.时间格式转换为字符型: ctime(&now)

这个函数把总共的 秒 转换为 字符型格式的数据,如:Sat Jan 1 03:24:03 2000 ,表示 2000 年 1 月 1 日,星期:6 , 3:24:3

cpp 复制代码
rt_kprintf("%s\n", ctime(&now));

5.时间格式转换为整形:struct tm* localtime(const time_t* t)

这个是个系统函数,作用是把 秒 转换成 系统定义的时间结构体中对应的整形数据

cpp 复制代码
localtime(&now_time);

6.自定义函数:void user_now_time(struct user_time *u_time)

把系统时间转换为自定义的时间结构体,方便使用。

cpp 复制代码
struct user_time
{
    uint16_t year;      /* 年 */
    uint8_t months;     /* 月 */
    uint8_t mday;       /* 日 */
    uint8_t days;       /* 星期 */
    uint8_t hour;       /* 时 */
    uint8_t min;        /* 分 */
    uint8_t sec;        /* 秒 */
}u_now_time;

/* 功能:获取系统RTC时间
 * 入参:struct user_time *u_time 存储时间的结构体指针
 * */
void user_now_time(struct user_time *u_time)
{
    struct tm *rt_time;
    time_t now_time;

    now_time = time(RT_NULL); 
    rt_time = localtime(&now_time);
    u_time->year = rt_time->tm_year + 1900;
    u_time->months = rt_time->tm_mon +1;
    u_time->mday = rt_time->tm_mday;
    u_time->days = rt_time->tm_wday;
    u_time->hour = rt_time->tm_hour;
    u_time->min  = rt_time->tm_min;
    u_time->sec  = rt_time->tm_sec;
}

2.2 官方应用例程

cpp 复制代码
/*
 * Copyright (c) 2006-2018, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2018-11-30     misonyo      first implementation.
 */
/*
 * 程序清单:这是一个 RTC 设备使用例程
 * 例程导出了 rtc_sample 命令到控制终端
 * 命令调用格式:rtc_sample
 * 程序功能:设置RTC设备的日期和时间,延时一段时间后获取当前时间并打印显示。
*/
#include <rtthread.h>
#include <rtdevice.h>
static int rtc_sample(int argc, char *argv[])
{
    rt_err_t ret = RT_EOK;
    time_t now;
    /* 设置日期 */
    ret = set_date(2018, 12, 3);
    if (ret != RT_EOK)
    {
        rt_kprintf("set RTC date failed\n");
        return ret;
    }
    /* 设置时间 */
    ret = set_time(11, 15, 50);
    if (ret != RT_EOK)
    {
        rt_kprintf("set RTC time failed\n");
        return ret;
    }
    /* 延时3秒 */
    rt_thread_mdelay(3000);
    /* 获取时间 */
    now = time(RT_NULL);
    rt_kprintf("%s\n", ctime(&now));
    return ret;
}
/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(rtc_sample, rtc sample);

3. RTC应用例程

rtc_app.c

cpp 复制代码
/*
 * Copyright (c) 2006-2020, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 *
 * RTC 时钟应用
 * 版本:VER 1.0
 * 功能:
 * 1. 获取当前系统 RTC 时间,并更新 到  变量 struct user_time u_now_time;
 * 2. 设置时间和日期,将要设置的 日期和时间 更新到 struct user_time u_set_time; 变量后,再释放对于的 日期和时间设置的信号量。
 * 2.1 日期设置和时间设置是分开的,需要分别释放 日期信号量  rt_sem_release(&rx_sem_set_rtc_data);和时间信号量    rt_sem_release(&rx_sem_set_rtc_time);
 * 2.2 如果只更新时间 释放对于的时间信号量即可,日期不会改变。
 * 2.3 如果只更新日期 释放对于的日期信号量即可,时间不会改变。
 */

#include "user_cfg.h"


/*定义用于接收消息的信号量*/
struct rt_semaphore rx_sem_set_rtc_data;                   /* 设置日期信号量 */
struct rt_semaphore rx_sem_set_rtc_time;                   /* 设置日期信号量 */

static void num2str(char *c, int i)
{
    c[0] = i / 10 + '0';
    c[1] = i % 10 + '0';
}


/* 功能:时间格式转换为字符型格式  如:20210608-164530 格式输出
 * 入参:无
 * */
void use_time_num2str(void)
{
    num2str(&u_now_time.str_now_time[0] + 0, u_now_time.year / 100);
    num2str(&u_now_time.str_now_time[0] + 2, u_now_time.year % 100);
    num2str(&u_now_time.str_now_time[0] + 4,u_now_time.months);
    num2str(&u_now_time.str_now_time[0] + 6,u_now_time.mday);
    u_now_time.str_now_time[8] = '-';
    num2str(&u_now_time.str_now_time[0] + 9,u_now_time.hour);
    num2str(&u_now_time.str_now_time[0] + 11,u_now_time.min);
    num2str(&u_now_time.str_now_time[0] + 13,u_now_time.sec);
    u_now_time.str_now_time[15] = 0;
}



/* 功能:获取系统RTC时间
 * 入参:struct user_time *u_time 存储时间的结构体指针
 * */
void user_now_time(struct user_time *u_time)
{
    struct tm *rt_time;
    time_t now_time;

    now_time = time(RT_NULL);
    rt_time = localtime(&now_time);
    u_time->year = rt_time->tm_year + 1900;
    u_time->months = rt_time->tm_mon +1;
    u_time->mday = rt_time->tm_mday;
    u_time->days = rt_time->tm_wday;
    u_time->hour = rt_time->tm_hour;
    u_time->min  = rt_time->tm_min;
    u_time->sec  = rt_time->tm_sec;

    if (u_time->days == 0)
    {
        u_time->days = 7;
    }

    use_time_num2str();
}

/* 线程 now_time_thread 的入口函数 */
/* 负责定时更新时钟变量,数据源来做系统提供的RTC时钟 */
static void now_time_entry(void *param)
{
    rt_err_t ret = RT_EOK;
    time_t now_time;

    /*初始化信号量,批量初始化所有定义的信号量 */
    rt_sem_init(&rx_sem_set_rtc_data, "rx_sem_set_rtc_data", 0, RT_IPC_FLAG_FIFO);            /*初始化信号量 */
    rt_sem_init(&rx_sem_set_rtc_time, "rx_sem_set_rtc_time", 0, RT_IPC_FLAG_FIFO);            /*初始化信号量 */

    while (1)
    {
        if (rt_sem_trytake(&rx_sem_set_rtc_data) == RT_EOK)
        {
            /* 设置日期 */
            ret = set_date(u_set_time.year, u_set_time.months, u_set_time.mday);

            if (ret != RT_EOK)
            {
                rt_kprintf("set RTC date failed\n");
            }

        }

        if (rt_sem_trytake(&rx_sem_set_rtc_time) == RT_EOK)
        {
            /* 设置时间 */
            ret = set_time(u_set_time.hour, u_set_time.min, u_set_time.sec);

            if (ret != RT_EOK)
            {
                rt_kprintf("set RTC time failed\n");
            }
        }

        user_now_time(&u_now_time);/* 获取系统时间 */

        /* 测试用:用系统RTC函数打印字符型格式时间 */
        now_time = time(RT_NULL);
        rt_kprintf("%s\n", ctime(&now_time));
        /* 测试用:打印自定义格式*/
        rt_kprintf("%d 年 %d 月 %d 日,星期:%d , %d:%d:%d \r\n",u_now_time.year,u_now_time.months,u_now_time.mday,u_now_time.days,u_now_time.hour,u_now_time.min,u_now_time.sec);
        rt_kprintf("%s \r\n",u_now_time.str_now_time);


        rt_thread_mdelay(1000);
    }
}

/*线程创建函数*/
int now_time_thread(void)
{
    rt_thread_t tid1;                                 /*创建线程控制块指针来接收线程创建函数的返回值,目的是通过返回值判断线程是否创建ok*/

    /* 创建线程 1,名称是 now_time_thread,入口是 now_time_entry*/

    tid1 = rt_thread_create("now_time_thread",        /*线程名称,系统打印线程时会显示这个线程的名字*/
                            now_time_entry,           /*线程入口函数,入口函数函数名*/
                            RT_NULL,                  /*入口参数*/
                            1000,                     /*设置内存堆栈大小*/
                            10,                       /*设置优先级*/
                            100);                     /*时间片参数,时间片是在有多个相同优先级线程时,这个线程每次被执行多少个时间片*/


    /* 如果获得线程控制块,启动这个线程 */
    if (tid1 != RT_NULL)
    {
        rt_thread_startup(tid1);
        //rt_kprintf("now_time_thread 线程创建成功...\r\n");
    }
    else
    {
       // rt_kprintf("now_time_thread 线程创建失败...\r\n");
    }

    return RT_EOK;
}
INIT_APP_EXPORT(now_time_thread);






/* 信号量的定义和使用流程 */

///*step1: 定义用于接收消息的信号量*/
//static struct rt_semaphore rx_sem;  或者 static rt_sem_t rx_sem;
//
///*step2: 初始化信号量 */
//rt_sem_init(&rx_sem, "rx_sem", 0, RT_IPC_FLAG_FIFO);
//
///*step3:获取信号量函数,阻塞等待接收信号量,等到信号量后再次读取数据,RT_WAITING_FOREVER参数,永远阻塞,直到获得资源 */
//rt_sem_take(&rx_sem, RT_WAITING_FOREVER);
//
///*step4:释放信号量可以唤醒挂起在该信号量上的线程。释放信号量使用下面的函数。可以在中断或线程内使用*/
//rt_sem_release(&rx_sem);
//示例:rt_sem_release(&rx_sem_adc_dma);//释放信号量

rtc_app.h

cpp 复制代码
#ifndef APPLICATIONS_RTC_APP_H_
#define APPLICATIONS_RTC_APP_H_

struct user_time
{
    uint16_t year;          /* 年 */
    uint8_t months;         /* 月 */
    uint8_t mday;           /* 日 */
    uint8_t days;           /* 星期 */
    uint8_t hour;           /* 时 */
    uint8_t min;            /* 分 */
    uint8_t sec;            /* 秒 */
    char str_now_time[16];  /* 字符格式时间,年月日-时分秒 如:20210608-164530 格式输出*/
};

struct user_time u_now_time; /* 当前时间 */
struct user_time u_set_time; /* 要设置的时间 */

extern void user_now_time(struct user_time *u_time) ;

extern struct rt_semaphore rx_sem_set_rtc_data;                   /* 设置日期信号量 */
extern struct rt_semaphore rx_sem_set_rtc_time;                   /* 设置日期信号量 */

#endif /* APPLICATIONS_RTC_APP_H_ */
相关推荐
A9better19 分钟前
嵌入式开发学习日志37——stm32之USART
stm32·嵌入式硬件·学习
国科安芯4 小时前
ASP4644芯片低功耗设计思路解析
网络·单片机·嵌入式硬件·安全
充哥单片机设计4 小时前
【STM32项目开源】基于STM32的智能厨房火灾燃气监控
stm32·单片机·嵌入式硬件
CiLerLinux11 小时前
第四十九章 ESP32S3 WiFi 路由实验
网络·人工智能·单片机·嵌入式硬件
时光の尘11 小时前
【PCB电路设计】常见元器件简介(电阻、电容、电感、二极管、三极管以及场效应管)
单片机·嵌入式硬件·pcb·二极管·电感·三极管·场效应管
Lu Zelin11 小时前
单片机为什么不能跑Linux
linux·单片机·嵌入式硬件
宁静致远202112 小时前
stm32 freertos下基于hal库的模拟I2C驱动实现
stm32·嵌入式硬件·freertos
Wave84517 小时前
STM32--智能小车
stm32·单片机·嵌入式硬件
wdfk_prog19 小时前
[Linux]学习笔记系列 -- lib/timerqueue.c Timer Queue Management 高精度定时器的有序数据结构
linux·c语言·数据结构·笔记·单片机·学习·安全
helesheng1 天前
用低成本FPGA实现FSMC接口的多串口(UART)控制器
stm32·fsmc·fpga·uart控制器