CC2541有四個振盪器,分別是:
- 32MHz外部晶振
- 16MHz內部RC振盪器
- 32kHz外部晶振
- 32kHz內部RC振盪器
32MHz的外部晶振有兩個作用:為內部時鍾提供時鍾源和用於RF收發器
16MHz的RC內部振盪器的作用:為內部時鍾提供時鍾源,注意它不可以用於RF收發器操作
16MHz的RC內部振盪器功耗小但是精度差,這也是它不能用於RF收發器的原因。
32kHz外部晶振運行在32.768KHz上,32kHz內部RC振盪器運行在32.753kHz,這兩個時鍾主要使用在Sleep Timer 和Watchdog Timer上,其中內部的32kHz振盪器功耗小,但是精度低,這兩個隨意選擇一個,但不能同時使用,言外之意就是如果要求精度不高的時候電路中可以不接外部32kHz晶振。
注意:系統上電,默認的是使用內部16Mhz時鍾和內部32kHz振盪器
怎么選擇這四個振盪器呢? 由CLKONCMD時鍾控制命令寄存器選擇,CLKONCMD寄存器定義如下:

解釋下CLKONCMD這個寄存器
OSC32K:32kHz選擇位
OSC:主時鍾選擇位
TICKSPD:對主時鍾進行分頻,控制定時器1、定時器3 和定時器4 的全局時鍾划分。分頻器值的設置可以從0.25 MHz 到32 MHz 。注意如果CLKCONCMD.TICKSPD 表示頻率高於系統時鍾,CLKCONSTA.TICKSPD 中指明的實際分頻器值和系統時鍾相同。簡言之:定時器1、3、4的時鍾。
CLKSPD:對主時鍾進行分頻,分頻后的頻率作為主時鍾,類似於PLL,一般這個值設為000,即主時鍾為32Mhz
當選擇32MHz晶振作為主時鍾源時(CLKONCMD.OSC = 0),內部時鍾並不是一下子變為32Mhz,內部首先選擇16MHz RC振盪器使系統運行起來,當32MHz晶振穩定以后才使用32MHz晶振作為主時鍾。判斷是否穩定的依據是看“CLKONSTA時鍾控制狀態寄存器”,定義如下

CLKONSTA.OSC == 1時才能說明32Mhz時鍾已經穩定。所以在程序里,要加一個等待的語句,防止時鍾未穩定的程序執行錯誤。
時鍾初始化代碼如下。
1 /**************************************************************** 2 *函 數 名:InitClock 3 *功 能:系統時鍾初始化 4 *入口參數:無 5 *出口參數:無 6 *****************************************************************/ 7 void InitClock(void) 8 { 9 CLKCONCMD &= ~0x40; // 設置系統時鍾源為 32MHZ晶振 10 while(CLKCONSTA & 0x40); // 等待晶振穩定 11 CLKCONCMD &= ~0x47; // 設置系統主時鍾頻率為 32MHZ 12 }
但是實際調試時,調用該函數,總是得不到32MHz的時鍾,16MHz的工作時鍾始終不變,找了很久,不知道為什么,調試的時候程序一直停在第10行代碼那。后來用饅頭科技的時鍾程
序,調試成功,系統工作時鍾變為32MHz,以后就用這個程序了,程序代碼如下:
1 /**************************************************************** 2 *函 數 名:SysStartXOSC 3 *功 能:系統時鍾初始化 4 *入口參數:無 5 *出口參數:無 6 *****************************************************************/ 7 void SysStartXOSC(void) 8 { 9 SLEEPCMD &= ~0x04; // 啟動所有晶振 10 while (!(SLEEPSTA & 0x40)); // 等待晶振穩定 11 12 CLKCONCMD = (CLKCONCMD & 0x80) | 0x49; // 使用16M晶振作為主時鍾 13 while ((CLKCONSTA & ~0x80) != 0x49 ); // 等待主時鍾切換到16M晶振 14 15 CLKCONCMD = (CLKCONCMD & ~0x80) ; // 使用外部32K晶振作為休眠時鍾 16 while ( (CLKCONSTA & 0x80) != 0 ); // 等待睡眠時鍾切換到外部32K晶振 17 18 CLKCONCMD = (CLKCONCMD & 0x80) ; // 使用32M晶振作為主時鍾 19 while ( (CLKCONSTA & ~0x80) != 0 ); // 等待主時鍾切換到32M晶振 20 21 SLEEPCMD |= 0x04; // 關閉未使用的晶振 22 }