在STM32上利用PWM原理實現呼吸燈效果


在ST32項目中第一次接觸到PWM這個概念,PWM是Plus width modulation的英文縮寫,百度百科有詳細介紹。

因為介紹的太詳細了,對於做軟件開發的人員來說看着還是有些暈乎,知道了一個大概。最后我簡化理解為高中物理中的方波,

將一個方波周期分解問n份,1份代表一個高電平,這樣我們就可以得到n+1個值,0個高電平,1個高電平,2個高電平,...,n個高電平。

不能將高電平理解為計算機軟件中的1,低電平為0,如果按照這個理解n份代表的是2^n個數。作為軟件開發人員比較容易理解為2^n. 

現在想想開始不太理解PWM的原因可能就是2^n的搞得鬼。

大概理解PWM概念后,就是關於頻率和Duty Circle的概念。頻率容易理解就是高中物理的平路,周期數/秒 。 T = 1/f. Duty Circle說的就是一個周期內高電平份數。

在嵌入式開發中PWM能用來做什么呢?這也是我個人的理解,應該是很不全面的。

  1. 控制風扇,燈等設備的檔位:由於我們將方波一個周期分為n個Duty Circle(高電平),這樣就將GPIO的有效電壓輸出分為0...n(n+1)份,再通過一些放大電路就可以將風扇、燈等設備分為n擋進行數字化控制了。呼吸燈也是這個原理,將燈分為n擋,然后在周期性的調整Duty Circle的值達到呼吸燈的效果。
  2. 用PWM波模擬數字化的0,1對燈帶等設備進行控制,這樣做的優點是僅僅需要兩根線就可以控制燈帶設備了。例如將PWM周期分為三份,1個Duty Circle表示二進制的0,2個Duty Circle表示二進制的1,這樣就可以發送24bit的色彩值給燈帶控制芯片控制燈帶顏色了,也可以做跟復雜的事情了。

 

這里開始介紹如何在STM32上實現呼吸燈效果,參考英文的教程 https://breiteneder.me/?p=424&amp=1&lang=en

這個英文教程用的是Timer中斷來控制LED燈值的變化,實現呼吸燈的效果。由於僅僅是呼吸燈效果,

不需要嚴格控制每個周期的Duty Circle值(上文的PWM第二種作用),我這里使用的freertos的task來控制Duty Circle的數值,相對簡單一些。

我將代碼放到Github上了,有興趣的可以自取。https://github.com/magicduan/demo_pwm

開發板:STM32G431Rb 開發環境:STM32 Cube IDE 1.8

  • Step1:將開發板配置為freertos. 可以參考這篇英文文章.
  • Step2:STM32G431Rb板上的LED等對應的GPIO為PA5,將PA5管腳配置為TIM2_CH1

            

  • Step3:配置Timer2,將 Clock Source 設置為“Internal Clock”,Channel1 設置為“PWM Generation CH1”. 

**注意:板子的不同你能選擇的TIMER和Channel都可能不同,上面給的英文的文章配置的就是TIM2_CH2,如果配置的是TIM2_CH2就需要將Channel 2設為PWM

  • Step4: 設置TIM2的周期,Duty Circle等參數。“Parameter Setting”
    1. Prescale -->就是對Timer的頻率進行降頻處理,在Clock Configuration中可以看到APB1, APB2的timer頻率值為170MHZ(每個板子可能不同),這里我將Prescale的值設置為68,這樣我們我們得到頻率為170MHZ/68 = 2MHZ的頻率。
    2. Counter Period-> 就是上面說的高電平的份數(Duty Circle)設置為100,也就是將LED燈的亮度切割為0...100個值
    3. PWM Generation Channel 1中"Fast Mode” 設置為Enable(為什么要設置為Enable,還沒有去深究), Plus(32bits value)設置為100,這個值無所謂,就是初始的Duty Circle 值,0 ~ 100之間都可以。

         

         

 

  • Step5 配置完成,利用STM32 Cube IDE生成代碼。
  • Step6 生成代碼后,進行最后的編程處理
    • main.c 中main函數中啟動PWM波 HAL_TIM_PWM_Start(&html2,TIM_CHANNEL_1)
  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_TIM2_Init();
  /* USER CODE BEGIN 2 */
  HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_1);

  /* USER CODE END 2 */

  /* Init scheduler */
  osKernelInitialize();
    • main.c中加入全局變量pwm_plus_value就是Duty Circle的值,pwm_dir表示呼吸燈值是變大還是變小,其實也可以不用全局變量的。
    • /* USER CODE BEGIN PFP */
      uint8_t pwm_plus_value = 50;
      uint8_t pwm_dir = 0; // 0 for UP, 1 for Down
      
      /* USER CODE END PFP */

      main.c中加入修改pwm_plus_value的處理函數,就是達到最大值100后,改為遞減,達到最小值0時,變為遞增。設置TIM2的PWM的Duty Circle值的寄存器

    • 我們這里用的是Channel1,設置的就是CCR1,前面英文的文章中用的是Channel 2,設置的是CCR2,以此類推。
    • /* USER CODE BEGIN 4 */
      void update_pwm_value()
      {
        if (pwm_dir == 0){
          pwm_plus_value++;
        }else{
          pwm_plus_value--;
        }
        if (pwm_plus_value >= 100){
          pwm_dir = 1;
        }else if (pwm_plus_value <= 0){
          pwm_dir =0;
        }
        htim2.Instance->CCR1 = (htim2.Init.Period*pwm_plus_value)/100u;
      
      }
      /* USER CODE END 4 */

      在defaultTask中周期調用update_pwm_value()函數就可以實現效果了

    • void StartDefaultTask(void *argument)
      {
        /* USER CODE BEGIN 5 */
        /* Infinite loop */
        for(;;)
        {
          update_pwm_value();
      //    HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_5);
          osDelay(5);
        }
        /* USER CODE END 5 */
      }

       

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM