MC9S08DZ60單片機測量時間的問題

1.    問題描述

用DZ60的計時器測週期時發現,TPM(計時器)在初始化後,需要等待500多ms才能勉強測到。

TPM產生的波形如下圖,藍色波形上升沿爲初始化指令執行完成時間點,用一個IO口輸出高電平並延時100ms作爲示波器觸發源,黃色波形爲TPM的PWM方式輸出波形。


2.    問題分析

         在DZ60DATASHEET中文版第313頁找到這段話。

大概意思是TPM的通道控制寄存器的更新時機由clksb:clksa控制。而clksb:clksa的功能如表16-3所示。

        合起來就是說,對通道控制寄存器的寫入,不是直接寫到寄存器裏面,而是先寫到寄存器對應的緩衝器。當TPM計數器關閉時,寫入的數據從緩衝器寫入完成後立即更新到寄存器;而當TPM有時鐘在運行時,寫入的數據更新則需要等到,計時器從0xfffe變成0xffff纔開始進行。

        由此想到,產生問題的TPM初始化是128分頻(16MHZ總線時鐘下,週期爲8us)。16位TPM計數器從0開始計數,則有更新設置需等待時間爲65535×8us=524ms。與所見波形符合。



3.    問題解決

         無論TPM用作輸入捕捉,還是PWM或者比較輸出,所有TPM控制寄存器初始化時,都要先把時鐘關掉,即clksb:clksa=0b00。問題解決後得到波形如下:


4.      正確實例

  

//初始化時必須先關掉時鐘,否則以下兩個寄存器要到將要溢出即(0xfffe->0xffff)時纔會更新。
    //--如果設置128分頻,則初始化時間需要 16MHz/128*65535=524ms
//關掉時鐘初始化,則寄存器在寫入完成後立即更新,無需等待。
//TPM2產生中央對齊PWM輸出
    TPM_CSTR(TPM_NUM_2) =0b001<span style="color:#ff0000;">00</span>111;
    //                      |||||||
    //                      ||||||+-----PS0\
    //                      |||||+------PS1 ----128倍分頻
    //                      ||||+-------PS2/
    //                      |||+--------CLKSA\
    //                      ||+---------CLKSB/--關時鐘
    //                      |+----------CPWMS---所有通道以中央對齊PWM模式運行
    //                      +-----------TOIE----禁止溢出中斷
//TPM1設置爲輸入捕捉
    TPM_CSTR(TPM_NUM_1) =0b000<span style="color:#ff0000;">00</span>111;
    //                      |||||||
    //                      ||||||+-----PS0\
    //                      |||||+------PS1 ----128倍分頻
    //                      ||||+-------PS2/
    //                      |||+--------CLKSA\
    //                      ||+---------CLKSB/--關時鐘
    //                      |+----------CPWMS---所有通道以輸入捕捉運行
    //                      +-----------TOIE----禁止溢出中斷
//TPM2通道設置
    TPM2_CHSCSTR(TPM_CHNo)=0b00101000;
    //                        |||||
    //                        ||||+-----ELSA\
    //                        |||+------ELSB/---High-true 脈衝(清除向上比較輸出)
    //                        ||+-------MSA\
    //                        |+--------MSB/----CPWMS=1時,此設置無效
    //                        +---------CHIE----禁止中斷
    tmp = Period * (125) / 2;
    TPM2MOD = tmp;     //週期Period以ms爲單位
    TPM2C0V = tmp / 10 * Duty / 10;   //佔空比Duty爲0~100整數
    TPM2SC_CLKSB = 0;
    TPM2SC_CLKSA = 1;  <span style="color:#ff0000;">//寄存器設置完成,再打開總線時鐘,避免長時間的寄存器更新。</span>
//TPM2通道設置
    TPM1SC_CLKSB = 0;
    TPM1SC_CLKSA = 1;  <span style="color:#ff0000;">//寄存器設置完成,再打開總線時鐘,避免長時間的寄存器更新。</span>
    TPM1SC_TOIE = 1;   //使能輸入捕捉中斷
EnableTPM1ChInt(G_TMUch_Start);

中斷程序的寫法如下
interrupt void isrT1Ch0In(void)
{
   DisableInterrupt();          //禁止總中斷

   if(TPM1C0SC_CH0F == 1)   //判斷是否發生輸入捕捉中斷
   {
       TPM1C0SC_CH0F = 0;     //清除標誌位
       switch(g_trigged)
       {
       case 0:
           //第一次觸發,保存數據
           g_start_data = TPM1C0V;
           g_trigged++;
           //設置第二次觸發邊沿方式
           <span style="color:#ff0000;">TPM_CSTR(TPM_NUM_1) =0b00000111;//重新初始化,避免長時間的寄存器更新。</span>
           switch(G_Edge_Stop) 
           {
             case POS_EDGE:
                 TPM1_CHSCSTR(G_TMUch_Stop)=0b00000100;
                 //                              |||||
                 //                              ||||+-----ELSA\
                 //                              |||+------ELSB/---上升邊沿捕捉
                 //                              ||+-------MSA\
                 //                              |+--------MSB/----輸入捕捉模式
                 //                              +---------CHIE----禁止通道中斷
                 break;
             case NEG_EDGE:
                 TPM1_CHSCSTR(G_TMUch_Stop)=0b00001000;//下降邊沿捕捉
                 break;
             default:
                 TPM1_CHSCSTR(G_TMUch_Stop)=0b00000100;//默認爲上升邊沿捕捉
                 break;
           }           
          <span style="color:#ff0000;"> //寄存器設置完成,再打開總線時鐘,避免長時間的寄存器更新。
           TPM1SC_CLKSB = 0;
           TPM1SC_CLKSA = 1; 
           TPM1SC_TOIE = 1;</span>
           EnableTPM1ChInt(G_TMUch_Stop);
           break;
       case 1:
           //第二次觸發,保存數據
           g_stop_data = TPM1C0V;
           g_trigged++;
           //時間採集完畢,恢復成IO功能
           TPM1_CHSCSTR(G_TMUch_Start)=0b00000000; 
           TPM1_CHSCSTR(G_TMUch_Stop)=0b00000000;  //恢復成IO功能
           break;
       default:
           break;
       } 
   }
   
   EnableInterrupt();           //開放總中斷
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章