GD32E230 RTC报警中断使用
- GD32E230 RTC时钟源有3个,一个是内部RC振动器产生的40KHz作为时钟源,或者是有外部32768Hz晶振.,或者外部高速时钟晶振分频作为时钟源。
- 🔖个人认为最难理解难点的就是有关RTC时钟异步预分频和同步预分频的计算。在对应的用户手册上仅仅潦草一段说明就没有了,这里参考别人有关stm32 相同外设功能的介绍借鉴学习。《STM32如何计算RTC时钟异步预分频和同步预分频》
-
📑预分频寄存器 (RTC_PSC)
-
🌿
EmbeddedBuilder
参数配置填写:
c
/* structure for initialization of the RTC */
typedef struct
{
uint8_t rtc_year; /*!< RTC year value: 0x0 - 0x99(BCD format) */
hal_rtc_month_enum rtc_month; /*!< RTC month value */
uint8_t rtc_date; /*!< RTC date value: 0x1 - 0x31(BCD format) */
hal_rtc_day_of_week_enum rtc_day_of_week; /*!< RTC weekday value */
uint8_t rtc_hour; /*!< RTC hour value */
uint8_t rtc_minute; /*!< RTC minute value: 0x0 - 0x59(BCD format) */
uint8_t rtc_second; /*!< RTC second value: 0x0 - 0x59(BCD format) */
uint16_t rtc_subsecond; /*!< RTC subsecond value: 0x0 - 0xFFFF */
uint16_t rtc_factor_asyn; /*!< RTC asynchronous prescaler value: 0x0 - 0x7F */
uint16_t rtc_factor_syn; /*!< RTC synchronous prescaler value: 0x0 - 0x7FFF */
uint32_t rtc_am_pm; /*!< RTC AM/PM value */
uint32_t rtc_display_format; /*!< RTC time notation */
}hal_rtc_init_struct;
- 🥕参考前面的文章内容,计算方法给出的例程:
若想实现普通计数功能,例如使用频率为 32.768 kHz 的 LSE 获得频率为 1 Hz 的内部时钟 (ck_spre),为了最大程度降低功耗,PREDIV_A=127,则(f ck_spre)
同步预分频=32768Hz/(PREDIV_S+1)x(127+1),
1Hz=32768Hz/(PREDIV_S+1)x(127+1),
计算得,PREDIV_S=255。
- 🌿如果使用外部32768Hz晶振作为时钟源配置:
c
.rtc_factor_asyn = 0x7F;// 异步预分频系数
.rtc_factor_syn = 0xff; //同步预分频系数
- 🌿如果使用外部40KHz晶振作为时钟源配置:
c
.rtc_factor_asyn = 0x7f;
.rtc_factor_syn = 0x137;//40000//(PREDIV_S+1)x(127+1)
- ✨如果使用
EmbeddedBuilder
软件自动配置IRC40K时钟源,生成的代码,
📙使用外部32768晶振硬件电路参考
- 电路
- 🌿负载电容参数选择参考:
🎉贴出来,主要是因为在个人设计的板子上,焊接的12pf电容起振困难,不走时,后面换成了6.8pf才正常走时。
- 🌿硬件布局参考:
📗RTC时间参数数据类型说明
- 🌿有关结构体:
c
/* structure for initialization of the RTC */
typedef struct
{
uint8_t rtc_year; /*!< RTC year value: 0x0 - 0x99(BCD format) */
hal_rtc_month_enum rtc_month; /*!< RTC month value */
uint8_t rtc_date; /*!< RTC date value: 0x1 - 0x31(BCD format) */
hal_rtc_day_of_week_enum rtc_day_of_week; /*!< RTC weekday value */
uint8_t rtc_hour; /*!< RTC hour value */
uint8_t rtc_minute; /*!< RTC minute value: 0x0 - 0x59(BCD format) */
uint8_t rtc_second; /*!< RTC second value: 0x0 - 0x59(BCD format) */
uint16_t rtc_subsecond; /*!< RTC subsecond value: 0x0 - 0xFFFF */
uint16_t rtc_factor_asyn; /*!< RTC asynchronous prescaler value: 0x0 - 0x7F */
uint16_t rtc_factor_syn; /*!< RTC synchronous prescaler value: 0x0 - 0x7FFF */
uint32_t rtc_am_pm; /*!< RTC AM/PM value */
uint32_t rtc_display_format; /*!< RTC time notation */
}hal_rtc_init_struct;
/* structure for RTC alarm configuration */
typedef struct
{
uint32_t rtc_alarm_mask; /*!< RTC alarm mask */
uint32_t rtc_weekday_or_date; /*!< specify RTC alarm is on date or weekday */
uint8_t rtc_alarm_day; /*!< RTC alarm date or weekday value*/
uint8_t rtc_alarm_hour; /*!< RTC alarm hour value */
uint8_t rtc_alarm_minute; /*!< RTC alarm minute value: 0x0 - 0x59(BCD format) */
uint8_t rtc_alarm_second; /*!< RTC alarm second value: 0x0 - 0x59(BCD format) */
uint32_t rtc_alarm_subsecond; /*!< RTC alarm subsecond value: (0x000 - 0x7FFF) */
uint32_t rtc_alarm_subsecond_mask; /*!< RTC alarm subsecond mask */
uint32_t rtc_am_pm; /*!< RTC alarm AM/PM value */
}hal_rtc_alarm_struct;
/* structure for RTC time-stamp configuration */
typedef struct
{
uint8_t rtc_timestamp_month; /*!< RTC time-stamp month value */
uint8_t rtc_timestamp_date; /*!< RTC time-stamp date value: 0x1 - 0x31(BCD format) */
uint8_t rtc_timestamp_day; /*!< RTC time-stamp weekday value */
uint8_t rtc_timestamp_hour; /*!< RTC time-stamp hour value */
uint8_t rtc_timestamp_minute; /*!< RTC time-stamp minute value: 0x0 - 0x59(BCD format) */
uint8_t rtc_timestamp_second; /*!< RTC time-stamp second value: 0x0 - 0x59(BCD format) */
uint32_t rtc_timestamp_subsecond; /*!< RTC time-stamp subsecond value: 0x0 - 0xFFFF */
uint32_t rtc_am_pm; /*!< RTC time-stamp AM/PM value */
}hal_rtc_timestamp_struct;
- 🌟注意相关注释,有些参数是BCD编码。其中
年
、日
、分
、秒
为BCD格式,其余为BIN格式。
- 🌿有关BCD码转BIN码网上随便一搜即可获得:
c
// 将BCD格式转换为BIN格式
uint8_t bcd_to_bin(uint8_t bcd_value) {
uint8_t tens = bcd_value >> 4;
uint8_t ones = bcd_value & 0x0F;
return (tens * 10) + ones;
}
// 将BIN格式转换为BCD格式
uint8_t bin_to_bcd(uint8_t bin_value) {
uint8_t tens = bin_value / 10;
uint8_t ones = bin_value % 10;
return (tens << 4) | ones;
}
- 🌿RTC初始化配置代码:
c
void msd_rtc_init(void)
{
/* user code [rtc_init local 0] begin */
/* user code [rtc_init local 0] end */
hal_rtc_init_struct rtc_init_parameter;
hal_rtc_alarm_struct rtc_alarm_parameter;
/* enable the RTC */
// rcu_periph_clock_enable(RCU_RTC);
// hal_rcu_periph_clk_enable(RCU_RTC);
// rcu_periph_clock_enable(RCU_PMU); //使能PMU电源管理单元时钟
// pmu_backup_write_enable(); //使能电源备份源,RTC需要此备份域
if (ENABLE_LXTAL)
{
rcu_osci_on(RCU_LXTAL);
rcu_osci_stab_wait(RCU_LXTAL);
rcu_rtc_clock_config(RCU_RTCSRC_LXTAL); // 配置RTC时钟源
}
else
{
/* enable the IRC40K oscillator */
rcu_osci_on(RCU_IRC40K);
/* wait till IRC40K is ready */
rcu_osci_stab_wait(RCU_IRC40K);
/* select the RTC clock source */
rcu_rtc_clock_config(RCU_RTCSRC_IRC40K); // 配置RTC时钟源
}
rcu_periph_clock_enable(RCU_RTC);
rtc_register_sync_wait();
hal_rtc_struct_init(HAL_RTC_INIT_STRUCT, &rtc_init_parameter);
hal_rtc_struct_init(HAL_RTC_ALARM_STRUCT, &rtc_alarm_parameter);
hal_rtc_deinit();
if (ENABLE_LXTAL)
{
rtc_init_parameter.rtc_factor_asyn = 0x7F;// 高位分频
rtc_init_parameter.rtc_factor_syn = 0xff; //低位分频
}
else
{
rtc_init_parameter.rtc_factor_asyn = 0x7f;
rtc_init_parameter.rtc_factor_syn = 0x137;
}
rtc_init_parameter.rtc_display_format = HAL_RTC_24HOUR;
rtc_init_parameter.rtc_year = 0x24;//BCD format
rtc_init_parameter.rtc_month = HAL_RTC_SEP;
rtc_init_parameter.rtc_date = 0x7; //BCD format
rtc_init_parameter.rtc_day_of_week = HAL_RTC_SATURDAY;
rtc_init_parameter.rtc_hour = 10;
rtc_init_parameter.rtc_minute = 0x30;//BCD format
rtc_init_parameter.rtc_second = 0x0; //BCD format
hal_rtc_init(&rtc_init_parameter);
hal_rtc_daylight_saving_time_adjust(HAL_RTC_DAYLIGHTSAVING_NONE, HAL_RTC_RECORD_DAYLIGHTSAVING_RESET);
rtc_alarm_parameter.rtc_alarm_mask = HAL_RTC_ALARM_DATE_MASK | HAL_RTC_ALARM_HOUR_MASK | HAL_RTC_ALARM_MINUTE_MASK;
rtc_alarm_parameter.rtc_weekday_or_date = HAL_RTC_ALARM_DATE_SELECTED;
rtc_alarm_parameter.rtc_alarm_day = 0x7;
rtc_alarm_parameter.rtc_alarm_hour = 10;
rtc_alarm_parameter.rtc_alarm_minute = 0x30;
rtc_alarm_parameter.rtc_alarm_second = 0x09;
rtc_alarm_parameter.rtc_alarm_subsecond = 0x0;
rtc_alarm_parameter.rtc_alarm_subsecond_mask = HAL_RTC_MASK_SUBSECOND;
hal_rtc_alarm_config(&rtc_alarm_parameter);
hal_nvic_periph_irq_enable(RTC_IRQn, 1);
/* user code [rtc_init local 1] begin */
rtc_interrupt_enable(RTC_INT_ALARM);//使能RTC中断
rtc_alarm_enable();//使能RTC报警中断
/* user code [rtc_init local 1] end */
}
- 🌿RTC初始化之后就是对中断回调函数进行补充:
c
volatile uint8_t RTC_ALRM_FLAG = 0; //闹钟标志位
hal_rtc_irq_struct rtc_irq;
void RTC_ALRM_Callback(void)//报警中断回调任务,不是RTC中断执行的任务。
{
printf("RTC alarm Task\n\r");
}
......
rtc_irq.alarm_handle = RTC_ALRM_Callback;
hal_rtc_irq_handle_set(&rtc_irq);
- 🌿RTC中断函数
c
void RTC_IRQHandler(void)
{
/* user code [RTC_IRQn local 0] begin */
/* user code [RTC_IRQn local 0] end */
hal_rtc_irq();
// if(RESET != rtc_flag_get(RTC_STAT_ALRM0F)){
// rtc_flag_clear(RTC_STAT_ALRM0F);
// exti_flag_clear(EXTI_17);
// gpio_bit_toggle(GPIOC, GPIO_PIN_13);
// }
/* user code [RTC_IRQn local 1] begin */
RTC_ALRM_FLAG =1;
gpio_bit_toggle(GPIOC, GPIO_PIN_13);
/* user code [RTC_IRQn local 1] end */
}
- 🔖每分钟中断一次打印:
- 🌟需要注意:在使用RTC报警中断时,也是会触发RTC中断,报警中断需要执行的任务函数可以通过下面来传递执行:(具体书写看上面贴出的完整代码)
c
rtc_irq.alarm_handle = RTC_ALRM_Callback;//传递任务句柄
hal_rtc_irq_handle_set(&rtc_irq);
也可以报警中断需要执行的任务放在RTC中断函数中调用或者置标记位。
c
void RTC_IRQHandler(void)
{
/* user code [RTC_IRQn local 0] begin */
/* user code [RTC_IRQn local 0] end */
hal_rtc_irq();
// if(RESET != rtc_flag_get(RTC_STAT_ALRM0F)){//判断报警类型
// rtc_flag_clear(RTC_STAT_ALRM0F);
// exti_flag_clear(EXTI_17);
// gpio_bit_toggle(GPIOC, GPIO_PIN_13);
// }
/* user code [RTC_IRQn local 1] begin */
RTC_ALRM_FLAG =1;
gpio_bit_toggle(GPIOC, GPIO_PIN_13);
/* user code [RTC_IRQn local 1] end */
}
- 🌿配置时间打印函数:
c
/*!
\brief display the current time
\param[in] none
\param[out] none
\retval none
*/
void rtc_show_time(void)
{
hal_rtc_init_struct rtc_init;
uint32_t time_subsecond = 0;
uint8_t subsecond_ss = 0;
hal_rtc_current_time_get(&rtc_init);
/* convert the subsecond value into fractional format */
time_subsecond = rtc_init.rtc_subsecond;
subsecond_ss = (1000 - (time_subsecond * 1000 + 1000) / 400) / 100;
// subsecond_ts = (1000 - (time_subsecond * 1000 + 1000) / 400) % 100 / 10;
// subsecond_hs = (1000 - (time_subsecond * 1000 + 1000) / 400) % 10;
printf("Current Date: 20%0.2d-%0.2d-%0.2d T:%0.1d \n\r", \
bcd_to_bin(rtc_init.rtc_year), rtc_init.rtc_month, bcd_to_bin(rtc_init.rtc_date), rtc_init.rtc_day_of_week);
printf("Current Time: %0.2d:%0.2d:%0.2d.%d \n\r", \
rtc_init.rtc_hour, bcd_to_bin(rtc_init.rtc_minute), bcd_to_bin(rtc_init.rtc_second), \
subsecond_ss);
}
-🌿 测试代码在《GD32E230程序烧录和开发环境使用介绍》文中。