【时钟】
CW32L083 内置多路时钟产生电路,通过分频器和多路选择器产生各种不同频率的时钟给 CPU 及各外设使用。系统时钟树结构示意图如图 4-1 系统内部时钟树所示。
系统内部时钟 SysClk 经过分频为 CPU 内核提供高级高性能总线时钟 HCLK,HCLK 时钟经过分频为数字及模拟外
设提供高级外设时钟 PCLK。
系统时钟 SYSCLK 有 5 个时钟源:
● 外部高速振荡器时钟(HSE)
● 外部低速振荡器时钟(LSE)
● HSI 时钟,由内部高速 RC 振荡器时钟(HSIOSC)经过分频产生
● 内部低速 RC 振荡器时钟(LSI)
● PLL 锁相环时钟,由 HSE 时钟或 HSI 时钟经锁相环 PLL 倍频(2~12 倍)产生
【时钟源选择】
CW32L083最高可以跑到64MHz,开发板上板载了16M晶振。因此本次使用外部晶振做为MCU的时钟源,使用PLL进行4倍扩频产生HCLK64M
【代码编写】
由于Flash在不同的时钟需要指定相应的读取延时,所以需要引入cw32l083_flash固件库。并使用RCC_AHBPeriphClk_Enable(RCC_AHB_PERIPH_FLASH, ENABLE); //打开FLASH时钟,
我们开机时是使用HSI时钟的,所以选RCC_HSE_Enable切换到HSE。再使用RCC_PLL_Enable开启PLL,同时设置FLASH延时为2。代码如下。
void RCC_Config(void) { uint8_t res; //以下从HSI切换到HSE RCC_AHBPeriphClk_Enable(RCC_AHB_PERIPH_FLASH, ENABLE); //打开FLASH时钟 //以下从HSI切换到PLL RCC_HSE_Enable(RCC_HSE_MODE_OSC, 16000000, RCC_HSE_DRIVER_NORMAL, RCC_HSE_FLT_CLOSE); //开启外部高速时钟HSE,实际频率需要根据实际晶体频率进行填写 RCC_PLL_Enable(RCC_PLLSOURCE_HSEOSC, 16000000, RCC_PLL_MUL_4); //开启PLL,PLL时钟来源为HSE FLASH_SetLatency(FLASH_Latency_3); //频率大于24M需要配置FlashWait=2 res = RCC_SysClk_Switch(RCC_SYSCLKSRC_PLL); //切换系统时钟到PLL if (res == 0x00) //切换系统时钟成功 { RCC_HSI_Disable(); //切换时钟到PLL后关闭源时钟HSI } }
如果时钟选择成功,则关闭HSI时钟。
【测试】
在设置时钟成功后,使用打印函数进行验证:
说明,时钟切换是成功的。
时钟切换好后,我们需要用到精确的us延时,因此,添加delay.c/h函数到工程之中。根据相关寄存器图:
1、我们先使用设置systick的时钟,设定1us 溢出一次
void Delay_Init(void) { /* SystemFrequency / 1000 1ms溢出一次 * SystemFrequency / 100000 10us溢出一次 * SystemFrequency / 1000000 1us溢出一次 */ SysTick_Config(RCC_Sysctrl_GetHClkFreq()/1000000); }
2、编写微秒延时,首先向LOAD寄存器,延后向VAL寄存器写入0x00,再打开CTRL位的SysTick_CTRL_ENABLE_Msk。最后等待SysTick_CTRL_COUNTFLAG_Msk置位。
void Delay_US(uint16_t us) { SysTick->LOAD = us*64; SysTick->VAL = 0x00; SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; while( !(SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk)); } void Delay_MS(uint16_t ms) { while(ms--) { Delay_US(1000); } }
【验证】
在主函数中延时1000毫秒,在串口打印时间,可以看到延时准确:
int32_t main(void) { led.LED_Port = CW_GPIOC; led.LED_Pin = GPIO_PIN_3; LED_Init(&led); RCC_Config(); Delay_Init(); UART1_Init(961200); CW_U1_printf("hello world\r\n"); CW_U1_printf("%d,%c,%x\n",0x30,0x30,0x30); CW_U1_printf("%s\n%s\n",__FILE__,__TIME__); CW_U1_printf("HCLK(Hz):%d\r\n",RCC_Sysctrl_GetHClkFreq()); CW_U1_printf("PCLK(Hz):%d\r\n",RCC_Sysctrl_GetPClkFreq()); while(1) { led.LED_Toggle(&led); Delay_MS(1000); CW_U1_printf("hello world\r\n"); } }
【总结】
本篇分享了如何切换HSE时钟,与SysTick实现精准延时。为后面的工程打好基础。
【附源代码】