1、通用定時器的PWM功能
STM32F103ZET6有4個通用定時器,分別是TIM2、TIM3、TIM4、TIM5。
通用定時器由一個可編程預分頻器驅動的16位自動裝載計數器構成。
通用定時器的很多功能與基本定時器是一樣的,但是每個通用定時器都有4個IO口,可以用來測量輸入信號的脈沖長度(輸入捕獲)或產生輸出波形(輸出比較和PWM)。
通用定時器可以用來輸出PWM信號,每個通用定時器可以輸出4路PWM信號。
2、通用定時器的輸入/輸出腳
每個通用定時器都具有4個輸入/輸出通道,即4個IO口,它們的對應關系如下圖:

3、通用定時器的計數方式
通用定時器的框圖如下:

圖中TIMx_CH1、TIMx_CH2、TIMx_CH3、TIMx_CH4就是用來輸出PWM的腳位,對應定時器的4個通道。
通用定時器的功能是在基本定時器功能上的擴展,定時部分跟基本定時器是差不多的,只是基本定時器只能是向上計數,而通用定時器既可以設置成向上計數、也可以設置成向下計數、或是設置成向上/向下計數。
通用定時器的向上計數模式跟基本定時器是一樣的。
通用定時器的向下計數模式:
在向下計數模式中,計數器先從TIMx_ARR自動裝載寄存器中獲取計數初值,然后開始向下計數,當計數到0時產生中斷並重新從TIMx_ARR自動裝載寄存器中獲取初值。
通用定時器的向上/向下計數模式:
在向上/向下計數模式中,計數器從0開始計數到TIMx_ARR-1的值后產生中斷,然后向下計數到1並產生中斷;然后再從0開始重新計數。
在向上/向下計數模式中,不能對TIMx_CR1寄存器中的DIR位賦值,DIR位由硬件更新,可以通過讀取DIR位來確認當前是向上計數還是向下計數。
在向上/向下計數模式中,如果內部時鍾分頻因子為1,TIMx_ARR自動裝載寄存器的值為0x06,那么定時器的的時序圖如下:

從圖中可以看到,計數器向上計數到0x05的時候產生了溢出中斷,計數器向下計數到1的時候產生了溢出中斷。
通用定時器通過TIMx_CR1控制寄存器的CMS[1:0]位和DIR位來控制定時器的計數方向。
4、通用定時器PWM輸出的工作原理
通用定時器PWM輸出的頻率由TIMx_ARR自動重裝載寄存器和TIMx_PSC預分頻器寄存器確定、占空比由TIMx_CCRx捕獲/比較寄存器決定。
通用定時器PWM的工作模式:
通用定時器的PWM可以設置為兩種模式:PWM模式1和PWM模式2,模式的選擇是根據TIMx_CCMRx捕獲/比較模式寄存器OCxM[2:0](x范圍是1~4,表示4個通道)這三個位的設置決定的。
這里需要特別注意的是每個定時器的PWM輸出通道有4個,但是捕獲/比較模式寄存器只有2個:TIMx_CCMR1和TIMx_CCMR2,TIMx_CCMR1寄存器的低16位為有效位,低8位用來配置通道1,高8位用來配置通道2;TIMx_CCMR2寄存器也是低16位為有效位,低8位用來配置通道3,高8位用來配置通道4。也就是說每8個位配置一個通道,這8個位的配置參數是一樣的,不一樣的只是配置的通道不一樣。
PWM模式1:
當OCxM[2:0] = 110時,PWM處於模式1下。
當定時器的計數器的值小於捕獲/比較寄存器的值時(TIMx_CNT < TIMx_CCRx),輸出通道輸出有效電平。
當定時器的計數器的值大於等於捕獲/比較寄存器的值時(TIMx_CNT >= TIMx_CCRx),輸出通道輸出無效電平。
PWM模式2:
當OCxM[2:0] = 111時,PWM處於模式2下。
當定時器的計數器的值小於捕獲/比較寄存器的值時(TIMx_CNT < TIMx_CCRx),輸出通道輸出無效電平。
當定時器的計數器的值大於等於捕獲/比較寄存器的值時(TIMx_CNT >= TIMx_CCRx),輸出通道輸出有效電平。
通過對比可以看出,PWM模式1和PWM模式2的輸出電平剛好是相反的。
有效電平和無效電平:
在PWM模式1和PWM模式2的介紹中可以看到PWM輸出通道輸出分為有效電平和無效電平兩種狀態。有效和無效電平是根據TIMx_CCER捕獲/比較使能寄存器的bit1位CCxP來決定是什么狀態的。
當CCxP = 0時,輸出通道的有效電平為高電平,無效電平為低電平。
當CCxP = 1時,輸出通道的有效電平為低電平,無效電平為高電平。
當CCxP = 0時,如果PWM處於模式1的狀態下,當TIMx_CNT < TIMx_CCRx時,輸出通道輸出高電平,當TIMx_CNT >= TIMx_CCRx時,輸出通道輸出低電平;如果PWM處於模式2的狀態下,當TIMx_CNT < TIMx_CCRx時,輸出通道輸出低電平,當TIMx_CNT >= TIMx_CCRx時,輸出通道輸出高電平。模式1和模式2剛好相反。
當CCxP = 1時,如果PWM處於模式1的狀態下,當TIMx_CNT < TIMx_CCRx時,輸出通道輸出低電平,當TIMx_CNT >= TIMx_CCRx時,輸出通道輸出高電平。如果PWM處於模式2的狀態下,當TIMx_CNT < TIMx_CCRx時,輸出通道輸出高電平,當TIMx_CNT >= TIMx_CCRx時,輸出通道輸出低電平。模式1和模式2剛好相反。
在PWM模式1或2下,TIMxCNT寄存器和TIMx_CCRx寄存器始終在進行比較(一句計數器的計數方向)以確定是否符合TIMx_CCRx <= TIMx_CNT或者TIMx_CNT <= TIMx_CCRx。
當使能定時器后,計數器開始計數,可以將定時器設置為向上計數、向下計數、向上/向上計數。
在STM3參考手冊中,用邊沿對齊模式來指示計數器向上計數、計數器向下計數這兩種模式,具體是向上還是向下,需要根據TIMx_CR1寄存器的DIR位來設置,當DIR=0時是向上計數模式;當DIR=1時是向下計數模式。用中央對齊模式來指示計數器向上和向下同時計數的模式。
通過TIMx_CR1控制寄存器的bit6~bit5位CMS[1:0]來選擇是邊沿對齊模式還是中央對齊模式。
PWM邊沿對齊模式:
定時器向上計數:
當TIMx_CR1寄存器的bit4位DIR為0時,定時器向上計數。
下圖是PWM選擇為模式1,有效電平為高電平,OCXREF指示輸出的電平狀態,TIMx_ARR的值為8,也就是計數器TIMx_CNT遞增到8后清0從新計數。
從圖中可以看,當CCRx = 4,若TIMx_CNT < 4,則OCXREF輸出的是高電平;若TIMx_CNT >= 4,則OCXREF輸出的是低電平。
當CCRx = 8,若TIMx_CNT < 8,則OCXREF輸出高電平;若TIMx_CNT >= 8,則OCXREF輸出低電平。
當CCRx > 8,則TIMx_CNT一直小於CCRx,則OCXREF一直保持高電平。
當CCRx = 0,則TIMx_CNT一直不小於CCRx,則OCXREF一直保持低電平。
從圖中還可以看到,CCxIF中斷狀態位的變化,CCRx與TIMx_CNT每比較成功一次就會置位CCxIF,當CCRx > TIMx_CNT或CCRx = 0時,在定時器計數器溢出時,CCxIF會被置位。

定時器向下計數:
當TIMx_CR1寄存器的bit4位DIR為1時,定時器向下計數。
這個跟向上計數模式是差不多的,只是計數方向不一樣。
PWM中央對齊模式:
當TIMx_CR1寄存器中的CMS位不為'00'時,定時器的計數方式為中央對齊模式。
根據不同的CMS位設置,比較標志可以在計數器向上計數時被置1、在計數器向下計數時被置1、或是在計數器向上和向下計數時被置1。
當定時器工作在中央對齊模式時,TIMx_CR1寄存器中的計數方向位DIR由硬件更新,DIR變為只讀位,不能軟件修改。
如下圖是定時器工作在中央對齊模式時的PWM圖形:

進入中央對齊模式時,軟件不能同時修改TIMx_CR1寄存器中的DIR位和CMS位。
使用中央對齊模式最保險的方法,就是在啟動計數器之前產生一個軟件更新(設置TIMx_EGR寄存器中的UG位),不要在計數器工作的過程中修改計數器的值。
5、通用定時器PWM的配置流程
1、開啟使用到的通用定時器的時鍾,配置相應的輸出通道的腳位為復用輸出,如果腳位需要重映射,還需要根據具體需求進行重映射配置。
2、通過TIMx_CR1寄存器的bit6~bit5位CMS[1:0]來選擇定時器的計數模式,如果設置的是邊沿對齊模式,還需要設置TIMx_CR1寄存器的bit4位DIR來選擇計數器是向上計數還是向下計數;若選擇的是中央對齊模式,則不需要設置DIR位。
3、通過設置TIMx_ARR寄存器和TIMx_PSC寄存器來決定PWM輸出的頻率,如果TIMx_ARR寄存器需要使用緩沖功能,還需要將TIMx_CR1的bit7位ARPE位置1。
4、通過設置TIMx_CCRx捕獲/比較寄存器來決定PWM輸出的占空比。
5、通過捕獲/比較模式寄存器TIMx_CCMRx配置相應的通道為輸出和PWM的模式。這里需要注意的是每個定時器的捕獲/比較模式寄存器只有兩個,而通道有4個,這是應為TIMx_CCMR1配置的是CH1和CH2;而TIMx_CCMR2配置的CH3和CH4。TIMx_CCMR1寄存器的低8位配置的是CH1,高8位配置的是CH2;而TIMx_CCMR2寄存器的低8位配置的是CH3,高8位配置的是CH4。每8個位配置一個通道,每個通道配置的位都是相同的。通過TIMx_CCMRx寄存器的OCxM[2:0]位選擇PWM的工作模式,OCxM[2:0]只有“110”和“111”這兩個數值是配置為PWM模式。TIMx_CCMRx寄存器的CCxS[1:0]位用來配置通道是輸出還是輸入,這里將CCxS[1:0]設置為“00”,將通道配置為輸出。
6、通過捕獲/比較使能寄存器TIMx_CCER來配置輸出通道的有效電平和使能相應的通道輸出PWM。TIMx_CCER寄存器可以配置4個通道,每個通道占的bit位置不同。使用TIMx_CCER寄存器的CCxP位選擇輸出通道的有效電平的狀態。通過置位TIMx_CCER寄存器的CCxE位來開啟PWM信號輸出到對應的腳位,也可以通過清零CCxE位來禁止PWM輸出。
7、最后置位TIMx_CR1寄存器的bit0位CEN來啟動定時器開始計數。
8、因為這里是配置PWM的輸出功能,沒有用到中斷,所以不需要配置中斷。
6、HAL庫操作PWM輸出
初始化代碼如下:
1 TIM_HandleTypeDef TIM5_Handler_Init; 2 TIM_OC_InitTypeDef PWM_Handler_Init; 3
4 void PWM_Init(void) 5 { 6 GPIO_InitTypeDef GPIO_InitStruct; 7
8 __HAL_RCC_GPIOA_CLK_ENABLE(); 9 __HAL_RCC_TIM5_CLK_ENABLE(); 10
11 GPIO_InitStruct.Pin = GPIO_PIN_0; 12 GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; 13 GPIO_InitStruct.Pull = GPIO_NOPULL; 14 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; 15 HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); 16
17 HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET); 18
19 TIM5_Handler_Init.Instance = TIM5; 20 TIM5_Handler_Init.Init.Prescaler = 7200-1; 21 TIM5_Handler_Init.Init.Period = 1000; 22 TIM5_Handler_Init.Init.CounterMode = TIM_COUNTERMODE_UP; 23 HAL_TIM_Base_Init(&TIM5_Handler_Init); 24
25 PWM_Handler_Init.OCMode = TIM_OCMODE_PWM1; 26 PWM_Handler_Init.Pulse = 500; 27 PWM_Handler_Init.OCPolarity = TIM_OCPOLARITY_HIGH; 28 PWM_Handler_Init.OCFastMode = TIM_OCFAST_DISABLE; 29
30 HAL_TIM_PWM_ConfigChannel(&TIM5_Handler_Init,&PWM_Handler_Init,TIM_CHANNEL_1); 31
32 HAL_TIM_PWM_Start(&TIM5_Handler_Init,TIM_CHANNEL_1); 33 }
這里配置的是通用定時器TIM5的通道1來作為PWM輸出,對應的IO為PA0。
第1、2行定義兩個結構體變量,TIM5_Handler_Init用來初始化通用定時器,PWM_Handler_Init用來初始化PWM輸出通道。
第8、9行是開啟GPIA和TIM5定時器的時鍾。
第11到17行配置的是PA0口為復用輸出功能。
第19到23行配置的是TIM5定時器的自動重裝值和預分頻的值,還有TIM5定時器計數模式。
第25到28行配置的是PWM功能,第25行是選擇PWM的工作模式;第26行是設置PWM的占空比;第27行是選擇通道的有效電平;
第30行是對PWM輸出通道進行初始化。
第32行是使能PWM信號輸出到對應的腳位和啟動TIM5定時器。
