1、為什么要進行時鍾管理?
時鍾系統是一個數字器件的命脈,對於普通的51單片機來說,它的時鍾來源只有外部晶振,然后每12個振盪周期完成一個基本操作,所以也叫做12T單片機,但對於當前高級一點的單片機來說,比如MSP430F5529有5個時鍾來源,經過UCS(Unified Clock System,通用時鍾系統)模塊之后,產生MCLK(Master Clock),SMCLK(Subsystem master clock ),ACLK(Auxiliary clock)三個時鍾;對於更高端的單片機,比STM32F103ZET6里面有專門用來管理時鍾的RCC單元(Reset Clock Control),也就是通常所說的時鍾樹,在時鍾管理上更加強大!
首先來看兩個例子:
1、MSP430F5529單片機的時鍾設計:
該單片機中通過UCS單元產生三路信號,MCLK供CPU使用,SMCLK供高速外設使用,ACLK供低速外設使用,這樣設計后,每個外設都具有自己的時鍾源,可以獨立工作,不需要的時候可以空閑的時鍾源關閉,進入低功耗模式,根據時鍾不同程度上的關閉,分為7中低功耗模式;
2、STM32F103ZET6單片機的時鍾設計
該單片機中通過RCC單元產生SYSCLK,HCLK,PCLK2,PCLK1四路時鍾,獨立工作,並且默認情況下所有外設時鍾都處於關閉狀態,即使要使用一個IO口輸出,也需要先使能相應GPIO時鍾,可見STM32的時鍾管理單元更加精妙;
通過這兩個例子,可以看出時鍾管理這個單元往往被開發者所忽略是因為一般情況下單片機設計者已經為我們設置好了最優的時鍾狀態,系統工作都采用默認時鍾,我們利用這個默認設置可以完成大部分項目,但是在一些必須要求低功耗的場合,比如智能手環,智能儀表,性能需求不是很高,但是必須要求低功耗,那么如何實現低功耗呢?有兩種途徑,一是關閉沒有用到的外設的時鍾,停止工作;二是降低系統CPU工作頻率。這兩種途徑都是通過操作單片機的時鍾管理單元實現的,所以掌握時鍾的管理尤其重要!
2、器材資料准備
在這里我們深入探究一下MSP430F5529的UCS單元
- 實驗平台:MSP430F55529launchpad開發板
- 實驗儀器:示波器或者邏輯分析儀
- 參考資料:MSP430F55529launchpad開發板原理圖《MSP-EXP430F5529LP_Schematic》以及MSP430F5529的官方參考手冊《MSP430x5xx and MSP430x6xx Family User's Guide》
3、統一時鍾系統(Unified Clock System,UCS)
1)功能簡圖
2)由圖中可以看到時鍾來源一共有5個:
-
- XT1CLK —— 外部低頻率或高頻率振盪源,32.768Khz(LF模式)或4-32Mhz(HF模式);
- VLOCLK —— 內部超低功耗振盪源,典型值10Khz;
- REFOCLK —— 內部低頻參考源,典型值32.768Khz;
- DCOCLK —— 內部數字時鍾振盪器,由FLL穩定后得到;
- XT2CLK —— 外部高頻振盪源4-32Mhz;
注:DCOCLK是通過內部FLL單元穩定而來,並不算是一個通過振盪產生時鍾的源,所以在圖中未標注;
3)這5個時鍾源經過UCS單元后,產生3個時鍾信號,這三個時鍾的時鍾源可由軟件控制從XT1,REFO,VLO,DCO,DCOCLK,XT2中選擇,其中DCOCLKDIV經由DCO1/2/4/8/16/32分頻得到;另外ACLK也可以被再次1/2/4/8/16/32分頻;
-
- MCLK —— CPU使用;
- SMCLK —— 高速外設使用;
- ACLK —— 低速外設使用;
4)單獨的MOSOSC模塊,產生5Mhz的MDOCLK時鍾信號,只為FLASH控制模塊和ADC12模塊提供時鍾,該模塊不使用時自動關閉,使用時無需使能即可響應請求,為外設提供時鍾;
5)具體的時鍾框圖如下(圖片來源於官方參考手冊):
4、實驗驗證
了解了UCS單元的基本功能后,接下來開始實驗:
首先查看開發板原理圖,搞清楚硬件連接,可以看到,單片機在XIN(P5.4)和XOUT(P5.5)引腳接了一個32.768K的手表晶振,在XT2IN(P5.2)和XT2OUT(P5.3)處接了一個4M的有源晶振;
1)復位后的時鍾情況
系統上電復位后,XT1在LF低頻模式,作為XT1CLK的時鍾來源,XT1CLK又被選中作為ACLK的時鍾源;當XT1無效時,低頻模式自動切換為REFO,其它情況切換為DCO;
FLL使能,FLL的參考時鍾源FLLREFCLK選中XT1CLK,當XT1無效時,低頻模式自動切換為REFO,經過鎖頻環FLL穩定倍頻,分頻,穩定頻率之后,產生DCOCLK和DCOCLKDIV;
這個時候要注意最關鍵的,如果連接XT1和XT2的引腳不進行PXSEL的設置,那么這兩個時鍾源都是無效的,而內部時鍾源REFOCLK,VLOCLK,DCOCLK默認都是可用的;並且在單片機復位之后,XT2OFFG,XT1HFOFFG清零,沒有故障失效,XT1LFOFFG,DCOCLK置位,產生故障失效,而且在剛打開時鍾的時候,這些故障位都會置位,一旦被置位,即使晶振恢復到正常狀態也將一直保持置位,直到手動用軟件將故障失效標志位清零,清零之后,若晶振故障失效情況仍然存在,晶振故障失效標志位將自動再次被置位;
所以,單片機默認情況下雖然全被配置為XT1CLK,但是因為XT1引腳未配置,並且故障位置位,所以自動切換使用REFO,即:
ACLK =REFOCLK = 32.768Khz;
FLLREFCLK = REFOCLK = 32.768K;
MCLK = SMCLK = DCOCLKDIV =1.048576MHZ;
DCOCLK = 2.097152Mhz;
接下來將時鍾信號輸出到示波器上驗證一下,MCLK輸出復用P7.7腳,SMCLK輸出復用P2.2腳,ACLK復用P1.0腳,實驗板上只引出P1.0和P2.2,所以我們只測試ACLK和SMCLK,可以看到ACLK = 32.86khz,SMCLK = MCLK = 1.05Mhz,LED閃爍頻率大約為1hz;
1 #include <msp430.h> 2 3 int main(void) 4 { 5 volatile unsigned int i; //循環變量 6 WDTCTL = WDTPW | WDTHOLD; // stop watchdog timer 7 P4DIR |= (BIT1+BIT7); //P4.7觀察現象,P4.1用於示波器觀測 8 P4OUT |= (BIT1+BIT7); //輸出高電平,點亮LED 9 P1DIR |= BIT0; 10 P1SEL |= BIT0; //P1.0輸出ACLK 11 P2DIR |= BIT2; 12 P2SEL |= BIT2; //P2.2輸出SMCLK 13 while(1) 14 { 15 P4OUT ^= (BIT1+BIT7); //LED狀態取反 16 for(i = 50000;i>0;i--); //delay 17 } 18 }
2)配置內部時鍾源
編程思路:內部鍾源默認都可用,所以直接修改UCSCTL4寄存器配置即可;
1、修改時鍾源,將ACLK配置為VLOCLK內部超低功耗振盪器,可以看到,ACLK = VCOCLK = 9.21Khz
加入這行代碼:
UCSCTL4 |= SELA_1; //配置ACLK = VCOCLK
2、修改時鍾源,配置ACLK為REFOCLK,內置調整低頻參考振盪器,可以看到,ACLK = REFOCLK = 32.86Khz
UCSCTL4 |= SELA_2; //配置ACLK = REFOCLK
3、修改時鍾源,配置ACLK為DCOCLK,可以看到,ACLK = DCOCLK = 2.11Mhz
UCSCTL4 |= SELA_3; //配置ACLK = DCOCLK
4、修改時鍾源,配置ACLK為DCOCLKDIV,可以看到,ACLK = DCOCLKDIV = 1.06Mhz
UCSCTL4 |= SELA_4; //配置ACLK = DCOCLKDIV
3)配置外部時鍾源
編程思路:
- 配置XT1/XT2連接晶振的引腳(PXSEL)
- 清除XT1,XT2,DCO失效標志位
- 修改UCSCTL4寄存器,選擇時鍾源
1、修改時鍾源,配置ACLK = 32.768Khz,MCLK = SMCLK = DCOCLKDIV=1.05M;
#include <msp430.h> int main(void) { volatile unsigned int i; //循環變量 WDTCTL = WDTPW | WDTHOLD; // stop watchdog timer P4DIR |= (BIT1+BIT7); //P4.7觀察現象,P4.1用於示波器觀測 P4OUT |= (BIT1+BIT7); //輸出高電平,點亮LED P1DIR |= BIT0; P1SEL |= BIT0; //P1.0輸出ACLK P2DIR |= BIT2; P2SEL |= BIT2; //P2.2輸出SMCLK P5SEL |= BIT4+BIT5; //P5.4和P5.5選擇XT1晶振功能 UCSCTL3 |= SELREF_0; //設置FLL參考時鍾源為XT1 do { UCSCTL7 &= ~(XT2OFFG + XT1LFOFFG + DCOFFG); //清除XT2,XT1,DCO故障失效標志位 SFRIFG1 &= ~OFIFG; //清除晶振故障失效中斷標志位 }while(SFRIFG1&OFIFG); //晶振故障失效中斷標志位 UCSCTL6 &= ~XT1DRIVE_0; //減少XT1驅動能力 UCSCTL4 |= SELA_0; //ACLK = XT1CLK while(1) { P4OUT ^= (BIT1+BIT7); //LED狀態取反 for(i = 50000;i>0;i--); //delay } }
2、修改時鍾源,配置ACLK = MCLK = SMCLK = XT2CLK =4Mhz
#include <msp430.h> int main(void) { volatile unsigned int i; //循環變量 WDTCTL = WDTPW | WDTHOLD; // stop watchdog timer P4DIR |= (BIT1+BIT7); //P4.7觀察現象,P4.1用於示波器觀測 P4OUT |= (BIT1+BIT7); //輸出高電平,點亮LED P1DIR |= BIT0; P1SEL |= BIT0; //P1.0輸出ACLK P2DIR |= BIT2; P2SEL |= BIT2; //P2.2輸出SMCLK P5SEL |= BIT2+BIT3; //P5.2和P5.3選擇XT2晶振功能 UCSCTL3 |= SELREF_5; //設置FLL參考時鍾源為XT2CLK UCSCTL4 |= SELA_5; //必須要設置這一句配置ACLK = XT2CLK do { UCSCTL7 &= ~(XT2OFFG + XT1LFOFFG + DCOFFG); //清除XT2,XT1,DCO故障失效標志位 SFRIFG1 &= ~OFIFG; //清除晶振故障失效中斷標志位 }while(SFRIFG1&OFIFG); //晶振故障失效中斷標志位 UCSCTL6 &= ~XT2DRIVE_0; //XT2 = 4M,減少XT2驅動能力 UCSCTL4 |= SELS_5 + SELM_5; //配置MCLK = SMCLK = XT2CLK while(1) { P4OUT ^= (BIT1+BIT7); //LED狀態取反 for(i = 50000;i>0;i--); //delay } }
示波器觀測結果,可以看到LED閃爍頻率也比之前加快4倍:
3、修改時鍾源,配置ACLK = 32.768Khz,MCLK = SMCLK = XT1CLK * (499+1) =16Mhz
#include <msp430.h> int main(void) { volatile unsigned int i; //循環變量 WDTCTL = WDTPW | WDTHOLD; // stop watchdog timer P4DIR |= (BIT1+BIT7); //P4.7觀察現象,P4.1用於示波器觀測 P4OUT |= (BIT1+BIT7); //輸出高電平,點亮LED P1DIR |= BIT0; P1SEL |= BIT0; //P1.0輸出ACLK P2DIR |= BIT2; P2SEL |= BIT2; //P2.2輸出SMCLK P5SEL |= BIT4+BIT5; //P5.4和P5.5選擇XT1晶振功能 UCSCTL3 |= SELREF_0; //設置FLL參考時鍾源為XT1 UCSCTL4 |= SELA_0; //ACLK = XT1CLK UCSCTL0 = 0; //設置DCO=MOD=0 do { UCSCTL7 &= ~(XT2OFFG + XT1LFOFFG + DCOFFG); //清除XT2,XT1,DCO故障失效標志位 SFRIFG1 &= ~OFIFG; //清除晶振故障失效中斷標志位 }while(SFRIFG1&OFIFG); //晶振故障失效中斷標志位 UCSCTL6 &= ~XT1DRIVE_0; //減少XT1驅動能力 __bis_SR_register(SCG0); //禁止FLL UCSCTL1 = DCORSEL_4; //選擇DCO頻率范圍 UCSCTL2 |= 499; //設置頻率16Mhz __bic_SR_register(SCG0); //啟用FLL for(i = 50000;i>0;i--); //delay,等待FLL穩定 while(1) { P4OUT ^= (BIT1+BIT7); //LED狀態取反 for(i = 50000;i>0;i--); //delay } }
示波器測試結果