F407无法使用RTC,手册上的RTC实验例程跑不通。请各位不吝赐教!

发布于 2020-08-31 19:44:44

今天在407上打算用RTC实现一个时间计时,各种配置后使用RT手册的RTC例程编译发现:
1.

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;
}

这里报错"set RTC date failedn"。然后发现是rt_device_find("rtc") 找不到RTC设备,使用list_device命令发现不存在RTC设备。于是手动进行设备注册

    RT_ASSERT(!rt_device_find("rtc"));
    if(RT_EOK != rt_device_register(&rtc_dev, "rtc", RT_DEVICE_FLAG_RDWR))
    {
        rt_kprintf("rt_device_register failed\n");
    }
    INIT_DEVICE_EXPORT(rt_rtc_init);

编译,list_device出现设备RTC,但继续报错:
2.

rt_err_t set_date(rt_uint32_t year, rt_uint32_t month, rt_uint32_t day)
{
    time_t now;
    struct tm *p_tm;
    struct tm tm_new;
    rt_device_t device;
    rt_err_t ret = -RT_ERROR;

    /* get current time */
    now = time(RT_NULL);

    /* lock scheduler. */
    rt_enter_critical();
    /* converts calendar time time into local time. */
    p_tm = localtime(&now);
    /* copy the statically located variable */
    memcpy(&tm_new, p_tm, sizeof(struct tm));
    /* unlock scheduler. */
    rt_exit_critical();

    /* update date. */
    tm_new.tm_year = year - 1900;
    tm_new.tm_mon  = month - 1; /* tm_mon: 0~11 */
    tm_new.tm_mday = day;

    /* converts the local time in time to calendar time. */
    now = mktime(&tm_new);

    device = rt_device_find("rtc");
    if (device == RT_NULL)
    {
        return -RT_ERROR;
    }

    /* update to RTC device. */
    ret = rt_device_control(device, RT_DEVICE_CTRL_RTC_SET_TIME, &now);
    rt_kprintf("4.rt_device_control==%d \n",ret);
    return ret;
}

发现是该函数最后一行:“ ret = rt_device_control(device, RT_DEVICE_CTRL_RTC_SET_TIME, &now);”返回异常,于是发现是由于该函数内的

    /* call device_write interface */
    if (device_control != RT_NULL)
    {
        rt_kprintf("5.device_control==%d \n",device_control(dev, cmd, arg));
        return device_control(dev, cmd, arg);
    }

device_control为NULL,即上面函数的设备参数dev->control为NULL,该参数是在set_date里面调用

rt_device_control(device, RT_DEVICE_CTRL_RTC_SET_TIME, &now)

时传入的,于是接下来在调用之前把设备参数进行手动初始化。手动为

    rtc_dev.type     = RT_Device_Class_RTC;    /**< RTC device */
    /* register rtc device */
    soft_rtc_dev.ops     = &soft_rtc_ops;
    rtc_dev.init    = RT_NULL;
    rtc_dev.open    = RT_NULL;
    rtc_dev.close   = RT_NULL;
    rtc_dev.read    = RT_NULL;
    rtc_dev.write   = RT_NULL;
    rtc_dev.control = rtc_control;
    rtc_dev.user_data = RT_NULL;

其中,将rtc_control设置为

rtc_control(rt_device_t dev, int cmd, void *args)
{return RT_EOK;}

此时编译通过,运行正常。但是时间永远是1970-01-01-00-00-00.
研究发现,这应该是

ret = rt_device_control(device, RT_DEVICE_CTRL_RTC_SET_TIME, &now);

里面的第二个参数没有起作用,该参数应该在

rtc_control(rt_device_t dev, int cmd, void *args)

进行处理,而我设置成了空函数。靠!QTQ。
后来把sort_rtc里面的sort_rtc_control函数搬过来

static rt_err_t rtc_control(rt_device_t dev, int cmd, void *args)
{
    time_t *time;
    struct tm time_temp;

    RT_ASSERT(dev != RT_NULL);
    memset(&time_temp, 0, sizeof(struct tm));    
    switch (cmd)
    {
    case RT_DEVICE_CTRL_RTC_GET_TIME:
        time = (time_t *) args;
        *time = init_time + (rt_tick_get() - init_tick) / RT_TICK_PER_SECOND;
        break;

    case RT_DEVICE_CTRL_RTC_SET_TIME:
    {
        time = (time_t *) args;
        init_time = *time - (rt_tick_get() - init_tick) / RT_TICK_PER_SECOND;
        break;
    }
    }

    return RT_EOK;
}

编译运行成功,时间可以变化了。然而,断电重启407后,时间又回到了初始化的时间。

静下来思考发现,想不通:明明我是用的407的片上RTC,并且VBAT引脚电池有电,为什么手册上的RTC例程会上来就找不到‘rtc’设备呢?注册了设备又为什么开始在set_date这里就一路报错呢?请各位不吝赐教!

附上例程链接:RTC例程

以下为RTthread配置:
CubeMX
image.png

image.png

image.png

Menuconfig
image.png

image.png

image.png

image.png

查看更多

关注者
0
被浏览
221
nongxiaoming
nongxiaoming 2020-09-01

你要通过备份寄存器去判断是不是需要设置时间,不是每次启动都要设置时间的,不然时间就又被设置回去了。

3 个回答
mii
mii 2020-09-01

首先,你确定cube配置时钟的函数已经修改到RTT上了。第二,确保rtc时钟有起振,STM32有个奇怪的现象,RTC的无源晶振有时候不会起振。第三,根据RTT官方文档开启配置,我实测是不需要修改文件的,建议你选择最新的系统版本。

clickcheck
clickcheck 2020-09-01

感谢各位的耐心回答。早上过来看了下@nongxiaoming 的回复,这给我提了个醒。于是翻了一下bspstm32librariesHAL_Drivers的文件,发现了drv_rtc.c文件!它并没有在一些列配置后自动加入到工程中,于是在keil5工程手动导入该文件。
至此,问题解决!

撰写答案

请登录后再发布答案,点击登录

发布
问题

分享
好友