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;
}
相关文章:
38. RTC实验
一、RTC原理详解 1、6U内部自带到了一个RTC外设,确切的说是SRTC。6U和6ULL的RTC内容在SNVS章节。6U的RTC分为LP和HP。LP叫做SRTC,HP是RTC,但是HP的RTC掉电以后数据就丢失了,即使用了纽扣电池也没用。所以必须要使用LP,…...
Flutter 新春第一弹,Dart 宏功能推进暂停,后续专注定制数据处理支持
在去年春节,Flutter 官方发布了宏(Macros)编程的原型支持, 同年的 5 月份在 Google I/O 发布的 Dart 3.4 宣布了宏的实验性支持,但是对于 Dart 内部来说,从启动宏编程实验开始已经过去了几年,但…...
巴菲特价值投资思想的核心原则
巴菲特价值投资思想的核心原则 关键词:安全边际、长期投资、内在价值、管理团队、经济护城河、简单透明 摘要:本文深入探讨了巴菲特价值投资思想的核心原则,包括安全边际、长期投资、企业内在价值、优秀管理团队、经济护城河和简单透明的业务…...
C 或 C++ 中用于表示常量的后缀:1ULL
1ULL 是一个在 C 或 C 中用于表示常量的后缀,它具体指示编译器将这个数值视为特定类型的整数。让我们详细解释一下: 1ULL 的含义 1: 这是最基本的部分,表示数值 1。U: 表示该数值是无符号(Unsigned)的。这意味着它只…...
vue3中el-input无法获得焦点的问题
文章目录 现象两次nextTick()加setTimeout()解决结论 现象 el-input被外层div包裹了,设置autofocus不起作用: <el-dialog v-model"visible" :title"title" :append-to-bodytrue width"50%"><el-form v-model&q…...

程序诗篇里的灵动笔触:指针绘就数据的梦幻蓝图<3>
大家好啊,我是小象٩(๑ω๑)۶ 我的博客:Xiao Xiangζั͡ޓއއ 很高兴见到大家,希望能够和大家一起交流学习,共同进步。 今天我们来对上一节做一些小补充,了解学习一下assert断言,指针的使用和传址调用…...

(三)QT——信号与槽机制——计数器程序
目录 前言 信号(Signal)与槽(Slot)的定义 一、系统自带的信号和槽 二、自定义信号和槽 三、信号和槽的扩展 四、Lambda 表达式 总结 前言 信号与槽机制是 Qt 中的一种重要的通信机制,用于不同对象之间的事件响…...

Qt 5.14.2 学习记录 —— 이십이 QSS
文章目录 1、概念2、基本语法3、给控件应用QSS设置4、选择器1、子控件选择器2、伪类选择器 5、样式属性box model 6、实例7、登录界面 1、概念 参考了CSS,都是对界面的样式进行设置,不过功能不如CSS强大。 可通过QSS设置样式,也可通过C代码…...

Hot100之哈希
1两数之和 题目 思路解析 解法1--两次循环 解法2--哈希表一次循环 代码 解法1--两次循环 class Solution {public int[] twoSum(int[] nums, int target) {int nums1[] new int[2];int length nums.length;for (int i 0; i < length; i) {for (int j i 1; j < …...
油漆面积——蓝桥杯
1.题目描述 X 星球的一批考古机器人正在一片废墟上考古。 该区域的地面坚硬如石、平整如镜。 管理人员为方便,建立了标准的直角坐标系。 每个机器人都各有特长、身怀绝技。它们感兴趣的内容也不相同。 经过各种测量,每个机器人都会报告一个或多个矩…...
深度解析:网站快速收录与服务器性能的关系
本文转自:百万收录网 原文链接:https://www.baiwanshoulu.com/37.html 网站快速收录与服务器性能之间存在着密切的关系。服务器作为网站运行的基础设施,其性能直接影响到搜索引擎对网站的抓取效率和收录速度。以下是对这一关系的深度解析&am…...

925.长按键入
目录 一、题目二、思路三、解法四、收获 一、题目 你的朋友正在使用键盘输入他的名字 name。偶尔,在键入字符 c 时,按键可能会被长按,而字符可能被输入 1 次或多次。 你将会检查键盘输入的字符 typed。如果它对应的可能是你的朋友的名字&am…...
JavaScript 中的 var 和 let :关键区别与使用建议
在 JavaScript 开发中,变量声明是基础且重要的部分。 var 和 let 都是用于声明变量的关键字,但它们在作用域、变量提升、重复声明等方面存在显著差异。本文将详细探讨它们的区别,并给出使用建议。 1. 作用域 1.1 var 的作用域 …...
寒假刷题Day19
一、923. 三数之和的多种可能 class Solution { public:int threeSumMulti(vector<int>& arr, int target) {const int MOD 1000000007; // 正确的模数long long ans 0; // 使用 long long 防止溢出std::sort(arr.begin(), arr.end());for (size_t i 0; i < a…...
写好简历的三个关键认知
在当今竞争激烈的就业市场中,一份优秀的简历往往是敲开理想企业大门的第一把钥匙。然而,很多求职者在写简历时往往不得要领,让宝贵的机会从指间溜走。今天,让我们一起探讨如何提升简历写作水平,让你的职业之路走得更顺…...

工具的应用——安装copilot
一、介绍Copilot copilot是一个AI辅助编程的助手,作为需要拥抱AI的程序员可以从此尝试进入,至于好与不好,应当是小马过河,各有各的心得。这里不做评述。重点在安装copilot的过程中遇到了一些问题,然后把它总结下&…...
Koa 基础篇(二)—— 路由与中间件
let app new Koa() router.get(“/”,async ctx > { ctx.body “hello koa router” }) app.use(router.routes()) app.use(router.allowedMethods()) app.listen(3000) 运行项目,在浏览器访问本地3000端口,在页面上就会看到输出的语句。这就…...

帆软 FCA -业务分析师认证学习
帆软 FCA -业务分析师认证学习 认证概述 适合人群 企业中有需求管理、指标梳理、业务逻辑梳理、项目规划等需求的人员,想提升综合数据能力、推进数据应用落地的业务/IT骨干。 具体-FCA-业务分析理论 考试要求: FCA-业务分析理论考试- 费用:…...
Miniconda 安装及使用
文章目录 前言1、Miniconda 简介2、Linux 环境说明2.1、安装2.2、配置2.3、常用命令2.4、常见问题及解决方案 前言 在 Python 中,“环境管理”是一个非常重要的概念,它主要是指对 Python 解释器及其相关依赖库进行管理和隔离,以确保开发环境…...
solidity高阶 -- Eth支付
在区块链的世界里,智能合约是实现去中心化应用(DApp)的核心技术之一。Solidity 是一种专门用于编写以太坊智能合约的编程语言,它可以帮助开发者构建各种功能,包括支付功能。 今天,我们就来探讨如何使用 Sol…...
云计算——弹性云计算器(ECS)
弹性云服务器:ECS 概述 云计算重构了ICT系统,云计算平台厂商推出使得厂家能够主要关注应用管理而非平台管理的云平台,包含如下主要概念。 ECS(Elastic Cloud Server):即弹性云服务器,是云计算…...
vue3 字体颜色设置的多种方式
在Vue 3中设置字体颜色可以通过多种方式实现,这取决于你是想在组件内部直接设置,还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法: 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...

高等数学(下)题型笔记(八)空间解析几何与向量代数
目录 0 前言 1 向量的点乘 1.1 基本公式 1.2 例题 2 向量的叉乘 2.1 基础知识 2.2 例题 3 空间平面方程 3.1 基础知识 3.2 例题 4 空间直线方程 4.1 基础知识 4.2 例题 5 旋转曲面及其方程 5.1 基础知识 5.2 例题 6 空间曲面的法线与切平面 6.1 基础知识 6.2…...

苍穹外卖--缓存菜品
1.问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得,如果用户端访问量比较大,数据库访问压力随之增大 2.实现思路 通过Redis来缓存菜品数据,减少数据库查询操作。 缓存逻辑分析: ①每个分类下的菜品保持一份缓存数据…...
Qt Http Server模块功能及架构
Qt Http Server 是 Qt 6.0 中引入的一个新模块,它提供了一个轻量级的 HTTP 服务器实现,主要用于构建基于 HTTP 的应用程序和服务。 功能介绍: 主要功能 HTTP服务器功能: 支持 HTTP/1.1 协议 简单的请求/响应处理模型 支持 GET…...

新能源汽车智慧充电桩管理方案:新能源充电桩散热问题及消防安全监管方案
随着新能源汽车的快速普及,充电桩作为核心配套设施,其安全性与可靠性备受关注。然而,在高温、高负荷运行环境下,充电桩的散热问题与消防安全隐患日益凸显,成为制约行业发展的关键瓶颈。 如何通过智慧化管理手段优化散…...

JUC笔记(上)-复习 涉及死锁 volatile synchronized CAS 原子操作
一、上下文切换 即使单核CPU也可以进行多线程执行代码,CPU会给每个线程分配CPU时间片来实现这个机制。时间片非常短,所以CPU会不断地切换线程执行,从而让我们感觉多个线程是同时执行的。时间片一般是十几毫秒(ms)。通过时间片分配算法执行。…...
使用Matplotlib创建炫酷的3D散点图:数据可视化的新维度
文章目录 基础实现代码代码解析进阶技巧1. 自定义点的大小和颜色2. 添加图例和样式美化3. 真实数据应用示例实用技巧与注意事项完整示例(带样式)应用场景在数据科学和可视化领域,三维图形能为我们提供更丰富的数据洞察。本文将手把手教你如何使用Python的Matplotlib库创建引…...

用机器学习破解新能源领域的“弃风”难题
音乐发烧友深有体会,玩音乐的本质就是玩电网。火电声音偏暖,水电偏冷,风电偏空旷。至于太阳能发的电,则略显朦胧和单薄。 不知你是否有感觉,近两年家里的音响声音越来越冷,听起来越来越单薄? —…...

使用LangGraph和LangSmith构建多智能体人工智能系统
现在,通过组合几个较小的子智能体来创建一个强大的人工智能智能体正成为一种趋势。但这也带来了一些挑战,比如减少幻觉、管理对话流程、在测试期间留意智能体的工作方式、允许人工介入以及评估其性能。你需要进行大量的反复试验。 在这篇博客〔原作者&a…...