查看/修改STM32的时钟频率+精确测量程序运行时间+测量不准怎么办+delay函数

一、查看STM32各个时钟的频率

#include "stm32f10x_rcc.h"提供了查看时钟频率的函数:void RCC_GetClocksFreq(RCC_ClocksTypeDef* RCC_Clocks);

查看/修改STM32的时钟频率+精确测量程序运行时间+测量不准怎么办+delay函数_第1张图片

把RCC_Clocks添加到watch窗口用jlink观察即可,或者用串口把数据打印出来也行。

查看/修改STM32的时钟频率+精确测量程序运行时间+测量不准怎么办+delay函数_第2张图片

可以看到,所有的时钟都列出来了,其中系统时钟为SYSCLK,其值为0x044AA200,也即72000000=72M

注意:这个函数能否正确返回MCU真正的频率,还得看看这个函数的帮助:
查看/修改STM32的时钟频率+精确测量程序运行时间+测量不准怎么办+delay函数_第3张图片

最后一条很关键:如果你使用的外部晶振频率是带小数的,这个函数的返回值可能会出错。

正确设置HSE_VALUE、HSI_VALUE的值也很关键,这个函数内部会自动判断MCU正在使用HSI、HSE、还是PLL,但是HSI/HSE的频率还是得人为的告诉程序具体频率值是多少,这两个值是个宏。

 

 

 

二、修改STM32的时钟频率

设置系统时钟频率,一般是在SystemInit函数中,这个函数在boot文件中被调用,然后才进入main函数:
查看/修改STM32的时钟频率+精确测量程序运行时间+测量不准怎么办+delay函数_第4张图片

void SystemInit(void)
{
  /* FPU settings ------------------------------------------------------------*/
  #if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
    SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2));  /* set CP10 and CP11 Full Access */
  #endif
  /* Reset the RCC clock configuration to the default reset state ------------*/
  /* Set HSION bit */
  RCC->CR |= (uint32_t)0x00000001;

  /* Reset CFGR register */
  RCC->CFGR = 0x00000000;

  /* Reset HSEON, CSSON and PLLON bits */
  RCC->CR &= (uint32_t)0xFEF6FFFF;

  /* Reset PLLCFGR register */
  RCC->PLLCFGR = 0x24003010;

  /* Reset HSEBYP bit */
  RCC->CR &= (uint32_t)0xFFFBFFFF;

  /* Disable all interrupts */
  RCC->CIR = 0x00000000;

#if defined (DATA_IN_ExtSRAM) || defined (DATA_IN_ExtSDRAM)
  SystemInit_ExtMemCtl(); 
#endif /* DATA_IN_ExtSRAM || DATA_IN_ExtSDRAM */
         
  /* Configure the System clock source, PLL Multiplier and Divider factors, 
     AHB/APBx prescalers and Flash settings ----------------------------------*/
  SetSysClock();

  /* Configure the Vector Table location add offset address ------------------*/
#ifdef VECT_TAB_SRAM
  SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */
#else
  SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */
#endif
}

SystemInit函数的操作操作流程如下:首先使能内部8M高速时钟HSI作为总时钟源,然后进入SetSysClock()函数设置PLL_CLK/APB_CLK/AHB_CLK等,SetSysClock()函数中会首先启动外部高速时钟HSE,如果能正常起振,则把总时钟源切换到外部晶振HSE,并使能PLL,PLL输出作为SYSCLK。

按照官方库函数的话,只要正确设置了外部时钟的频率,系统就能正常工作,外部晶振的频率宏为HSE_VALUE,默认为25M,一般我们用的是8M,需要改一下。

 

三、查看程序的精确的运行时间

正确填写外部晶振的频率(我实测过,填错了也不要紧,不知道这个Xtal是干嘛的,为了保险起见,还是把它填对吧)

查看/修改STM32的时钟频率+精确测量程序运行时间+测量不准怎么办+delay函数_第5张图片

然后在KEIL中设置MCU的实际的SYSCLK频率,上文中我们已经查到了SYSCLK的频率,然后把这个值填到->魔术棒->Debug->settings->Trace->Core框里面,如下图所示。(测量不准,原因就出在这里,这个必须要设置正确)

查看/修改STM32的时钟频率+精确测量程序运行时间+测量不准怎么办+delay函数_第6张图片

进入debug模式:

查看/修改STM32的时钟频率+精确测量程序运行时间+测量不准怎么办+delay函数_第7张图片

每进入下一个断点,sec都会更新,

查看/修改STM32的时钟频率+精确测量程序运行时间+测量不准怎么办+delay函数_第8张图片

截图中的这个示例程序是用TIM定时器写的一个定时20ms函数,keil测量实际的时间为19.85602ms,差别不大。

 

当然,利用上述方法查看时间差,需要自己用计算器减出来,不是很方便,实际上,keil也提供了仿真计时清0的功能,在keil主界面的右下角,你可以在任意断点时,reset这个仿真计时器是它归0。(实测发现,这个功能有时候不大好使,时行时不行)

查看/修改STM32的时钟频率+精确测量程序运行时间+测量不准怎么办+delay函数_第9张图片

四、精确的delay函数

有了这个仿真计时功能,我们就能写出死等的delay函数。执行以下程序

   查看/修改STM32的时钟频率+精确测量程序运行时间+测量不准怎么办+delay函数_第10张图片

我们发现这个while死等就是3条汇编指令:MOVS SUB BNE,当Tscl<>0时,BNE就会跳转回0x080009E0地址处,也即MOVS指令处,就这3条指令。这3条指令执行10000次,通过断点仿真计时来查看,总共耗时0.00023812s=238.12纳秒。
由于ARM从flash取指需要耗时,ARM又采用了三级、五级、七级等流水线,导致我们无法直接根据指令数求出延时,所以还得靠仿真测量,如果哪有朋友有好的方法,请留言指教。

于是很容易推导出:t = 41999; while(t--);会耗时1ms。(SYSCLK=168M)

后记:使用这种delay过程中发现,即使SYSCLK频率不变、全程不开中断,同一段while死等耗时也不相同,刚上电时跑的慢,后来就快了,最终决定舍弃这种delay方法,还是用硬件定时器中断来计时吧

 

 

 

 

你可能感兴趣的:(stm32/单片机)