#申请原创# @21小跑堂
3.了解系统时钟与延时函数的实现
3.1认识CW32L083的时钟源
CW32L083可选择5种时钟源,包括HSE、LSE、PLL、HSI、LSI
HSE是外部高速时钟,有两种工作模式
可以使用的晶振频率如下
评估板上焊接了一颗16MHz的晶振作为高速时钟源
LSE是外部低速时钟,与HSE类似也有两种工作模式
评估板上接的是32.768K的晶振作为低速时钟源
HSI是内部高速时钟,由内部RC振荡器产生并分频而来,不需要外部电路,比HSE时钟的成本低,启动速度快,HSIOSC时钟频率固定为48MHz,频率精度低于HSE时钟
LSI是内部低速时钟,由内部低速RC振荡器产生,默认频率为 32.8kHz,与HSI类似内部低速RC振荡器不需要外部电路,比LSE时钟的成本低,但精度低于LSE时钟
PLL可对输入时钟源进行倍频输出,通过PLL可以使用最高64MHz的时钟,可用的时钟源有
3.2使用不同的时钟源
在之前创建的工程中并没有特意的配置时钟,通过手册可以知道通电默认使用的HSI频率为8MHz
使用MCO_OUT(PA08)输出HCLK的512分频波形
int32_t main(void)
{
RCC_HCLKPRS_Config(RCC_HCLK_DIV1);
RCC_PCLKPRS_Config(RCC_PCLK_DIV1);
RCC_MCO_OUT(RCC_MCO_SRC_HCLK,RCC_MCO_DIV512);
while(1)
{
}
}
查看输出的波形
15.625KHz x 512 = 8000KHz = 8MHz
接下来使用内部48MHz时钟不分频初始化,需要注意的是CW32的FLASH存储器支持最快24MHz的操作时钟,当系统时钟设置超过24MHz后要设置FLASH的等待周期,且此操作必须在时钟频率切换之前执行,这里输出时改用1024分频
void RCC_HSI_init()
{
//< 当使用的时钟源HCLK大于24M,小于等于48MHz:设置FLASH 读等待周期为2 cycle >
__RCC_FLASH_CLK_ENABLE();
FLASH_SetLatency(FLASH_Latency_2);
/* HSI使能 */
RCC_HSI_Enable(RCC_HSIOSC_DIV1); //1分频要在设置之前设置FLASH读等待周期
RCC_SystemCoreClockUpdate(48000000);
}
int32_t main(void)
{
RCC_HSI_init();
RCC_HCLKPRS_Config(RCC_HCLK_DIV1);
RCC_PCLKPRS_Config(RCC_PCLK_DIV1);
RCC_MCO_OUT(RCC_MCO_SRC_HCLK,RCC_MCO_DIV1024);
while(1)
{
}
}
输出波形
45.455KHz x 1024 = 46545.92KHz = 46.5MHz
再来用外部16MHz晶振来初始化
void RCC_HSE_16M_init()
{
RCC_HSE_Enable( RCC_HSE_MODE_OSC, 16000000, RCC_HSE_DRIVER_NORMAL, RCC_HSE_FLT_CLOSE);
RCC_SysClk_Switch( RCC_SYSCLKSRC_HSE );
RCC_HSI_Disable();
RCC_SystemCoreClockUpdate(16000000);
}
int32_t main(void)
{
RCC_HSE_16M_init();
RCC_HCLKPRS_Config(RCC_HCLK_DIV1);
RCC_PCLKPRS_Config(RCC_PCLK_DIV1);
RCC_MCO_OUT(RCC_MCO_SRC_HCLK,RCC_MCO_DIV1024);
while(1)
{
}
}
输出波形
15.625KHz x 1024 = 16000KHz = 16MHz
接下来使用外部时钟PLL到64MHz
void RCC_HSE_16M_PLL64M_init()
{
//< 当使用的时钟源HCLK大于48M,小于等于72MHz:设置FLASH 读等待周期为3 cycle >
__RCC_FLASH_CLK_ENABLE();
FLASH_SetLatency(FLASH_Latency_3);
RCC_HSE_Enable( RCC_HSE_MODE_OSC, 16000000, RCC_HSE_DRIVER_NORMAL, RCC_HSE_FLT_CLOSE);
RCC_PLL_Enable(RCC_PLLSOURCE_HSEOSC,16000000,RCC_PLL_MUL_4);
RCC_SysClk_Switch( RCC_SYSCLKSRC_PLL );
RCC_HSI_Disable();
RCC_SystemCoreClockUpdate(64000000);
}
int32_t main(void)
{
RCC_HSE_16M_PLL64M_init();
RCC_HCLKPRS_Config(RCC_HCLK_DIV1);
RCC_PCLKPRS_Config(RCC_PCLK_DIV1);
RCC_MCO_OUT(RCC_MCO_SRC_HCLK,RCC_MCO_DIV1024);
while(1)
{
}
}
输出波形
62.5KHz x 1024 = 64000KHz = 64MHz
接下来用内部48MHz时钟6分频得到8MHz再倍频到64MHz
void RCC_HSI_PLL64M_init()
{
//< 当使用的时钟源HCLK大于48M,小于等于72MHz:设置FLASH 读等待周期为3 cycle >
__RCC_FLASH_CLK_ENABLE();
FLASH_SetLatency(FLASH_Latency_3);
RCC_HSI_Enable(RCC_HSIOSC_DIV6);
RCC_PLL_Enable(RCC_PLLSOURCE_HSI,8000000,RCC_PLL_MUL_8);
RCC_SysClk_Switch( RCC_SYSCLKSRC_PLL );
RCC_SystemCoreClockUpdate(64000000);
}
int32_t main(void)
{
RCC_HSI_PLL64M_init();
RCC_HCLKPRS_Config(RCC_HCLK_DIV1);
RCC_PCLKPRS_Config(RCC_PCLK_DIV1);
RCC_MCO_OUT(RCC_MCO_SRC_HCLK,RCC_MCO_DIV1024);
while(1)
{
}
}
输出波形
62.5KHz x 1024 = 64000KHz = 64MHz
使用内部低速时钟LSI
void RCC_LSI_init()
{
RCC_LSI_Enable();
RCC_SysClk_Switch(RCC_SYSCLKSRC_LSI);
RCC_HSI_Disable();
RCC_SystemCoreClockUpdate(32800);
}
int32_t main(void)
{
RCC_LSI_init();
RCC_HCLKPRS_Config(RCC_HCLK_DIV1);
RCC_PCLKPRS_Config(RCC_PCLK_DIV1);
RCC_MCO_OUT(RCC_MCO_SRC_HCLK,RCC_MCO_DIV1);
while(1)
{
}
}
输出波形
使用外部低速晶振
void RCC_LSE_init()
{
RCC_LSE_Enable(RCC_LSE_MODE_OSC,RCC_LSE_AMP_LARGER,RCC_LSE_DRIVER_LARGER);
RCC_SysClk_Switch(RCC_SYSCLKSRC_LSE);
RCC_HSI_Disable();
RCC_SystemCoreClockUpdate(32768);
}
int32_t main(void)
{
RCC_LSE_init();
RCC_HCLKPRS_Config(RCC_HCLK_DIV1);
RCC_PCLKPRS_Config(RCC_PCLK_DIV1);
RCC_MCO_OUT(RCC_MCO_SRC_HCLK,RCC_MCO_DIV1);
while(1)
{
}
}
输出波形
3.3延时函数的实现
L083的system_cw32l083.c中有一个FirmwareDelay方法用于延时
但是这个并不好控制具体延时多长时间,利用SysTick可以做一个Arm内核的通用延时方法,SysTick定时器(又名系统滴答定时器)是存在于ARM Cotex-M系列内核中的定时器。具体实现方法
extern uint32_t SystemCoreClock;
void yuyy_delay_us(uint16_t us)
{
uint32_t temp;
SysTick->CTRL = 0x0; /*!< disable systick function */
SysTick->LOAD = us * (SystemCoreClock/1000000); /*!< time count for 1us with SYSCLK */
SysTick->VAL = 0x00; /*!< clear counter */
SysTick->CTRL = 0x5; /*!< start discrease with Polling */
do
{
temp = SysTick->CTRL;
}
while ((temp & 0x01) && !(temp & (1 << 16))); /*!< wait time count done */
SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; /*!< Close Counter */
SysTick->VAL = 0X00;
}
void yuyy_delay_ms(uint16_t ms)
{
while(ms--)
yuyy_delay_us(1000);
}
这个延时方法我已经在M0 M3 M4 M33的MCU上都使用过了,移植基本不用改动,只要注意修改时钟源后更新系统时钟就行了
|
概述CW32L083的时钟系统,并基于滴答定时器实现延时函数