概念:
时钟系统是由振荡器(信号源)、定时唤醒器、倍频器、分频器等组成的电路。常用的信号源有晶体振荡器和RC振荡器。
意义:
时钟是嵌入式系统的脉搏,处理器啮合在时钟的驱动下完成指令执行,状态转换等等动作,外设部件在时钟的驱动下完成各种工作,比如串口数据的发送、A/D转换、定时器计数等等。因此时钟对于计算机系统是至关重要的,通常时钟系统出现问题也是致命的,比如振荡器不起振、振荡不稳、停振等问题。
一般来说,CPU内核所能接受的振荡频率是比较高的,比如说stm32f103c8t6这个芯片就能够承受72MHZ的频率,但是由于外部石英晶振和内部RC晶振都只是8MHZ的频率,显然不满足我们CPU所需要的频率,所以我们一般需要PLL倍频器来进行频率的倍频,将外部石英晶振或者内部RC晶振的频率提高,以达到CPU需要的频率。
但是呢,由于高速时钟源只能有一路输入,所以,很多外设并不能承受72MHZ的频率,因此,就会有分频器来降低频率,以达到各个外设都能使用的程度,这也就是为什么一个时钟电路需要加上倍频器和分频器的原因了。
概念:
振荡器是用来产生重复电子讯号的电子元件。其构成的电路叫振荡电路,能将直流电转换为具有一定频率交流信号输出的电子电路或装置。
分类:
振荡器主要可以分为两类:
一类是RC、LC振荡器,这两种振荡器主要是由电阻电容等电子元器件来构成的;RC振荡器采用RC网络作为选频相网络的振荡器。LC振荡器是采用LC振荡回路作为移相和选频网络的正反馈振荡器。
另一类是晶体振荡器,主要是由石英晶体来进行起振从而来输出一定的频率的。
RC振荡器:
RC振荡器是由电阻电容构成的振荡电路,能将直流电转换成具有一定频率的交流信号输出的电子电路或装置。
优点:实现的成本比较低,毕竟就是一个电阻电容。
缺点:是由于电阻电容的精度问题所以RC振荡器的振荡频率会有误差,同时受到温度、湿度的影响较大。
因此我们在stm32中给CPU提供频率的时候,一般都不选用这个RC振荡器作为稳定时钟源,一般都是在很短的时间内提供时钟源以替代晶体振荡器。
晶体振荡器:
石英晶体振荡器是高精度和高稳定度的振荡器,被广泛应用于彩电、计算机、遥控器等各类振荡电路中,以及通信系统中用于频率发生器、为数据处理设备产生时钟信号和为特定系统提供基准信号。
优点:是相对来说振荡频率一般都比较稳定,同时精度较高。
缺点:价格稍微贵一点,并且还需要接两个起振电容。
因此我们在stm32正常运行过程中一般都使用晶体振荡器来提供稳定的振荡频率提供给CPU。
一般而讲,我们在给单片机上电的时候,此时由于晶体振荡器起振需要一定的时间,所以此时就会让RC振荡器来顶替一段时间来作为振荡源的输入,当晶体振荡器起振以后,就会将晶体振荡器作为稳定的振荡源输入。
stm32中主要有四个时钟源
我们来配置stm32的系统时钟一般都是在cubemx中直接配置的,如果我们不进行时钟配置的话,很多时候时钟系统就默认外部高速时钟或者内部高速时钟直接输入,这样大概时钟频率在8MHZ,我们知道stm32f103的CPU最大承受的时钟频率为72MHZ,这样就会大大浪费CPU的资源,导致资源的浪费,因此,我们需要进行配置,将输入时钟从倍频器输入,这样就可以使得时钟频率变快。
我们首先来进行引脚的配置
然后我们进行时钟的配置
从图中我们可以看到,第一块和第二块都是选择HSI(内部高速时钟)来进行输入的,我们可以看到,第三块就只有8MHZ的时钟频率,而下面写着最大72MHZ,这样就是很浪费CPU资源的,所以我们需要进行配置,来使时钟频率变高。
我们需要对第一块、第二块进行配置。
通过以上的操作,我们就将stm32的系统时钟配置好了。
概念:
定时器,能够定时、计数的器件称为定时器
SysTick,称作系统滴答定时器,简称滴答定时器。是一个定时设备,位于cortex-M3的内核中,是属于内核外设。
系统定时器一般用于操作系统,用于产生时基,维持操作系统的心跳。根据这个中断,系统就可以实现时间片的计算从而切换进程。
工作原理:
滴答定时器是一个24位定时器,也就是最多能技术2^24。在使用的时候,我们一般给计数器送一个初始的技术支持,计数器向下计数(滴答定时器只能向下计数),每来一个时钟信号,计数初值就减一,计数值减到0的时候,就会发出一次中断。然后重新从计数初值再减一计数,循环不断。
通过上面的图片我们就可以看出来,Systick是属于内核外设的,因此systick只会挂载到AHB总线上的,既不属于APB1总线,也不属于APB2总线。
然后,我们一般都不会将AHB总线进行分频的操作,并且cortex系统时钟前的8分频既可以使用,也可以不使用,我们在实际配置过程中是没有使用8分频的,因此我们系统时钟的频率为72MHZ。
systick的工作原理如上图所示
systick在工作时会有一个重载数值寄存器和定时计数器,我们可以进行重载数值寄存器初始值的设置,这个值是我们用户自己去设置的。
当我们设置完成重载数值寄存器的值以后,重载数值寄存器会将计数值写入定时计数器,然后,每来一个时钟脉冲以后,定时计数器的值就会自动进行减一的操作,当定时计数器的值减到0以后,就会触发一次中断响应,然后供用户执行相关操作。
当定时计数器的值减到0以后,重载数值寄存器的值会重新加载到定时计数器中,又会开启一轮新的计数。
比如说我们想要1ms触发一次中断,我们就以72MHZ的时钟频率来说,那么每1/72MHZs就会产生一次时钟脉冲,当我们要1ms触发一次中断,那么就用0.001s/1/72MHZs就可以得到重载计数器的值,我们将这些值写入到重载数值寄存器中,就可以实现1ms触发一次中断的效果了。
下面一步我们来分析代码
我们从main.c函数中找到系统时钟配置函数,转到这个函数。
我们可以看到,这个函数的主体内容就是用来配置系统时钟的,上面的块包括选择外部高速时钟、进行分频操作,内部锁相环选择等内容;下面的块主要就是用来配置各个总线时钟分频系数的,我们可以看到,这个结构体的设置和我们在cubemx中用图形化设置的界面是相同的。
然后我们需要在这个地方再调用一下SysTick_Config();这个函数来配置一下重载数值寄存器(因为我在自动导出的文件中找了半天,没有找到配置重载数值寄存器的函数,所以我们就自己来配置一下吧);括号里面填入我们计算好的自动重载值,这样就可以配置完成了。(这样就可以实现1ms触发一次中断的状态了)。
然后我们在hal_cortex.c中找到SYSTICK_CALLback,这个函数就是用来进行中断操作的。我们可以在main函数中进行这个函数的重写。
通过对这个函数的重写,我们就可以实现1s使PA1的电平翻转一次,实现LED灯亮灭的切换。
systick主要用到下面四个寄存器:
首先我们来分析控制及状态寄存器(由于systick是属于内核外设,因此,在stm32中文手册中并没有systick相关寄存器的介绍,systick相关寄存器的介绍是在内核手册中才有介绍的。)
控制及状态寄存器主要是用来配置systick的相关状态的,比如说,AHB上的分频系数、是否开启计数到0的中断、是否使能systick外设等功能。手册上的功能框图如下图:
其次我们来分析重装载数值寄存器
这个寄存器就是我们用来设置重载数值寄存器的值的,我们从前面就说过,systick需要从重载寄存器将重载值放置入定时计数器中,这样就可以进行递减计数了。我们知道,systick的递减计数器的值最大为24位,所以,这个寄存器也就用了24位来组成重装载数值寄存器。
然后我们来分析当前值寄存器
当前值寄存器就是用来记录当前值的一个寄存器,我们前面讲过,当每次都有一个脉冲输入的时候,定时计数器的值都会进行减1的操作,所以当前值寄存器就是用来记录目前定时计数器还有多少数可以用来进行减1操作,当定时计数器的值减到0以后,就会触发中断来进行中断操作。
最后还有一个数值校准寄存器,这个寄存器是用来进行数值校准的,我们在实际运用过程中是不会经常用到这个寄存器的,目前来讲,我从来都没用到过这个寄存器,所以我们不需要太过于了解这个寄存器。
以上就是对systick整个寄存器的一个描述。
HAL_Delay()函数的实现其实和systick定时器有着密切的关系。
首先我们在主函数中随便写一个HAL_Delay()函数。
然后我们追进去看
**
然后我们就可以看到,其实这个HAL_Delay()函数其实就是采用了一个while循环进行死等的操作。
我们首先看到,在进入这个函数以后,会在1给tickstart附一个HAL_GetTick的值,然后我们在2处不断将新的HAL_GetTick的值与初始值进行比较,当新的值和初始值差值等于我们给到的Delay的毫秒数以后,跳出循环,继续执行。
所以,HAL_GetTick这个函数就比较重要了,我们追进去看。
我们追进去看以后,发现这个函数每次执行的操作就是返回一个数值,这个数值就是我们在while死循环里面等待相减的数值。
然后我们全局搜索uwTick这个变量。
我们就可以发现,这个变量每次都会通过HAL_IncTick这个函数来进行加uwTickFreq这个变量,我们追进去看这个变量。
我们追到最后,会发现这个HAL_IncTick函数就是给uwTick进行自加1的操作,所以HAL_IncTick这个函数就是关键了。
其实这个函数就是我们一开始就发现了,这个函数其实就在Systick_Handler()这个函数中。
所以,最终结论就是,HAL_Delay这个函数,和系统时钟中断有着密不可分的关系,也就是说:每次systick中的定时计数器数值减到0以后,就会触发一次中断,从而使得HAL_Delay函数进行1ms的延时,这样就可以进行传参延时,这也就是官方提供的HAL_Delay是毫秒延时器的原因了。
以上就是我对于系统时钟的一些学习和了解,欢迎大家进行批评指正!!!