• 第 42 章 RTC—实时时钟


    42.1 RTC 实时时钟简介

    42.2 RTC 外设框图剖析

    在这里插入图片描述

    框图中浅灰色的部分都是属于备份域的,在 VDD 掉电时可在 VBAT 的驱动下继续运行。这部分仅包括 RTC 的分频器,计数器,和闹钟控制器。

    运用流程

    若 VDD 电源有效,RTC 可以触发 RTC_Second(秒中断)、RTC_Overflflow(溢出事件) 和 RTC_Alarm(闹钟中断)。从结构图可以分析到,其中的定时器溢出事件无法被配置为中断。若 STM32 原本处于待机状态,可由闹钟事件或 WKUP 事件 (外部唤醒事件,属于 EXTI 模块,不属于 RTC) 使它退出待机模式。闹钟事件是在计数器 RTC_CNT 的值等于闹钟寄存器 RTC_ALR 的值时触发的。

    在备份域中所有寄存器都是 16 位的,RTC 控制相关的寄存器也不例外。它的计数器 RTC_CNT的 32 位由 RTC_CNTL 和 RTC_CNTH 两个寄存器组成,分别保存定时计数值的低 16 位和高 16位。在配置 RTC 模块的时钟时,通常把输入的 32768Hz 的 RTCCLK 进行 32768 分频得到实际驱动计数器的时钟TR_CLK=RTCCLK/32768= 1 Hz,计时周期为 1 秒,计时器在 TR_CLK 的驱动下计数,即每秒计数器 RTC_CNT 的值加 1。

    由于备份域的存在,使得 RTC 核具有了完全独立于 APB1 接口的特性,也因此对 RTC 寄存器的访问要遵守一定的规则

    系统复位后,默认禁止访问后备寄存器和 RTC,防止对后备区域 (BKP) 的意外写操作。执行以下操作使能对后备寄存器和 RTC 的访问:

    (1) 设置 RCC_APB1ENR 寄存器的 PWREN 和 BKPEN 位来使能电源和后备接口时钟。

    (2) 设置 PWR_CR 寄存器的 DBP 位使能对后备寄存器和 RTC 的访问。

    设置后备寄存器为可访问后,在第一次通过 APB1 接口访问 RTC 时,因为时钟频率的差异,所以必须等待 APB1 与 RTC 外设同步,确保被读取出来的 RTC 寄存器值是正确的。若在同步之后,一直没有关闭 APB1 的 RTC 外设接口,就不需要再次同步了。

    如果内核要对 RTC 寄存器进行任何的写操作,在内核发出写指令后,RTC 模块在 3 个 RTCCLK时钟之后,才开始正式的写 RTC 寄存器操作。由于 RTCCLK 的频率比内核主频低得多,所以每次操作后必须要检查 RTC 关闭操作标志位 RTOFF,当这个标志被置 1 时,写操作才正式完成。

    42.3 UNIX 时间戳

    如果从现在起,把计数器 RTC_CNT 的计数值置 0,然后每秒加 1,RTC_CNT 什么时候会溢出呢?

    由于 RTC_CNT 是 32 位寄存器,可存储的最大值为 (232-1),即这样计时的话,在 2^32 秒后溢出,

    即它将在今后的 136 年时溢出:N = 232/365/24/60/60 ≈136 年

    假如某个时刻读取到计数器的数值为 X = 606024*2,即两天时间的秒数,而假设又知道计数器是在 2011 年 1 月 1 日的 0 时 0 分 0 秒置 0 的,那么就可以根据计数器的这个相对时间数值,计算得这个 X 时刻是 2011 年 1 月 3 日的 0 时 0 分 0 秒了。而计数器则会在 (2011+136) 年左右溢出,也就是说到了(2011+136)年时,如果我们还在使用这个计数器提供时间的话就会出现问题。

    在这个例子中,定时器被置 0 的这个时间被称为计时元年,相对计时元年经过的秒数称为时间戳,也就是计数器中的值。

    42.4 与 RTC 控制相关的库函数

    4.1 等待时钟同步和操作完成

    4.2 使能备份域说及 RTC 配置

    4.3 设置 RTC 时钟分频

    4.4 设置、获取 RTC 计数器及闹钟

    42.5 利用 RTC 提供北京时间

    5.1 硬件设计

    在这里插入图片描述

    原理图中的右上角是备份域的供电电路,在本开发板中提供了一个钮扣电池插槽,可以接入型号为 CR1220 的钮扣电池,该型号的钮扣电池电压为 3.2V,图中的 BAT54C 双向二极管可切换输入到 STM32 备份域电源引脚 VBAT 的供电,当主电源正常供电时,由稳压器输出的 3.3V 供电,当主电源掉电时,由钮扣电池供电。

    原理图下方的是本开发板采用的 LSE 晶振电路,此处使用的晶振频率为 32.768KHz,RTC 外设可以使用 LSE 作为时钟,把它进行分频得到 1Hz 的 RTC 计时时钟。

    注意: 本实验默认使用 LSI 内部时钟,使用内部时钟时,即使安装了钮扣电池,主电源掉电后时间是不会继续走的,只会保留上次断电的时间。若要持续运行,需要修改 bsp_rtc.h 文件,使用 RTC_CLOCK_SOURCE_LSE 宏,切换成使用 LSE 外部时钟。

    5.2 软件设计

    5.2.1 程序设计要点

    (1) 初始化 RTC 外设;

    (2) 设置时间以及添加配置标志;

    (3) 获取当前时间;

    5.2.2 代码分析

    1.RTC 实验配置相关宏定义
    在这里插入图片描述

    • USE_LCD_DISPLAY:这个宏可以用于切换本工程是否使用液晶屏显示时间,把它注释掉可以关闭液晶显示,方便移植到没有液晶的应用中。

    • RTC_CLOCK_SOURCE_LSE/LSI:这两个宏用于选择使用 LSE 作外部时钟还是 LSI 作外部时钟。提供两种选择主要是因为 STM32 的 LSE 晶振在批量产品时容易不起振,而 LSI 则在主电源关闭后计时时间不会继续增加。

    • RTC_BKP_DRX 和 RTC_BKP_DATA:这两个宏用于在备份域寄存器设置 RTC 已配置标志,本实验中初始化 RTC 后,向备份域寄存器写入一个数字,若下次芯片上电检测到该标志,说明 RTC 之前已经配置好时间,所以不应该再设置 RTC,而如果备份域电源也掉电,备份域内记录的该标志也会丢失,所以芯片上电后需要重新设置时间。这两个宏的值中,BKP_DR1是备份域的其中一个寄存器,而 0xA5A5 则是随意选择的数字,只要写入和检测一致即可。

    • TIME_ZOOM:这个宏用于设置时区的秒数偏移,例如北京时间为 (GMT+8) 时区,即相对于格林威治时间 (GMT) 早 8 个小时,此处使用的宏值即为 8 个小时的秒数(86060),若使用其它时区,修改该宏即可。

    2.初始化 RTC

    3.时间管理结构体

    4.时间格式转换

    5.配置时间

    6.检查并配置 RTC

    7.转换并输出时间

    8.中断服务函数

    9.main 函数

    main.c

    #include "stm32f10x.h"
    #include "./usart/bsp_usart.h"
    #include "./rtc/bsp_rtc.h"
    #include "./lcd/bsp_ili9341_lcd.h"
    #include "./key/bsp_key.h"  
    
    
    // N = 2^32/365/24/60/60 = 136 年
    
    /*时间结构体,默认时间2000-01-01 00:00:00*/
    struct rtc_time systmtime=
    {
    0,0,0,1,1,2000,0
    };
    
    extern __IO uint32_t TimeDisplay ;
    
    
    
    //【*】注意事项:
    //在bsp_rtc.h文件中:
    
    //1.可设置宏USE_LCD_DISPLAY控制是否使用LCD显示
    //2.可设置宏RTC_CLOCK_SOURCE_LSI和RTC_CLOCK_SOURCE_LSE控制使用LSE晶振还是LSI晶振
    
    //3.STM32的LSE晶振要求非常严格,同样的电路、板子批量产品时总有些会出现问题。
    //  本实验中默认使用LSI晶振。
    //  
    //4.!!!若希望RTC在主电源掉电后仍然运行,需要给开发板的电池槽安装钮扣电池,
    //  !!!且改成使用外部晶振模式RTC_CLOCK_SOURCE_LSE
    //  钮扣电池型号:CR1220
    /**
      * @brief  主函数
      * @param  无  
      * @retval 无
      */
    int main()
    {		
    	
    //可使用该宏设置是否使用液晶显示
    #ifdef  USE_LCD_DISPLAY
    	
    		ILI9341_Init ();         //LCD 初始化
    		LCD_SetFont(&Font8x16);
    		LCD_SetColors(RED,BLACK);
    
    		ILI9341_Clear(0,0,LCD_X_LENGTH,LCD_Y_LENGTH);	/* 清屏,显示全黑 */
    
    		ILI9341_DispStringLine_EN(LINE(0),"        BH RTC demo");
    #endif
    	
    	  USART_Config();		
    	
    		Key_GPIO_Config();
    
    		/* 配置RTC秒中断优先级 */
    	  RTC_NVIC_Config();
    	  RTC_CheckAndConfig(&systmtime);
    	
    	  while (1)
    	  {
    	    /* 每过1s 更新一次时间*/
    	    if (TimeDisplay == 1)
    	    {
    				/* 当前时间 */
    	      Time_Display( RTC_GetCounter(),&systmtime); 		  
    	      TimeDisplay = 0;
    	    }
    			
    			//按下按键,通过串口修改时间
    			if( Key_Scan(KEY1_GPIO_PORT,KEY1_GPIO_PIN) == KEY_ON  )
    			{
    				struct rtc_time set_time;
    
    				/*使用串口接收设置的时间,输入数字时注意末尾要加回车*/
    				Time_Regulate_Get(&set_time);
    				/*用接收到的时间设置RTC*/
    				Time_Adjust(&set_time);
    				
    				//向备份寄存器写入标志
    				BKP_WriteBackupRegister(RTC_BKP_DRX, RTC_BKP_DATA);
    
    			} 			
    	  }
    }
    
    /***********************************END OF FILE*********************************/
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89

    calendar.h

    /******************** (C) COPYRIGHT 2009 www.armjishu.com ************************
    * File Name          : calendar.h
    * Author             : www.armjishu.com Team
    * Version            : V1.0
    * Date               : 10/1/2009
    * Description      : 超强的日历,支持农历,24节气几乎所有日历的功能
                              日历时间以1970年为元年,用32bit的时间寄存器可以运
                              行到2100年左右
    *******************************************************************************/
    
    #ifndef __CALENDAR_H
    #define __CALENDAR_H
    #include "stm32f10x.h"
    
    
    u8 GetMoonDay(u8 month_p,unsigned short table_addr);
    u8 GetChinaCalendar(u16  year,u8 month,u8 day,u8 *p);
    void GetSkyEarth(u16 year,u8 *p);
    void StrCopy(u8 *target,u8 const *source,u8 no);
    void GetChinaCalendarStr(u16 year,u8 month,u8 day,u8 *str);
    u8 GetJieQi(u16 year,u8 month,u8 day,u8 *JQdate);
    u8 GetJieQiStr(u16 year,u8 month,u8 day,u8 *str);
    #endif 
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    calendar.c

    #include "./rtc/bsp_calendar.h"
    
    const uint8_t year_code[597]=
    {
    	0x04,0xAe,0x53, //1901 0
    	0x0A,0x57,0x48, //1902 3
    	0x55,0x26,0xBd, //1903 6
    	0x0d,0x26,0x50, //1904 9
    	0x0d,0x95,0x44, //1905 12
    	0x46,0xAA,0xB9, //1906 15
    	0x05,0x6A,0x4d, //1907 18
    	0x09,0xAd,0x42, //1908 21
    	0x24,0xAe,0xB6, //1909
    	0x04,0xAe,0x4A, //1910
    	0x6A,0x4d,0xBe, //1911
    	0x0A,0x4d,0x52, //1912
    	0x0d,0x25,0x46, //1913
    	0x5d,0x52,0xBA, //1914
    	0x0B,0x54,0x4e, //1915
    	0x0d,0x6A,0x43, //1916
    	0x29,0x6d,0x37, //1917
    	0x09,0x5B,0x4B, //1918
    	0x74,0x9B,0xC1, //1919
    	0x04,0x97,0x54, //1920
    	0x0A,0x4B,0x48, //1921
    	0x5B,0x25,0xBC, //1922
    	0x06,0xA5,0x50, //1923
    	0x06,0xd4,0x45, //1924
    	0x4A,0xdA,0xB8, //1925
    	0x02,0xB6,0x4d, //1926
    	0x09,0x57,0x42, //1927
    	0x24,0x97,0xB7, //1928
    	0x04,0x97,0x4A, //1929
    	0x66,0x4B,0x3e, //1930
    	0x0d,0x4A,0x51, //1931
    	0x0e,0xA5,0x46, //1932
    	0x56,0xd4,0xBA, //1933
    	0x05,0xAd,0x4e, //1934
    	0x02,0xB6,0x44, //1935
    	0x39,0x37,0x38, //1936
    	0x09,0x2e,0x4B, //1937
    	0x7C,0x96,0xBf, //1938
    	0x0C,0x95,0x53, //1939
    	0x0d,0x4A,0x48, //1940
    	0x6d,0xA5,0x3B, //1941
    	0x0B,0x55,0x4f, //1942
    	0x05,0x6A,0x45, //1943
    	0x4A,0xAd,0xB9, //1944
    	0x02,0x5d,0x4d, //1945
    	0x09,0x2d,0x42, //1946
    	0x2C,0x95,0xB6, //1947
    	0x0A,0x95,0x4A, //1948
    	0x7B,0x4A,0xBd, //1949
    	0x06,0xCA,0x51, //1950
    	0x0B,0x55,0x46, //1951
    	0x55,0x5A,0xBB, //1952
    	0x04,0xdA,0x4e, //1953
    	0x0A,0x5B,0x43, //1954
    	0x35,0x2B,0xB8, //1955
    	0x05,0x2B,0x4C, //1956
    	0x8A,0x95,0x3f, //1957
    	0x0e,0x95,0x52, //1958
    	0x06,0xAA,0x48, //1959
    	0x7A,0xd5,0x3C, //1960
    	0x0A,0xB5,0x4f, //1961
    	0x04,0xB6,0x45, //1962
    	0x4A,0x57,0x39, //1963
    	0x0A,0x57,0x4d, //1964
    	0x05,0x26,0x42, //1965
    	0x3e,0x93,0x35, //1966
    	0x0d,0x95,0x49, //1967
    	0x75,0xAA,0xBe, //1968
    	0x05,0x6A,0x51, //1969
    	0x09,0x6d,0x46, //1970
    	0x54,0xAe,0xBB, //1971
    	0x04,0xAd,0x4f, //1972
    	0x0A,0x4d,0x43, //1973
    	0x4d,0x26,0xB7, //1974
    	0x0d,0x25,0x4B, //1975
    	0x8d,0x52,0xBf, //1976
    	0x0B,0x54,0x52, //1977
    	0x0B,0x6A,0x47, //1978
    	0x69,0x6d,0x3C, //1979
    	0x09,0x5B,0x50, //1980
    	0x04,0x9B,0x45, //1981
    	0x4A,0x4B,0xB9, //1982
    	0x0A,0x4B,0x4d, //1983
    	0xAB,0x25,0xC2, //1984
    	0x06,0xA5,0x54, //1985
    	0x06,0xd4,0x49, //1986
    	0x6A,0xdA,0x3d, //1987
    	0x0A,0xB6,0x51, //1988
    	0x09,0x37,0x46, //1989
    	0x54,0x97,0xBB, //1990
    	0x04,0x97,0x4f, //1991
    	0x06,0x4B,0x44, //1992
    	0x36,0xA5,0x37, //1993
    	0x0e,0xA5,0x4A, //1994
    	0x86,0xB2,0xBf, //1995
    	0x05,0xAC,0x53, //1996
    	0x0A,0xB6,0x47, //1997
    	0x59,0x36,0xBC, //1998
    	0x09,0x2e,0x50, //1999 294
    	0x0C,0x96,0x45, //2000 297
    	0x4d,0x4A,0xB8, //2001 300
    	0x0d,0x4A,0x4C, //2002
    	0x0d,0xA5,0x41, //2003
    	0x25,0xAA,0xB6, //2004
    	0x05,0x6A,0x49, //2005
    	0x7A,0xAd,0xBd, //2006
    	0x02,0x5d,0x52, //2007
    	0x09,0x2d,0x47, //2008
    	0x5C,0x95,0xBA, //2009
    	0x0A,0x95,0x4e, //2010
    	0x0B,0x4A,0x43, //2011
    	0x4B,0x55,0x37, //2012
    	0x0A,0xd5,0x4A, //2013
    	0x95,0x5A,0xBf, //2014
    	0x04,0xBA,0x53, //2015
    	0x0A,0x5B,0x48, //2016
    	0x65,0x2B,0xBC, //2017
    	0x05,0x2B,0x50, //2018
    	0x0A,0x93,0x45, //2019
    	0x47,0x4A,0xB9, //2020
    	0x06,0xAA,0x4C, //2021
    	0x0A,0xd5,0x41, //2022
    	0x24,0xdA,0xB6, //2023
    	0x04,0xB6,0x4A, //2024
    	0x69,0x57,0x3d, //2025
    	0x0A,0x4e,0x51, //2026
    	0x0d,0x26,0x46, //2027
    	0x5e,0x93,0x3A, //2028
    	0x0d,0x53,0x4d, //2029
    	0x05,0xAA,0x43, //2030
    	0x36,0xB5,0x37, //2031
    	0x09,0x6d,0x4B, //2032
    	0xB4,0xAe,0xBf, //2033
    	0x04,0xAd,0x53, //2034
    	0x0A,0x4d,0x48, //2035
    	0x6d,0x25,0xBC, //2036
    	0x0d,0x25,0x4f, //2037
    	0x0d,0x52,0x44, //2038
    	0x5d,0xAA,0x38, //2039
    	0x0B,0x5A,0x4C, //2040
    	0x05,0x6d,0x41, //2041
    	0x24,0xAd,0xB6, //2042
    	0x04,0x9B,0x4A, //2043
    	0x7A,0x4B,0xBe, //2044
    	0x0A,0x4B,0x51, //2045
    	0x0A,0xA5,0x46, //2046
    	0x5B,0x52,0xBA, //2047
    	0x06,0xd2,0x4e, //2048
    	0x0A,0xdA,0x42, //2049
    	0x35,0x5B,0x37, //2050
    	0x09,0x37,0x4B, //2051
    	0x84,0x97,0xC1, //2052
    	0x04,0x97,0x53, //2053
    	0x06,0x4B,0x48, //2054
    	0x66,0xA5,0x3C, //2055
    	0x0e,0xA5,0x4f, //2056
    	0x06,0xB2,0x44, //2057
    	0x4A,0xB6,0x38, //2058
    	0x0A,0xAe,0x4C, //2059
    	0x09,0x2e,0x42, //2060
    	0x3C,0x97,0x35, //2061
    	0x0C,0x96,0x49, //2062
    	0x7d,0x4A,0xBd, //2063
    	0x0d,0x4A,0x51, //2064
    	0x0d,0xA5,0x45, //2065
    	0x55,0xAA,0xBA, //2066
    	0x05,0x6A,0x4e, //2067
    	0x0A,0x6d,0x43, //2068
    	0x45,0x2e,0xB7, //2069
    	0x05,0x2d,0x4B, //2070
    	0x8A,0x95,0xBf, //2071
    	0x0A,0x95,0x53, //2072
    	0x0B,0x4A,0x47, //2073
    	0x6B,0x55,0x3B, //2074
    	0x0A,0xd5,0x4f, //2075
    	0x05,0x5A,0x45, //2076
    	0x4A,0x5d,0x38, //2077
    	0x0A,0x5B,0x4C, //2078
    	0x05,0x2B,0x42, //2079
    	0x3A,0x93,0xB6, //2080
    	0x06,0x93,0x49, //2081
    	0x77,0x29,0xBd, //2082
    	0x06,0xAA,0x51, //2083
    	0x0A,0xd5,0x46, //2084
    	0x54,0xdA,0xBA, //2085
    	0x04,0xB6,0x4e, //2086
    	0x0A,0x57,0x43, //2087
    	0x45,0x27,0x38, //2088
    	0x0d,0x26,0x4A, //2089
    	0x8e,0x93,0x3e, //2090
    	0x0d,0x52,0x52, //2091
    	0x0d,0xAA,0x47, //2092
    	0x66,0xB5,0x3B, //2093
    	0x05,0x6d,0x4f, //2094
    	0x04,0xAe,0x45, //2095
    	0x4A,0x4e,0xB9, //2096
    	0x0A,0x4d,0x4C, //2097
    	0x0d,0x15,0x41, //2098
    	0x2d,0x92,0xB5  //2099
    };
    
    / 
    //         以下为24节气计算相关程序			   
    // 
    //    每年24节气标志表   
    //    有兴趣的朋友可按照上面给的原理添加其它年份的表格
    //    不是很清楚的朋友可给我发EMAIL		   
    /
    const uint8_t YearMonthBit[]=
    {
    	0x4E,0xA6,0x99,		//2000
    	0x9C,0xA2,0x98,		//2001
    	0x80,0x00,0x18,		//2002
    	0x00,0x10,0x24,		//2003
    	0x4E,0xA6,0x99,		//2004
    	0x9C,0xA2,0x98,		//2005
    	0x80,0x82,0x18,		//2006
    	0x00,0x10,0x24,		//2007
    	0x4E,0xA6,0xD9,		//2008
    	0x9E,0xA2,0x98,		//2009
    
    	0x80,0x82,0x18,		//2010
    	0x00,0x10,0x04,		//2011
    	0x4E,0xE6,0xD9,		//2012
    	0x9E,0xA6,0xA8,		//2013
    	0x80,0x82,0x18,		//2014
    	0x00,0x10,0x00,		//2015
    	0x0F,0xE6,0xD9,		//2016
    	0xBE,0xA6,0x98,		//2017
    	0x88,0x82,0x18,		//2018
    	0x80,0x00,0x00,		//2019
    
    	0x0F,0xEF,0xD9,		//2020
    	0xBE,0xA6,0x99,		//2021
    	0x8C,0x82,0x98,		//2022
    	0x80,0x00,0x00,		//2023
    	0x0F,0xEF,0xDB,		//2024
    	0xBE,0xA6,0x99,		//2025
    	0x9C,0xA2,0x98,		//2026
    	0x80,0x00,0x18,		//2027
    	0x0F,0xEF,0xDB,		//2028
    	0xBE,0xA6,0x99,		//2029
    
    	0x9C,0xA2,0x98,		//2030
    	0x80,0x00,0x18,		//2031
    	0x0F,0xEF,0xDB,		//2032
    	0xBE,0xA2,0x99,		//2033
    	0x8C,0xA0,0x98,		//2034
    	0x80,0x82,0x18,		//2035
    	0x0B,0xEF,0xDB,		//2036
    	0xBE,0xA6,0x99,		//2037
    	0x8C,0xA2,0x98,		//2038
    	0x80,0x82,0x18,		//2039
    
    	0x0F,0xEF,0xDB,		//2040
    	0xBE,0xE6,0xD9,		//2041 
    	0x9E,0xA2,0x98,		//2042
    	0x80,0x82,0x18,		//2043
    	0x0F,0xEF,0xFB,		//2044
    	0xBF,0xE6,0xD9,		//2045
    	0x9E,0xA6,0x98,		//2046
    	0x80,0x82,0x18,		//2047
    	0x0F,0xFF,0xFF,		//2048
    	0xFC,0xEF,0xD9,		//2049
    	0xBE,0xA6,0x18 		//2050
    };
    
    const uint8_t days[24]=
    {
    	6,20,4,19,6,21,         //一月到三月  的节气基本日期
    	5,20,6,21,6,21,         //四月到六月  的节气基本日期
    	7,23,8,23,8,23,         //七月到九月  的节气基本日期
    	8,24,8,22,7,22,         //十月到十二月的节气基本日期
    };
    
    //以公历日期先后排序
    const int8_t *JieQiStr[24]=   
    {
     // 名称        角度    公历日期     周期 //
    	"小寒",     //285     1月 6日
    	"大寒",     //300     1月20日    29.5天
    	"立春",     //315     2月 4日
    	"雨水",     //330     2月19日    29.8天
    	"惊蛰",     //345     3月 6日
    	"春分",     //  0     3月21日    30.2天
    	"清明",     // 15     4月 5日
    	"谷雨",     // 30     4月20日    30.7天
    	"立夏",     // 45     5月 6日
    	"夏满",     // 60     5月21日    31.2天
    	"芒种",     // 75     6月 6日
    	"夏至",     // 90     6月21日    31.4天
    	"小暑",     //105     7月 7日
    	"大暑",     //120     7月23日    31.4天
    	"立秋",     //135     8月 8日
    	"处暑",     //150     8月23日    31.1天
    	"白露",     //165     9月 8日
    	"秋分",     //180     9月23日    30.7天
    	"寒露",     //195    10月 8日
    	"霜降",     //210    10月24日    30.1天
    	"立冬",     //225    11月 8日
    	"小雪",     //240    11月22日    29.7天
    	"大雪",     //255    12月 7日
    	"冬至"      //270    12月22日    29.5天
    };
    
    //下部分数据是农历部分要使用的
    //月份数据表
    uint8_t  const day_code1[9]={0x0,0x1f,0x3b,0x5a,0x78,0x97,0xb5,0xd4,0xf3};
    unsigned short const day_code2[3]={0x111,0x130,0x14e};
    uint8_t const table_week[12]={0,3,3,6,1,4,6,2,5,0,3,5}; //月修正数据表
    uint8_t const *sky[10]=  {"甲","乙","丙","丁","戊","己","庚","辛","壬","癸",};//天干
    uint8_t const *earth[12]={"子","丑","寅","卯","辰","巳","午","未","申","酉","戌","亥",};//地支
    uint8_t const *monthcode[12]={"一","二","三","四","五","六","七","八","九","十","冬","腊",};//农历月份
    uint8_t const *nongliday[4]={"初","十","廿","三",};//农历日期  
    
    ///
    //支持从1900年到2099年的农历查询
    //支持从2000年到2050年的节气查询
    //子函数,用于读取数据表中农历月的大月或小月,如果该月为大返回1,为小返回0
    uint8_t GetMoonDay(uint8_t month_p,unsigned short table_addr)
    {
    	switch (month_p)
    	{
    		case 1:
    			if((year_code[table_addr]&0x08)==0)	return(0);
    			else 								return(1); 
    		case 2:
    			if((year_code[table_addr]&0x04)==0)	return(0);
    			else 								return(1);
    		case 3:
    			if((year_code[table_addr]&0x02)==0)	return(0);
    			else 								return(1);
    		case 4:
    			if((year_code[table_addr]&0x01)==0)	return(0);
    			else 								return(1);
    		case 5:
    			if((year_code[table_addr+1]&0x80)==0)	return(0);
    			else 									return(1);
    		case 6:
    			if((year_code[table_addr+1]&0x40)==0)	return(0);
    			else 									return(1);
    		case 7:
    			if((year_code[table_addr+1]&0x20)==0)	return(0);
    			else 									return(1);
    		case 8:
    			if((year_code[table_addr+1]&0x10)==0)	return(0);
    			else 									return(1);
    		case 9:
    			if((year_code[table_addr+1]&0x08)==0)	return(0);
    			else 									return(1);
    		case 10:
    			if((year_code[table_addr+1]&0x04)==0)	return(0);
    			else 									return(1);
    		case 11:
    			if((year_code[table_addr+1]&0x02)==0)	return(0);
    			else 									return(1);
    		case 12:
    			if((year_code[table_addr+1]&0x01)==0)	return(0);
    			else 									return(1);
    		case 13:
    			if((year_code[table_addr+2]&0x80)==0)	return(0);
    			else 									return(1);
    	}
    	return(0);
    }
    
    / 
    // 函数名称:GetChinaCalendar
    //功能描述:公农历转换(只允许1901-2099年)
    // 输 入:  year        公历年
    //          month       公历月
    //          day         公历日
    //          p           储存农历日期地址
    // 输 出:  1           成功
    //          0           失败																			 
    /
    uint8_t GetChinaCalendar(uint16_t  year,uint8_t month,uint8_t day,uint8_t *p)
    { 
    	uint8_t temp1,temp2,temp3,month_p,yearH,yearL;	
    	uint8_t flag_y;
    	unsigned short temp4,table_addr;
    
    	yearH=year/100;	yearL=year%100;//年份的高低两个字节 
    	if((yearH!=19)&&(yearH!=20))return(0);//日期不在19xx ~ 20xx 范围内,则退出
    	
    	// 定位数据表地址  
    	if(yearH==20)	table_addr=(yearL+100-1)*3;
    	else  			table_addr=(yearL-1)*3;
    
    	// 取当年春节所在的公历月份  
    	temp1=year_code[table_addr+2]&0x60;	
    	temp1>>=5;
    
    	// 取当年春节所在的公历日  
    	temp2=year_code[table_addr+2]&31; 
    
    	// 计算当年春年离当年元旦的天数,春节只会在公历1月或2月  
    	if(temp1==1) 	temp3=temp2-1; 
    	else 			temp3=temp2+31-1; 
    
    	// 计算公历日离当年元旦的天数  
    	if (month<10) 	temp4=day_code1[month-1]+day-1;
    	else  			temp4=day_code2[month-10]+day-1;
    	// 如果公历月大于2月并且该年的2月为闰月,天数加1  
    	if ((month>2)&&(yearL%4==0)) 	temp4++;
    
    	// 判断公历日在春节前还是春节后  
    	if (temp4>=temp3)
    	{ 						
    		temp4-=temp3;
    		month=1;
    		month_p=1;
    							
    		flag_y=0;
    		if(GetMoonDay(month_p,table_addr)==0)	temp1=29; //小月29天
    		else 									temp1=30; //大小30天
    		// 从数据表中取该年的闰月月份,如为0则该年无闰月  
    		temp2=year_code[table_addr]/16; 	
    		while(temp4>=temp1)
    		{
    			temp4-=temp1;
    			month_p++;
    			if(month==temp2)
    			{
    				flag_y=~flag_y;
    				if(flag_y==0)month++;
    			}
    			else month++;
    			if(GetMoonDay(month_p,table_addr)==0)	temp1=29;
    			else 									temp1=30;
    		}
    		day=temp4+1;
    	}
    	// 公历日在春节前使用下面代码进行运算  
    	else
    	{ 						
    		temp3-=temp4;
    		if (yearL==0)
    		{
    			yearL=100-1;
    			yearH=19;
    		}
    		else yearL--;
    		table_addr-=3;
    		month=12;
    		temp2=year_code[table_addr]/16; 	
    		if (temp2==0)	month_p=12; 
    		else 			month_p=13; 
    
    		flag_y=0;
    		if(GetMoonDay(month_p,table_addr)==0)	temp1=29; 
    		else 									temp1=30; 
    		while(temp3>temp1)
    		{
    			temp3-=temp1;
    			month_p--;
    			if(flag_y==0)		month--;
    			if(month==temp2)	flag_y=~flag_y;
    			if(GetMoonDay(month_p,table_addr)==0)	temp1=29;
    			else 									temp1=30;
    		}
    		day=temp1-temp3+1;
    	}
    
    	*p++=yearH;
    	*p++=yearL;
    	*p++=month;
    	*p=day;	
    	return(1);
    }
    
    //
    // 函数名称:GetSkyEarth
    // 功能描述:输入公历日期得到一个甲子年(只允许1901-2099年)
    // 输 入:  year        公历年
    //          p           储存星期地址
    // 输 出:  无																							   
    /
    void GetSkyEarth(uint16_t year,uint8_t *p)
    {
    	uint8_t x;
    	
    	if(year>=1984)
    	{
    		year=year-1984;
    		x=year%60;				
    	}
    	else
    	{
    		year=1984-year;
    		x=60-year%60;
    	}
    	*p=x;
    }
    //将指定字符source复制no个给target
    void StrCopy(uint8_t *target,uint8_t const *source,uint8_t no)
    {
    	uint16_t i;	 
    	for(i=0;i<no;i++)
    	{
    		*target++=*source++;
    	}
    }
    //
    // 函数名称:GetChinaCalendarStr
    // 功能描述:输入公历日期得到农历字符串	
    //          如:GetChinaCalendarStr(2007,02,06,str) 返回str="丙戌年腊月十九"
    // 输 入:  year        公历年
    //          month       公历月
    //          day         公历日
    //          str         储存农历日期字符串地址   15Byte
    // 输 出:  无																							  
    /
    void GetChinaCalendarStr(uint16_t year,uint8_t month,uint8_t day,uint8_t *str)
    {
    	uint8_t NLyear[4];
    	uint8_t SEyear;
    	
    	StrCopy(&str[0],(u8 *)"甲子年正月初一",15);
    	if(GetChinaCalendar(year,month,day,(u8 *)NLyear)==0)	return;
    	GetSkyEarth(NLyear[0]*100+NLyear[1],&SEyear);
    	StrCopy(&str[0],(u8 *)  sky[SEyear%10],2);	//  甲
    	StrCopy(&str[2],(u8 *)earth[SEyear%12],2);	//  子	
    	
    	if(NLyear[2]==1)	StrCopy(&str[6],(u8 *)"正",2);
    	else				StrCopy(&str[6],(u8 *)monthcode[NLyear[2]-1],2);		
    	
    	if(NLyear[3]>10) 	StrCopy(&str[10],(u8 *)nongliday[NLyear[3]/10],2);	
    	else				StrCopy(&str[10],(u8 *)"初",2);
    	StrCopy(&str[12],(u8 *)monthcode[(NLyear[3]-1)%10],2);
    }
    
    //
    // 函数名称:GetJieQi
    // 功能描述:输入公历日期得到本月24节气日期 day<15返回上半月节气,反之返回下半月	
    //          如:GetJieQiStr(2007,02,08,str) 返回str[0]=4
    // 输 入:  year        公历年
    //          month       公历月
    //          day         公历日
    //          str         储存对应本月节气日期地址   1Byte
    // 输 出:  1           成功
    //          0           失败																			  
    /
    u8 GetJieQi(u16 year,u8 month,u8 day,u8 *JQdate)
    {
    	u8 bak1,value,JQ;
    
    	if((year<2000)||(year>2050))     return 0;//节气表的范围限制
    	if((month==0) ||(month>12))      return 0;
    	JQ = (month-1) *2 ;		                        //获得节气顺序标号(0~23
    	if(day >= 15) JQ++; 	                        //判断是否是上半月
    
    	bak1=YearMonthBit[(year-2000)*3+JQ/8];          //获得节气日期相对值所在字节  
    	value =((bak1<<(JQ%8))&0x80);                   //获得节气日期相对值状态
    
    	*JQdate=days[JQ];								//得到基本节气日
    	if( value != 0 )
    	{
    		//判断年份,以决定节气相对值1代表1,还是-1。
    		if( (JQ== 1||JQ== 11||JQ== 18||JQ== 21)&&year< 2044)  (*JQdate)++;
    		else                                                  (*JQdate)--;
    	}
    	return 1;
    }
    static u8 const MonthDayMax[]={31,28,31,30,31,30,31,31,30,31,30,31,};
    //
    // 函数名称:GetJieQiStr
    // 功能描述:输入公历日期得到24节气字符串	
    //          如:GetJieQiStr(2007,02,08,str) 返回str="离雨水还有11天"
    // 输 入:  year        公历年
    //          month       公历月
    //          day         公历日
    //          str         储存24节气字符串地址   15Byte
    // 输 出:  1           成功
    //          0           失败																			  
    /
    u8 GetJieQiStr(u16 year,u8 month,u8 day,u8 *str)
    {
    	u8 JQdate,JQ,MaxDay;
    
    	if(GetJieQi(year,month,day,&JQdate)==0)	return 0;
    
    	JQ = (month-1) *2 ;                             //获得节气顺序标号(0~23
    	if(day >= 15) JQ++;                             //判断是否是上半月
    
    	if(day==JQdate)                                 //今天正是一个节气日
    	{
    		StrCopy(str,(u8 *)JieQiStr[JQ],5);
    		return 1;
    	}
    	                                                //今天不是一个节气日
    	StrCopy(str,(u8 *)"离立冬还有??天",15);
    	if(day<JQdate)                                  //如果今天日期小于本月的节气日期
    	{
    		StrCopy(&str[2],(u8 *)JieQiStr[JQ],4);
    		day=JQdate-day;
    	} 
    	else                                            //如果今天日期大于本月的节气日期
    	{
                 if((JQ+1) >23)  return 0;
    		StrCopy(&str[2],(u8 *)JieQiStr[JQ+1],4);
    		if(day < 15)
    		{
    			GetJieQi(year,month,15,&JQdate);
    			day=JQdate-day;
    		}
    		else                                        //翻月
    		{
    			MaxDay=MonthDayMax[month-1];
    			if(month==2)                            //润月问题
    			{
    				if((year%4==0)&&((year%100!=0)||(year%400==0))) MaxDay++;
    			}
    			if(++month==13)	month=1;
    			GetJieQi(year,month,1,&JQdate);
    			day=MaxDay-day+JQdate;
    		}
    	}
    	str[10]=day/10+'0';
    	str[11]=day%10+'0';
    	return 1;
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299
    • 300
    • 301
    • 302
    • 303
    • 304
    • 305
    • 306
    • 307
    • 308
    • 309
    • 310
    • 311
    • 312
    • 313
    • 314
    • 315
    • 316
    • 317
    • 318
    • 319
    • 320
    • 321
    • 322
    • 323
    • 324
    • 325
    • 326
    • 327
    • 328
    • 329
    • 330
    • 331
    • 332
    • 333
    • 334
    • 335
    • 336
    • 337
    • 338
    • 339
    • 340
    • 341
    • 342
    • 343
    • 344
    • 345
    • 346
    • 347
    • 348
    • 349
    • 350
    • 351
    • 352
    • 353
    • 354
    • 355
    • 356
    • 357
    • 358
    • 359
    • 360
    • 361
    • 362
    • 363
    • 364
    • 365
    • 366
    • 367
    • 368
    • 369
    • 370
    • 371
    • 372
    • 373
    • 374
    • 375
    • 376
    • 377
    • 378
    • 379
    • 380
    • 381
    • 382
    • 383
    • 384
    • 385
    • 386
    • 387
    • 388
    • 389
    • 390
    • 391
    • 392
    • 393
    • 394
    • 395
    • 396
    • 397
    • 398
    • 399
    • 400
    • 401
    • 402
    • 403
    • 404
    • 405
    • 406
    • 407
    • 408
    • 409
    • 410
    • 411
    • 412
    • 413
    • 414
    • 415
    • 416
    • 417
    • 418
    • 419
    • 420
    • 421
    • 422
    • 423
    • 424
    • 425
    • 426
    • 427
    • 428
    • 429
    • 430
    • 431
    • 432
    • 433
    • 434
    • 435
    • 436
    • 437
    • 438
    • 439
    • 440
    • 441
    • 442
    • 443
    • 444
    • 445
    • 446
    • 447
    • 448
    • 449
    • 450
    • 451
    • 452
    • 453
    • 454
    • 455
    • 456
    • 457
    • 458
    • 459
    • 460
    • 461
    • 462
    • 463
    • 464
    • 465
    • 466
    • 467
    • 468
    • 469
    • 470
    • 471
    • 472
    • 473
    • 474
    • 475
    • 476
    • 477
    • 478
    • 479
    • 480
    • 481
    • 482
    • 483
    • 484
    • 485
    • 486
    • 487
    • 488
    • 489
    • 490
    • 491
    • 492
    • 493
    • 494
    • 495
    • 496
    • 497
    • 498
    • 499
    • 500
    • 501
    • 502
    • 503
    • 504
    • 505
    • 506
    • 507
    • 508
    • 509
    • 510
    • 511
    • 512
    • 513
    • 514
    • 515
    • 516
    • 517
    • 518
    • 519
    • 520
    • 521
    • 522
    • 523
    • 524
    • 525
    • 526
    • 527
    • 528
    • 529
    • 530
    • 531
    • 532
    • 533
    • 534
    • 535
    • 536
    • 537
    • 538
    • 539
    • 540
    • 541
    • 542
    • 543
    • 544
    • 545
    • 546
    • 547
    • 548
    • 549
    • 550
    • 551
    • 552
    • 553
    • 554
    • 555
    • 556
    • 557
    • 558
    • 559
    • 560
    • 561
    • 562
    • 563
    • 564
    • 565
    • 566
    • 567
    • 568
    • 569
    • 570
    • 571
    • 572
    • 573
    • 574
    • 575
    • 576
    • 577
    • 578
    • 579
    • 580
    • 581
    • 582
    • 583
    • 584
    • 585
    • 586
    • 587
    • 588
    • 589
    • 590
    • 591
    • 592
    • 593
    • 594
    • 595
    • 596
    • 597
    • 598
    • 599
    • 600
    • 601
    • 602
    • 603
    • 604
    • 605
    • 606
    • 607
    • 608
    • 609
    • 610
    • 611
    • 612
    • 613
    • 614
    • 615
    • 616
    • 617
    • 618
    • 619
    • 620
    • 621
    • 622
    • 623
    • 624
    • 625
    • 626
    • 627
    • 628

    data.h

    /******************** (C) COPYRIGHT 2009 www.armjishu.com ************************
    * File Name          : date.h
    * Author             : www.armjishu.com Team
    * Version            : V1.0
    * Date               : 12/1/2009
    * Description        : 日期相关函数
    *******************************************************************************/
    #ifndef __DATE_H
    #define __DATE_H
    
    #include "stm32f10x.h"
    
    struct rtc_time {
    	int tm_sec;
    	int tm_min;
    	int tm_hour;
    	int tm_mday;
    	int tm_mon;
    	int tm_year;
    	int tm_wday;
    };
        
    void GregorianDay(struct rtc_time * tm);
    uint32_t mktimev(struct rtc_time *tm);
    void to_tm(uint32_t tim, struct rtc_time * tm);
    #endif 
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    data.c

    /**
      ******************************************************************************
      * @file    bsp_date.c
      * @author  移植自linux万年历
      * @version V1.0
      * @date    2013-xx-xx
      ******************************************************************************
      * @attention
      *
      * 实验平台:野火 F103-指南者 STM32 开发板 
      * 论坛    :http://www.firebbs.cn
      * 淘宝    :https://fire-stm32.taobao.com
      *
      ******************************************************************************
      */
    
    #include "./rtc/bsp_date.h"
    
    #define FEBRUARY		2
    #define	STARTOFTIME		1970
    #define SECDAY			86400L           /*  一天有多少s */
    #define SECYR			(SECDAY * 365)
    #define	leapyear(year)		((year) % 4 == 0)
    #define	days_in_year(a) 	(leapyear(a) ? 366 : 365)
    #define	days_in_month(a) 	(month_days[(a) - 1])
    
    static int month_days[12] = {	31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
    
    /*
     * This only works for the Gregorian calendar - i.e. after 1752 (in the UK)
     */
     /*计算公历*/
    void GregorianDay(struct rtc_time * tm)
    {
    	int leapsToDate;
    	int lastYear;
    	int day;
    	int MonthOffset[] = { 0,31,59,90,120,151,181,212,243,273,304,334 };
    
    	lastYear=tm->tm_year-1;
    
    	/*计算从公元元年到计数的前一年之中一共经历了多少个闰年*/
    	leapsToDate = lastYear/4 - lastYear/100 + lastYear/400;      
    
         /*如若计数的这一年为闰年,且计数的月份在2月之后,则日数加1,否则不加1*/
    	if((tm->tm_year%4==0) &&
    	   ((tm->tm_year%100!=0) || (tm->tm_year%400==0)) &&
    	   (tm->tm_mon>2)) {
    		/*
    		 * We are past Feb. 29 in a leap year
    		 */
    		day=1;
    	} else {
    		day=0;
    	}
    
    	day += lastYear*365 + leapsToDate + MonthOffset[tm->tm_mon-1] + tm->tm_mday; /*计算从公元元年元旦到计数日期一共有多少天*/
    
    	tm->tm_wday=day%7;
    }
    
    /* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
     * Assumes input in normal date format, i.e. 1980-12-31 23:59:59
     * => year=1980, mon=12, day=31, hour=23, min=59, sec=59.
     *
     * [For the Julian calendar (which was used in Russia before 1917,
     * Britain & colonies before 1752, anywhere else before 1582,
     * and is still in use by some communities) leave out the
     * -year/100+year/400 terms, and add 10.]
     *
     * This algorithm was first published by Gauss (I think).
     *
     * WARNING: this function will overflow on 2106-02-07 06:28:16 on
     * machines were long is 32-bit! (However, as time_t is signed, we
     * will already get problems at other places on 2038-01-19 03:14:08)
     *
     */
    u32 mktimev(struct rtc_time *tm)
    {
    	if (0 >= (int) (tm->tm_mon -= 2)) {	/* 1..12 -> 11,12,1..10 */
    		tm->tm_mon += 12;		/* Puts Feb last since it has leap day */
    		tm->tm_year -= 1;
    	}
    
    	return (((
    		(u32) (tm->tm_year/4 - tm->tm_year/100 + tm->tm_year/400 + 367*tm->tm_mon/12 + tm->tm_mday) +
    			tm->tm_year*365 - 719499
    	    )*24 + tm->tm_hour /* now have hours */
    	  )*60 + tm->tm_min /* now have minutes */
    	)*60 + tm->tm_sec; /* finally seconds */	 
    }
    
    
    
    void to_tm(u32 tim, struct rtc_time * tm)
    {
    	register u32    i;
    	register long   hms, day;
    
    	day = tim / SECDAY;			/* 有多少天 */
    	hms = tim % SECDAY;			/* 今天的时间,单位s */
    
    	/* Hours, minutes, seconds are easy */
    	tm->tm_hour = hms / 3600;
    	tm->tm_min = (hms % 3600) / 60;
    	tm->tm_sec = (hms % 3600) % 60;
    
    	/* Number of years in days */ /*算出当前年份,起始的计数年份为1970年*/
    	for (i = STARTOFTIME; day >= days_in_year(i); i++) {
    		day -= days_in_year(i);
    	}
    	tm->tm_year = i;
    
    	/* Number of months in days left */ /*计算当前的月份*/
    	if (leapyear(tm->tm_year)) {
    		days_in_month(FEBRUARY) = 29;
    	}
    	for (i = 1; day >= days_in_month(i); i++) {
    		day -= days_in_month(i);
    	}
    	days_in_month(FEBRUARY) = 28;
    	tm->tm_mon = i;
    
    	/* Days are what is left over (+1) from all that. *//*计算当前日期*/
    	tm->tm_mday = day + 1;
    
    	/*
    	 * Determine the day of week
    	 */
    	GregorianDay(tm);
    	
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134

    其他配置:

    在这里插入图片描述

    注意: 必须强调的是,使用 scanf 通过串口输入时,每次输入完毕后都要加入回车,这样才

    能正常接收,见图使用串口配置时间的注意事项 。

  • 相关阅读:
    大数据Doris(十八):演示单分区和复合分区
    数据可视化
    C语言基础知识入门
    区块链跨链技术
    基于SpringBoot的医疗预约服务管理系统
    智能座舱架构与芯片- (13) 软件篇 下
    微信小程序商城搭建二手汽车拍卖系统+后台管理系统|前后分离VUE.js
    STM32F4---PWM输出
    包溴丁苯酞PLGA纳米颗粒|葫芦素BE聚乳酸纳米微粒|长春新碱-槲皮素PLGA复方纳米粒
    在C++中怎么把std::string类型的数字转成int类型的数字
  • 原文地址:https://blog.csdn.net/C_say_easy_to_me/article/details/126473451