實現定時器輸出PWM(基於STM32103ZET6)

我們使用 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 不停的由暗變到亮,然後又從亮變到暗。

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