STM32F103入門 | 12.PWM實現呼吸燈

 

重要補充:由於STM32F103入門這個系列的教程都是基於 6.工程模板的建立 裏面的那個工程模板進行編程的,所以,在 6.工程模板的建立 的第 (11) 那裏,LIB 需要添加<src>文件夾中所有的 .c 文件。(不然的話,從 9.定時器簡述 開始,編譯器就會瘋狂報錯啦)

 

12.1. PWM簡介

PWM全稱爲“Pulse Width Modulation”。中文翻譯爲:脈衝寬度調製。脈衝寬度指的是 脈衝持續的時間,既高電平或低電平保持(持續)的時間。而PWM通俗的說就是人爲的(通過微處理器)去控制電平高低保持的時間。這裏引出一個新名詞,佔空比:在一個脈衝的循環中,通電時間相對於總時間所佔的比例。

STM32 的定時器除了 TIM6 和 TIM7。其他的定時器都可以用來產生 PWM 輸出。其中高級定時器 TIM1 和 TIM8 可以同時產生多達 7 路的 PWM 輸出。而通用定時器也能同時產生多達 4 路的 PWM 輸出,這樣,STM32 最多可以同時產生 30 路 PWM 輸出!


12.2. PWM相關寄存器

除了定時器章節介紹的幾個寄存器( ARR、PSC、 CR1 等) 外,還會用到 4 個寄存器(通用定時器則只需要 3 個),來控制 PWM 的輸出。這四個寄存器分別是:捕獲/比較模式寄存器( TIMx_CCMR1/2)、捕獲/比較使能寄存器( TIMx_CCER)、捕獲/比較寄存器( TIMx_CCR1~4) 以及剎車和死區寄存器( TIMx_BDTR)。

(1)捕獲/比較模式寄存器( TIMx_CCMR1/2)

該寄存器總共有 2 個, TIMx _CCMR1 和 TIMx _CCMR2。TIMx_CCMR1 控制 CH1 和 CH2,而 TIMx_CCMR2 控制 CH3 和 CH4。

寄存器分了 2 層,上面一層對應輸出時的設置而下面的則對應輸入時的設置。模式設置位 OCxM,此部分由 3 位組成。總共可以配置成 7 種模式,我們使用的是 PWM 模式,這 3 位必須設置爲110/111。這兩種 PWM 模式的區別就是輸出電平的極性相反。 另外 CCxS 用於設置通道的方向(輸入/輸出)默認設置爲 0,就是設置通道作爲輸出使用。

/**
  * 沒有重映射時,TIM3的四個通道CH1, CH2, CH3, CH4分別對應PA6, PA7, PB0, PB1
  * 部分重映射時,TIM3的四個通道CH1, CH2, CH3, CH4分別對應PB4, PB5, PB0, PB1
  * 完全重映射時,TIM3的四個通道CH1, CH2, CH3, CH4分別對應PC6, PC7, PC8, PC9
  * 
  * 110:PWM模式1 - 在向上計數時,一旦TIMx_CNT<TIMx_CRRx時,通道x爲有效電平,
  * 否則爲無效電平;在向下計數時,一旦TIMx_CNT>TIMx_CRRx時,通道x爲無效電平,
  * 否則爲有效電平。
  *
  * 111:PWM模式2 - 在向上計數時,一旦TIMx_CNT<TIMx_CRRx時,通道x爲無效電平,
  * 否則爲有效電平;在向下計數時,一旦TIMx_CNT>TIMx_CRRx時,通道x爲有效電平,
  * 否則爲無效電平。
  */

(2)捕獲/比較使能寄存器( TIMx_CCER)

這裏只用到了 CC1E 位,該位是輸入/捕獲 1 輸出使能位,要想PWM 從 IO 口輸出,這個位必須設置爲 1。

 

(3)捕獲/比較寄存器( TIMx_CCR1~4)

該寄存器總共有 4 個,對應 4 個輸通道 CH1~CH4。在輸出模式下,該寄存器的值與 CNT 的值比較,根據比較結果產生相應動作。利用這點,我們通過修改這個寄存器的值,就可以控制 PWM 的輸出脈寬了。

 

(4)剎車和死區寄存器( TIMx_BDTR)

如果是通用定時器,則配置以上三個寄存器就夠了,但是如果是高級定時器,則還需要配置:剎車和死區寄存器( TIMx_BDTR)。該寄存器,我們只需要關注最高位: MOE 位,要想高級定時器的 PWM 正常輸出,則必須設置 MOE 位爲 1,否則不會有輸出。注意:通用定時器不需要配置這個。


12.3. PWM波形產生原理

通用定時器可以利用 GPIO 引腳進行脈衝輸出,在配置爲比較輸出、PWM 輸出功能時,捕獲/比較寄存器 TIMx_CCR 被用作比較功能,下面把它簡稱爲比較寄存器。

這裏直接舉例說明定時器的PWM輸出工作過程:若配置脈衝計數器TIMx_CNT 爲向上計數,而重載寄存器 TIMx_ARR 被配置爲 N,即 TIMx_CNT 的當前計數值數值X在 TIMxCLK 時鐘源的驅動下不斷累加,當 TIMx_CNT 的數值X大於 N 時,會重置 TIMx_CNT 數值爲 0 重新計數。

而在 TIMxCNT 計數的同時,TIMxCNT 的計數值X會與比較寄存器TIMx_CCR 預先存儲了的數值 A 進行比較,當脈衝計數器 TIMx_CNT 的數值X小於比較寄存器 TIMx_CCR 的值A時,輸出高電平(或低電平),相反地,當脈衝計數器的數值X大於或等於比較寄存器的值 A 時,輸出低電平(或高電平)。

如此循環,得到的輸出脈衝週期就爲重載寄存器 TIMx_ARR 存儲的數值 (N+1) 乘以觸發脈衝的時鐘週期,其脈衝寬度則爲比較寄存器 TIMx_CCR 的值 A 乘以觸發脈衝的時鐘週期,即輸出PWM的佔空比爲 A/(N+1) 。


12.4 PWM配置步驟

1.開啓TIM3時鐘、GPIOB時鐘和複用功能時鐘
2.配置GPIOB5爲複用輸出
3.設置TIM3_CH2重映射到PB5上
4.初始化TIM3,設置ARR和PSC
5.設置TIM3_CH2的PWM模式
6.使能TIM3的CH2輸出
7.使能TIM3
8.在主函數中改變佔空比完成呼吸燈

 

12.5 定時器引腳複用功能映射

 

根據以上重映像表,我們使用定時器3的通道2作爲PWM的輸出引腳,所以需要對PB5引腳進行配置。注意:如果使用PB4當做TIM3部分重映射的CH1輸出,除了要進行部分重映射配置外,還需要禁用JTAG!並在開啓複用時鐘後禁用JTAG!

GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE); //禁用JTAG,在開啓複用時鐘後禁用

 

1. 新建兩個文件,pwm.c 和 pwm.h

 

2. 在頭文件 pwm.h 添加下面代碼:

 

 

3. 把 pwm.c 添加到工程中

 

4. 在 pwm.c 中添加以下代碼:

#include "pwm.h"

void PWM_Init(u16 arr,u16 psc)
{
    GPIO_InitTypeDef GPIO_InitStructure;              //定義GPIO結構體
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;    //定義TIMx定時器結構體
    TIM_OCInitTypeDef TIM_OCInitStructure;            //定義定時器脈寬調製結構體
    
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);                     //使能TIM3時鐘
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO,ENABLE);//使能GPIOB時鐘和AFIO複用時鐘
    
    GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3,ENABLE);                     //TIM3部分重映射 TIM3_CH2->PB5
    
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;                               //TIM_CH2
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;                         //複用推輓輸出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;                       //配置輸出速率
    GPIO_Init(GPIOB,&GPIO_InitStructure);                                   //初始化GPIOB
    
    TIM_TimeBaseStructure.TIM_Period = arr;                                 //設置自動重裝載寄存器週期的值 arr=value-1
    TIM_TimeBaseStructure.TIM_Prescaler = psc;                              //設置預分頻值 psc=value-1
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;                            //設置時鐘分割:TDTS = Tck_tim
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;             //TIM向上計數模式
    TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStructure);                          //初始化TIMx時間基數
    
    //初始化TIM3 Channel2 PWM模式     
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;                       //選擇定時器模式:TIM脈衝寬度調製模式1
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;           //使能比較輸出
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;               //輸出極性:TIM輸出比較極性高
    TIM_OC2Init(TIM3,&TIM_OCInitStructure);                                 //根據T指定的參數初始化外設TIM3 OC2

    TIM_OC2PreloadConfig(TIM3,TIM_OCPreload_Enable);                        //使能TIM3在CCR2上的預裝載寄存器
    TIM_Cmd(TIM3, ENABLE);                                                  //使能TIM3
}

 

 

5. 實現PWM呼吸燈功能

 

 

歡迎關注微信公衆號『OpenSSR』

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