38. RTC实验

一、RTC原理详解

1、6U内部自带到了一个RTC外设,确切的说是SRTC。6U和6ULL的RTC内容在SNVS章节。6U的RTC分为LP和HP。LP叫做SRTC,HP是RTC,但是HP的RTC掉电以后数据就丢失了,即使用了纽扣电池也没用。所以必须要使用LP,也就是SRTC。
SNVS章节有些是跟加密有关的,需要与NXP签订NDA协议才可以拿到。
RTC分为SNVS_LP和SNVS_HP,
如果做产品,建议使用外置RTC芯片,PCF8563。
RTC很类似定时器,外接32.768KHz的晶振,然后就开始计时,RTC使用两个寄存器来保存计数值。
RTC使用很简单,打开RTC,然后RTC就开始工作,我们要做的就是不断地读取RTC计数寄存器,获取时间值,或者向RTC计数器写入时间值,也就是调整时间。
SNVS_HPCOMR的bit31置1,表示所有的软件都可以访问SNVS所有寄存器。Bit8也是和安全有关的,我们置1,也可以不置1.
SNVS_LPCR寄存器,bit0置1,开始SRTC功能。
SNVS_LPSRTCMR的bit14:0为RTC计数寄存器的高15位
SNVS_LPSRTCLR是低32为RTC计数器,与LPSRTCMR共同组成了SRTC计数器,,每1秒数据加1。
6U的RTC模式从1970年1月1日0时0点0分0秒。

二、时间乱码的问题

1、问题
当我们按照6U的参考手册编写代码,读取SRTC的LPSRTCMR和LPSRTCLR获取时间值的时候,发现按照手册的说法,时间是错误的。
手册上写的:LPSRTCMR是SRTC的高15bit。LPSRTCLR寄存器是SRTC的低32位。RTC计数器是47bit。

2、问题解决方法
LPSRTCMR作为SRTC计数器的高15位,但是LPSRTCLR寄存器bit31:15作为SRTC计数器的低17位。相当于SRTC的计数器是个32位的。不是47位!

三、代码

参考:7、I.MX6U参考资料\3、I.MX6ULL SDK包\devices\MCIMX6Y2\drivers

//bsp_rtc.c

#include "bsp_rtc.h"
#include "stdio.h"/* * 描述:初始化RTC*/
void rtc_init(void)
{/** 设置HPCOMR寄存器* bit[31] 1 : 允许访问SNVS寄存器,一定要置1* bit[8]  1 : 此位置1,需要签署NDA协议才能看到此位的详细说明,*             这里不置1也没问题*/SNVS->HPCOMR |= (1 << 31) | (1 << 8);#if 0struct rtc_datetime rtcdate;rtcdate.year = 2018U;rtcdate.month = 12U;rtcdate.day = 13U;rtcdate.hour = 14U;rtcdate.minute = 52;rtcdate.second = 0;rtc_setDatetime(&rtcdate); //初始化时间和日期
#endifrtc_enable();   //使能RTC}/** 描述: 开启RTC*/
void rtc_enable(void)
{/** LPCR寄存器bit0置1,使能RTC*/SNVS->LPCR |= 1 << 0;   while(!(SNVS->LPCR & 0X01));//等待使能完成}/** 描述: 关闭RTC*/
void rtc_disable(void)
{/** LPCR寄存器bit0置0,关闭RTC*/SNVS->LPCR &= ~(1 << 0);    while(SNVS->LPCR & 0X01);//等待关闭完成
}/** @description : 判断指定年份是否为闰年,闰年条件如下:* @param - year: 要判断的年份* @return      : 1 是闰年,0 不是闰年*/
unsigned char rtc_isleapyear(unsigned short year)
{   unsigned char value=0;if(year % 400 == 0)value = 1;else {if((year % 4 == 0) && (year % 100 != 0))value = 1;else value = 0;}return value;
}/** @description     : 将时间转换为秒数* @param - datetime: 要转换日期和时间。* @return          : 转换后的秒数*/
unsigned int rtc_coverdate_to_seconds(struct rtc_datetime *datetime)
{   unsigned short i = 0;unsigned int seconds = 0;unsigned int days = 0;unsigned short monthdays[] = {0U, 0U, 31U, 59U, 90U, 120U, 151U, 181U, 212U, 243U, 273U, 304U, 334U};for(i = 1970; i < datetime->year; i++){days += DAYS_IN_A_YEAR;         /* 平年,每年365天 */if(rtc_isleapyear(i)) days += 1;/* 闰年多加一天       */}days += monthdays[datetime->month];if(rtc_isleapyear(i) && (datetime->month >= 3)) days += 1;/* 闰年,并且当前月份大于等于3月的话加一天 */days += datetime->day - 1;seconds = days * SECONDS_IN_A_DAY + datetime->hour * SECONDS_IN_A_HOUR +datetime->minute * SECONDS_IN_A_MINUTE +datetime->second;return seconds; 
}/** @description     : 设置时间和日期* @param - datetime: 要设置的日期和时间* @return          : 无*/
void rtc_setdatetime(struct rtc_datetime *datetime)
{unsigned int seconds = 0;unsigned int tmp = SNVS->LPCR; rtc_disable();  /* 设置寄存器HPRTCMR和HPRTCLR的时候一定要先关闭RTC *//* 先将时间转换为秒         */seconds = rtc_coverdate_to_seconds(datetime);SNVS->LPSRTCMR = (unsigned int)(seconds >> 17); /* 设置高16位 */SNVS->LPSRTCLR = (unsigned int)(seconds << 15); /* 设置地16位 *//* 如果此前RTC是打开的在设置完RTC时间以后需要重新打开RTC */if (tmp & 0x1)rtc_enable();
}/** @description     : 将秒数转换为时间* @param - seconds : 要转换的秒数* @param - datetime: 转换后的日期和时间* @return          : 无*/
void rtc_convertseconds_to_datetime(unsigned int seconds, struct rtc_datetime *datetime)
{unsigned int x;unsigned int  secondsRemaining, days;unsigned short daysInYear;/* 每个月的天数       */unsigned char daysPerMonth[] = {0U, 31U, 28U, 31U, 30U, 31U, 30U, 31U, 31U, 30U, 31U, 30U, 31U};secondsRemaining = seconds; /* 剩余秒数初始化 */days = secondsRemaining / SECONDS_IN_A_DAY + 1;         /* 根据秒数计算天数,加1是当前天数 */secondsRemaining = secondsRemaining % SECONDS_IN_A_DAY; /*计算天数以后剩余的秒数 *//* 计算时、分、秒 */datetime->hour = secondsRemaining / SECONDS_IN_A_HOUR;secondsRemaining = secondsRemaining % SECONDS_IN_A_HOUR;datetime->minute = secondsRemaining / 60;datetime->second = secondsRemaining % SECONDS_IN_A_MINUTE;/* 计算年 */daysInYear = DAYS_IN_A_YEAR;datetime->year = YEAR_RANGE_START;while(days > daysInYear){/* 根据天数计算年 */days -= daysInYear;datetime->year++;/* 处理闰年 */if (!rtc_isleapyear(datetime->year))daysInYear = DAYS_IN_A_YEAR;else    /*闰年,天数加一 */daysInYear = DAYS_IN_A_YEAR + 1;}/*根据剩余的天数计算月份 */if(rtc_isleapyear(datetime->year)) /* 如果是闰年的话2月加一天 */daysPerMonth[2] = 29;for(x = 1; x <= 12; x++){if (days <= daysPerMonth[x]){datetime->month = x;break;}else{days -= daysPerMonth[x];}}datetime->day = days;}/** @description : 获取RTC当前秒数* @param       : 无* @return      : 当前秒数 */
unsigned int rtc_getseconds(void)
{unsigned int seconds = 0;seconds = (SNVS->LPSRTCMR << 17) | (SNVS->LPSRTCLR >> 15);return seconds;
}/** @description     : 获取当前时间* @param - datetime: 获取到的时间,日期等参数* @return          : 无 */
void rtc_getdatetime(struct rtc_datetime *datetime)
{unsigned int seconds = 0;seconds = rtc_getseconds();rtc_convertseconds_to_datetime(seconds, datetime);  
}

//bsp_rtc.h

#ifndef _BSP_RTC_H
#define _BSP_RTC_H
#include "imx6ul.h"/* 相关宏定义 */ 
#define SECONDS_IN_A_DAY        (86400) /* 一天86400秒         */
#define SECONDS_IN_A_HOUR       (3600)  /* 一个小时3600秒        */
#define SECONDS_IN_A_MINUTE     (60)    /* 一分钟60秒           */
#define DAYS_IN_A_YEAR          (365)   /* 一年365天           */
#define YEAR_RANGE_START        (1970)  /* 开始年份1970年        */
#define YEAR_RANGE_END          (2099)  /* 结束年份2099年        *//* 时间日期结构体 */   
struct rtc_datetime
{unsigned short year;  /* 范围为:1970 ~ 2099        */unsigned char month;  /* 范围为:1 ~ 12             */unsigned char day;    /* 范围为:1 ~ 31 (不同的月,天数不同).*/unsigned char hour;   /* 范围为:0 ~ 23             */unsigned char minute; /* 范围为:0 ~ 59             */unsigned char second; /* 范围为:0 ~ 59             */
};/* 函数声明 */
void rtc_init(void);
void rtc_enable(void);
void rtc_disable(void);
unsigned int rtc_coverdate_to_seconds(struct rtc_datetime *datetime);
unsigned int rtc_getseconds(void);
void rtc_setdatetime(struct rtc_datetime *datetime);
void rtc_getdatetime(struct rtc_datetime *datetime)
;#endif

//main.c

/**************************************************************
描述     : I.MX6U开发板裸机实验17 RTC实时时钟实验
其他     : 本实验学习如何编写I.MX6U内部的RTC驱动,使用内部RTC可以实现一个实时时钟。
**************************************************************/
#include "bsp_clk.h"
#include "bsp_delay.h"
#include "bsp_led.h"
#include "bsp_beep.h"
#include "bsp_key.h"
#include "bsp_int.h"
#include "bsp_uart.h"
#include "bsp_lcd.h"
#include "bsp_lcdapi.h"
#include "bsp_rtc.h"
#include "stdio.h"/** @description : main函数* @param       : 无* @return      : 无*/
int main(void)
{unsigned char key = 0;int i = 3, t = 0;char buf[160];struct rtc_datetime rtcdate;unsigned char state = OFF;int_init();                 /* 初始化中断(一定要最先调用!) */imx6u_clkinit();            /* 初始化系统时钟          */delay_init();               /* 初始化延时            */clk_enable();               /* 使能所有的时钟          */led_init();                 /* 初始化led           */beep_init();                /* 初始化beep          */uart_init();                /* 初始化串口,波特率115200 */lcd_init();                 /* 初始化LCD           */rtc_init();                 /* 初始化RTC           */tftlcd_dev.forecolor = LCD_RED;lcd_show_string(50, 10, 400, 24, 24, (char*)"ZERO-IMX6UL RTC TEST");    /* 显示字符串 */lcd_show_string(50, 40, 200, 16, 16, (char*)"ATOM@ALIENTEK");  lcd_show_string(50, 60, 200, 16, 16, (char*)"2019/3/27");  tftlcd_dev.forecolor = LCD_BLUE;memset(buf, 0, sizeof(buf));while(1){if(t==100)  //1s时间到了{t=0;printf("will be running %d s......\r", i);lcd_fill(50, 90, 370, 110, tftlcd_dev.backcolor); /* 清屏 */sprintf(buf, "will be running %ds......", i);lcd_show_string(50, 90, 300, 16, 16, buf); i--;if(i < 0)break;}key = key_getvalue();if(key == KEY0_VALUE){rtcdate.year = 2018;rtcdate.month = 1;rtcdate.day = 15;rtcdate.hour = 16;rtcdate.minute = 23;rtcdate.second = 0;rtc_setdatetime(&rtcdate); /* 初始化时间和日期 */printf("\r\n RTC Init finish\r\n");break;}delayms(10);t++;}tftlcd_dev.forecolor = LCD_RED;lcd_fill(50, 90, 370, 110, tftlcd_dev.backcolor); /* 清屏 */lcd_show_string(50, 90, 200, 16, 16, (char*)"Current Time:");           /* 显示字符串 */tftlcd_dev.forecolor = LCD_BLUE;while(1)                    {   rtc_getdatetime(&rtcdate);sprintf(buf,"%d/%d/%d %d:%d:%d",rtcdate.year, rtcdate.month, rtcdate.day, rtcdate.hour, rtcdate.minute, rtcdate.second);lcd_fill(50,110, 300,130, tftlcd_dev.backcolor);lcd_show_string(50, 110, 250, 16, 16,(char*)buf);  /* 显示字符串 */state = !state;led_switch(LED0,state);delayms(1000);  /* 延时一秒 */}return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/12975.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

hot100(7)

61.31. 下一个排列 - 力扣&#xff08;LeetCode&#xff09; 数组问题&#xff0c;下一个更大的排列 题解&#xff1a;31. 下一个排列题解 - 力扣&#xff08;LeetCode&#xff09; &#xff08;1&#xff09;从后向前找到一个相邻的升序对&#xff08;i,j)&#xff0c;此时…

图像分类与目标检测算法

在计算机视觉领域&#xff0c;图像分类与目标检测是两项至关重要的技术。它们通过对图像进行深入解析和理解&#xff0c;为各种应用场景提供了强大的支持。本文将详细介绍这两项技术的算法原理、技术进展以及当前的落地应用。 一、图像分类算法 图像分类是指将输入的图像划分为…

记录一次-Rancher通过UI-Create Custom- RKE2的BUG

一、下游集群 当你的下游集群使用Mysql外部数据库时&#xff0c;会报错&#xff1a; **他会检查ETCD。 但因为用的是Mysql外部数据库&#xff0c;这个就太奇怪了&#xff0c;而且这个检测不过&#xff0c;集群是咩办法被管理的。 二、如果不选择etcd,就选择控制面。 在rke2-…

SpringUI Web高端动态交互元件库

Axure Web高端动态交互元件库是一个专为Web设计与开发领域设计的高质量资源集合&#xff0c;旨在加速原型设计和开发流程。以下是关于这个元件库的详细介绍&#xff1a; 一、概述 Axure Web高端动态交互元件库是一个集成了多种预制、高质量交互组件的工具集合。这些组件经过精…

MySQL表的CURD

目录 一、Create 1.1单行数据全列插入 1.2多行数据指定列插入 1.3插入否则更新 1.4替换 2.Retrieve 2.1 select列 2.1.1全列查询 2.1.2指定列查询 2.1.3查询字段为表达式 2.1.4为查询结果指定别名 2.1.5结果去重 2.2where条件 2.3结果排序 2.4筛选分页结果 三…

文字加持:让 OpenCV 轻松在图像中插上文字

前言 在很多图像处理任务中,我们不仅需要提取图像信息,还希望在图像上加上一些文字,或是标注,或是动态展示。正如在一幅画上添加一个标语,或者在一个视频上加上动态字幕,cv2.putText 就是这个“文字魔术师”,它能让我们的图像从“沉默寡言”变得生动有趣。 今天,我们…

(9)gdb 笔记(2):查看断点 info b,删除断点 delete 3,回溯 bt,

&#xff08;11&#xff09; 查看断点 info b&#xff1a; # info b举例&#xff1a; &#xff08;12&#xff09;删除断点 delete 2 或者删除所有断点&#xff1a; # 1. 删除指定的断点 delete 3 # 2. 删除所有断点 delete 回车&#xff0c;之后输入 y 确认删除所有断点 举…

游戏引擎学习第88天

仓库:https://gitee.com/mrxiao_com/2d_game_2 调查碰撞检测器中的可能错误 在今天的目标是解决一个可能存在的碰撞检测器中的错误。之前有人提到在检测器中可能有一个拼写错误&#xff0c;具体来说是在测试某个变量时&#xff0c;由于引入了一个新的变量而没有正确地使用它&…

【2025】camunda API接口介绍以及REST接口使用(3)

前言 在前面的两篇文章我们介绍了Camunda的web端和camunda-modeler的使用。这篇文章主要介绍camunda结合springboot进行使用&#xff0c;以及相关api介绍。 该专栏主要为介绍camunda的学习和使用 &#x1f345;【2024】Camunda常用功能基本详细介绍和使用-下&#xff08;1&…

Java高频面试之SE-17

hello啊&#xff0c;各位观众姥爷们&#xff01;&#xff01;&#xff01;本牛马baby今天又来了&#xff01;哈哈哈哈哈嗝&#x1f436; Java缓冲区溢出&#xff0c;如何解决&#xff1f; 在 Java 中&#xff0c;缓冲区溢出 (Buffer Overflow) 虽然不是像 C/C 中那样直接可见…

用 Python 绘制爱心形状的简单教程

1. 引言 在本教程中&#xff0c;我们将学习如何使用 Python 和 Matplotlib 库来绘制一个简单的爱心形状。这是一个有趣且简单的项目&#xff0c;适合初学者练习图形绘制和数据可视化。 2. 环境准备 首先&#xff0c;确保您的系统上安装了 Python 和 Matplotlib 库。如果还未…

107,【7】buuctf web [CISCN2019 华北赛区 Day2 Web1]Hack World

这次先不进入靶场 看到红框里面的话就想先看看uuid是啥 定义与概念 UUID 是 Universally Unique Identifier 的缩写&#xff0c;即通用唯一识别码。它是一种由数字和字母组成的 128 位标识符&#xff0c;在理论上可以保证在全球范围内的唯一性。UUID 的设计目的是让分布式系…

Linux之安装MySQL

1、查看系统当前版本是多少位的 getconf LONG_BIT2.去官网下载对应的MYSQL安装包 这里下载的是8版本的&#xff0c;位数对应之前的64位 官网地址&#xff1a;https://downloads.mysql.com/archives/community/ 3.上传压缩包 4.到对应目录下解压 tar -xvf mysql-8.0.26-lin…

【NLP 20、Encoding编码 和 Embedding嵌入】

目录 一、核心定义与区别 二、常见Encoding编码 (1) 独热编码&#xff08;One-Hot Encoding&#xff09; (2) 位置编码&#xff08;Positional Encoding&#xff09; (3) 标签编码&#xff08;Label Encoding&#xff09; (4) 注意事项 三、常见Embedding词嵌入 (1) 基础词嵌入…

【ArcGIS Pro 简介1】

ArcGIS Pro 是由 Esri &#xff08;Environmental Systems Research Institute&#xff09;公司开发的下一代桌面地理信息系统&#xff08;GIS&#xff09;软件&#xff0c;是传统 ArcMap 的现代化替代产品。它结合了强大的空间分析能力、直观的用户界面和先进的三维可视化技术…

初学 Xvisor 之理解并跑通 Demo

官网&#xff1a;https://www.xhypervisor.org/ quick-start 文档&#xff1a;https://github.com/xvisor/xvisor/blob/master/docs/riscv/riscv64-qemu.txt 零、Xvisor 介绍 下面这部分是 Xvisor 官方的介绍 Xvisor 是一款开源的 Type-1 虚拟机管理程序&#xff0c;旨在提供一…

“AI智能分析综合管理系统:企业管理的智慧中枢

在如今这个快节奏的商业世界里&#xff0c;企业面临的挑战越来越多&#xff0c;数据像潮水一样涌来&#xff0c;管理工作变得愈发复杂。为了应对这些难题&#xff0c;AI智能分析综合管理系统闪亮登场&#xff0c;它就像是企业的智慧中枢&#xff0c;让管理变得轻松又高效。 过去…

LabVIEW涡轮诊断系统

一、项目背景与行业痛点 涡轮机械是发电厂、航空发动机、石油化工等领域的核心动力设备&#xff0c;其运行状态直接关系到生产安全与经济效益。据统计&#xff0c;涡轮故障导致的非计划停机可造成每小时数十万元的经济损失&#xff0c;且突发故障可能引发严重安全事故。传统人…

Hugging Face 的研究人员正致力于打造 OpenAI 深度研究工具的“开源版

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

Java进阶(JVM调优)——阿里云的Arthas的使用 安装和使用 死锁查找案例,重新加载案例,慢调用分析

前言 JVM作为Java进阶的知识&#xff0c;是需要Java程序员不断深度和理解的。 本篇博客介绍JVM调优的工具阿里云的Arthas的使用&#xff0c;安装和使用&#xff0c;命令的使用案例&#xff1b;死锁查询的案例&#xff1b;重新加载一个类信息的案例&#xff1b;调用慢的分析案…