系列文章目录
1.连续打卡第一天:提前对CPK_RA2E1是瑞萨RA系列开发板的初体验,了解一下
2.开发环境的选择和调试(从零开始,加油)
3.欲速则不达,今天是对RA2E1 基础知识的补充学习。
4.e2 studio 使用教程
5.Keil配置使用(使用 RASC 生成 Keil 工程)
6.Keil配置使用(使用 RASC 生成 Keil 工程)
7.(电脑重装系统)学习RA产品家族选型手册
8.问题解决、学习RA寄存器、用寄存器的方式点亮第一个LED灯。
9.继续学习RA寄存器
10.FSP固件库开发及FSP配置详解。
11.FSP固件库开发点亮第一个灯。
12.FSP固件库开发按键输入检测控制LED灯闪烁
13.FSP固件库开发启动文件详解
14.FSP固件库开发延时函数(时钟详解)
15.FSP固件库外部中断处理编程(外部中断检测按键控制LED闪烁)
16.FSP固件库系统定时器(滴答定时器SysTick)每2秒LED闪烁一次
17.FSP固件库开发GPT — PWM通用定时器 定时2s LED 闪烁
18.FSP固件库开发GPT — PWM输出波形 — LED呼吸灯
19.RA2E1串口通信基础知识
20.RA2E1_UART —— 串口通信例程
21.RA2E1_UART —— 串口控制LED亮灭
文章目录
系列文章目录
文章目录
前言
一、RTC是什么?
二、RTC特性
三、RTC时钟日历(实操)
1.新建工程
2.FSP配置
3.keil代码编写
总结
前言
随着时钟的学习,这次学习RTC时钟。(本文章参考野火教程)
一、RTC是什么?
RTC(Real Time Clock)外设,实质是一个掉电后还继续运行的定时器。从定时器的角度来说,相对于GPT外设,要简单很多 ,只有计时和触发中断以及输入捕获的功能。所以RTC外设的特别之处并不在于它的定时功能,而在于它掉电还继续运行的特性。
以上所说的掉电,是指主电源VDD断开的情况,为了RTC外设掉电继续运行,必须通过VBAT引脚接上纽扣电池给RA6M5的RTC供电。 当主电源VDD有效时,由VDD给RTC外设供电; 而当VDD掉电后,由VBAT给RTC外设供电,继续日历计数器的计时,除此之外RTC的其他功能都无法使用。 若VDD和VBAT都掉电,日历计数器的计时会丢失
子时钟振荡器或LOCO可以选择作为时间计数器的计数源。RTC使用128Hz的时钟,通过将计数源除以预分频器的值获得: 年、月、日、星期、上午/下午。 (12/24 小时模式)、时、分、秒或32位二进制按1/128秒计数。
二、RTC特性
RTC 特性:
计数模式:日历计数模式和二进制计数模式。
时钟源:子时钟或LOCO。
日历计数模式:年,月,日,星期,小时,分钟,秒计数。
二进制计数模式:32位计二进制计数。
闹钟中断:在日历计数模式下,可以与年,月,日,星期,小时,分钟和秒进行比较。在二进制计数模式下则与32位2进制计数器进行对比。
周期性中断:可以选择2秒,1秒,1/2秒,1/4秒,1/8秒,1/16秒,1/32秒,1/64秒、1/128秒或1/256秒作为中断周期。
进位中断:当从64HZ计数器到二进制计数器的进位时和当改变64Hz计数器和R64同时读取CNT寄存器时进行中断。
输入捕获:当检测到捕获时间输入引脚的电平发生跳变时(上升沿或者下降沿时),可以进行输入捕获。 该输入捕获可以用日历计数或者二进制计数。电平跳变时可以产生中断。与GPT相同的是,该输入捕获也能使用噪声滤波器。
事件关联:周期性输出事件。
TrustZone过滤器:可以设置安全属性。
三、RTC时钟日历(实操)
1.新建工程
对于 Keil 开发环境:
拷贝一份我们之前的 Keil 工程 “RA_UART”, 然后将工程文件夹重命为 “RA_RTC_Date”, 并进入该文件夹里面双击 Keil 工程文件,打开该工程。
2.FSP配置
双击 configuration.xml 打开配置界面:
然后点开“Pins”->“Peripherals”->“Timers:RTC”->“RTC0”来配置SCI模块: 将“Operation Mode”配置为“Enabled”
点击配置窗口底部的“Stack”,如图步骤加入RTC模块。
属性解释,如下图:
属性
描述
Parameter Cheacking
参数检查,如果设置为Enabled则会检查RTC设置的日历时间是否合法,并通
过年月日自动计算星期。
Set Source Clock in Open
若设置为Enabled,则在函数“R_RTC_Open”中初始化时钟源,若设置为
Disabled,必须调用R_RTC_ClockSourceSet来设置RTC时钟源。
Name
模块名字,可以根据个人需要取名。
Clock Source
设置时钟源,可以选择LOCO和Sub-Clock。
Frequency Comparision Value(LOCO)
使用LOCO作为时钟源时的分频值,取值范围是7-511,默认为255,
则此时输出给日历计数器/二进制计数器的时钟脉冲为
LOCO/(255+1) = 32768/256 = 128Hz
Automatic Adjustment Mode
自动校正模式,用于校正Sub-Clock震荡过快或过慢引起的误差
(例如芯片老化,环境温度过低或过高),默认为Enable。
Automatic Adjustment Period
自动校正的时间,可选择10秒,1分钟或NONE
Adjustment Type(Plus-Minus)
自动校正类型,可以选择None,Addtion或Substraction。选择Addtion则是在
每次自动校正的时候在分频器中加上Error Adjustment Value。
选择Substraction则是在每次自动校正的时候在分频器中减去Error Adjustment Value。
Error Adjustment Value
在触发自动校正时候分频器减去或增加的值。
Callback
RTC中断回调函数的名称,根据读者需求进行设置即可。
Alarm Interrupt Priority
选择闹钟中断的优先级,如果选择Disabled则不使能闹钟中断。
Period Interrupt Priority
选择周期性中断的优先级,如果选择Disabled则不使能周期性中断。
Carry Interrupt Priority
选择进位中断的优先级。
RTCOUT
输出引脚选择,可输出1Hz或64Hz的方波,无法在待机模式下使用。
RTCICn
输入捕获引脚选择。
点击刚刚加入的窗口,在左下角的“属性”窗口中配置中断,时钟源,模块名字等属性。由于只有Sub-Clock能使用纽扣电池供电, 故时钟源建议选择Sub-Clock。
3.keil代码编写
#include "hal_data.h"
#include "stdio.h"
FSP_CPP_HEADER
void R_BSP_WarmStart(bsp_warm_start_event_t event);
FSP_CPP_FOOTER
/**********日期宏定义**********/
#define RTC_YEAR_SET 2008 //年
#define RTC_MON_SET 8 //月
#define RTC_MDAY_SET 8 //日
/*通过蔡勒公式计算星期*/
#define RTC_WDAY_SET (RTC_YEAR_SET-2000 \
+ ((RTC_YEAR_SET-2000)/4) \
- 35 + (26*(RTC_MON_SET+1))/10 \
+ RTC_MDAY_SET -1 )%7
/**********时间宏定义**********/
#define RTC_HOUR_SET 0 //时
#define RTC_SEC_SET 0 //秒
#define RTC_MIN_SET 0 //分
void RTC_Init(void)
{
//初始化时设定的时间
rtc_time_t set_time =
{ .tm_sec = RTC_SEC_SET, //秒
.tm_min = RTC_MIN_SET, //分
.tm_hour = RTC_HOUR_SET, //小时
.tm_mday = RTC_MDAY_SET, //日(一个月中)
.tm_wday = RTC_WDAY_SET, //星期
.tm_mon = RTC_MON_SET, //月份
.tm_year = RTC_YEAR_SET-1900, //年份(如今年是2008,则这里输入2008-1900=108)
};
/*打开RTC模块*/
R_RTC_Open (rtc.p_ctrl, rtc.p_cfg);
/*时钟源设置,如果在FSP Configuration设置"Set Source Clock in Open"为"enabled",那这一步可以被跳过*/
R_RTC_ClockSourceSet (rtc.p_ctrl);
/*若RTC时钟已经使用纽扣电池工作了一段时间,则可以使用这个函数获取当前日历并设置当前时间*/
//R_RTC_CalendarTimeGet(rtc.p_ctrl,&set_time);
/*这个函数至少调用一次以启动RTC*/
R_RTC_CalendarTimeSet (rtc.p_ctrl, &set_time); //设置当前时间
/*设置周期中断的周期为1秒*/
R_RTC_PeriodicIrqRateSet (rtc.p_ctrl, RTC_PERIODIC_IRQ_SELECT_1_SECOND);
}
void rtc_callback(rtc_callback_args_t *p_args)
{
static rtc_time_t get_time;
switch (p_args->event)
{
/*若是周期中断,则发送日期给串口并切换LED电平*/
case RTC_EVENT_PERIODIC_IRQ:
R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_05_PIN_01, BSP_IO_LEVEL_LOW); //反转LED
/*获取当前时间*/
R_RTC_CalendarTimeGet (rtc.p_ctrl, &get_time);
/*打印当前时间*/
printf ("\r\n%d-%d-%d-%d:%d:%d\r\n", get_time.tm_year + 1900, get_time.tm_mon, get_time.tm_mday,
get_time.tm_hour, get_time.tm_min, get_time.tm_sec);
break;
default:
break;
}
}
/* 调试串口 UART0 初始化 */
void UART0_Init(void)
{
fsp_err_t err = FSP_SUCCESS;
err = R_SCI_UART_Open (&g_uart0_ctrl, &g_uart0_cfg);
assert(FSP_SUCCESS == err);
}
/* 发送完成标志 */
volatile bool uart_send_complete_flag = false;
/* 串口中断回调 */
void uart0_callback (uart_callback_args_t * p_args)
{
switch (p_args->event)
{
case UART_EVENT_RX_CHAR:
{
/* 把串口接收到的数据发送回去 */
R_SCI_UART_Write(&g_uart0_ctrl, (uint8_t *)&(p_args->data), 1);
break;
}
case UART_EVENT_TX_COMPLETE:
{
uart_send_complete_flag = true;
break;
}
default:
break;
}
}
/* 重定向 printf 输出 */
#if defined __GNUC__ && !defined __clang__
int _write(int fd, char *pBuffer, int size); //防止编译警告
int _write(int fd, char *pBuffer, int size)
{
(void)fd;
R_SCI_UART_Write(&g_uart4_ctrl, (uint8_t *)pBuffer, (uint32_t)size);
while(uart_send_complete_flag == false);
uart_send_complete_flag = false;
return size;
}
#else
int fputc(int ch, FILE *f)
{
(void)f;
R_SCI_UART_Write(&g_uart0_ctrl, (uint8_t *)&ch, 1);
while(uart_send_complete_flag == false);
uart_send_complete_flag = false;
return ch;
}
#endif
/*******************************************************************************************************************//**
* main() is generated by the RA Configuration editor and is used to generate threads if an RTOS is used. This function
* is called by main() when no RTOS is used.
**********************************************************************************************************************/
void hal_entry(void) //相当于主函数 函数最终执行的地方
{
R_BSP_PinAccessEnable(); //启用对PFS寄存器的访问,因为后面写IO口都用BSP内联函数
UART0_Init();
RTC_Init(); //初始化RTC
printf("硬件初始化完毕\r\n");
while(1){
}
/* TODO: add your own code here */
#if BSP_TZ_SECURE_BUILD
/* Enter non-secure code */
R_BSP_NonSecureEnter();
#endif
}
效果:
总结
虽然没有板载的RTC试试效果,但是参照了学习,发现难度并不大,于是学习了分享给大家。