精华内容
下载资源
问答
  • 年份寄存器
    万次阅读 多人点赞
    2018-04-23 20:40:36

    STM32F1xx官方资料:

    《STM32中文参考手册V10》-第16章  实时时钟(RTC)

     

    RTC实时时钟

    RTC实时时钟简介

    实时时钟是一个独立的定时器。RTC模块拥有一组连续计数的计数器,在相应软件配置下,可提供时钟日历的功能。修改计数器的值可以重新设置系统当前的时间和日期。 RTC模块和时钟配置系统(RCC_BDCR寄存器)处于后备区域,即在系统复位或从待机模式唤醒后,RTC的设置和时间维持不变。 

    BKP备份寄存器简介

    备份寄存器是42个16位的寄存器,可用来存储84个字节的用户应用程序数据。他们处在备份域里,当Vdd电源被切断,他们仍然由Vbat维持供电。当系统在待机模式下被唤醒,或系统复位或电源复位时,他们也不会被复位。

    此外,BKP控制寄存器用来管理侵入检测和RTC校准功能。在本文中,使用备份寄存器来存储RTC的相关信息(标记时钟是否已经经过了配置)。

    复位后,对备份寄存器和RTC的访问被禁止,并且备份域被保护以防止可能存在的意外的写操作。执行以下操作可以使能对备份寄存器和RTC的访问。

    • 通过设置寄存器RCC_APB1ENR的PWREN和BKPEN位来打开电源和后备接口的时钟;
    • 电源控制寄存器(PWR_CR)的DBP位来使能对后备寄存器和RTC的访问。

    RTC实时时钟的主要特征

    • 可编程的预分频系数:分频系数最高为220;
    • 32位的可编程计数器,可用于较长时间段的测量;
    • 2个分离的时钟:用于APB1接口的PCLK1和RTC时钟(RTC时钟的频率必须小于PCLK1时钟频率的四分之一以上);
    • 可以选择以下三种RTC的时钟源:
    1. HSE时钟除以128;
    2. LSE振荡器时钟;
    3. LSI振荡器时钟;
    • 2个独立的复位类型:
    1. APB1接口由系统复位;
    2. RTC核心(预分频器、闹钟、计数器和分频器)只能由后备域复位;
    • 3个专门的可屏蔽中断:
    1. 闹钟中断,用来产生一个软件可编程的闹钟中断;
    2. 秒中断,用来产生一个可编程的周期性中断信号(最长可达1秒);
    3. 溢出中断,指示内部可编程计数器溢出并回转为0的状态。

     

    RTC工作原理

    RTC工作原理框图

    由工作框图可以看出,RTC由两部分组成:

    • APB1接口:用来和APB1总线相连。通过APB1接口可以访问RTC的相关寄存器(预分频值,计数器值,闹钟值)
    • RTC核心:由一组可编程计数器组成,分两个主要模块:
    1. RTC预分频模块,它可以编程产生最长1秒的RTC时间基TR_CLK。如果设置了秒中断允许位,可以产生秒中断;
    2. 32位的可编程计数器,可被初始化为当前时间。系统时间按TR_CLK周期累加并与存储在RTC_ALR寄存器中的可编程时间相比,当匹配时候如果设置了闹钟中断允许位,可以产生闹钟中断;如果溢出,可以产生溢出中断。

    复位过程

    • 除了RTC_PRL、RTC_ALR、RTC_CNT和RTC_DIV寄存器外,所有的系统寄存器都由系统复位或电源复位进行异步复位。
    • RTC_PRL、RTC_ALR、RTC_CNT和RTC_DIV寄存器仅能通过备份域复位信号复位。

    读RTC寄存器

    RTC内核完全独立于APB1接口,软件通过APB1接口对RTC相关寄存器访问。但是相关寄存器只在RTC APB1时钟进行重新同步的RTC时钟的上升沿被更新。所以软件必须先等待寄存器同步标志位(RTC_CRL的RSF位)被硬件置1才读。

    这意味着,如果APB1接口曾经被关闭,而读操作又是在刚刚重新开启APB1之后,则在第一次的内部寄存器更新之前,从APB1上读出的RTC寄存器数值可能被破坏了(通常读到0)。简单地讲,在APB1接口被禁止(复位、无时钟或断电)的情况下,RTC核仍保持运行状态。接着,重新打开APB1接口,此时必须等待RTC_CRL寄存器中的RSF位(寄存器同步标志)被硬件置1,同步之后,读RTC寄存器的值才不会有误。

    因此,若在读取RTC寄存器时,RTC的APB1接口曾经处于禁止状态,则软件首先必须等待RTC_CRL寄存器的RSF位被硬件置1。

    写RTC寄存器

    必须设置RTC_CRL寄存器中的CNF位,使RTC进入配置模式后,才能写入RTC_PRL、RTC_CNT、RTC_ALR寄存器。

    另外,对RTC任何寄存器的写操作,都必须在前一次写操作结束后进行。可以通过查询RTC_CR寄存器中的RTOFF状态位,判断RTC寄存器是否处于更新中。仅当RTOFF状态位是1时,才可以写入RTC寄存器。

     

    RTC相关配置寄存器

    RTC控制寄存器高位(RTC_CRH)

    作用:配置3个专门的可屏蔽中断(溢出中断、闹钟中断、秒中断)使能。

    RTC控制寄存器低位(RTC_CRL)

    作用:RTC操作是否完成判断、配置模式判断、寄存器同步判断、3个中断的标志位。

    这个寄存器尤其重要(尤其是位5、位4、位3):

    • 写任何寄存器之前,必须判断上一次写操作已经结束,也就是判断RTOFF位是否置1;
    • 写CNT、ALR、PRL寄存器,必须先配置CNF位进入配置模式,修改完之后,设置CNF位为0退出配置模式;
    • 读任何寄存器,必须先判断RSF位,确定已经同步。

    RTC预分频装载寄存器(RTC_PRLH、RTC_PRLL)

    作用:配置RTC预分频装载值,这个值是20bit长度。

    根据这个寄存器的值可以确定,TR_CLK和RTCCLK之间的关系公式:

    fTR_CLK=fRTCCLK/(PRL+1)

    如果输入时钟频率是32.768kHz(fRTCCLK,也就是以LSE作为时钟源),这个寄存器中写入7FFFh(32767)可获得周期为1秒钟的信号。

    RTC预分频器余数寄存器(RTC_DIVH、RTC_DIVL)

    作用:获得预分频计数器的当前值,也就是从RTC预分频装载寄存器倒数到0之间的一个值(以RTCCLK为时钟)。

    RTC计数器寄存器(RTC_CNTH、RTC_CNTL)

    作用:存放计数器内的计数值(以TR_CLK为时钟)。

    注意:由于RTC预分频器余数寄存器以RTCCLK为时钟,而RTC计数器寄存器以TR_CLK为时钟,而RTCCLK的时钟通常远远大于TR_CLK,所以利用RTC预分频器余数寄存器可以获得更准确的控制。比如,RTC计数器寄存器存储当前时间,精确到秒;但是利用由于RTC预分频器余数寄存器,可以在RTC预分频装载寄存器倒数到0的平均数处停下,从而达到0.5秒的更精确时间。

    RTC闹钟寄存器(RTC_ALRH、RTC_ALRL)

    作用:当RTC计数器寄存器的值与RTC闹钟寄存器的值相等的时候,触发一个闹钟事件,产生一个闹钟中断。

     

    读写RTC寄存器的步骤

    读RTC寄存器

    • 查询RSF位(寄存器同步标志位),直至RSF的值变成1;
    • 对一个或多个RTC寄存器进行读操作。

    写RTC寄存器

    • 查询RTOFF位(RTC操作关闭位),直到RTOFF的值变为1 ;
    • 置CNF位(配置标志位)值为1,进入配置模式(仅仅PRL、CNT、ALR寄存器);
    • 对一个RTC寄存器进行写操作;
    • 清除CNF标志位,退出配置模式(仅仅PRL、CNT、ALR寄存器);
    • 查询RTOFF,直至RTOFF位变为1以确认写操作已经完成。

    也就是说:对寄存器的写操作,无论是设置中断使能等等,每操作一次就需要查询一次RTOFF位。而对于PRL、CNT、ALR寄存器,还需要进入配置模式,这个就没有必要每操作一次就退出配置模式,可以等都配置完成了再退出。

     

    RTC相关配置库函数

    • 2个时钟源操作函数
    void RCC_RTCCLKConfig(uint32_t RCC_RTCCLKSource);
    void RCC_RTCCLKCmd(FunctionalState NewState);

    作用:确定RTC的时钟源,使能RTC时钟(通常选用LSE时钟源)。

    • 3个参数配置函数
    void RTC_SetCounter(uint32_t CounterValue);
    void RTC_SetPrescaler(uint32_t PrescalerValue);
    void RTC_SetAlarm(uint32_t AlarmValue);

    作用:配置预分频装载寄存器的值、计数器的值、闹钟配置。

    • 1个中断配置函数
    void RTC_ITConfig(uint16_t RTC_IT, FunctionalState NewState);

    作用:配置RTC中断的选择和使能。

    • 2个配置模式函数
    void RTC_EnterConfigMode(void);
    void RTC_ExitConfigMode(void);

    作用:前者允许RTC配置,后者退出配置模式。

    • 2个同步函数
    void RTC_WaitForLastTask(void);
    void RTC_WaitForSynchro(void);

    作用:前者等待上次操作完成(CRL寄存器的RTOFF位),后者等待时钟同步(CRL寄存器的RSF位)。

    • 4个状态位函数
    FlagStatus RTC_GetFlagStatus(uint16_t RTC_FLAG);
    void RTC_ClearFlag(uint16_t RTC_FLAG);
    ITStatus RTC_GetITStatus(uint16_t RTC_IT);
    void RTC_ClearITPendingBit(uint16_t RTC_IT);

    作用:前两者获取(或清除)状态标志位,后两者为获取(或清除)中断状态标志位。

    • 其他的相关函数
    void PWR_BackupAccessCmd(FunctionalState NewState);
    void RCC_APB1PeriphClockCmd(uint32_t RCC_APB1Periph, FunctionalState NewState);
    void RCC_LSEConfig(uint8_t RCC_LSE);

    作用:第一个函数使能BKP后备区域访问使能,第二个函数使能PWR和BKP时钟,第三个函数开启LSE时钟(这里为什么使用这几个函数?是在上文:BKP备份寄存器简介中讲到)。

    void BKP_WriteBackupRegister(uint16_t BKP_DR, uint16_t Data);
    uint16_t BKP_ReadBackupRegister(uint16_t BKP_DR);

    作用:上面的PWR_BackupAccessCmd()函数使能BKP后备区域使能之后,就可以通过这两个函数来读BKP的寄存器,写BKP的寄存器。

     

    RTC一般步骤

    • 使能PWR和BKP时钟。调用函数:RCC_APB1PeriphClockCmd();
    • 使能后备寄存器访问。调用函数:PWR_BackupAccessCmd();
    • 配置RTC时钟源,使能RTC时钟。调用函数:RCC_RTCCLKConfig();RCC_RTCCLKCmd();
    • 如果使用LSE,要打开LSE:RCC_LSEConfig(RCC_LSE_ON);
    • 设置RTC预分频系数。调用函数:RTC_SetPrescaler();
    • 设置时间。调用函数:RTC_SetCounter();
    • 开启相关中断(如果需要)。调用函数:RTC_ITConfig();
    • 编写中断服务函数。调用函数:RTC_IRQHandler();
    • 部分操作要等待写操作完成和同步。调用函数:RTC_WaitForLastTask();RTC_WaitForSynchro()。

    下面按照这个一般步骤来进行一个简单的RTC程序:

    //时间结构体
    typedef struct 
    {
    	vu8 hour;
    	vu8 min;
    	vu8 sec;			
    	//公历日月年周
    	vu16 w_year;
    	vu8  w_month;
    	vu8  w_date;
    	vu8  week;		 
    }_calendar_obj;	
    _calendar_obj calendar;//时钟结构体 
     
    static void RTC_NVIC_Config(void)
    {	
        NVIC_InitTypeDef NVIC_InitStructure;
    	NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn;		//RTC全局中断
    	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;	//先占优先级1位,从优先级3位
    	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;	//先占优先级0位,从优先级4位
    	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;		//使能该通道中断
    	NVIC_Init(&NVIC_InitStructure);		//根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
    }
    
    //实时时钟配置
    //初始化RTC时钟,同时检测时钟是否工作正常
    //BKP->DR1用于保存是否第一次配置的设置
    //返回0:正常
    //其他:错误代码
    
    u8 RTC_Init(void)
    {
    	//检查是不是第一次配置时钟
    	u8 temp=0;
    	RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);	//使能PWR和BKP外设时钟   
    	PWR_BackupAccessCmd(ENABLE);	//使能后备寄存器访问  
    	
    	if (BKP_ReadBackupRegister(BKP_DR1) != 0x5050)		//从指定的后备寄存器中读出数据:读出了与写入的指定数据不相乎
    		{	 			
    		BKP_DeInit();	//复位备份区域 	
    			
    		RCC_LSEConfig(RCC_LSE_ON);	//设置外部低速晶振(LSE),使用外设低速晶振
    		while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET&&temp<250)	//检查指定的RCC标志位设置与否,等待低速晶振就绪
    			{
    			temp++;
    			delay_ms(10);
    			}
    		if(temp>=250)return 1;//初始化时钟失败,晶振有问题	    
    			
    		RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);		//设置RTC时钟(RTCCLK),选择LSE作为RTC时钟    
    		RCC_RTCCLKCmd(ENABLE);	//使能RTC时钟  
    			
    		RTC_WaitForLastTask();	//等待最近一次对RTC寄存器的写操作完成
    		RTC_WaitForSynchro();		//等待RTC寄存器同步  
    		RTC_ITConfig(RTC_IT_SEC, ENABLE);		//使能RTC秒中断
    		RTC_WaitForLastTask();	//等待最近一次对RTC寄存器的写操作完成
    			
    		RTC_EnterConfigMode();/// 允许配置	
    		RTC_SetPrescaler(32767); //设置RTC预分频的值
    		RTC_WaitForLastTask();	//等待最近一次对RTC寄存器的写操作完成
    			
    		RTC_Set(2015,1,14,17,42,55);  //设置时间	
    		RTC_ExitConfigMode(); //退出配置模式  
    			
    		BKP_WriteBackupRegister(BKP_DR1, 0X5050);	//向指定的后备寄存器中写入用户程序数据
    		}
    	else//系统继续计时
    		{
    		RTC_WaitForLastTask();	//等待最近一次对RTC寄存器的写操作完成
    		RTC_ITConfig(RTC_IT_SEC, ENABLE);	//使能RTC秒中断
    		RTC_WaitForLastTask();	//等待最近一次对RTC寄存器的写操作完成
    		}
    		
    	RTC_NVIC_Config();//RCT中断分组设置		    				     
    	RTC_Get();//更新时间	
    	return 0; //ok
    
    }		 				    
    //RTC时钟中断
    //每秒触发一次  
    //extern u16 tcnt; 
    void RTC_IRQHandler(void)
    {		 
    	if (RTC_GetITStatus(RTC_IT_SEC) != RESET)//秒钟中断
    	{							
    		RTC_Get();//更新时间   
     	}
    	if(RTC_GetITStatus(RTC_IT_ALR)!= RESET)//闹钟中断
    	{
    		RTC_ClearITPendingBit(RTC_IT_ALR);		//清闹钟中断	  	
    	  RTC_Get();				//更新时间   
      	printf("Alarm Time:%d-%d-%d %d:%d:%d\n",calendar.w_year,calendar.w_month,calendar.w_date,calendar.hour,calendar.min,calendar.sec);//输出闹铃时间	
    		
      	} 				  								 
    	RTC_ClearITPendingBit(RTC_IT_SEC|RTC_IT_OW);		//清闹钟中断
    	RTC_WaitForLastTask();	  	    						 	   	 
    }
    //判断是否是闰年函数
    //月份   1  2  3  4  5  6  7  8  9  10 11 12
    //闰年   31 29 31 30 31 30 31 31 30 31 30 31
    //非闰年 31 28 31 30 31 30 31 31 30 31 30 31
    //输入:年份
    //输出:该年份是不是闰年.1,是.0,不是
    u8 Is_Leap_Year(u16 year)
    {			  
    	if(year%4==0) //必须能被4整除
    	{ 
    		if(year%100==0) 
    		{ 
    			if(year%400==0)return 1;//如果以00结尾,还要能被400整除 	   
    			else return 0;   
    		}else return 1;   
    	}else return 0;	
    }	 			   
    //设置时钟
    //把输入的时钟转换为秒钟
    //以1970年1月1日为基准
    //1970~2099年为合法年份
    //返回值:0,成功;其他:错误代码.
    //月份数据表											 
    u8 const table_week[12]={0,3,3,6,1,4,6,2,5,0,3,5}; //月修正数据表	  
    //平年的月份日期表
    const u8 mon_table[12]={31,28,31,30,31,30,31,31,30,31,30,31};
    u8 RTC_Set(u16 syear,u8 smon,u8 sday,u8 hour,u8 min,u8 sec)
    {
    	u16 t;
    	u32 seccount=0;
    	if(syear<1970||syear>2099)return 1;	   
    	for(t=1970;t<syear;t++)	//把所有年份的秒钟相加
    	{
    		if(Is_Leap_Year(t))seccount+=31622400;//闰年的秒钟数
    		else seccount+=31536000;			  //平年的秒钟数
    	}
    	smon-=1;
    	for(t=0;t<smon;t++)	   //把前面月份的秒钟数相加
    	{
    		seccount+=(u32)mon_table[t]*86400;//月份秒钟数相加
    		if(Is_Leap_Year(syear)&&t==1)seccount+=86400;//闰年2月份增加一天的秒钟数	   
    	}
    	seccount+=(u32)(sday-1)*86400;//把前面日期的秒钟数相加 
    	seccount+=(u32)hour*3600;//小时秒钟数
        seccount+=(u32)min*60;	 //分钟秒钟数
    	seccount+=sec;//最后的秒钟加上去
    
    	RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);	//使能PWR和BKP外设时钟  
    	PWR_BackupAccessCmd(ENABLE);	//使能RTC和后备寄存器访问 
    	RTC_SetCounter(seccount);	//设置RTC计数器的值
    
    	RTC_WaitForLastTask();	//等待最近一次对RTC寄存器的写操作完成  	
    	return 0;	    
    }
    
    //初始化闹钟		  
    //以1970年1月1日为基准
    //1970~2099年为合法年份
    //syear,smon,sday,hour,min,sec:闹钟的年月日时分秒   
    //返回值:0,成功;其他:错误代码.
    u8 RTC_Alarm_Set(u16 syear,u8 smon,u8 sday,u8 hour,u8 min,u8 sec)
    {
    	u16 t;
    	u32 seccount=0;
    	if(syear<1970||syear>2099)return 1;	   
    	for(t=1970;t<syear;t++)	//把所有年份的秒钟相加
    	{
    		if(Is_Leap_Year(t))seccount+=31622400;//闰年的秒钟数
    		else seccount+=31536000;			  //平年的秒钟数
    	}
    	smon-=1;
    	for(t=0;t<smon;t++)	   //把前面月份的秒钟数相加
    	{
    		seccount+=(u32)mon_table[t]*86400;//月份秒钟数相加
    		if(Is_Leap_Year(syear)&&t==1)seccount+=86400;//闰年2月份增加一天的秒钟数	   
    	}
    	seccount+=(u32)(sday-1)*86400;//把前面日期的秒钟数相加 
    	seccount+=(u32)hour*3600;//小时秒钟数
        seccount+=(u32)min*60;	 //分钟秒钟数
    	seccount+=sec;//最后的秒钟加上去 			    
    	//设置时钟
    	RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);	//使能PWR和BKP外设时钟   
    	PWR_BackupAccessCmd(ENABLE);	//使能后备寄存器访问  
    	//上面三步是必须的!
    	
    	RTC_SetAlarm(seccount);
     
    	RTC_WaitForLastTask();	//等待最近一次对RTC寄存器的写操作完成  	
    	
    	return 0;	    
    }
    
    
    //得到当前的时间
    //返回值:0,成功;其他:错误代码.
    u8 RTC_Get(void)
    {
    	static u16 daycnt=0;
    	u32 timecount=0; 
    	u32 temp=0;
    	u16 temp1=0;	  
        timecount=RTC_GetCounter();	 
     	temp=timecount/86400;   //得到天数(秒钟数对应的)
    	if(daycnt!=temp)//超过一天了
    	{	  
    		daycnt=temp;
    		temp1=1970;	//从1970年开始
    		while(temp>=365)
    		{				 
    			if(Is_Leap_Year(temp1))//是闰年
    			{
    				if(temp>=366)temp-=366;//闰年的秒钟数
    				else {temp1++;break;}  
    			}
    			else temp-=365;	  //平年 
    			temp1++;  
    		}   
    		calendar.w_year=temp1;//得到年份
    		temp1=0;
    		while(temp>=28)//超过了一个月
    		{
    			if(Is_Leap_Year(calendar.w_year)&&temp1==1)//当年是不是闰年/2月份
    			{
    				if(temp>=29)temp-=29;//闰年的秒钟数
    				else break; 
    			}
    			else 
    			{
    				if(temp>=mon_table[temp1])temp-=mon_table[temp1];//平年
    				else break;
    			}
    			temp1++;  
    		}
    		calendar.w_month=temp1+1;	//得到月份
    		calendar.w_date=temp+1;  	//得到日期 
    	}
    	temp=timecount%86400;     		//得到秒钟数   	   
    	calendar.hour=temp/3600;     	//小时
    	calendar.min=(temp%3600)/60; 	//分钟	
    	calendar.sec=(temp%3600)%60; 	//秒钟
    	calendar.week=RTC_Get_Week(calendar.w_year,calendar.w_month,calendar.w_date);//获取星期   
    	return 0;
    }	 
    //获得现在是星期几
    //功能描述:输入公历日期得到星期(只允许1901-2099年)
    //输入参数:公历年月日 
    //返回值:星期号																						 
    u8 RTC_Get_Week(u16 year,u8 month,u8 day)
    {	
    	u16 temp2;
    	u8 yearH,yearL;
    	
    	yearH=year/100;	yearL=year%100; 
    	// 如果为21世纪,年份数加100  
    	if (yearH>19)yearL+=100;
    	// 所过闰年数只算1900年之后的  
    	temp2=yearL+yearL/4;
    	temp2=temp2%7; 
    	temp2=temp2+day+table_week[month-1];
    	if (yearL%4==0&&month<3)temp2--;
    	return(temp2%7);
    }			  
    
     int main(void)
     {	 
     	u8 t=0;	
    	delay_init();	    	 //延时函数初始化	  
    	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级
    	uart_init(115200);	 	//串口初始化为115200
     	LED_Init();			     //LED端口初始化
    	LCD_Init();			 	
    	usmart_dev.init(SystemCoreClock/1000000);	//初始化USMART	
    	RTC_Init();	  			//RTC初始化
    	POINT_COLOR=RED;//设置字体为红色 
    	LCD_ShowString(60,50,200,16,16,"WarShip STM32");	
    	LCD_ShowString(60,70,200,16,16,"RTC TEST");	
    	LCD_ShowString(60,90,200,16,16,"ATOM@ALIENTEK");
    	LCD_ShowString(60,110,200,16,16,"2015/1/14");		
    	//显示时间
    	POINT_COLOR=BLUE;//设置字体为蓝色
    	LCD_ShowString(60,130,200,16,16,"    -  -  ");	   
    	LCD_ShowString(60,162,200,16,16,"  :  :  ");		    
    	while(1)
    	{								    
    		if(t!=calendar.sec)
    		{
    			t=calendar.sec;
    			LCD_ShowNum(60,130,calendar.w_year,4,16);									  
    			LCD_ShowNum(100,130,calendar.w_month,2,16);									  
    			LCD_ShowNum(124,130,calendar.w_date,2,16);	 
    			switch(calendar.week)
    			{
    				case 0:
    					LCD_ShowString(60,148,200,16,16,"Sunday   ");
    					break;
    				case 1:
    					LCD_ShowString(60,148,200,16,16,"Monday   ");
    					break;
    				case 2:
    					LCD_ShowString(60,148,200,16,16,"Tuesday  ");
    					break;
    				case 3:
    					LCD_ShowString(60,148,200,16,16,"Wednesday");
    					break;
    				case 4:
    					LCD_ShowString(60,148,200,16,16,"Thursday ");
    					break;
    				case 5:
    					LCD_ShowString(60,148,200,16,16,"Friday   ");
    					break;
    				case 6:
    					LCD_ShowString(60,148,200,16,16,"Saturday ");
    					break;  
    			}
    			LCD_ShowNum(60,162,calendar.hour,2,16);									  
    			LCD_ShowNum(84,162,calendar.min,2,16);									  
    			LCD_ShowNum(108,162,calendar.sec,2,16);
    			LED0=!LED0;
    		}	
    		delay_ms(10);								  
    	};  
     }

    STM32控制程序分析

    RTC_Init()函数:RTC初始化函数。

    按照之前的RTC一般步骤初始化RTC函数,这里需要注意的是,为了区分是否是第一次执行RTC_Init()函数,这里使用了一个flag(向BKP_DR1寄存器写入0x5050,当然写入其他的数字也都是可以的)。

    if (BKP_ReadBackupRegister(BKP_DR1) != 0x5050)		//从指定的后备寄存器中读出数据:读出了与写入的指定数据不相乎
    		{	 			
    		//第一次执行RTC_Init
    		BKP_WriteBackupRegister(BKP_DR1, 0X5050);	//向指定的后备寄存器中写入用户程序数据
    		}
    	else//系统继续计时
    		{
    		//不是第一次执行RTC_Init
    		}

    为什么要区分是否第一次执行RTC_Init呢?因为如果由于断电等因素,程序中断,但是RTC时钟却还是在执行中;等恢复供电,重新启动程序,这个时候就不需要再对RTC时钟进行初始化了。

    同时,设置外部低速晶振(LSE),使用外设低速晶振。需要检查指定的RCC标志位设置与否,等待低速晶振就绪。

    这里时间的设置是:距离1970年1月1日0点0分0秒的时间距离。其中,RTC_Get()、RTC_Set()等函数的内容涉及到时间距离转换的各种算法,就不在本文的讨论范围了。

     

    更多相关内容
  • SD卡的接口中定义了8个寄存器:OCR,CID,CSD,RCA,DSR,SCR,SSR,CSR。

    1.SD卡寄存器

    SDIO接口中定义了8个寄存器:OCRCIDCSDRCADSRSCRSSR(仅sdio卡支持),CSR(仅sdio卡支持)。
    这些寄存器只能通过对应的命令访问
    其中OCR,CID,CSD,SCR寄存器保存了卡/内容的特定信息,RCA和DSR寄存器是配置寄存器,存储当前的配置参数。
    为了使能扩展功能,寄存器的保留位卡应该返回 0
    在这里插入图片描述
    注意:RCA在SPI模式下不可用。

    1.1操作条件寄存器——OCR

    32位的操作条件寄存器(OCR)存储了卡的VDD电压描述和2个状态信息位。
    包含了Vdd支持电压,并且包含了card的状态信息,用以表示该card是否power up,以及表示card是否为大容量和标准容量。
    在这里插入图片描述
    bit 7是新定义的,用于双电压卡默认设置为0。如果双电压卡没有收到CMD 8,则该位为0,如果收到CMD 8,则该位为1。
    bit 31-卡上电状态位,这个状态位在卡的上电流程完成后设置。
    bit 30-卡容量状态位,如果是SDHC或SDXC,设置为1,如果是SDSC,设置为0。卡容量状态位只有在上电流程完成,且bit 31设置为1之后才有效。主机应该读取这个状态位来判断卡的种类

    1.2卡识别寄存器——CID

    在这里插入图片描述
    ·MID
    一个用于识别卡厂商的8-bit二进制数。MID号由SD-3C,LLC.(松下,闪迪和东芝成立的公司)控制、定义和分配给SD卡厂商。此过程用以保证CID 寄存器的唯一性。

    ·OID
    一个用以识别卡的OEM和/或卡内容(当ROM或FLASH卡被用作发布媒介时)的2字符的ASCII字符串。OID 号由SD-3C,LLC控制、定义和分配给SD 卡厂家。此过程用以保证CID 寄存器的唯一性。

    注意:SD-3C,LLC给想要生产和/或者销售SD卡的公司授权,包括但不限于Flash记忆卡,ROM,OTP,RAM和SDIO Combo卡。

    ·PNM
    产品名,5字符的ASCII字符串。

    ·PRV
    产品版本由两个二进制编码的十进制(BCD)数字,每个占4 bit,代表一个"n.m"版本号。"n"在高半字节,"m"是在低半字节。
    例如,产品版本"6.2"的PRV二进制值域为:0110 0010b

    ·PSN
    序列号,32位二进制数。

    ·MDT
    出厂日期由两个16进制数组成,一个8bit 代表年份(y),另外4bit 代表月份(m)。
    "m"域是月份码。1为一月份。
    "y"域是年份码。0为2000。
    例如,出厂日期"April 2001"对应的日期域的二进制值为:00000001 0100。

    ·CRC
    CRC7校验和(7bit),这是对CID 内容计算的校验和。

    1.3特定数据寄存器——CSD

    特定数据寄存器——CSD(card specific data register)
    通过发送CMD9命令来读取CSD

    CSD分为V1.0和V2.0两个版本,其中V2.0只适用于高容量SD卡,本文也是以V2.0为参考。
    插入的区域名字是固定值,并且主机不一定要求涉及这些区域。这些区域的固定值使主机保持对CSD V1.0的兼容。
    单元类型区域中,R=可读,W(1) =写一次,W=反复写。
    在这里插入图片描述
    ·CSD_STRUCTURE
    记录了 CSD 的版本号,CSD version 1.0 为标准容量卡所用,CSD version 2.0 为大容量或超大容量卡所用。·
    在这里插入图片描述

    最大数据传速速率(TRAN_SPEED)
    对于标准SD卡,这个区域值应该总是00110010b(32h),这个等于25Mhz, 是强制的SD卡最大操作频率。
    对于高速卡来说,这个值应该是01011010b(5Ah),这个值代表50Mhz,当时序通过CMD 6和CMD 0命令回到默认的时候,这个值会重新设置为032h。

    ·卡命令类(CCC)
    表示卡支持的命令类,class0~11。
    一个CCC 中的一位值为1表明支持对应的命令分类。
    在这里插入图片描述

    ·读数据块最大长度(READ_BL_LEN)
    其值固定为9h,代表READ_BL_LEN=512byte。

    ·READ_BL_PARTIAL
    这个值固定为0,表明不允许部分块读操作,只能按块进行访问。

    ·WRITE_BLK_MISALIGN
    这个值固定为0,表明高容量卡中,写操作不允许越过物理块边界

    ·READ_BLK_MISALIGN
    这个值固定为0,表明高容量卡中,读操作不允许越过物理块边界

    ·DSR _IMP
    定义是否可配置驱动阶段在卡上整合了。如果设置了,驱动阶段寄存器(DSR) 就应该使用,0一不实现DSR,1一实现DSR。

    ·C_SIZE
    这个值有22bit,可以支持最大到2Tbyte(和通过32Bit块地址指定的最大存储空间一致) 这个参数是用来计算sd卡的用户数据区域容量的(不包括保护区域)。公式如下:
    memory capacity = (C_SIZE+1) * 512K byte。
    鉴于V 2.0支持的最大容量是32GB,超过6bit的部分都设置为0.

    ·ERASE_BLK_EN
    这个值固定为1,代表着主机可以擦除1个或者多个512字节单位。

    ·SECTOR_SIZE
    这个值固定是7Fh,这个代表64字节。这个值同擦除操作没关系。V2.0的卡通过AU尺寸来表明存储边界,不用这个值。

    ·WP_GRP_SIZE
    这个值固定是0,高容量SD卡不支持写保护组。

    ·WP_GRP_ENABLE
    这个值固定为0,高容量卡不支持写保护组。

    ·R2W_FACTOR
    这个值固定是2h, 代表4倍。写超时可以通过读访问时间和R2W_FACTOR的乘积计算。但是,对于写超时,主机不应该用这个参数,而是应该用固定的250ms。

    ·WRITE_BL_LEN
    这个值固定是9h,代表WRITE_BL_LEN=512Byte。

    ·WRITE_BL_PARTIAL
    这个值固定是0,表明部分块写不支持,值支持块整数倍的写操作。

    ·FILE_FORMAT_GRP
    这个值固定是0,主机不应该使用这个值。

    ·COPY
    定义是否内容是原始的(0) ,或者是拷贝的(1)。拷贝位对于销售到终端用户的OTP和MTP设备来说是设置为1的,这表明卡的内容是拷贝的。拷贝位是一次性编程位。

    ·PERM_WRITE_PROTECT
    永久保护整个卡内容,不允许写和擦除(所有相关命令都无效)。默认值是0,非永久写保护。

    ·TMP_WRITE_PROTECT
    临时保护卡的内容,不允许写和擦除(所有相关命令都临时无效)。这个值可以设置和复位,默认值是0,非写保护。

    ·FILE_FORMAT
    这个值固定为0,主机不应该使用这个值

    1.4相对地址寄存器——RCA

    相对地址寄存器——RCA(relative card address register)
    可写的16位卡相对地址寄存器,在卡的初始化期间,由卡向外发布的卡地址。这个地址用于卡初始化进程之后,主机同卡之间的交互寻址。
    默认的RCA寄存器值是0x0000,这个值保留着,用来通过CMD 7设置所有卡到standby状态。
    卡的RCA地址如何确定???根据是什么???
    RCA地址默认值为0x0000,在卡识别过程中,接收到CMD 3命令后,由SD卡给自己动态分配的暂时的16bit非零值。每次接收CMD 3后,重新分配地址。

    1.5驱动阶段寄存器——DSR

    驱动阶段寄存器——DSR(driver stage register)
    16位驱动阶段寄存器,是可选的,可以用来在扩展操作条件中,提高总线性能(受总线长度,传输速率和卡数目的影响)。CSD寄存器中有DSR寄存器是否使用的标志。DSR默认值是0x404。

    1.6SD配置寄存器——SCR

    64bit的SD配置寄存器作为CSD寄存器的补充,提供了SD卡的特殊功能的信息。
    在这里插入图片描述
    ·DATA_STAT_AFTER_ERASE
    定义了擦除之后的数据状态,可能是0或者1,由厂家定义。

    ·SD BUS WIDTHS
    描述了卡支持的所有DAT总线宽度,如表所示。SD卡最少应该支持1bit和4bit的宽度,所以SD卡的bit 0和bit 2必须有一个为1。
    在这里插入图片描述

    1.7SD状态寄存器——SSR

    SD状态寄存器——SSR(SD status register)
    SD卡专有特征的信息。
    包含了sd存储卡的专有属性并为以后的功能扩展保留了足够空间。SD 状态大小是一个512 Bit的数据块。寄存器通过DAT线发送给host的内容有16bit CRC。SD 状态作为ACMD13(CMD55 跟随CMD13)的响应通过Dat 总线发送给Host。ACMD13 只能在‘Trans_State’状态发送给卡(卡被选中)。SD 状态结构描述如下。没有使用的保留Bit 应该设成0。

    1.8卡状态寄存器——CSR

    卡状态寄存器——CSR(card status register)
    卡状态信息。
    CSR(卡状态)寄存器总共 32bits,代表了执行一个命令的错误和状态信息,其信息包含在 R1 格式的应答中返回给主机。

    2.SD卡存储器

    SD卡属于连续存储介质(NAND型Flash),它是由许多小的区块组成,每个区块都可以存储一定数量的数据,因此SD卡的读写是以“数据块”为单位进行传输的。
    n块(Block):是文件系统上的概念,指最小读写单位,块的长度是字节的整数倍,一般为512字节,有的SD卡的数据块为1024或2048等等,要修改SD卡中一个字节,必须重写整个数据块。
    n扇区:扇区是擦除单位,表示擦除操作要擦除的块的数目,通常:1扇区=128块=64KByte。注意:文件系统中,V 2.0的卡通过AU尺寸来表明存储边界,不使用扇区。
    nAU(分配单元),也称为簇,是文件系统为每一个单元地址划分的空间大小,类似于一栋大楼将它换分为若干房间,并分配相应的门牌号,其中房间的大小就是所说的分配单元大小。
    存储文件时,系统将文件按照分配单元的大小分为若干部分,比如分配单元为4096Byte,一个4096Byte的文件刚好放进一个分配单元中,如果是4097Byte的文件则需占用两个分配单元。擦除时也是同样道理,一次最小擦除一个分配单元。因此分配单元越小,越节约空间,但是浪费读取时间;分配单元越大,越节约读取时间,但是浪费空间。
    卡的容量决定最大的AU大小,默认分为:2048Byte、4096Byte,8192Byte, 16KB,32KB和64KB,最大为一个扇区即64KB,一般默认设置为4096Byte,格式化时分配单元设置。
    在这里插入图片描述

    展开全文
  • STM32——RTC实时时钟原理+BKP寄存器原理

    一、RTC实时时钟特征与原理

    1、RTC(Real Time Clock):实时时钟

    2、RTC是个独立的BCD定时器/计数器。RTC提供一个日历时钟,两个可编程闹钟中断,以及一个具有中断功能的周期性可编程唤醒标志。RTC还包含于管理低功耗模式的自动唤醒单元。

    3、两个32位寄存器包含二进制码十进制格式(BCD)的秒、分钟、小时、星期几、日期、月份和年份。此外还可以提供二进制的亚秒值。

    4、系统可以自动将月份的天数补偿为28、29(闰年),30、31天,并且可以进行夏令时补偿。

    RTC工作原理框图

     

     

     

    1)通常情况下时钟源LSE(32.768KHz)经过精确校准进入异步通道分频(默认127+1),生成ck_apre(默认256Hz),进行粗略校准后进行同步分频,之后产生CK_spre(默认1Hz),从而产生“日历”。闹钟A与闹钟B将与“日历”比较,相等则会产生时钟。

    (RTCCLOCK/(127+1)产生ck_apre时钟,ck_apre时钟再经过同步分频产生ck_spre时钟。影子寄存器亚秒是默认值分之一)

    2)RTCCLOCK“走”下半部分预分频器,然后进入一个选择器(有来自ck_spre的也有来自下半部分预分频器的),到达自动装载寄存器(16位的RTC_WUTR)。自动装载寄存器计数到零后会唤醒开启标志位从而产生中断。

    5、RTC BKP备份寄存器

    提醒:一共有20个32位备份寄存器。常用来保存一些系统配置信息和相关标志位。

     

    6、RTC相关常用寄存器

    1)RTC时间寄存器(RTC_TR)    2)RTC日期寄存器(RTC_DR)  3)RTC亚秒寄存器(RTC_SSR)

    4)RTC控制寄存器(RTC_CR)   5)RTC初始化和状态寄存器(RTC_ISR)

    6)RTC预分频寄存器(RTC_PRER)  7)RTC唤醒寄存器定时器(RTC_WUTR)

    8)RTC闹钟A寄存器(RTC_ALRMAR)  9)RTC闹钟A亚秒寄存器(RTC_ALRMARSSR)

    10)RTC闹钟B寄存器(RTC_ALRMBR)  11)RTC闹钟B亚秒寄存器(RTC_ALRMBRSSR)

    12)RTC写保护寄存器(RTC_WPR)  13)RTC备份寄存器(RTC_BKPxR)

    14)RTC时间戳时间寄存器(RTC_TSTR)  15)RTC时间戳日期寄存器(RTC_TSDR)

    16)RTC时间戳亚秒寄存器(RTC_TSSSR)

    二、RTC相关寄存器

    1、RTC预分频寄存器(RTC_PRER)

     

    先进行一个七位的异步预分频,再进行十五位的同步预分频。(两次分频产生更精准的时钟)

    2、RTC时间寄存器(RTC_TR)

     

    BCD码:又称二进码十进数。用4位二进制数来表示1位十进制数中的0~9这10个数码。

    3、RTC日期寄存器(RTC_DR)

     

    存储年月日,以及星期几

    4、RTC亚秒寄存器(RTC_SSR)

     

    亚秒寄存器保存比秒更精确。

    时间寄存器、日期寄存器和亚秒寄存器,这三个寄存器保存的是时间

    5、RTC唤醒定时器寄存器(RTC_WUTR)

     

    6、RTC闹钟A/B寄存器(RTC_ALRMAR/RTC_ALRMBR)

     

    闹钟寄存器需要同日历进行比较。掩码:时间比较的精确位。比如日期比较时不用精确到时间

    三、RTC相关常用库函数

    ErrorStatus RTC_Init(RTC_InitTypeDef* RTC_InitStruct);

    ErrorStstus RTC_EnterInitMode(void);

    void RTC_ExitInitMode(void);

    ErrorStatus RTC_SetTime(uint32_ RTC_Format,RTC_TimeTypeDef* RTC_TimeStruct);

    void RTC_GetTime(uint32_t RTC_Format,RTC_TimeTypeDef* RTC_TimeStruct);

    uint32_t RTC_GetSubSecond(void);

    ErrorStatus RTC_SetDate(uint32_t RTC_Format,RTC_DateTypeDef* RTC_DateStruct);

    void RTC_GetDate(uint32_t RTC_Format,RTC_Date TypeDef* RTC_DateStruct);

    void RTC_SetAlarm();

    void RTC_GetAlarm();

    ErrorStatus RTC_AlarmCmd(uint32_t RTC_Alarm,FunctionalStatus NewState);

    void RTC_AlarmSubSecondConfig(uint32_t RTC_Alarm,uint32_t RTC_AlarmSubSecondValue,uint32_t RTC_AlarmSubSecondMask);

    uint32_t RTC_GetAlarmSubSecond(uint32_t RTC_Alarm);

    RTC时钟源和时钟操作函数:

    void RCC_RTCCLKConfig(uint32_t CLKSource);//时钟源选择
    
    void RCC_RTCCLKCmd(FunctionalState NewState);//时钟使能

    RTC初始化函数:

    ErrorStatus RTC_Init(RTC_InitTypeDef* RTC_InitStruct);
    
    typedef struct
    
    {
    
    uint32_t RTC_HourFormat;//小时格式:24/12
    
    uint32_t RTC_AsynchPrediv;//异步分频系数
    
    uint32_t RTC_SynchPrediv;//同步分频系数
    
    }RTC_InitTypeDe

    RTC日历配置相关函数:

    ErrorStatus RTC_SetTime(uint32_t RTC_Format,RTC_TimeTypeDef* RTC_TimeStruct);
    
    void RTC_GetTime(uint32_t RTC_Format,RTC_TimeTypeDef*RTC_TimeStruct);
    
    ErrorStatus RTC_SetDate(uint32_t RTC_Format,RTC_DateTypeDef*RTC_DateStruct);
    
    void RTC_GetDate(uint32_t RTC_Format,RTC_DateTypeDef*RTC_DateStruct);
    
    uint32_t RTC_GetSubSecond(void);

    RTC闹钟相关函数:

    ErrorStatus RTC_AlarmCmd(uint32_t RTC_Alarm,FunctionalState NewState);
    
    void RTC_SetAlarm(uint32_t RTC_Format,uint32_t RTC_Alarm,RTC_AlarmTypeDef*RTC_AlarmStruct);
    
    void RTC_GetAlarm(uint32_t RTCFormat,uint32_t RTC_Alarm,RTC_AlarmTypeDef*RTCAlarmStruct);
    
    void RTCAlarmSubSecondConfig(uint32_t RTC_Alarm,uint32_t RTC_AlarmSubSecondValue,uint32_t RTC_AlarmSubSecondMask);
    
    uint32_t RTC_GetAlarmSubSecond(uint32_t RTC_Alarm);

    RTC周期唤醒相关函数:

    void RTC_WakeUpClockConfig(uint32_t RTC_WakeUpClock);
    
    void RTC_SetWakeUpCounter(uint32_t RTC_WakeUpCounter);
    
    uint32_t RTC_GetWakeUpCounter(void);
    
    RTC_WakeUpCmd(DISABLE);//关闭WAKEUP

    RTC中断配置以及状态相关函数:

    void RTC_ITConfig(uint32_t RTC_IT,FunctionalState NewState);
    
    FlagStatus RTC_GetFlagStatus(uint32_t RTC_FLAG);
    
    void RTC_ClearFlag(uint32_t RTC_FLAG);
    
    ITStatus RTC_GetITStatus(uint32_t RTC_IT);
    
    void RTC_ClearITPendingBit(uint32_t RTC_IT);

    RTC相关约束函数:

    void RTC_WriteProtectionCmd(FunctionalState NewState);//取消写保护
    
    ErrorStatus RTC_EnterInitMode(void);//进入配置模式,RTC_ISR_INITF位设置为1
    
    void RTC_ExitInitMode(void);//退出初始化模式

    其它相关函数:

    uint32_t RTC_ReadBackupRegister(uint32_t RTC_BKP_DR);
    
    void RTC_WriteBackupRegister(uint32_t RTC_BKP_DR,uint32_t Data);
    
    void RTC_ITConfig(uint32_t RTC_IT,FunctionalState NewState);

    展开全文
  • <p>i have column register on table jadwal: <pre><code>CREATE TABLE IF NOT EXISTS 'jadwal' ('register' int(5) zerofill NOT NULL AUTO_INCREMENT, PRIMARY KEY ('register') </code></pre> ...
  • 1、Interrupt Pending Register (INTP, R/W, Address = 0xE280_...中断挂起寄存器: You can clear specific bits of INTP register by writing 1’s to the bits that you want to clear regardless of RTCEN value.

    1、Interrupt Pending Register (INTP, R/W, Address = 0xE280_0030)

    中断挂起寄存器:

    You can clear specific bits of INTP register by writing 1’s to the bits that you want to clear regardless of RTCEN value.



    不论RTCEN的值是多少,如果你想清除INTP特定的位可以通过对相应的位写入1.

    2、Real Time Clock Control Register (RTCCON, R/W, Address = 0xE280_0040)

    RTC控制寄存器:
    The RTCCON register consists of 10 bits such as the RTCEN, which controls the read/ write enable of the BCDSEL, CNTSEL, CLKRST, TICCKSEL and TICEN for testing, and CLKOUTEN for RTC clock output control.
    RTCEN bit controls all interfaces between the CPU and the RTC, therefore it should be set to 1 in an RTC control routine to enable data read/ write after a system reset. To prevent inadvertent writing into BCD counter registers the RTCEN bit should be cleared to 0 before power off.
    CLKRST is counter reset for 2
    15 clock divider. Before RTC clock setting, 215 clock divider must be reset for exact RTC operation.
    RTCCON寄存器包含10个位,如下图所示。RTCEN控制CPU和RTC所有的接口,因此在系统复位后在RTC中使能相应的读写数据操作RTCEN应该被置1。为了防止因为数据意外写到BCD计数器寄存器时,应该在电源关闭前将RTCEN位置0。

    CLKRST是对2^15时钟分频器的计数器复位。在RTC时钟设置之前,为了RTC精确的运行,2^15时钟分频器必须复位。


    3、Tick Time Count Register (TICNT, R/W, Address = 0xE280_0044)

    这个寄存器暂时我们不用,它一般用在操作系统中。


    4、RTC Alarm Control Register (RTCALM, R/W, Address = 0xE280_0050)
    The RTCALM register determines the alarm enable and the alarm time. Note that the RTCALM register
    generates the alarm signal through both ALARM_INT and ALARM_WK in power down mode, but only through ALARM_INT in the normal operation mode. Enable ALMEN to use ALARM_INT and ALARM_WK.
    If compare value is year, ALMEN and YEAREN must be enabled. If compare values are year, month, day, hour,min and sec, ALMEN, YEAREN, MONEN, DAYEN, HOUREN, MINEN and SECEN must be enabled.
     

    RTC闹钟控制寄存器:
    RTCALM寄存器决定使能闹钟和设置闹钟时间。注意:RTCALM寄存器产生闹钟信号,在断电模式下通过闹钟中断和闹钟唤醒信号,在正常运行模式下只能通过闹钟中断信号。使能ALMEN后使用闹钟中断和闹钟唤醒信号。如果比较的是只是年份则必须同时ALMEN和YEAREN使能。如果是年月日时分秒则必须ALMEN, YEAREN, MONEN, DAYEN, HOUREN, MINEN and SECEN都使能。

    5、Alarm Second Data Register (ALMSEC, R/W, Address = 0xE280_0054)
    设置闹钟的秒数寄存器


    下面这几个也是设置闹钟相关日期/时间的寄存器:



    下面这几个是设置正常时实时时钟的时间寄存器:





    最后一个是设置TICK相关的寄存器,暂时我们还不用:




    展开全文
  • 在imx 6q的4.1.15版本linux系统上适配hym8563这款rtc芯片,配置上驱动后产生了如上面的问题,设置时间没有问题,设置年份会比减六年存储。但是如果设置的是15年及以下就不会有这个问题。 这是时间的读取程序,使用...
  • 2) BKP备份寄存器特征与原理; 3) RTC常用寄存器+库函数介绍; 4) 相关实验代码解读。 官方资料:《STM32中文参考手册V10》第16章——实时时钟(RTC)和第5章——备份寄存器 1. RTC实时时钟特征与原理 1.1 RTC ...
  • STM32学习笔记——基于RTC获取时间(精确到毫秒) 本文记录一下基于STM32F429开发板的RTC获取时间,精确到毫秒。 RTC相关寄存器 STM32F429 的RTC(Real_Time ...两个 32 位寄存器(TR 和 DR)包含二进码十进数格式 (BCD)
  • 这也是很多配置过程的第一步,可以通过RCC_APB1ENR寄存器来设置。在中文参考手册中是设置寄存器RCC_APB1ENR的PWREN和BKPEN位 寄存器方式:RCC_APB1ENR=1<<28; RCC_APB1ENR=1<<27; 库函数方式:RCC_APB1...
  • DS1302详解

    千次阅读 2022-05-26 17:03:23
    此外,DS1302 还有年份寄存器、控制寄存器、充电寄存器、时钟突发寄存器及与RAM相关的寄存器等。时钟突发寄存器可一次性顺序读写除充电寄存器外的所有寄存器内容。 DS1302与RAM相关的寄存器分为两类:一类是单个RAM...
  • //写入初始年份数据10 write_1302(0x8e,0x80); //打开写保护 } //------------------------------------ //温度显示子函数 void write_temp(uchar add,uchar dat)//向LCD写温度数据,并指定显示位置 { uchar gw,sw,...
  • 单片机蓝桥杯——DS1302

    千次阅读 2022-03-19 15:15:04
    此外,DS1302 还有年份寄存器、控制寄存器、充电寄存器、时钟突发寄存器 及与 RAM 相关的寄存器等。如下图所示,时钟日历包含在 7 个读/写寄存器内,读/写寄存器中的数据是BCD 码。 秒寄存器的 BIT7 定义为时间暂停...
  •  直接操作寄存器中,可以自由设定这个时间戳起始的年份,RTC的32位寄存器存储的只是距离这个起始年份的总秒数,所以不会遇到这个问题。而且可以用无符号32位的二进制表示时间,这意味着此类系统的时间戳可以表示更...
  • 4.7 51单片机-DS1302 实时时钟芯片

    千次阅读 2021-10-29 11:40:32
     } /* 函数功能: 设置DS1302芯片的时间 DS1302的时间基准是从2000年开始的,设置年份时要减去2000再传入设置 例如:DS1302_WriteTime(20,1,18,14,46,20,6); */ void DS1302_WriteTime(u8 year,u8 mon,u8 mday,...
  • 51单片机之电子钟设计

    万次阅读 多人点赞 2015-09-30 22:08:00
    #include //#include"DS18B20_3.H" #include #include #define uint unsigned int #define uchar unsigned char #define wd 1 //定义是否有温度功能 =0时无温度,=1时有温度 ...#define yh 0x80 //LCD第一行的初始...
  • java判断年份

    2022-09-25 23:07:44
    //关闭输入 计算机回收计算机资源 (cpu,内存,寄存器)// 整形和字符串拼接 输出的是字符串。// 请输入一个整形的数字 表示年份。(1)能被4整除 但不能被100整除。// 输入当年二月的天数。// 提示输入一个年份。...
  • 请输入一个年份

    2022-09-25 19:24:46
    请输入一个年份
  • 提升输入一个年份

    2022-09-25 19:10:34
    提升输入一个年份
  • 从键盘输入一个表示年份的正整数(1~65535),然后判断其是否为闰年。若是,则输出"Yes",否则,输出"No"。 思路: 主程序部分实现字符串数字的输入并输出提示信息。通过调用字符串转数字子程序string2num_2实现字符...
  • package Day03.Day3; public class Test02 { public static void main(String[]arge){ //输入 java.util.Scanner input =new java.util.... //关闭输入 计算机回收计算机资源(CPU,内存,寄存器) input.close(); } }
  • // 请输入一个整形数字,表示年份 System.out.println("请输入一个年份"); // 先定义一个平年的天数,默认输入的是平年 int year = input.nextInt(); int days = 28; /* 闰年: (1) 和 (2) 只要满足一个就行,表示...
  • // 关闭输入 计算机回收计算机资源(CPU,内存,寄存器)// 先定义一个平年的天数 默认输入的是平年。(1) 能被4整除 但不能被100整除。// 整形和字符串拼接 输出的是字符串。// 请输入一个整形数字 表示年份。// ...
  • 基于STM32F1实现秒表及万年历功能【寄存器版】

    千次阅读 多人点赞 2019-05-21 23:34:27
    【这里尚未对当前操作位做特殊操作,比如年份闪烁表示正在对其进行操作,之后补充】 关键代码 秒表 /****************普通按键初始化函数******************** * 通用定时器中断初始化 * 这里时钟选择为APB1的...
  • 51单片机DS1302时钟

    2022-04-07 18:49:20
    DS1302 时钟操作可通过 AM/PM 指示决定采用 24 或 12 小时格式。 DS1302 与单片机之间能简单地 采用同步串行方式进行通信,仅用到...此外, DS1302 还有年份寄存器、控制寄存器、充电寄存器、时钟突发寄存器 及与 RAM
  • CPU 通过读取 RTC 模块中寄存器 BCDSE、CBCDMIN、BCDHOU、RBCDDA、YBCDDAT、EBCDMON和 BCDYEAR的值,得到当前的相应时间值。然而,由于多个寄存器依次读出,所以有可能产生错误。比如:用户依次读取年(1989)、月...
  • 可用的寄存器,si,di,bp,bx,cx ; ;设置数据来源,并设置si为偏移变量 mov bx,data mov ds,bx mov si,0 ;设置数据目的地,并设置di为偏移变量 mov ax,table mov es,ax mov di,0 ;设置总收入...
  • 一个例子输出一段话,另一个例子计算年份: //1、files:hello1.c hello1no.s hello1.exe #include int main(void) { printf("This is an example of sometjing printed!"); return 0; } //2、files:helloyear.c...
  • 真空管计算机,输入和输出:穿孔卡片,对计算机操作起来非常不便,做一件事可能需要十几个人去共同去完成,年份大概是:1945-1955。而且耗电量特别大,如果那个时候你家里有台计算机的话,可能你一开计算机你家的电...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,352
精华内容 940
热门标签
关键字:

年份寄存器