基於STM32103ZET6實現定時器輸出PWM

我們使用 TIM3 的通道 2,把通道 2 重映射到 PB5,產生 PWM 來控制 DS0 的亮度!
這是數字電路控制模擬電路的一個典型例子

原理講解:就一句話

PWM是脈衝寬度調製,通過定時器產生固定頻率的脈衝波形,通過配置寄存器TIM3_CCR2值,改變(輸出比較)這一固定頻率的輸出佔空比,實現改變PWM佔空比目的,實現led點亮。
問題
那麼問題就到了怎們配置定時器定時器產生固定頻率波形,需要使能什麼功能,用到了哪些外設。。。
概述
STM32開發板定時器都可以用來產生PWM,且可同時產生多路PWM,具體多少路大家可以深入瞭解,反正就是按照多少定時器計算,我們這個實驗,只需要TIM3的通道二(CH2),除了在上一講博客中提到的定時器的寄存器初始化外,還有幾個重要的定時器配置需要講解:
捕獲/比較模式寄存器(TIMx_CCMR1/2)
在這裏插入圖片描述
這個0-15是控制CH1和CH2的,該寄存器總共有 2 個,TIMx_CCMR1和 TIMx _CCMR2。TIMx_CCMR1 控制 CH1 和2,而 TIMx_CCMR2 控制 CH3 和 4。
在OC1M(4-6位)與OC2M(12-14位)是配置成7種模式,爲什麼PWM還有7種模式?是因爲在不同模式下,有些寄存器的位功能會不同,我們需要的是PWM模式,所以通道二中的值必須爲110或者111,兩者差別就是輸出極性相反!
捕獲/比較使能寄存器(TIMx_CCER)
在這裏插入圖片描述
所謂使能,就是打開,就操作CCXE位,使用到的通道二,就只操作CC2E就可以了,寫入值爲1就好,
捕獲/比較寄存器(TIMx_CCR1~4)
在這裏插入圖片描述
該寄存器個數爲四個,正好對應CH1-CH4,配置是一樣的,以通道1爲例在輸出模式下,該寄存器的值與 (計數器)CNT 的值比較,根據比較結果產生相應動作。利用這點,我們通過修改這個寄存器的值,就可以控制 PWM 的輸出脈寬了,我們要使用通道二,就要配置CCR2寄存器
重映射
想要用pwm控制led0,但是硬件連接上並沒有連接在一起,STM32很強大,可以利用重映射使得pwm口輸出電平到led0,STM32 的重映射控制是由複用重映射調試 IO 配置寄存器AFIO_MAPR控制的
在這裏插入圖片描述
我們用到的是TIM3,所以重映射選擇10-11位,但是兩位有四種重映射值,那麼我們重映射到底映射到哪個IO口了呢?
在這裏插入圖片描述
這時候我們選擇的是led0控制口PB5,當我們的PA7映射到PB5的同時,PA6也映射到了PA4,PB0與PB1不變。
梳理軟件步驟
(1):使能定時器時鐘使能APB1,GPIO複用時鐘直接使用配置函數
實際操作:RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
實際操作:RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
(2):GPIO初始化,配置GPIO複用推輓輸出!定時器初始化,確定週期,配置爲pwm模式
初始化代碼過多,詳情見代碼
(3):GPIO重映射
函數:void GPIO_PinRemapConfig(uint32_t GPIO_Remap, FunctionalState NewState);
實際操作:GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE);
(4):配置pwm模式,使能通道二輸出
初始化代碼過多,詳情見代碼
(5):使能定時器
TIM_Cmd(TIM3, ENABLE);
(6):最後控制佔空比用void TIM_SetCompare2(TIM_TypeDef* TIMx, uint16_t Compare2);函數,Compare2參數取值範圍爲0-899;可根據自己的情況佈置pwm;

PWM頭文件pwm.h

#ifndef PWM_H
#define PWM_H
#include “sys.h”
void pwm_init(u16,u16);
#endif

PWM源文件pwm.c

#include “pwm.h”
#include “sys.h”

void pwm_init(u16 arr,u16 psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_OCInitTypeDef TIM_TypeStructure;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO, ENABLE);
GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE);
TIM_TimeBaseInitStructure.TIM_ClockDivision=0;
TIM_TimeBaseInitStructure.TIM_CounterMode= TIM_CounterMode_Up;;
TIM_TimeBaseInitStructure.TIM_Period=arr;
TIM_TimeBaseInitStructure.TIM_Prescaler=psc;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);
TIM_TypeStructure.TIM_OutputState=TIM_OutputState_Enable;
TIM_TypeStructure.TIM_OCMode=TIM_OCMode_PWM2;;
TIM_TypeStructure.TIM_OCPolarity=TIM_OCPolarity_High;
TIM_OC2Init(TIM3, &TIM_TypeStructure);
TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_5;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStructure);
TIM_Cmd(TIM3, ENABLE);
}
如上配置在前面的步驟中梳理出來的,看起來有點繁瑣,可以對應步驟來看

PWM主函數源文件main.c

#include “led.h”
#include “sys.h”
#include “delay.h”
#include “pwm.h”
int main(void)
{
int led1;
int led2;
delay_init();
LED_Init();
pwm_init(899,0);

 while(1)
 { 
	 delay_ms(10);
	 if(led1<300)
	 {
		 TIM_SetCompare2(TIM3,led1);
		 led1++;
		 if(led1>=300)
		 {
			 led2=300;
		 }
	 }
	else
		 {
			 TIM_SetCompare2(TIM3,led2);
			 led2--;
			 if(led2<=0)
			 {
				 led1=0; 
			 }	 
		 }
	 
 }

}
主函數實現很簡單,可根據自己的喜好來設置顯示內容。
唯有實踐,纔是能體會到過程的快樂!

現象

在完成軟件設計之後,將我們將編譯好的文件下載到精英 STM32 開發板上,觀看其運行結果是否與我們編寫的一致。如果沒有錯誤,我們將看 DS0 不停的由暗變到亮,然後又從亮變到暗。

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