返回列表 发新帖我要提问本帖赏金: 30.00元(功能说明)

[CW32L083系列] CW32L083评估板学习-3.了解系统时钟与延时函数的实现

[复制链接]
 楼主| yuyy1989 发表于 2023-8-5 20:06 | 显示全部楼层 |阅读模式
<
#申请原创# @21小跑堂
3.了解系统时钟与延时函数的实现
3.1认识CW32L083的时钟源
CW32L083可选择5种时钟源,包括HSE、LSE、PLL、HSI、LSI
QQ截图20230804224728.png
HSE是外部高速时钟,有两种工作模式
QQ截图20230804232346.png
可以使用的晶振频率如下
QQ截图20230804232621.png
评估板上焊接了一颗16MHz的晶振作为高速时钟源
LSE是外部低速时钟,与HSE类似也有两种工作模式
QQ截图20230804232802.png
评估板上接的是32.768K的晶振作为低速时钟源
HSI是内部高速时钟,由内部RC振荡器产生并分频而来,不需要外部电路,比HSE时钟的成本低,启动速度快,HSIOSC时钟频率固定为48MHz,频率精度低于HSE时钟
LSI是内部低速时钟,由内部低速RC振荡器产生,默认频率为 32.8kHz,与HSI类似内部低速RC振荡器不需要外部电路,比LSE时钟的成本低,但精度低于LSE时钟
PLL可对输入时钟源进行倍频输出,通过PLL可以使用最高64MHz的时钟,可用的时钟源有
QQ截图20230804234001.png
3.2使用不同的时钟源
在之前创建的工程中并没有特意的配置时钟,通过手册可以知道通电默认使用的HSI频率为8MHz
QQ截图20230805000404.png
使用MCO_OUT(PA08)输出HCLK的512分频波形

  1. int32_t main(void)
  2. {
  3.     RCC_HCLKPRS_Config(RCC_HCLK_DIV1);
  4.     RCC_PCLKPRS_Config(RCC_PCLK_DIV1);
  5.     RCC_MCO_OUT(RCC_MCO_SRC_HCLK,RCC_MCO_DIV512);
  6.     while(1)
  7.     {
  8.     }
  9. }
查看输出的波形
QQ截图20230805155946.png
15.625KHz x 512 = 8000KHz = 8MHz
接下来使用内部48MHz时钟不分频初始化,需要注意的是CW32的FLASH存储器支持最快24MHz的操作时钟,当系统时钟设置超过24MHz后要设置FLASH的等待周期,且此操作必须在时钟频率切换之前执行,这里输出时改用1024分频

  1. void RCC_HSI_init()
  2. {
  3.     //< 当使用的时钟源HCLK大于24M,小于等于48MHz:设置FLASH 读等待周期为2 cycle >
  4.     __RCC_FLASH_CLK_ENABLE();
  5.     FLASH_SetLatency(FLASH_Latency_2);
  6.     /* HSI使能 */
  7.     RCC_HSI_Enable(RCC_HSIOSC_DIV1); //1分频要在设置之前设置FLASH读等待周期
  8.     RCC_SystemCoreClockUpdate(48000000);
  9. }
  10. int32_t main(void)
  11. {
  12.         RCC_HSI_init();
  13.     RCC_HCLKPRS_Config(RCC_HCLK_DIV1);
  14.     RCC_PCLKPRS_Config(RCC_PCLK_DIV1);
  15.     RCC_MCO_OUT(RCC_MCO_SRC_HCLK,RCC_MCO_DIV1024);
  16.     while(1)
  17.     {
  18.     }
  19. }
输出波形
QQ截图20230805160612.png
45.455KHz x 1024 = 46545.92KHz = 46.5MHz
再来用外部16MHz晶振来初始化

  1. void RCC_HSE_16M_init()
  2. {
  3.     RCC_HSE_Enable( RCC_HSE_MODE_OSC, 16000000, RCC_HSE_DRIVER_NORMAL, RCC_HSE_FLT_CLOSE);
  4.     RCC_SysClk_Switch( RCC_SYSCLKSRC_HSE );
  5.     RCC_HSI_Disable();
  6.     RCC_SystemCoreClockUpdate(16000000);
  7. }
  8. int32_t main(void)
  9. {
  10.         RCC_HSE_16M_init();
  11.     RCC_HCLKPRS_Config(RCC_HCLK_DIV1);
  12.     RCC_PCLKPRS_Config(RCC_PCLK_DIV1);
  13.     RCC_MCO_OUT(RCC_MCO_SRC_HCLK,RCC_MCO_DIV1024);
  14.     while(1)
  15.     {
  16.     }
  17. }
输出波形
QQ截图20230805160848.png
15.625KHz x 1024 = 16000KHz = 16MHz
接下来使用外部时钟PLL到64MHz

  1. void RCC_HSE_16M_PLL64M_init()
  2. {
  3.     //< 当使用的时钟源HCLK大于48M,小于等于72MHz:设置FLASH 读等待周期为3 cycle >
  4.     __RCC_FLASH_CLK_ENABLE();
  5.     FLASH_SetLatency(FLASH_Latency_3);
  6.     RCC_HSE_Enable( RCC_HSE_MODE_OSC, 16000000, RCC_HSE_DRIVER_NORMAL, RCC_HSE_FLT_CLOSE);
  7.     RCC_PLL_Enable(RCC_PLLSOURCE_HSEOSC,16000000,RCC_PLL_MUL_4);
  8.     RCC_SysClk_Switch( RCC_SYSCLKSRC_PLL );
  9.     RCC_HSI_Disable();
  10.     RCC_SystemCoreClockUpdate(64000000);
  11. }
  12. int32_t main(void)
  13. {
  14.         RCC_HSE_16M_PLL64M_init();
  15.     RCC_HCLKPRS_Config(RCC_HCLK_DIV1);
  16.     RCC_PCLKPRS_Config(RCC_PCLK_DIV1);
  17.     RCC_MCO_OUT(RCC_MCO_SRC_HCLK,RCC_MCO_DIV1024);
  18.     while(1)
  19.     {
  20.     }
  21. }
输出波形
QQ截图20230805161006.png
62.5KHz x 1024 = 64000KHz = 64MHz
接下来用内部48MHz时钟6分频得到8MHz再倍频到64MHz

  1. void RCC_HSI_PLL64M_init()
  2. {
  3.     //< 当使用的时钟源HCLK大于48M,小于等于72MHz:设置FLASH 读等待周期为3 cycle >
  4.     __RCC_FLASH_CLK_ENABLE();
  5.     FLASH_SetLatency(FLASH_Latency_3);
  6.     RCC_HSI_Enable(RCC_HSIOSC_DIV6);
  7.     RCC_PLL_Enable(RCC_PLLSOURCE_HSI,8000000,RCC_PLL_MUL_8);
  8.     RCC_SysClk_Switch( RCC_SYSCLKSRC_PLL );
  9.     RCC_SystemCoreClockUpdate(64000000);
  10. }
  11. int32_t main(void)
  12. {
  13.         RCC_HSI_PLL64M_init();
  14.     RCC_HCLKPRS_Config(RCC_HCLK_DIV1);
  15.     RCC_PCLKPRS_Config(RCC_PCLK_DIV1);
  16.     RCC_MCO_OUT(RCC_MCO_SRC_HCLK,RCC_MCO_DIV1024);
  17.     while(1)
  18.     {
  19.     }
  20. }
输出波形
QQ截图20230805161534.png
62.5KHz x 1024 = 64000KHz = 64MHz
使用内部低速时钟LSI

  1. void RCC_LSI_init()
  2. {
  3.     RCC_LSI_Enable();
  4.     RCC_SysClk_Switch(RCC_SYSCLKSRC_LSI);
  5.     RCC_HSI_Disable();
  6.     RCC_SystemCoreClockUpdate(32800);
  7. }
  8. int32_t main(void)
  9. {
  10.         RCC_LSI_init();
  11.     RCC_HCLKPRS_Config(RCC_HCLK_DIV1);
  12.     RCC_PCLKPRS_Config(RCC_PCLK_DIV1);
  13.     RCC_MCO_OUT(RCC_MCO_SRC_HCLK,RCC_MCO_DIV1);
  14.     while(1)
  15.     {
  16.     }
  17. }
输出波形
QQ截图20230805162833.png
使用外部低速晶振

  1. void RCC_LSE_init()
  2. {
  3.     RCC_LSE_Enable(RCC_LSE_MODE_OSC,RCC_LSE_AMP_LARGER,RCC_LSE_DRIVER_LARGER);
  4.     RCC_SysClk_Switch(RCC_SYSCLKSRC_LSE);
  5.     RCC_HSI_Disable();
  6.     RCC_SystemCoreClockUpdate(32768);
  7. }
  8. int32_t main(void)
  9. {
  10.         RCC_LSE_init();
  11.     RCC_HCLKPRS_Config(RCC_HCLK_DIV1);
  12.     RCC_PCLKPRS_Config(RCC_PCLK_DIV1);
  13.     RCC_MCO_OUT(RCC_MCO_SRC_HCLK,RCC_MCO_DIV1);
  14.     while(1)
  15.     {
  16.     }
  17. }
输出波形
QQ截图20230805162929.png
3.3延时函数的实现
L083的system_cw32l083.c中有一个FirmwareDelay方法用于延时
QQ截图20230805163131.png
但是这个并不好控制具体延时多长时间,利用SysTick可以做一个Arm内核的通用延时方法,SysTick定时器(又名系统滴答定时器)是存在于ARM Cotex-M系列内核中的定时器。具体实现方法

  1. extern uint32_t SystemCoreClock;
  2. void yuyy_delay_us(uint16_t us)
  3. {
  4.     uint32_t temp;
  5.     SysTick->CTRL = 0x0;               /*!< disable systick function */
  6.     SysTick->LOAD = us * (SystemCoreClock/1000000);         /*!< time count for 1us with SYSCLK */
  7.     SysTick->VAL  = 0x00;              /*!< clear counter */
  8.     SysTick->CTRL = 0x5;               /*!< start discrease with Polling */
  9.     do
  10.     {
  11.         temp = SysTick->CTRL;
  12.     }
  13.     while ((temp & 0x01) && !(temp & (1 << 16))); /*!< wait time count done */
  14.     SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;    /*!< Close Counter */
  15.     SysTick->VAL   = 0X00;
  16. }

  17. void yuyy_delay_ms(uint16_t ms)
  18. {
  19.     while(ms--)
  20.         yuyy_delay_us(1000);
  21. }
这个延时方法我已经在M0 M3 M4 M33的MCU上都使用过了,移植基本不用改动,只要注意修改时钟源后更新系统时钟就行了

打赏榜单

21小跑堂 打赏了 30.00 元 2023-08-23
理由:恭喜通过原创审核!期待你更多的原创作品~

评论

概述CW32L083的时钟系统,并基于滴答定时器实现延时函数  发表于 2023-8-23 16:56
chenjun89 发表于 2023-8-5 23:58 来自手机 | 显示全部楼层
这个是虚拟示波器的波形
weifeng90 发表于 2023-8-6 08:45 来自手机 | 显示全部楼层
波形上的点是怎么回事?
 楼主| yuyy1989 发表于 2023-8-6 10:13 | 显示全部楼层
weifeng90 发表于 2023-8-6 08:45
波形上的点是怎么回事?

就是采样点,因为不是真正的示波器,做不到太细
lulugl 发表于 2023-8-6 11:22 | 显示全部楼层
非常详细呀,点赞!
中国龙芯CDX 发表于 2023-8-7 12:43 | 显示全部楼层
SysTick定时器经常是使用延时程序进行的函数编写
小夏天的大西瓜 发表于 2023-8-26 11:50 | 显示全部楼层
楼主设置的第一个为48Mhz实测为46.5MHZ,这个是不是说频率越高误差越大?
 楼主| yuyy1989 发表于 2023-8-26 20:09 | 显示全部楼层
小夏天的大西瓜 发表于 2023-8-26 11:50
楼主设置的第一个为48Mhz实测为46.5MHZ,这个是不是说频率越高误差越大?

应该是虚拟示波器不准
星辰大海不退缩 发表于 2023-8-27 20:23 | 显示全部楼层
时钟源是不是选择高速时钟比较多
AdaMaYun 发表于 2023-8-27 21:47 | 显示全部楼层
理论上这些频率不是基础8M的基础上分频得到的嘛
OKAKAKO 发表于 2023-8-27 22:09 | 显示全部楼层
AdaMaYun 发表于 2023-8-27 21:47
理论上这些频率不是基础8M的基础上分频得到的嘛

理论上应该都是经过分频得到的相关时钟数据
tpgf 发表于 2023-9-4 13:19 | 显示全部楼层
是否可以写一个自适应的延时函数呢
 楼主| yuyy1989 发表于 2023-9-4 14:15 | 显示全部楼层
tpgf 发表于 2023-9-4 13:19
是否可以写一个自适应的延时函数呢

这个已经是自适应的了,修改时钟源后调用RCC_SystemCoreClockUpdate更新系统时钟就行了,不用修改延时函数的代码
nawu 发表于 2023-9-4 16:35 | 显示全部楼层
延时函数的时钟都可以选择哪种呢
aoyi 发表于 2023-9-4 16:43 | 显示全部楼层
虚拟示波器比较不容易带入干扰信号吧
zljiu 发表于 2023-9-4 16:53 | 显示全部楼层
小夏天的大西瓜 发表于 2023-8-26 11:50
楼主设置的第一个为48Mhz实测为46.5MHZ,这个是不是说频率越高误差越大?

不同的频率误差应该是不相同的 跟频率的大小没有关系
gwsan 发表于 2023-9-4 17:09 | 显示全部楼层
一般情况下在延时函数中跳不出来的原因是什么呢
tfqi 发表于 2023-9-4 19:00 | 显示全部楼层
单次延时函数能延时的时间是多长呢
您需要登录后才可以回帖 登录 | 注册

本版积分规则

认证:同飞软件研发工程师
简介:制冷系统单片机软件开发,使用PID控制温度

161

主题

815

帖子

10

粉丝
快速回复 在线客服 返回列表 返回顶部
认证:同飞软件研发工程师
简介:制冷系统单片机软件开发,使用PID控制温度

161

主题

815

帖子

10

粉丝
快速回复 在线客服 返回列表 返回顶部