本文最后更新于19 天前,其中的信息可能已经过时,如有错误请发送邮件到tudougin@163.com
1. 系统时钟的设定
BAT32G133内存在的各时钟:
- 主系统时钟 fMAIN
- 高速系统时钟 fMX
- X1时钟 fX
- 外部主系统时钟 fEX
- 高速内部振荡器时钟 fIH
- 高速系统时钟 fMX
- 副系统时钟 fSUB
- XT1时钟 fXT
- 外部副系统时钟 fEXS
- 低速内部振荡器时钟 f IL
- 高速内部振荡器时钟 f HOCO
- CPU/外围硬件时钟 fCLK
1.1 高速内部振荡器(fHOCO与fIH)
- fHOCO 与 fIH 的区别与联系
- fHOCO:指的是高速内部振荡器(HOCO)本身的原始频率。
- fIH:指的是系统实际使用的高速内部时钟(即经过分频后的 HOCO 输出)。
- 通过选项字节
000C2H
中的FRQSEL[4:0]
位设置 fHOCO与fIH- FRQSEL[4:3]:选择 HOCO 的基本输出频率,64MHz/48MHz;
- FRQSEL[2:0]:控制 HOCO 输出频率的分频系数,从而得到系统实际使用的主时钟 fIH。
- 设置方式在烧录阶段由编程工具写入,复位后即生效。
- 选项字节的设置
- 高速内部振荡器的频率选择寄存器(HOCODIV)的设置
对于这里,我在实际开发中遇到了一个错误。示例工程中用到的Bat32G133系统文件与keil中生成的文件不同system_BAT32G133.c
.这是前提。keil生成的文件及注释描述和例程的文件均与应用手册不完全一致。
使用库进行,对串口方面进行开发,发现发出数据有误,经排查猜测为时钟有问题。更换系统文件后编译下载,现象正常。系统文件的差异在于fHOCO存在8M及fIH最低为1M,且寄存器值不一致。在此记录一下,后续再去深究原因
1.2 X1时钟与XT1时钟的使能
引脚对 | 功能模式 | 描述 |
---|---|---|
X1/X2 | 外部主晶振输入 | 接入一个外部主晶体振荡器( <= 20MHz ) |
X2 | 外部主时钟输入 | 只使用 X2 接收外部提供的 CMOS 级时钟信号 |
XT1/XT2 | 外部低速晶振输入 | 通常接 32.768kHz 的晶体用于 RTC 等 |
XT2 | 外部低速时钟输入 | 仅使用 XT2 接收低速 CMOS 时钟信号 |
/***********************************************************************************************************************
* Function Name: CLK_Osc_Setting
* @brief This function initializes the Main OSC and Sub OSC.
* @param main
* - OSC_PORT: X1, X2 as PORT
* - OSC_OSCILLATOR: X1, X2 as oscillator and connect crystal/ceramic resonator
* - OSC_EXCLK: X1, as PORT, X2 as external clock input
* @param sub
* - OSC_PORT: XT1, XT2 as PORT
* - OSC_OSCILLATOR: XT1, XT2 as oscillator and connect crystal resonator
* - OSC_EXCLK: XT1 as PORT, XT2 as external clock input
* @return None
***********************************************************************************************************************/
void CLK_Osc_Setting(osc_pin_mode_t main, osc_pin_mode_t sub)
1.3 CPU/外围硬件时钟 fCLK
fCLK
是系统主时钟,决定了 CPU 和部分外设的运行速度。- 它可以通过寄存器选择自以下三个来源之一:
时钟源 | 描述 |
---|---|
fIH | 高速内部振荡器(HOCO) |
fMX | 外部主时钟(X2 或 X1/X2) |
fSUB | 外部子时钟(XT2 或 XT1/XT2,常用于 RTC) |
/***********************************************************************************************************************
* Function Name: CLK_Fclk_Select
* @brief This function selects the system clock(fCLK).
* @param cks
* - MAINCLK_FIH: fIH as system clock(fCLK)
* - MAINCLK_FMX: fMX as system clock(fCLK)
* - MAINCLK_FSUB: fSUB as system clock(fCLK)
* @return CKC register value
***********************************************************************************************************************/
uint8_t CLK_Fclk_Select(clock_select_t cks);
while((CGC->CKC & CGC_CKC_MCS_Msk) == 0); //MCS:0 fIH / 1 fMX ,校验fCLK是否切换到fMX
while((CGC->CKC & CGC_CKC_CLS_Msk) == 0); //MCS:0 fMAIN/ 1 fSUB,校验fCLK是否切换到fSUB
2. 滴答定时器
滴答定时器(SysTick Timer),不是BAT32G133的外设,而是基于 ARM Cortex-M 核心的微控制器中是一个标准组件,用于周期性中断,常被用于操作系统心跳、时间延迟、定时任务调度等。这里更多用于时间延迟。
SystemCoreClockUpdate();
SysTick_Config(SystemCoreClock / 1000);
volatile uint32_t GTick = 0;
DelayMs(500);
void DelayMs(uint32_t Time){
GTick = Time;
while(GTick);
}
void SysTick_Handler(void)
{
if(GTick) GTick--;
}
3. RTC时钟
RTC(Real-Time Clock)是一个可以记录时间的硬件模块(年、月、日、时、分、秒),常用于:
- 低功耗唤醒 / 实时时间记录
- 日历、定时器、报警功能
- 深度睡眠唤醒源
3.1 RTC时钟及中断的设置
RTC_Init(RTC_FSUB);
RTC_Start();
date_time.year = 0x19;
date_time.month = 0x08;
date_time.week = SATURDAY;
date_time.day = 0x31;
date_time.hour = 0x08;
date_time.min = 0x30;
date_time.sec = 0x00;
RTC_Set_CounterValue(&date_time);
RTC_Set_ConstPeriodInterruptOn(ONESEC);
3.2 RTC闹钟设置
rtc_alarm_value_t alarm = {0x00,0x08,0b00111110};
RTC_Set_AlarmValue(alarm);
RTC_Set_AlarmOn();
3.3 中断服务函数
/***********************************************************************************************************************
* Function Name: rtc_interrupt
* @brief RTC interrupt service routine
* @param None
* @return None
***********************************************************************************************************************/
void rtc_interrupt(void)
{
if (RTC->RTCC1 & RTC_RTCC1_WAFG_Msk)
{
RTC->RTCC1 &= (uint8_t)~_10_RTC_ALARM_MATCH; /* clear WAFG */
INTC_ClearPendingIRQ(RTC_IRQn); /* clear INTRTC flag */
rtc_callback_alarm();
}
if (RTC->RTCC1 & RTC_RTCC1_RIFG_Msk)
{
RTC->RTCC1 &= (uint8_t)~_08_RTC_INTC_GENERATE_FLAG; /* clear RIFG */
INTC_ClearPendingIRQ(RTC_IRQn); /* clear INTRTC flag */
rtc_callback_constperiod();
}
}
/***********************************************************************************************************************
* Function Name: rtc_callback_constperiod
* @brief This function is real-time clock constant-period interrupt service handler.
* @param None
* @return None
***********************************************************************************************************************/
static void rtc_callback_constperiod(void)
{
/* Start user code. Do not edit comment generated here */
g_rtcIntTaken++;
RTC_Get_CounterValue(&date_time);
printf("20%02x/%02x/%02x %02x:%02x:%02x\n", date_time.year, date_time.month, date_time.day, date_time.hour, date_time.min, date_time.sec);
/* End user code. Do not edit comment generated here */
}