在數字電路中時鐘是整個電路的心臟,電路的的一舉一動都是根據時鐘節拍下進行的,隨著信息量逐漸提高,對硬件信息處理能力提出了更大的需求,時鐘作為數字硬件的關鍵成員,其性能需要我們關注,尤其在高速電路設計中對模擬轉換芯片對時鐘性能有很高的需求,因此正確選擇時鐘是很關鍵的一步,前提是我們要了解時鐘的關鍵參數咯。在數字電路中最常見的時鐘元件有晶振和鎖相環、時鐘緩沖器等,本節對系統時鐘進行重點講解。
時鐘對于整個硬件系統來說是十分重要的,每一個外設包括CPU,如果沒有外部時鐘的驅動就無法工作,時鐘就相當于硬件的脈搏,在時鐘驅動下完成指令執行。CPU和外設工作的快慢和工作效率常用時鐘周期,主頻來進行評定。為了讓每一個外設包括CPU的工作效率達到最高,我們必須要對時鐘系統進行設置。頻率越高,系統越快。
時鐘系統是由振蕩器(時鐘源)、定時喚醒器、分頻器等組成的電路。常用的信號源有晶體振蕩器和RC振蕩器。
時鐘是嵌入式系統的脈搏,處理器內核在時鐘驅動下完成指令執行,狀態變換等動作,外設部件在時鐘的驅動下完成各種工作,比如串口數據的發送、A/D轉換、定時器計數等等。因此時鐘對于計算機系統是至關重要的,通常時鐘系統出現問題也是致命的,比如振蕩器不起振、振蕩不穩、停振等。
時鐘源的頻率一般是比較小的,需要使用倍頻器倍頻后共給CPU和外設使用,而外設的頻率很多都沒有CPU的頻率高,所以又需要分頻器進行降頻,以適應外設的工作頻率。
振蕩器是用來產生重復電子訊號的電子元件。其構成的電路叫振蕩電路,能將直流電轉換為具有一定頻率交流信號輸出的電子電路或裝置。
晶體振蕩器:
石英晶體振蕩器是高精度和高穩定度的振蕩器,被廣泛應用于彩電、計算機、遙控器等各類振蕩電路中,以及通信系統中用于頻率發生器、為數據處理設備產生時鐘信號和為特定系統提供基準信號。其優點是相對來說振蕩頻率比較穩定,精度也較高,精度不易受溫度、濕度等環境的影響,但價格相對較高,使用時還必須配備兩個起振電容。
STM32中主要有四個時鐘源:
HSI:高速內部時鐘,RC振蕩器,頻率為16MHz;該時鐘在系統一上電的時候暫時使用,此時外部管腳還沒有初始化,還無法使用外部高速時鐘,等系統初始化之后,通過配置時鐘就可以切換到外部時鐘源HSE,此后一直使用,倘若系統故障或癱瘓,仍然可以切換到HSI暫時使用,所謂內部是指在STM32芯片內部已經集成了時鐘源。
HSE:高速外部時鐘,可接石英/陶瓷諧振器,或者接外部時鐘源,頻率范圍為4MHz~26MHz,我們開發板是25MHz,所謂外部是指通過管腳外接一個時鐘源
LSI:低速內部時鐘,RC 振蕩器,頻率為 32kHz 左右。供獨立看門狗和自動喚醒單元使用。
LSE:低速外部時鐘,接頻率為 32.768kHz(非常精確)的石英晶體。這個主要是 RTC(Real_Time Clock,實時時鐘)的時鐘源,保證時間的精確性,如我們日常的事件一秒一秒的計時,都用此時鐘。
由此看出,低速的時鐘源都是給一些特定的外設使用的,而高速的時鐘源供系統以及大部分外設使用
復位和時鐘控制RCC( restoration and clock control)單元:主要是配置時鐘系統的分頻、倍頻,以及使能外設時鐘(即打開外設時鐘的開關)等,所有的控制都在RCC單元中。
時鐘樹:
1:低速內部時鐘,主要給獨立看門狗進行使用
2:低速外部時鐘,外接晶振,大小精確,主要供RTC使用
3:高速內部時鐘,16MHz,SW是一個通道選擇器,如果選擇的是HSI,那么該時鐘就被使用稱為SYCCLK。SW作為選擇器,有三種選擇,即HSE、HSI、PLLCLK(經過倍頻后的時鐘),芯片正常工作以后常選擇PLLCLK(HSE倍頻后)作為時鐘源,進入系統后還可以經過分頻系統降頻
4:高速外部時鐘,通常范圍是4-26MHz,STM32f407接的是一個25MHz的晶振,也可以通過SW進行選擇成為SYCCLK
5:STM32f407的CPU可以承受的最大主頻為168MHz,如果高速時鐘源直接接入CPU,那么CPU的使用效率是很低的,所以應當經過PLL倍頻因子倍頻后再接入,使CPU工作效率達到最高,高速內部時鐘和高速外部時鐘都可以經過PLL單元的倍頻再進入CPU,因此某些參考書中認為PLL單元也是一個時鐘源是有道理的
可通過多個預分頻器配置 AHB 頻率、高速 APB (APB2) 和低速 APB (APB1)。AHB 域的最大頻率為 168 MHz。高速 APB2 域的最大允許頻率為 84 MHz。低速 APB1 域的最大允許頻率為 42 MHz。
APB和AHB總線,類似于個人PC系統里的北橋和南橋總線。南橋總線上掛接的都是鼠標、鍵盤這些慢速的設備,北橋上掛接顯卡等高速設備。南橋頻率低,北橋頻率高。另外,南橋最后也要接到北橋上。這些感覺都類似于APB和AHB。AHB,是Advanced High performance Bus的縮寫,譯作高級高性能總線,這是一種“系統總線”。AHB主要用于高性能模塊(如CPU、DMA和DSP等)之間的連接。AHB 系統由主模塊、從模塊和基礎結構(Infrastructure)3部分組成,整個AHB總線上的傳輸都由主模塊發出,由從模塊負責回應。APB,是Advanced Peripheral Bus的縮寫,這是一種外圍總線。APB主要用于低帶寬的周邊外設之間的連接,例如UART、1284等,它的總線架構不像 AHB支持多個主模塊,在APB里面唯一的主模塊就是APB 橋。再往下,APB2(高速APB)負責AD,I/O,高級TIM,串口1;APB1(低速APB)負責DA,USB,SPI,I2C,CAN,串口2345,普通TIM。
STM32時鐘配置實例:
配置外部時鐘:
在時鐘配置界面進行外部高速時鐘配置時,發現該配置不可使用(文字圖標體現為灰色),那是因為連接外部晶振的管腳還未進行初始化,因此先配置管腳。
在RCC配置頁面選擇外部高速時鐘,選擇晶振,之后連接晶振的管腳會自動高亮,如下圖所示。
根據計算,設置分頻和倍頻參數的值,使得外設和內核都可以達到自己的最大工作頻率。
系統剛上電時啟動時使用的是內部高速時鐘源HSI,此設置在剛上電產生的復位中斷處理函數中進行,即“=SystemInit”在這個函數中配置了一些列RCC的寄存器就是為了使用初始時鐘的,之后跳轉到main函數中,即“=mian”,才進行外部高速時鐘源的配置。
在SystemClock_Config();函數中會進行電源的使能以及分頻和倍頻參數的設置,以及對系統定時器的重載數值寄存器進行填值等功能,來操控RCC的寄存器實現功能。
SysTick定時器:能夠定時、計數的器件稱為定時器
SysTick, 稱作系統滴答定時器,簡稱滴答定時器。是一個定時設備,位于Cortex內核中,可以對輸入的時鐘進行計數,當然,如果時鐘信號是周期性的,計數也就是計時。
系統定時器一般用于操作系統,用于產生時基,維持操作系統的心跳。根據這個中斷,系統就可以實現時間片的計算從而切換進程。
滴答定時器是一個24位定時器,也就是最多能計數2^24。在使用的時候,我們一般給計數器送一個初始的計數值,計數器向下計數,每來一個時鐘信號,計數初值就減一,計數值減到0的時候,就會發出一次中斷。然后重新從計數初值再減一計數,循環不斷。
SysTick定時器的時鐘來源是HCLK(168MHz),到達定時器的時鐘可以選擇分頻,也可以選擇不分頻。默認情況下不進行分頻,是168MHz。
重載數值寄存器需要用戶自己填寫,系統上電后,重載數值寄存器會將自己的value賦給定時器,重載數值寄存器的值設定好后,系統整個工作過程中中不會被改變。定時器每接收到一個CLK,就會將重載數值寄存器賦給自己的value值減1,一般時鐘源越快,減到0的速度也越快。減到0經歷的時長為vaue值常以一個CLK周期,在168MHz的情況下,一個CLK的周期為1/(169x1000000)秒。一旦減到0后就可以觸發異常中斷,同時重載數值寄存器會再一次將自己的value賦給定時器。所有的定時器的工作原理基本相同,SysTick定時器是系統使用的定時器,而用戶專門使用的定時器為Timer。
需要注意的是系統定時器的中斷配置在一初始化時就默認使能了,且默認1ms觸發一次中斷,因為系統的定時器常被操作系統使用,而且我們也不會去屏蔽它。如圖,在初始化外部時鐘源時,在SystemClock_Config();函數中會自動填充重載數值寄存器的值為時鐘源頻率除以1000,換算后可得系統每1ms觸發一次中斷。
系統定時器觸發異常中斷時會進入異常處理函數SysTick_Handler(),此函數入口在中斷向量表中存在,本質上上調用HAL_SYSTICK_IRQHandler () ;是真正的中斷處理函數。而HAL_SYSTICK_IRQHandler ()調用了一個回調函數,而該回調函數是弱生成的,用戶可以使用,在函數內部用戶可以重寫邏輯功能,若是帶有操作系統,操作系統會重寫這個回調函數,維持系統的時基,對多任務的進程進行計數。
由于系統默認每1ms觸發一次中斷,用戶想要想要達到1s后進行中斷處理功能,可讓系統中斷觸發1000次,因此在重寫HAL_SYsTICK_Callback ( void)回調函數時可進行如下編程:
void HAL_SYsTICK_Callback (void){
static uint32_t i=0;
i++;
if(i==1000){
printf("systick IRQn");//此處可改為用戶目標處理函數
}
}
補充知識:static關鍵字在C語言中的用法:
在修飾變量時,static修飾的靜態局部變量只執行一次,而且延長了局部變量的生命周期,直到程序運行結束以后才釋放。以上述代碼為例,每次觸發中斷進入回調函數中,i的值不為0,而是保留位上次回調函數中i的值。
static修飾全局變量的時,這個全局變量只能在本文件中訪問,不能在其它文件中訪問,即便是extern外部聲明也不可以。
static修飾一個函數,則這個函數的只能在本文件中調用,不能被其他文件調用。Static修飾的局部變量存放在全局數據區的靜態變量區。
HAL_Delay()的實現:
//利用SysTick實現精準的延時
__weak void HAL_Delay(uint32_tDelay) {
uint32_t tickstart = HAL_GetTick();//獲取當前的uwTick值賦值給tickstart
uint32_t wait = Delay;將用戶要延時的值(單位ms)賦值給wait
while((HAL_GetTick() - tickstart) < wait)
//只有當條件為假的時候退出,否則一直循環
//當最新的uwTick值與用戶想要進入延時獲得的uwTick的差小于
//用戶輸入的延時時間,說明延時時間未到,繼續循環
{ }
}
//下面代碼均在文件 stm32f4xx_hal.c 中
static __IO uint32_t uwTick; //定義計數全局變量
__weak uint32_t HAL_GetTick(void){
return uwTick;
}
//全局變量 uwTick 遞增
__weak void HAL_IncTick(void) {
uwTick++;
}
//Systick 中斷服務函數:文件 stm32f4xx_it.c 中
void SysTick_Handler(void) {
HAL_IncTick();
HAL_SYSTICK_IRQHandler();
}
每隔 1ms,uwTick增加 1
由于系統默認的值每1ms會進行一次系統時中斷,
也就是每1ms會進行一次時鐘中斷處理
在中斷處理函數中,系統每次都會調用函數HAL_IncTick();
而函數HAL_IncTick();的功能是將uwTick的值加1
由于系統默認的值每1ms會進行一次系統時中斷,也就是每1ms會進行一次時鐘中斷處理,在中斷處理函數SysTick_Hanqler ()中,系統每次都會調用函數HAL_IncTick();,而函數HAL_IncTick();的功能是將uwTick的值加1,由此可知,uwTick的值的單位是1ms。
由此可見,HAL_Delay()功能實現的本質就是要保障SysTick_Hanqler ()的正常運行以更新uwTick的值,因此一定要保證系統時鐘中斷的優先級在整個系統中處于足夠的高的地位,不能有外部中斷的優先級比系統時鐘中斷的優先級高。
HAL_Delay() 的局限:HAL庫的延時函數有一個局限性,在中斷服務函數中使用HAL_Delay會引起混亂,因為它是通過中斷方式實現,而 Systick 的中斷在一般操作系統優先級是最低的,所以在中斷中運行 HAL_Delay會導致死鎖的現象。
-
晶體振蕩器
+關注
關注
9文章
631瀏覽量
29252 -
模擬轉換器
+關注
關注
0文章
42瀏覽量
12753 -
陶瓷諧振器
+關注
關注
0文章
22瀏覽量
9574 -
時鐘控制
+關注
關注
0文章
17瀏覽量
6865 -
STM32F407
+關注
關注
15文章
188瀏覽量
29651
發布評論請先 登錄
相關推薦
評論