1. 程式人生 > >第二課 MC9S08DZ60之多功能時鐘發生器S08MCGV1

第二課 MC9S08DZ60之多功能時鐘發生器S08MCGV1

1.MC9S08DZ60系統時鐘分配(System Clock Distribution)

    在使用多用能時鐘發生器(MCG)之前,先來了解下這款微控制器的系統時鐘。

    微控制器的各個功能器件對命令的執行都是一步一步的進行的,每個步驟的執行都需要一個激勵,這個激勵就是時鐘,在一定的時鐘內完成給定的指令,這既是MCU工作的基本原理。可以打個不恰當的比方,MCU的時鐘就如人的心臟,心臟的每一跳動,都在給全身各個功能器官輸送血液養分和能量。MCU的時鐘也是如此,每一個時鐘跳動(震盪週期)片上資源(如ALG、SPI、IIC等)都會得到一個指令去執行。也即心臟如時鐘發生器,人體器官如MCU上的片上資源,血液養分和能量就如微控制器的指令和資料。

    大家可以到我的百度盤下載該晶片的中英文的資料https://pan.baidu.com/s/1dgVbkE https://pan.baidu.com/s/1o9qFU5c,進入1.3 System Clock Distribution章節,建議讀者先閱讀一遍該章節,可以說確實不難,很快就可以知道這個晶片的時鐘從產生到送到各個片上資源的路徑,以及有幾種時鐘可以選擇。這裡我把晶片資料中的系統時鐘圖Figure 1-2. MC9S08DZ60 System Clock Distribution Diagram 貼上上來做一個簡單的說明,重點是如何為這款微控制器配置系統時鐘,那就是寫程式碼!其他的多看看。


    A.首先從圖Figure 1-2 中要能知道這款微控制器的片上資源有哪些,它們分別是RTC、COP、TPM1、TPM2、IIC、SCI1、SCI2、SPI、CPU、BDC、ADC、MSCAN、FLASH、EEPROM、LPO、MCG、XOSC。

    B.這麼多的片上資源咱們如果是一頭蒙,不知道他們是幹什麼的話,那就不要管它們是什麼。這課主題是MCG,也就是比擬的心臟,其他的,如CPU就理解為人的大腦,MSCAN就理解為人的嘴巴用來溝通的,FLASH/EEPROM就理解為人的記憶器官, 反正總之這些片上資源它們是能各自完成各自的功能的,如果讀者是位初學者且之前沒有接觸過微控制器,那麼也沒關係,這些器件都會慢慢講解。

    C.看圖的左邊,MCG這個心臟為MCU片上資源提供了MCGERCLK、MCGIRCLK、MCGFFCLK、MCGOUT、MCGLCLK,並且知道MCG還控制一個(XOSC)外部振盪器以便把晶體或共鳴器用作外部參考時鐘。除了MCG外這款微控制器內部還有一個LPO 1KHZ的頻率發生器只用來給RTC、COP這兩個器件工作用。

    D.另外右下角有一段英文:The fixed frequency clock(FFCLK) is internally synchronized to the bus clock and must not exceed one half of the bus clock frequency 就是FFCLK這個時鐘頻率不要大於匯流排的2倍就可以,其實也不用擔心,因為從時鐘系統圖,看到硬體已經做了÷2的設定.

2.接下來就是看晶片資料的Chapter8 Multi-Purpose Clock Generator(S08MCGV1)來了解這個MCG和怎樣去用這個MCG來真正是的微控制器工作起來。

    很顯然,如果讀者是第一次接觸微控制器,你肯定很頭痛看這個晶片資料,或許看完之後也不知道怎麼去操作這個MCG。即使真是這樣,也沒關係。不過建議多看看晶片資料,真的會有進步,個人經驗,多看幾遍就懂了。因為這裡面涉及到很多理論概念加之讀者的學識以及時間的限制,不囉嗦介紹這個MCG,讀者自己看看咯。

3.現在來驅動這個MCG,讓它工作起來。

    看晶片資料的‘8.3 Register Definition',一共看到5個暫存器(register),分別是MCGC1、MCGC2、MCGTRM、MCGSC、MCGC3。這裡給這些暫存器分類為:MCGC1、MCGC2、MCGC3為控制類,MCGTRM為功能類、MCGSC為狀態類。好那就建立三個函式,分別來操作這個三類暫存器吧。這三個函式名就分別取MCG_Control,MCG_Function和MCG_Status。

     另外看到每個暫存器中有多個設定項,看下圖


      每個設定項又有多個選擇項,看下圖


     作者在這裡採用沒個設定項“位與”“異或非”:的方式來最終組成8位元組的暫存器內容和判斷暫存器中的值,也就是需要為每一個設定項定義多個define巨集,如:#define CLKS_FLL_PLL 00 ;其實code warrior 工程檔案加入晶片標頭檔案後 有類似的定義,也無需自己定義的,但是為了自己使用,還是自己寫了,俗話說看十遍,不如寫一遍--不要笑話哈。

另外還要理解晶片資料的介紹的“8.4.1 Operational Mode”。其中FEI(FLL Engaged Internal)是復位晶片的預設模式,如果要用其他模式,比如FBE(FLL Bypassed External),直接設定到FBE模式,一步即可,但是要想用PBE(PLL Bypassed External),那麼就要根據(雙向)箭頭的指示,找最短路線,先設定為FBE,然後在設定為PBE。怎麼去切換時鐘模式,在8.4.1節下面小節的每個模式說明中都有介紹,這個讀者自己去看了,我只把模式切換(Clock Switch Modes)圖貼過來:


    最後,讀者要了解下,MCG內部的機制,建議讀者通過一邊瀏覽程式碼一邊看MCG block diagram。通過這種方式,深入瞭解MCG提供的暫存器中各個設定項所做的事情,具體到MCG內部的詳細情況。不同模式對輸入的頻率都有限制,這在晶片資料中8.5.2 MCG Mode Switching及相關對CLOCK mode說明章節中都有說明,設定的時鐘分頻一定要符合要求。


4.不善言表,廢話也也多,上程式碼。

變數的重定義

#ifndef _DATA_TYPE_H_H
#define _DATA_TYPE_H_H

typedef char            INT8;
typedef unsigned char   UINT8;
typedef unsigned short  USHORT16;
typedef unsigned int    UNIT16;
typedef unsigned long   ULONG32;
typedef short           SHORT16;
typedef long            LONG32;
typedef unsigned char   BOOL;
#endif

   標頭檔案MCG.h

#ifndef _MCG_H_H
#define _MCG_H_H

#ifdef CRYSTAL2M
#define RDIV_PARAM 0x00  //2Mhz的外部時鐘頻率除16
#else
#ifdef CRYSTAL4M
#define RDIV_PARAM 0x08  //4Mhz的外部時鐘頻率除32
#else
#ifdef CRYSTAL8M
#define RDIV_PARAM 0x10  //8Mhz的外部時鐘頻率除64
#else
#define RDIV_PARAM 0x18  //其他頻率除128
#endif
#endif
#endif
//MCGC1
/*
         7     6   5 4 3      2       1           0
    R  |---------------------------------------------
       | CLKS    |RDIV   | IREFS | IRCLKEN | IREFSTEN
    W  |---------|-----------------------------------
Reset:  0      0   0 0 0     1        0           0
*/
#define CLKS_SHIFT   6
#define RDIV_SHIFT   3
#define IREFS_SHIFT  2
#define IRCLKEN_SHIFT 1
#define IREFSTEN_SHIFT 0

/*
只設置目標項,不影響其他專案的設定值,如設定CLKS為0b11那麼CLKS為0b11,其他的,如
RDIV不會改變,維持原來的值。
value:為目標設定的值,如設RDIV 0b011,那麼value=0x03,
shift:為目標設定項在暫存器中的起點,從0開始
具體方式是:先清零設定項,再給已經清零的設定項賦值。
*/
void MCGC1_Target_Set(UINT8 value,UINT8 shift);
/*
Notice! Put a brandnew value to MCGC1,the pre-Value in MCGC1 will erased.
new value will replace it.
引數setMCGC1可以使用 表1中所有巨集定義,如要設定多項,可以用位"與",來選擇多個不同
設定選項。
*/
void MCGC1_Set(UINT8 setMCGC1);
//表1
//Selects the system clock source-----------------------------------------------

  #define MCGC1_RESET 0x04   //晶片重啟\復位後暫存器初始值
  #define CLKS_SEL_FLL_PLL     0x00//(0x00<<6)    //Output of FLL or PLL is selected.    

  #define CLKS_SEL_INT_REF_CLK 0x01//(0x01<<6)    //Internal reference clock is selected.

  #define CLKS_SEL_EXT_REF_CLK 0x02//(0x02<<6)    //External reference clock is selected.

  #define CLKS_SEL_RESERVED    0x03//(0x03<<6)    //Reserved, defaults to 00.

//Selects the amount to divide down the reference clock selected by the IREFS bit. 

//If the FLL is selected, the resulting frequency must be in the range 31.25kHz to 

//39.0625kHz. If the PLL is selected, the resulting frequency must be in the range

//1 MHz to 2 MHz.

  #define RDIV_1   0x00//(0x00<<3)    //Divides reference clock by 1(reset default)

  #define RDIV_2   0x01//(0x01<<3)   //Divides reference clock by 2

  #define RDIV_4   0x02//(0x02<<3)  //Divides reference clock by 4

  #define RDIV_8   0x03//(0x03<<3)  //Divides reference clock by 8

  #define RDIV_16  0x04//(0x04<<3)  //Divides reference clock by 16

  #define RDIV_32  0x05//(0x05<<3)  //Divides reference clock by 32

  #define RDIV_64  0x06//(0x06<<3)  //Divides reference clock by 64

  #define RDIV_128 0x07//(0x07<<3)  //Divides reference clock by 128     

//Selects the reference clock source.

  #define IREFS_SEL_INT_REF_CLK 0x01//0x01//(0x01<<2)    //Internal reference clock selected

  #define IREFS_SEL_EXT_REF_CLK 0x00//(0x00<<2)    //External reference clock selected

//Enables the internal reference clock for use as MCGIRCLK.

  #define MCGIRCLK_ACTIVE   0x01//(0x01<<1)  //MCGIRCLK active

  #define MCGIRCLK_INACTIVE 0x00//(0x00<<1)  //MCGIRCLK inactive

//Controls whether or not the internal reference clock remains enabled when

//the MCG enters stop mode.

  #define INT_CLK_ENABLE_IN_STOP  0x01    //Internal reference clock stays enabled

                                      // in stop if IRCLKEN is set or if MCG is in 
                                      //FEI, FBI, or BLPI mode before entering stop

  #define INT_CLK_DISABLE_IN_STOP 0x00  //Internal reference clock is disabled in stop

//MCGC2

/*

        7 6   5      4    3    2       1        0
R     ----------------------------------------------
      |BDIV |RANGE| HGO |LP |EREFS |ERCLKEN |EREFSTEN
W     ----------------------------------------------
Reset: 0 1     0     0    0    0      0         0

*/
#define BDIV_SHIFT    6
#define RANGE_SHIFT   5
#define HGO_SHIFT     4
#define LP_SHIFT      3
#define EREFS_SHIFT   2
#define ERCLKEN_SHIFT  1
#define EREFSTEN_SHIFT  0
/*
只設置目標項,不影響其他專案的設定值,如設定BDIV為0b11那麼BDIV為0b11,其他的,如
RANGE不會改變,維持原來的值。
value:為目標設定的值,如設BDIV 0b11,那麼value=0x03,
shift:為目標設定項在暫存器中的起點,從0開始
具體方式是:先清零設定項,再給已經清零的設定項賦值。
*/
void MCGC2_Target_Set(UINT8 value,UINT8 shift);
/*
Notice!  Put a brandnew value to MCGC2,the pre-Value in MCGC2 will erased.
new value will replace it.
引數setMCGC2可以使用 表2 中所有巨集定義,如要設定多項,可以用位"與",來選擇多個不同
設定選項。
*/
void MCGC2_Set(UINT8 setMCGC2);
//表2
//Selects the amount to divide down the clock source selected by the CLKS bits in the

//MCGC2 register. This controls the bus frequency.
  #define MCGC2_RESET 0x40     //MCGC2復位值

  #define BDIV_1 0x00//(0x00<<6)    //Divides selected clock by 1

  #define BDIV_2 0x01//(0x01<<6)    //Divides selected clock by 2 (reset default)

  #define BDIV_4 0x02//(0x02<<6)    //Divides selected clock by 4

  #define BDIV_8 0x03//(0x03<<6)    //Divides selected clock by 8

//Selects the frequency range for the external oscillator or external clock source.

  #define RANGE_1_16_MHZ  0x01//(0x01<<5)   //High frequency range selected for the external 
                                    //oscillator of 1 MHz to 16 MHz

  #define RANGE_1_40_MHZ  0x01//(0x01<<5)    //1 MHz to 40 MHz for external clock source

  #define RANGE_32_100_KHZ  0x00//(0x00<<5)    //Low frequency range selected for the external
                                       // oscillator of 32 kHz to 100 kHz

  #define RANGE_32K_1M_HZ  0x00//(0x00<<5)    //32 kHz to 1 MHz for external clock source.

//Controls the external oscillator mode of operation

  #define HGO_HI_GAIN  0x01//(0x01<<4)    //Configure external oscillator for high gain operation

  #define HGO_LO_POW   0x00//(0x00<<4)    //Configure external oscillator for low power operation

//Controls whether the FLL (or PLL) is disabled in bypassed modes.

  #define LP_DISABLE  0x01//(0x01<<3)      //FLL (or PLL) is disabled in bypass modes (lower power).

  #define LP_ENABLE   0x00//(0x00<<3)      //FLL (or PLL) is not disabled in bypass modes.

//Selects the source for the external reference clock.

  #define EREFS_SEL_OSC    0x01//(0x01<<2)    //Oscillator requested

  #define EREFS_SEL_EXT_CLK  0x00//(0x00<<2)  //External Clock Source requested

//Enables the external reference clock for use as MCGERCLK.

  #define MCGERCLK_ACTIVE    0x01//(0x01<<1)    //MCGERCLK active

  #define MCGERCLK_INACTIVE  0x00//(0x00<<1)    //MCGERCLK inactive

//Controls whether or not the external reference clock remains enabled when

//the MCG enters stop mode.

  #define EXT_CLK_ENABLE_IN_STOP  0x01    //External reference clock stays enabled in stop
                                        // if ERCLKEN is set or if MCG is in FEE, FBE, PEE, PBE, 
                                        //or BLPE mode before entering stop

  #define INT_CLK_DISABLE_IN_STOP 0x00    //IExternal reference clock is disabled in stop

//MCGC3

/*

          7      6      5    4   3 2 1 0
R      ---------------------------------
       |LOLIE | PLLS | CME |0  |VDIV
W      ---------------------------------
Reset:    0       0     0    0   0 0 0 1

*/
#define LOLIE_SHIFT  7
#define PLLS_SHIFT   6
#define CME_SHIFT    5
#define VDIV_SHIFT   0
/*
只設置目標項,不影響其他專案的設定值,如設定LOLIE為0b1那麼LOLIE為0b1,其他的,如
PLLS不會改變,維持原來的值。
value:為目標設定的值,如設PLLS 0b1,那麼value=0x01,
shift:為目標設定項在暫存器中的起點,從0開始
具體方式是:先清零設定項,再給已經清零的設定項賦值。
*/
void MCGC3_Target_Set(UINT8 value,UINT8 shift);
/*
Put a brandnew value to MCGC3,the pre-Value in MCGC3 will erased.
new value will replace it.
引數setMCGC3可以使用 表3 中所有巨集定義,如要設定多項,可以用位"與",來選擇多個不同
設定選項。
*/
void MCGC3_Set(UINT8 setMCGC3);
//表3
//Determines if an interrupt request is made following a loss of lock indication.

//The LOLIE bit only has an effect when LOLS is set.
  #define MCGC3_RESET 0x10

  #define    LOLIE_INTR_DEN  0x00//(0x0<<7)    //No request on loss of lock.

  #define    LOLIE_INTR_REQ  0x01//(0x01<<7)    //Generate an interrupt request on loss of lock.

//Controls whether the PLL or FLL is selected. If the PLLS bit is clear, the PLL is disabled in all

//modes. If the PLLS is set, the FLL is disabled in all modes.

  #define PLL_SELECTED    0x01//(0x01<<6)    //PLL is selected

  #define FLL_SELECTED    0x00//(0x00<<6)    //FLL is selected

//Determines if a reset request is made following a loss of external clock indication. The
//CME bit should only be set to a logic 1 when either the MCG is in an operational mode that uses the external
//clock (FEE, FBE, PEE, PBE, or BLPE) or the external reference is enabled (ERCLKEN=1 in the MCGC2
//register). Whenever the CME bit is set to a logic 1, the value of the RANGE bit in the MCGC2 register should not

//be changed.

  #define MONITOR_DISABLED   0x00//(0x00<<5)    //Clock monitor is disabled

  #define LOSS_EXT_CLK_RESET 0x01//(0x01<<5)    //Generate a reset request on loss of external clock.
//Selects the amount to divide down the VCO output of PLL. The VDIV bits establish the

//multiplication factor (M) applied to the reference clock frequency.

  #define VDIV_0      0x00    //reselved

  #define VDIV_4      0x01   //Multiply by 4.

  #define VDIV_8      0x02   //Multiply by 8.

  #define VDIV_12      0x03   //Multiply by 12.

  #define VDIV_16      0x04   //Multiply by 16.

  #define VDIV_20      0x05   //Multiply by 20

  #define VDIV_24      0x06   //Multiply by 24.

  #define VDIV_28      0x07   //Multiply by 28.

  #define VDIV_32      0x08   //Multiply by 32.

  #define VDIV_36     0x09  //Multiply by 36.

  #define VDIV_40      0x0A   //Multiply by 40.

  #define VDIV_1011      0x0B   //Reserved (default to M=40).

  #define VDIV_11XX      0x0C/*TO 0xFF*/   //Reserved (default to M=40).


//MCGTRM
//MCG Trim Setting — Controls the internal reference clock frequency by controlling the internal reference clock
//period. The TRIM bits are binary weighted (i.e., bit 1 will adjust twice as much as bit 0). Increasing the binary
//value in TRIM will increase the period, and decreasing the value will decrease the period.
//An additional fine trim bit is available in MCGSC as the FTRIM bit.
//If a TRIM[7:0] value stored in nonvolatile memory is to be used, it’s the user’s responsibility to copy that value
//from the nonvolatile memory location to this register.
/*
TRIM
RW
POR:   1 0 0 0 0 0 0 0
Reset: U U U U U U U U
*/
/*
Controls the internal reference clock frequency by controlling the internal reference clock
period. The TRIM bits are binary weighted (i.e., bit 1 will adjust twice as much as bit 0). 
Increasing the binary value in TRIM will increase the period, and decreasing the value will 
decrease the period.An additional fine trim bit is available in MCGSC as the FTRIM bit.
If a TRIM[7:0] value stored in nonvolatile memory is to be used, it’s the user’s responsibility 
to copy that value from the nonvolatile memory location to this register.
*/
//extern uchar trm;
void MCG_Function(UINT8 mcgtrm);
//MCGSC

/*
      7      6     5      4       3 2     1        0
R     LOLS |LOCK |PLLST |IREFST |CLKST |OSCINIT |FTRIM
W
POR:  0      0     0      1        00     0        0
Reset:0      0     0      1        00     0        U
*/
#define LOLS_SHIFT    7
#define LOCK_SHIFT    6
#define PLLST_SHIFT   5
#define IREFST_SHIFT  4
#define CLKST_SHIFT   2
#define OSCINIT_SHIFT 1
#define FTRIM_SHIFT   0
/*
Get MCG Status and Control Register
當需求的狀態吻合時,返回真
*/
BOOL MCG_Status(UINT8 status,UINT8 shift);
//表4
//This bit is a sticky indication of lock status for the FLL or PLL. LOLS is set when lock
//detection is enabled and after acquiring lock, the FLL or PLL output frequency has fallen outside the lock exit
//frequency tolerance, Dunl. LOLIE determines whether an interrupt request is made when set. LOLS is cleared by
//reset or by writing a logic 1 to LOLS when LOLS is set. Writing a logic 0 to LOLS has no effect.

  #define MCGSC_RESET 0x10 //MCGSC復位值
  #define LOLS_FLL_PLL_LOCKED        0x00//(0x80^0x00)   //FLL or PLL has not lost lock since LOLS was last cleared

  #define LOLS_FLL_PLL_LOST_LOCK     0x80//(0x80^0x80)   //FLL or PLL has lost lock since LOLS was last cleared

//Lock Status — Indicates whether the FLL or PLL has acquired lock. Lock detection is disabled when both the
//FLL and PLL are disabled. If the lock status bit is set then changing the value of any of the following bits IREFS,
//PLLS, RDIV[2:0], TRIM[7:0] (if in FEI or FBI modes), or VDIV[3:0] (if in PBE or PEE modes), will cause the lock
//status bit to clear and stay cleared until the FLL or PLL has reacquired lock. Stop mode entry will also cause the
//lock status bit to clear and stay cle

  #define LOCK_FLL_PLL_UNLOCKED   0x00//(0x40^0x00)  //FLL or PLL is currently unlocked

  #define LOCK_FLL_PLL_LOCKED     0x40//(0x40^0x40)  //FLL or PLL is currently locked.

//PLL Select Status — The PLLST bit indicates the current source for the PLLS clock. The PLLST bit does not
//update immediately after a write to the PLLS bit due to internal synchronization between clock domains.

  #define PLLST_PLLS_IS_FLL                0x00//(0x20^0x00)   //Source of PLLS clock is FLL clock

  #define PLLST_PLLS_IS_PLL                0x20//(0x20^0x20)   //Source of PLLS clock is PLL clock.

//Internal Reference Status — The IREFST bit indicates the current source for the reference clock. The IREFST
//bit does not update immediately after a write to the IREFS bit due to internal synchronization between clock
//domains.

  #define IREFST_EXT_CLOCK               0x00//(0x10^0x00)  //Source of reference clock is external reference clock 
                                                    //(oscillator or external clock source as determined by the
                                                    //EREFS bit in the MCGC2 register).

  #define IREFST_INT_CLOCK               0x10//(0x10^0x10)  //Source of reference clock is internal reference clock

// Clock Mode Status — The CLKST bits indicate the current clock mode. The CLKST bits do not update
//immediately after a write to the CLKS bits due to internal synchronization between clock domains.
  #define CLKST_FLL_IS_SELECTED          0x00//(0x0C^0x00)  //Output of FLL is selected.

  #define CLKST_INT_CLK_SELECTED         0x04//(0x0C^0x04)  //Internal reference clock is selected

  #define CLKST_EXT_CLK_SELECTED         0x08//(0x0C^0x08)  //External reference clock is selected.

  #define CLKST_PLL_IS_SELECTED          0x0C//(0x0C^0x0C)   //Output of PLL is selected

//OSC Initialization — If the external reference clock is selected by ERCLKEN or by the MCG being in FEE, FBE,
//PEE, PBE, or BLPE mode, and if EREFS is set, then this bit is set after the initialization cycles of the external
//oscillator clock have completed. This bit is only cleared when either EREFS is cleared or when the MCG is in
//either FEI, FBI, or BLPI mode and ERCLKEN is cleared.
  #define OSCINIT_SET                    0x02//(0x02^0x00)

  #define OSCINT_CLEARD                  0x00//(0x02^0x02)

//MCG Fine Trim — Controls the smallest adjustment of the internal reference clock frequency. Setting FTRIM
//will increase the period and clearing FTRIM will decrease the period by the smallest amount possible.
//If an FTRIM value stored in nonvolatile memory is to be used, it’s the user’s responsibility to copy that value from
//the nonvolatile memory location to this register’s FTRIM bit.

  #define FTRIM_PROLONG                  0x00//(0x01^0x00)

  #define FTRIM_SHORTEN                  0x01//(0x01^0x01)




/*
Add new value to MCGC1 MCGC2 and MCGC3,previous bit-value will not be erased.
because here in the function use or('|') operator.
引數mcgc1、mcgc2、mcgc3分別可以使用表1、表2、表3中的巨集定義,每個引數如需設定多項,可以用位"與"
,來選擇多個不同設定選項。 如不想設定某個暫存器,直接給引數0即可。
*/
void MCG_Control(UINT8 mcgc1,UINT8 mcgc2,UINT8 mcgc3);


/*
one example for setting the mcg From the initial FEI clock mode to PEE clock mode.
*/
//從FEI到FBE模式的暫存器設定
//#define MCGC2_FEI_FBE  (BDIV_1|RANGE_1_40_MHZ|HGO_HI_GAIN|EREFS_SEL_OSC|MCGERCLK_ACTIVE)
//#define MCGC1_FEI_FBE  (CLKS_SEL_EXT_REF_CLK|RDIV_64|IREFS_SEL_EXT_REF_CLK)
extern void SetBusClock(void);

#endif

原始檔.C

#include <hidef.h>
#include "derivative.h"
#include "MCG.h"


//------VARIABLES PLACE HERE----------------------------------------------------
//uchar trm;

//------LOCAL FUNC PLACE HERE---------------------------------------------------

//------------------------------------------------------------------------------
void MCGC1_Target_Set(volatile UINT8 value,UINT8 shift) {
    switch(shift) {
      case  CLKS_SHIFT:
          if(0x03<value) value = 0x03;
          MCGC1 &=0x3F;
          MCGC1 |=0xC0 & (value<<shift);
      break;
      case  RDIV_SHIFT:
          if(0x07<value) value = 0x07;
          MCGC1 &= 0xC7;
          MCGC1 |=0x38 & (value<<shift);
      break;
      case  IREFS_SHIFT:
          if(0x01<value) value = 0x01;
          MCGC1 &= 0xFB;
          MCGC1 |= 0x04 & (value<<shift);
      break;
      case  IRCLKEN_SHIFT:
          if(0x01<value) value = 0x01;
          MCGC1 &= 0xFD;
          MCGC1 |= 0x02 & (value<<shift);
      break;
      case IREFSTEN_SHIFT:
          if(0x01<value) value = 0x01;
          MCGC1 &= 0xFE;
          MCGC1 |= 0x01 & (value<<shift);
      break;
      default:
      break;
    }
}
void MCGC1_Set(UINT8 setMCGC1)
{
    MCGC1 = setMCGC1;
}
//------------------------------------------------------------------------------
void MCGC2_Target_Set(UINT8 value,UINT8 shift) {
    switch(shift){
      case BDIV_SHIFT:
          if(0x03<value) value = 0x03;
          MCGC2 &= 0x3F;
          MCGC2 |= 0xC0 & (value<<shift);
      break;
      case RANGE_SHIFT:
          if(0x01<value) value = 0x01;
          MCGC2 &= 0xDF;
          MCGC2 |= 0x20 & (value<<shift);
      break;
      case HGO_SHIFT:
          if(0x01<value) value = 0x01;
          MCGC2 &= 0xEF;
          MCGC2 |= 0x10 & (value<<shift); 
      break;
      case LP_SHIFT:
          if(0x01<value) value = 0x01;
          MCGC2 &= 0xF7;
          MCGC2 |= 0x08 & (value<<shift);
      break;
      case EREFS_SHIFT:
          if(0x01<value) value = 0x01;
          MCGC2 &= 0xFB;
          MCGC2 |= 0x04 & (value<<shift);
      break;
      case ERCLKEN_SHIFT:
          if(0x01<value) value = 0x01;
          MCGC2 &= 0xFD;
          MCGC2 |= 0x02 & (value<<shift);
      break;
      case EREFSTEN_SHIFT:
          if(0x01<value) value = 0x01;
          MCGC2 &= 0xFE;
          MCGC2 |= 0x01 & (value<<shift);
      break;
      default:
      break;
    }
}
void MCGC2_Set(UINT8 setMCGC2) 
{
    MCGC2 = setMCGC2;
}
//------------------------------------------------------------------------------
void MCGC3_Target_Set(UINT8 value,UINT8 shift) {
    switch(shift) {
      case LOLIE_SHIFT:
          if(0x01<value) value = 0x01;
          MCGC3 &= 0x7F;
          MCGC3 |= 0x80 & (value<<shift); 
      break;

      case PLLS_SHIFT:
          if(0x01<value) value = 0x01;
          MCGC3 &= 0xBF;
          MCGC3 |= 0x40 & (value<<shift);
      break;
      case CME_SHIFT:
          if(0x01<<value) value = 0x01;
          MCGC3 &= 0xDF;
          MCGC3 |= 0x20 & (value<<shift);      
      break;
      case VDIV_SHIFT:
          if(0x0F<value) value = 0x0F;
          MCGC3 &= 0xF0;
          MCGC3 |= 0x0F &(value<<shift);
      break;
      default:
      break;
    }

}
void MCGC3_Set(UINT8 setMCGC3) 
{
    MCGC3 = setMCGC3;
}

void MCG_Control(UINT8 mcgc1,UINT8 mcgc2,UINT8 mcgc3) 
{
    MCGC1 |= mcgc1;
    MCGC2 |= mcgc2;
    MCGC3 |= mcgc3; 
}
void MCG_Function(UINT8 mcgtrm) {
    MCGTRM = mcgtrm;   
}
BOOL MCG_Status(UINT8 status,UINT8 shift) {
    BOOL temp;
    switch(shift){
      case LOLS_SHIFT:
          temp = ((MCGSC & 0x80) == status );    
      break;
      case LOCK_SHIFT:
          temp = ((MCGSC & 0x40) == status );
      break;
      case PLLST_SHIFT:
          temp = ((MCGSC & 0x20) == status );
      break;
      case IREFST_SHIFT:
          temp = ((MCGSC & 0x10) == status );
      break;
      case CLKST_SHIFT:
          temp = ((MCGSC & 0x0C) == status );
      break;
      case OSCINIT_SHIFT:
          temp = ((MCGSC & 0x02) == status );
      break;
      case FTRIM_SHIFT:
          temp = ((MCGSC & 0x01) == status);
      break;
      default:
      break;
    }
    return temp;
}
void SetBusClock(void) 
{
                                      
//----------------------從初始化FEI時鐘模式切換到FBE時鐘模式 -------------------
		/* Set MCGC2 register */
	MCGC2_Target_Set(BDIV_1,BDIV_SHIFT);         //被MCGC1_CLKS選中的時鐘源除1
	MCGC2_Target_Set(RANGE_1_16_MHZ,RANGE_SHIFT);//為外部振盪器選擇1-16MHz的高頻範
	                                              //圍,本實驗板外部晶振8Mhz
	MCGC2_Target_Set(HGO_HI_GAIN,HGO_SHIFT);      //外部振盪器的高增益執行
	MCGC2_Target_Set(LP_ENABLE,LP_SHIFT);         //旁路模式中啟用旁路模式FLL或PLL
	MCGC2_Target_Set(EREFS_SEL_OSC,EREFS_SHIFT);  //選擇振盪器
	MCGC2_Target_Set(MCGERCLK_ACTIVE,ERCLKEN_SHIFT);//外部參考時鐘用作MCGERCLK
	
	/* Set MCGC1 register */
	MCGC1_Set(MCGC1_RESET);
	MCGC1_Target_Set(CLKS_SEL_EXT_REF_CLK,CLKS_SHIFT);//選擇外部參考時鐘
	MCGC1_Target_Set(RDIV_16,RDIV_SHIFT);             //外部參考時鐘除16
	MCGC1_Target_Set(IREFS_SEL_EXT_REF_CLK,IREFS_SHIFT);//選擇外部參考時鐘
  MCGC1 |= RDIV_PARAM;//針對不同外部平率選擇
	while(!MCG_Status(OSCINIT_SET,OSCINIT_SHIFT))       
	{			/* Wait until external reference is stable */
	      //外部震盪時鐘初始化週期之後退出
	}
	while(!MCG_Status(IREFST_EXT_CLOCK,IREFST_SHIFT))   
	{			/* Wait until external reference is selected */
	      //參考時鐘源是外部參考時鐘退出
	}
	while(!MCG_Status(CLKST_EXT_CLK_SELECTED,CLKST_SHIFT)) 
	{		/* Wait until external clock is selected as a bus clock reference */
	    //選擇外部參考時鐘
	}
//----------------------從初始化FBE時鐘模式切換到PBE時鐘模式 -------------------	
	/* Set MCGC1 register */
	MCGC1_Target_Set(CLKS_SEL_EXT_REF_CLK,CLKS_SHIFT);
	MCGC1_Target_Set(RDIV_4,RDIV_SHIFT);
	/* Set MCGC3 register */
	MCGC3_Target_Set(PLL_SELECTED,PLLS_SHIFT);
	MCGC3_Target_Set(VDIV_20,VDIV_SHIFT);
	
	while(!MCG_Status(PLLST_PLLS_IS_PLL,PLLS_SHIFT))
	{			/* Wait until PLL is selected */
	}
	while(!MCG_Status(LOCK_FLL_PLL_LOCKED,LOCK_SHIFT))
	{			/* Wait until PLL is locked */
	}
//----------------------從初始化PBE時鐘模式切換到PEE時鐘模式 -------------------	
	MCGC1 = RDIV_PARAM;			/* Set MCGC1 register */
	while(!MCG_Status(CLKST_PLL_IS_SELECTED,CLKST_SHIFT))
	{		/* Wait until PLL clock is selected as a bus clock reference */
	}
	//---------------------最終PLL clock 作為BUS clock----------------------------	
}
5、最終從MCG分配出來的幾個時鐘頻率分別為MCGERCLK=8Mhz、MCGOUT=40Mhz、MCGFFCLK=2Mhz