2023年5月15日 星期一

for STM32F103,抓輸入的PWM的週期及高電位時間

 別看原子哥老師的程式碼寫的落落長,

反正就把握一個原則:
測量器TIM8的slave mode用reset mode (即:一有輸入,即觸發一次reset /update 事件)
TIM8的trigger是TI1FP1 (即,以timer input filter polarity channel1 做為觸源)
但,因為CNT的增減還是由這個timer自動動作,所以還是要有時基,故選內部時鐘
是要做為測量工具,儘可能求最細精度及最大週期,所以就用不分頻及period為65535為基礎,如下圖


至於direct & indirect ,是看pdf 教材來的

(摘錄自「STM32F103 战舰开发指南V1.1.pdf」22.5節  高級定時器PWM輸入模式實驗 323頁)
別隨便用chatGPT的code,那會讓你更迷糊的
至於待測物--PWM訊號源的話,先以TIM3 CHANNEL2為PWM源,跳線PB5<->PC6 (TIM8 channel1的GPIO pin),時鐘的基本設定上,因為考量到TIM1的最長週期為65535個count 約0.0009秒,即900微秒...
「這麼短,如果遇到超過1亳秒的週期豈不是掛了」
「先從小的測,測出來正確再放大」
TIM3的初設定:72-1分頻,ARR為100-1,佔空比為50 
初版程式如下:
------------------------------------------

int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_TIM3_Init();
  MX_TIM8_Init();
  MX_USART1_UART_Init();

   HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_2);
   HAL_Delay(5000);
   HAL_TIM_Base_Start(&htim8);
   HAL_TIM_IC_Start_IT(&htim8,TIM_CHANNEL_1);
   HAL_TIM_IC_Start_IT(&htim8,TIM_CHANNEL_2);
  
  while (1)
  {
      HAL_Delay(100);
      if(1)
      {
          printf(" period :%i ; hi-time:%i \r\n",period,high_time);
      }
  }
}
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
     period = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);
     high_time = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_2);
}
------------------------------------------
結果輸出的值是period為7198,hi-time為3598.都要加2才是正確的7200 & 3600
(其中的+1是因為「從0起算」;另一個加一是什麼?知道的朋友請開示一下)
驗算一下:7200* 1/72000000 = 0.0001 sec ,佔空比50%,故為3600 * 1/72000000=0.00005 sec



「那,放大到10ms的週期,要怎麼改?」
「就在TIM8的update事件都加上365536,就這麼簡單」
「可是update事件也可能是因為TIM3 rising edge引發的,也可能是TIM8自己的reset引發的,
如何是好?」
這就好好安排「update 」及「capture compare」兩個中斷的順序了
我們打算先在input capture做一個旗標,確定是真的已經進入了一個偵測流程了(而且要排除在半路遇到下降緣引發的input capture 中斷),日後的update interrupt 再來進行計次,
所以中斷的優先高低是input capture 高於 update 
「一定要這麼複雜嗎?」
「一定要,因為預設是update優於input capture」



然後,code小改一下...
1.main那裡要呼叫「__HAL_TIM_ENABLE_IT(&htim8,TIM_IT_UPDATE);」
(別忘了配置了什麼中斷就要用這方式enable起來)
---------------------------------
uint8_t begin_capture=0;
uint32_t overflow_count=0;
//讓timer8一直count下去吧
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if(htim->Instance==TIM8 && begin_capture==1)
    {
        overflow_count++;
    }
}
//加上over flow之後的推算
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
   if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1 )
   {
      //測得rsing edge,但是否為一個新的測量流程?
       if(begin_capture==0)
       {
           begin_capture=1;
           overflow_count=0;
           return;
       }else{
          //測量完畢
           begin_capture=0;
          //別忘了+2
           period = (HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1)+2)+
                            (overflow_count>0?(65536*(overflow_count-1)):0);
          
       }
       
   }
    //測得falling edge ,而且還是「測量中」才算數
   if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2 && begin_capture==1)
   {
       high_time = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_2)+2+
                            (overflow_count>0?(65536*(overflow_count-1)):0);
   }
}
---------------------------------
我們再去把TIM3改成很長的週期:預分頻為7200-1,ARR為50000-1,pulse為2500
程式輸出結果為
period:360000000 & hi-time:18000000 
算一下 360000000*72Mhz=5sec;  18000000 * 72Mhz=0.25秒,

 
正確無誤,
而且也不必像正點原子哥的程式那麼複雜
「為什麼那個overflow要減一才能乘65536?」
「因為第一次的input capture calback後還是執行了update中斷了,所以要把最初的那次扣掉」
(事實上我也是實驗,先修改/扣除...再回想,才了解這一點的,要學的東西太多了)

附記:
STM32 timer系列可以參考這個播放 清單, 這位老師也是座寶山....