搜索
bottom↓
回复: 0

《DNK210使用指南 -SDK版 V1.0》第十五章RTC实验

[复制链接]

出0入234汤圆

发表于 4 天前 | 显示全部楼层 |阅读模式
2.jpg
1)实验平台:正点原子DNK210开发板
2)购买链接:https://detail.tmall.com/item.htm?id=782801398750
3)全套实验源码+手册+视频下载地址:http://openedv.com/thread-348335-1-1.html
4)正点原子官方B站:https://space.bilibili.com/394620890
5)正点原子手把手教你学DNK210快速入门视频教程:https://www.bilibili.com/video/BV1kD421G7fu
6)正点原子FPGA交流群:132780729
1.png
3.png

第十五章RTC实验


       本章将介绍Kendryte K210的RTC外设使用。通过本章的学习,读者将学习到SDK编程技术使用Kendryte K210的的RTC模块。
       本章分为如下几个小节:
       15.1 RTC介绍
       15.2 硬件设计
       15.3 程序设计
       15.4 运行验证

       15.1 RTC介绍
       Kendryte K210的RTC是用来计时的单元,在设置时间后具备计时功能:
       1. 可使用外部高频晶振进行计时
       2. 可配置外部晶振频率与分频
       3. 支持万年历配置,可配置的项目包含世纪、年、月、日、时、分、秒与星期
       4. 可按秒进行计时,并查询当前时刻
       5. 支持设置一组闹钟,可配置的项目包含年、月、日、时、分、秒,闹钟到达时触发中断
       6. 中断可配置,支持每日、每时、每分、每秒触发中断
       7. 可读出小于1秒的计数器计数值,最小刻度单位为外部晶振的单个周期
       8. 上电/复位后数据清零
       实时时钟(RTC)能为系统提供一个准确的时间,Kendryte K210的RTC模块功能强大,支持万年历配置、闹钟、时间中断,能够适用于多种场景。通过本章的学习,读者将学习到RTC的使用。
       Kendryte K210官方SDK提供了多个操作RTC模块的函数,这里我们只讲述本实验用到的函数,这些函数介绍如下:

       1,rtc_init函数
       该函数主要用于RTC初始化,如下代码所示:
  1. int rtc_init(void)
  2. {
  3.     /* Reset RTC */
  4.     sysctl_reset(SYSCTL_RESET_RTC);
  5.     /* Enable RTC */
  6.     sysctl_clock_enable(SYSCTL_CLOCK_RTC);
  7.     /* Unprotect RTC */
  8.     rtc_protect_set(0);
  9.     /* Set RTC clock frequency */
  10.     rtc_timer_set_clock_frequency(
  11.         sysctl_clock_get_freq(SYSCTL_CLOCK_IN0));
  12.     rtc_timer_set_clock_count_value(1);
  13.     /* Set RTC mode to timer running mode */
  14.     rtc_timer_set_mode(RTC_TIMER_RUNNING);
  15.     return 0;
  16. }
复制代码
       首先我们要重新复位RTC,然后使能系统RTC时钟,撤销RTC的保护,让RTC能重新配置,为了保证RTC计时准确,我们需要根据系统时钟重新配置RTC时钟,最后配置RTC进入计时模式,RTC配置成功后该函数返回0,反之返回1。这里需要注意的是:RTC模块需要使能PLL0,并且CPU频率要大于30MHz。

       2,rtc_timer_set函数
       该函数用于设置RTC的日期和时间,如下代码所示:
  1. int rtc_timer_set(int year, int month, int day, int hour, int minute, int second);
复制代码
       Kendryte K210的RTC模块在上电/复位后数据会清零,所以我们每次启动RTC后要重新设置日期、时间数据,函数共有6个参数,参数分别对应年、月、日、小时、分钟和秒,设置成功函数返回0。

       3,rtc_timer_get函数
       该函数用来读取当前RTC的日期、时间数据,该函数原型及参数描述如下所示:
  1. int rtc_timer_get(int *year, int *month, int *day, int *hour, int *minute, int *second);
复制代码
       函数共有6个参数,参数分别对应年、月、日、小时、分钟和秒,读取成功函数返回0,返回其他表示读取失败。

       15.2 硬件设计

       15.2.1 例程功能

       1.程序编译时将当前系统的日期、时间设置为RTC的日期、时间,之后每秒打印输出RTC的时间数据。

       15.2.2 硬件资源

       1.UARTHS(ISP)
              UARTHS_TX – IO5
              UARTHS_RX – IO4

       15.2.3 原理图
       本章实验内容,主要讲解RTC模块的使用,无需关注原理图。

       15.3 程序设计

       15.3.1 RTC获取系统时间驱动代码
       RTC获取系统时间源码包括两个文件:rtcdate.c和rtcdate.h, rtcdate.h文件只包含了函数的声明,我们这里介绍下函数参数的结构体rtc_date_time_t。
  1. typedef struct _rtc_date_time
  2. {
  3.     uint32_t sec : 6;
  4.     uint32_t min : 6;
  5.     uint32_t hour : 5;
  6.     uint32_t week : 3;
  7.     uint32_t day : 5;
  8.     uint32_t month : 4;
  9.     uint16_t year;
  10. } rtc_date_time_t;
复制代码
       可以看到,这个结构体是用于存放RTC的时间和日期的,我们设置RTC时间的时候可以直接使用该结构体的参数,下面的们介绍rtcdate.c文件的内容。
  1. void get_compile_time(rtc_date_time_t *compile_time)
  2. {
  3.     const char date[12] = {__DATE__};
  4.     const char time[9] = {__TIME__};
  5.     uint8_t length;
  6.     const char *ptr;
  7.     char buffer[100];
  8.     uint8_t month_index;
  9.     const char *month_list[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};

  10.     if (compile_time == NULL)
  11.     {
  12.         return;
  13.     }

  14.     /* Set to default */
  15.     compile_time->sec = 0;
  16.     compile_time->min = 0;
  17.     compile_time->hour = 0;
  18.     compile_time->week = 6;
  19.     compile_time->day = 1;
  20.     compile_time->month = 1;
  21.     compile_time->year = 2000;

  22.     /* Month */
  23.     ptr = find_field(date, ' ', 0);
  24.     length = (uint8_t)(strchr(ptr, ' ') - ptr);
  25.     strncpy(buffer, ptr, length);
  26.     buffer[length] = '\0';
  27.     for (month_index=0; month_index<sizeof(month_list)/sizeof(month_list[0]); month_index++)
  28.     {
  29.         if (strcmp(buffer, month_list[month_index]) == 0)
  30.         {
  31.             compile_time->month = month_index + 1;
  32.         }
  33.     }
  34.    
  35.     /* Day */
  36.     ptr = find_field(date, ' ', 1);
  37.     length = (uint8_t)(strchr(ptr, ' ') - ptr);
  38.     strncpy(buffer, ptr, length);
  39.     buffer[length] = '\0';
  40.     compile_time->day = atoi(buffer);

  41.     /* Year */
  42.     ptr = find_field(date, ' ', 2);
  43.     length = (uint8_t)(strchr(ptr, ' ') - ptr);
  44.     strncpy(buffer, ptr, length);
  45.     buffer[length] = '\0';
  46.     compile_time->year = atoi(buffer);

  47.     /* Hour */
  48.     ptr = find_field(time, ':', 0);
  49.     length = (uint8_t)(strchr(ptr, ':') - ptr);
  50.     strncpy(buffer, ptr, length);
  51.     buffer[length] = '\0';
  52.     compile_time->hour = atoi(buffer);

  53.     /* Minute */
  54.     ptr = find_field(time, ':', 1);
  55.     length = (uint8_t)(strchr(ptr, ':') - ptr);
  56.     strncpy(buffer, ptr, length);
  57.     buffer[length] = '\0';
  58.     compile_time->min = atoi(buffer);

  59.     /* Second */
  60.     ptr = find_field(time, ':', 2);
  61.     length = (uint8_t)(strchr(ptr, '\0') - ptr);
  62.     strncpy(buffer, ptr, length);
  63.     buffer[length] = '\0';
  64.     compile_time->sec = atoi(buffer);

  65.     /* Week */
  66.     compile_time->week = rtc_get_wday(compile_time->year, compile_time->month, compile_time->day);
  67. }
复制代码
       首先我们介绍get_compile_time函数,函数主要功能就是获取系统时间,通过代码__DATE__和__TIME__就能读取到系统的日期和时间,这两个数据是以字符串的形式保存在数组中,我们不能直接使用,这时候就需要数据提取处理,接着我们对RTC的日期和时间结构体变量赋予一个默认值,完成后我们就对上面提取到的日期和时间数据处理了,在VSCode我们可以看到__DATE__和__TIME__这两个数据的宏定义分别为#define __DATE__ "Feb 21 2024"和#define __TIME__ "09:49:35",我们就可以根据这两个字符串的格式提取所需数据,这里我们还需要用到另外一个函数,函数的原型如下:
  1. /**
  2. * @brief   查找字符串中第n个分隔符后的地址
  3. * @param   string   :需要查找的字符串
  4. * @param   interval :分隔符
  5. * @param   index    :第n个分割符
  6. * @retval  返回第n个分隔符后的地址
  7. */
  8. static const char *find_field(const char *string, const char interval, uint8_t index)
  9. {
  10.     uint8_t index_loop = 0;
  11.     const char *field = string;

  12.     while (index_loop < index)
  13.     {
  14.         while (field[0] != interval)
  15.         {
  16.             field++;
  17.         }
  18.         while (field[0] == interval)
  19.         {
  20.             field++;       /* 偏移到分隔符地址后 */
  21.         }
  22.         index_loop++;
  23.     }

  24.     return field;
  25. }
复制代码
       这个函数是根据我们日期和时间的数据格式编写的,比如日期数据中两个数据之间是以空格符号分隔,时间是以‘:’符号分隔,那我们就可以以这两个分隔符提取数据处理了,这里我们通过三个参数便可读取到字符串中第n个分隔符后的数据地址了,如日期第一个数据是月份,后面是空格符号,通过find_field(date, ' ', 0)这段代码是直接读取到日期数据的第一个字符的首地址(第三个参数为0地址未偏移直接跳出),接着我们用strchr函数读取下个空格符的位置,就能够确定月份这个数据的所占的字节数,进而提取到到月份的字符串数据,我们可以再稍微处理下再保存到RTC存储日期、时间数据的结构体变量中,其他几个数据读取方法都相似,这里不再叙述。

       15.3.2 main.c代码
       main.c中的代码如下所示:
  1. int main(void)
  2. {
  3.     rtc_date_time_t time;
  4.     int year;
  5.     int month;
  6.     int day;
  7.     int hour;
  8.     int minute;
  9.     int second;
  10.     int second_prev = 0;

  11.     sysctl_pll_set_freq(SYSCTL_PLL0, 800000000); /* RTC模块需要开启PLL0,并且CPU频率要大于30MHz */

  12.     get_compile_time(&time);    /* 获取系统时间 */
  13.     rtc_init();
  14.     rtc_timer_set(time.year, time.month, time.day, time.hour, time.min, time.sec);

  15.     while (1)
  16.     {
  17.         msleep(100);
  18.         rtc_timer_get(&year, &month, &day, &hour, &minute, &second);
  19.         if (second_prev != second)
  20.         {
  21.             second_prev = second;
  22.             printf("%4d-%02d-%02d %02d:%02d:%02d\n", year, month, day, hour, minute, second);
  23.         }
  24.     }
  25. }
复制代码
       我们先定义6个日期、时间数据变量,然后开启PLL0时钟。RTC模块要求开启PLL0时钟,并且CPU频率大于30MHz,通过get_compile_time函数读取系统时钟存放在结构体变量中,然后初始化RTC,设置RTC时间。
       最后在一个循环中每隔100毫秒读取一次RTC的实时时间,当秒钟变量second发生变化时,就通过串口打印输出RTC的日期、时间数据。

       15.4 运行验证
       将DNK210开发板连接到电脑主机,通过VSCode将固件烧录到开发板中,此时,我们打开“串口终端”查看输出的数据,如下图所示:。

第十五章RTC实验6486.png
图15.4.1 串口终端输出时间

阿莫论坛20周年了!感谢大家的支持与爱护!!

你熬了10碗粥,别人一桶水倒进去,淘走90碗,剩下10碗给你,你看似没亏,其实你那10碗已经没有之前的裹腹了,人家的一桶水换90碗,继续卖。说白了,通货膨胀就是,你的钱是挣来的,他的钱是印来的,掺和在一起,你的钱就贬值了。
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-10-16 16:07

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

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