硬汉嵌入式论坛

 找回密码
 立即注册
查看: 630|回复: 15
收起左侧

[有问必答] RTC怎么可以读出来13月啊~~~~

[复制链接]

334

主题

2033

回帖

3040

积分

版主

Rank: 7Rank: 7Rank: 7

积分
3040
发表于 2023-12-20 14:03:56 | 显示全部楼层 |阅读模式

同一批次多数板子都是正常的,但是碰到一个奇怪的板子。
RTC设定今天2023年12月20日,按复位键重启,日期时间都是对的; 如果断电重启,只有月份读出来是13月,其他的都是正常的。怎么回事呢。。。。


Snipaste_2023-12-20_13-59-43.png

代码就是最简单的:

    MX_RTC_Init();   
    HAL_Delay(20);
    HAL_RTC_GetTime(&hrtc, &DeviceTime, RTC_FORMAT_BIN);
    HAL_RTC_GetDate(&hrtc, &DeviceDate, RTC_FORMAT_BIN);

回复

使用道具 举报

3

主题

96

回帖

105

积分

初级会员

积分
105
发表于 2023-12-20 14:43:32 | 显示全部楼层
检查一下硬件
回复

使用道具 举报

334

主题

2033

回帖

3040

积分

版主

Rank: 7Rank: 7Rank: 7

积分
3040
 楼主| 发表于 2023-12-20 15:00:26 | 显示全部楼层

也怀疑过硬件,示波器观察了电池电压,mcu的vcc电压建立曲线,reset信号的曲线,都是正常的。。。。
调试单步运行,确实从RTC寄存器里面读出来的月份是0x13。
回复

使用道具 举报

3

主题

124

回帖

133

积分

初级会员

积分
133
发表于 2023-12-20 15:55:27 | 显示全部楼层
RTC寄存器也是显示13月吗,看楼主描述,不带电池应该是正常的,可能初始化或者断电的时候程序做了什么操作
回复

使用道具 举报

75

主题

685

回帖

910

积分

金牌会员

积分
910
发表于 2023-12-20 16:36:16 | 显示全部楼层
使用RTC_FORMAT_BCD试试
回复

使用道具 举报

334

主题

2033

回帖

3040

积分

版主

Rank: 7Rank: 7Rank: 7

积分
3040
 楼主| 发表于 2023-12-20 17:14:52 | 显示全部楼层
本帖最后由 caicaptain2 于 2023-12-21 09:49 编辑
skyshine 发表于 2023-12-20 15:55
RTC寄存器也是显示13月吗,看楼主描述,不带电池应该是正常的,可能初始化或者断电的时候程序做了什么操作

再综合描述一下,请大家想想其他的测试方法:
1. 目前大概每10块板子,有2~3块有这种诡异的现象。 有时候是别的RTC数据在断电复位后变化,比如日,比如分钟之类。

已经排查过的可以因素有:
1. 32768晶振已经是官方推荐的爱普生的6pf型号,肯定是起振了,RTC的秒数据正常变化;
2. 电池CR1220是新的。
3. 示波器监控了stm32的VDD和RESET的上电时序、波形,都很完美。
4. 在线单步调试下,可以读取RTC的寄存器,这个板子的月份,确实读出来19,即0x13,13月。。。。
5. 修改年月日的时候,没有动“星期几”这个参数,  直接写的RTC,不知道这个错误的星期是否会造成问题?
6. 在去掉电池的情况下,芯片1脚(VBAT)即悬空,在上电过程中,此管脚出现了大约1毫秒的3V高电平,然后恢复为0V。这个无法解释。芯片规格书也没有说这个事。
7. 目前困难的是,板子一定是先上电才可能用jlink进入debug调试模式,所以无法跟踪上电过程中的问题。

补充一个上电过程中,VBAT管脚和VDD的上升波形。此时,VBAT管脚悬空,什么都没有接,对应上述的6.
新建文件1.png

接上电池后,上电和断电过程中的VBAT和VDD。显示无异常。
新建文件2.png 新建文件3.png



回复

使用道具 举报

5

主题

519

回帖

534

积分

金牌会员

积分
534
发表于 2023-12-21 08:55:04 | 显示全部楼层
最简单就是月&0X0F。日可以&XFF。
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106856
QQ
发表于 2023-12-21 09:25:31 | 显示全部楼层
caicaptain2 发表于 2023-12-20 17:14
再综合描述一下,请大家想想其他的测试方法:
1. 目前大概每10块板子,有2~3块有这种诡异的现象。 有时 ...

有个重要的一点,RTC的所有参数都要正确配置,包括星期,否则会有意想不到异常结果。
回复

使用道具 举报

334

主题

2033

回帖

3040

积分

版主

Rank: 7Rank: 7Rank: 7

积分
3040
 楼主| 发表于 2023-12-21 09:51:04 | 显示全部楼层
eric2013 发表于 2023-12-21 09:25
有个重要的一点,RTC的所有参数都要正确配置,包括星期,否则会有意想不到异常结果。

设定年月日的时候,并不知道应该是星期几啊。。。。难道要找个复杂的算法,算出来星期几么?
回复

使用道具 举报

3

主题

96

回帖

105

积分

初级会员

积分
105
发表于 2023-12-21 09:59:43 | 显示全部楼层
caicaptain2 发表于 2023-12-21 09:51
设定年月日的时候,并不知道应该是星期几啊。。。。难道要找个复杂的算法,算出来星期几么?

根据日期算出星期几有很多种方法,以下是一种简单的基于蔡勒公式(Zeller's congruence)的算法。

蔡勒公式的计算公式为:

```
h = (q + [(13 * (m + 1))/5] + K + [K/4] + [J/4] - 2*J) % 7
```

其中,h为星期几,q为当前日期,m为当前月份,K为世纪数,J为年份的前两位数(公元纪年法)。

注:[] 表示向下取整。

根据这个公式,可以通过以下步骤计算出指定日期的星期几:

1. 将输入的年月日分别存储在变量 y, m, d 中;
2. 如果 m < 3,则将月份增加12,年份减1,即 y = y-1, m= m+12;
3. 计算世纪数 K 和年份的前两位数 J,计算公式为 K = y/100,J = y%100;
4. 计算星期几,h = (q + [(13 * (m + 1))/5] + K + [K/4] + [J/4] - 2*J) % 7,其中 q = d;
5. 根据 h 的值来判断当天是星期几(h=0表示星期日,h=1表示星期一,以此类推)。

下面是一段 C++ 代码实现:

```c++
#include <iostream>
using namespace std;

int getWeekday(int y, int m, int d) {
    if(m < 3) {
        m += 12;
        y -= 1;
    }
    int q = d;
    int K = y / 100;
    int J = y % 100;
    int h = (q + ((13 * (m + 1)) / 5) + K + (K / 4) + (J / 4) - 2 * J) % 7;
    return h;
}

int main() {
    int y = 2022;
    int m = 11;
    int d = 22;
    int weekday = getWeekday(y, m, d);
    cout << "The weekday of " << y << "-" << m << "-" << d << " is " << weekday << endl;
    return 0;
}
```

这里的日期输入方式为年月日,程序输出的星期几是以数字形式输出(0表示星期日,1表示星期一,以此类推)。如果需要输出星期几的字符串形式,可以根据数字进行转换。
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106856
QQ
发表于 2023-12-21 10:01:07 | 显示全部楼层
caicaptain2 发表于 2023-12-21 09:51
设定年月日的时候,并不知道应该是星期几啊。。。。难道要找个复杂的算法,算出来星期几么?

对,直接带入这个函数即可

[C] 纯文本查看 复制代码
/*
*********************************************************************************************************
*        函 数 名: bsp_CalcWeek
*        功能说明: 根据日期计算星期几
*        形    参: _year _mon _day  年月日  (年是2字节整数,月和日是字节整数)
*        返 回 值: 周几 (1-7) 7表示周日
*********************************************************************************************************
*/
uint8_t RTC_CalcWeek(uint16_t _year, uint8_t _mon, uint8_t _day)
{
    /*
    蔡勒(Zeller)公式
    历史上的某一天是星期几?未来的某一天是星期几?关于这个问题,有很多计算公式(两个通用计算公式和
    一些分段计算公式),其中最著名的是蔡勒(Zeller)公式。
        即w=y+[y/4]+[c/4]-2c+[26(m+1)/10]+d-1

    公式中的符号含义如下,
         w:星期;
         c:年的高2位,即世纪-1
         y:年(两位数);
         m:月(m大于等于3,小于等于14,即在蔡勒公式中,某年的1、2月要看作上一年的13、14月来计算,
            比如2003年1月1日要看作2002年的13月1日来计算);
         d:日;
         [ ]代表取整,即只要整数部分。
        算出来的W除以7,余数是几就是星期几。如果余数是0,则为星期日。
            如果结果是负数,负数求余数则需要特殊处理:
                负数不能按习惯的余数的概念求余数,只能按数论中的余数的定义求余。为了方便
            计算,我们可以给它加上一个7的整数倍,使它变为一个正数,然后再求余数

    以2049年10月1日(100周年国庆)为例,用蔡勒(Zeller)公式进行计算,过程如下:
    蔡勒(Zeller)公式:w=y+[y/4]+[c/4]-2c+[26(m+1)/10]+d-1
    =49+[49/4]+[20/4]-2×20+[26× (10+1)/10]+1-1
    =49+[12.25]+5-40+[28.6]
    =49+12+5-40+28
    =54 (除以7余5)
    即2049年10月1日(100周年国庆)是星期5。
    */
    uint8_t y, c, m, d;
    int16_t w;

    if (_mon >= 3)
    {
        m = _mon;
        y = _year % 100;
        c = _year / 100;
        d = _day;
    }
    else        /* 某年的1、2月要看作上一年的13、14月来计算 */
    {
        m = _mon + 12;
        y = (_year - 1) % 100;
        c = (_year - 1) / 100;
        d = _day;
    }

    w = y + y / 4 +  c / 4 - 2 * c + ((uint16_t)26*(m+1))/10 + d - 1;
    if (w == 0)
    {
        w = 7;        /* 表示周日 */
    }
    else if (w < 0)        /* 如果w是负数,则计算余数方式不同 */
    {
        w = 7 - (-w) % 7;
    }
    else
    {
        w = w % 7;
    }

    /* modified by eric2013 -- 2016-12-25 */
    if (w == 0)
    {
        w = 7;        /* 表示周日 */
    }

    return w;
}
回复

使用道具 举报

2

主题

269

回帖

275

积分

高级会员

积分
275
发表于 2023-12-21 10:01:09 | 显示全部楼层
caicaptain2 发表于 2023-12-21 09:51
设定年月日的时候,并不知道应该是星期几啊。。。。难道要找个复杂的算法,算出来星期几么?

这个我熟,你直接设置0不就行了么反正你不用的,不然用基姆拉尔森计算公式(Kim Larsen Calculation Formula)
回复

使用道具 举报

3

主题

124

回帖

133

积分

初级会员

积分
133
发表于 2023-12-21 14:19:50 | 显示全部楼层
eric2013 发表于 2023-12-21 09:25
有个重要的一点,RTC的所有参数都要正确配置,包括星期,否则会有意想不到异常结果。

那修改rtc时间的时候也要改星期吗,之前我都是只改日期时间没改星期的
回复

使用道具 举报

3

主题

124

回帖

133

积分

初级会员

积分
133
发表于 2023-12-21 14:29:23 | 显示全部楼层
看了下芯片参考手册,week day 这个可以写0禁止,后续改时间结构体weekday那里留空或者写0就行。cubemx提供的rtc初始化好像没有写0的选项,按正确时间对应写入星期几应该就行
Bits 15:13 WDU[2:0]: Week day units
000: forbidden
001: Monday
...
111: Sunday


回复

使用道具 举报

3

主题

124

回帖

133

积分

初级会员

积分
133
发表于 2023-12-21 14:45:17 | 显示全部楼层
估计就是上电rtc初始化这个weekday出问题了,23年12月20日是周三
回复

使用道具 举报

210

主题

1044

回帖

1684

积分

至尊会员

More we do, more we can do.

积分
1684
发表于 2023-12-21 17:03:42 | 显示全部楼层
看了手册,对写入的值没有限制,得由软件保证。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-5-7 17:18 , Processed in 0.282236 second(s), 28 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表