關於STM32F103C8T6工程文件自己免積分下載https://download.csdn.net/download/weixin_45488643/12522971這個僅僅是一個核心工程文件,只需要自己添加以下代碼就可以。
PWM簡介
脈衝寬度調製(PWM),是英文“Pulse Width Modulation” 的縮寫,簡稱脈寬調製,是利用微處理器的數字輸出來對模擬電路進行控制的一種非常有效的技術。簡單一點,就是對脈衝寬度的控制。
STM32 的定時器除了 TIM6 和 7。其他的定時器都可以用來產生 PWM 輸出。其中高級定時器 TIM1 和 TIM8 可以同時產生多達 7 路的 PWM 輸出。而通用定時器也能同時產生多達 4路的 PWM 輸出,這樣,STM32 最多可以同時產生 30 路 PWM 輸出!這裏僅使用 TIM1的 CH1 產生一路 PWM 輸出。
要使 STM32 的高級定時器 TIM1 產生 PWM 輸出,除了上一章介紹的幾個寄存器(ARR、PSC、 CR1 等) 外,我們還會用到 4 個寄存器(通用定時器則只需要 3 個),來控制 PWM 的輸出。這四個寄存器分別是:捕獲/比較模式寄存器( TIMx_CCMR1/2)、捕獲/比較使能寄存器(TIMx_CCER)、捕獲/比較寄存器(TIMx_CCR1~4) 以及剎車和死區寄存器TIMx_BDTR)。
簡單介紹這四個寄存器。首先是捕獲/比較模式寄存器(TIMx_CCMR1/2),該寄存器總共有 2 個, TIMx CCMR1和 TIMx CCMR2。 TIMx_CCMR1 控制 CH1 和 CH2,而 TIMx_CCMR2 控制 CH3 和 CH4。
TIMx_CCMR1 寄存器各位描述:
介紹捕獲/比較使能寄存器(TIMx_CCER),該寄存器控制着各個輸入輸出通道的開關。
**TIMx CCER 寄存器各位描述**
捕獲/比較寄存器(TIMx_CCR1~4),該寄存器總共有 4 個,對應 4 個
輸通道 CH1~4。因爲這 4 個寄存器都差不多,僅以 TIMx_CCR1 爲例介紹。
**寄存器 TIMx CCR1 各位描述**
在輸出模式下,該寄存器的值與 CNT 的值比較,根據比較結果產生相應動作。利用這點,通過修改這個寄存器的值,就可以控制 PWM 的輸出脈寬了。
如果是通用定時器,則配置以上三個寄存器就夠了,但是如果是高級定時器,則還需要配置:剎車和死區寄存器(TIMx_BDTR),該寄存器各位描述如圖所以。
該寄存器,我們只需要關注最高位: MOE 位,要想高級定時器的 PWM 正常輸出,則必須設置 MOE 位爲 1,否則不會有輸出。注意:通用定時器不需要配置這個。
配置步驟:
1) 開啓 TIM1 時鐘,配置 PA8 爲複用輸出。要使用 TIM1,我們必須先開啓 TIM1 的時鐘。這裏我們還要配置 PA8 爲複用輸出(當然還要時能 PORTA 的時鐘),這是因爲 TIM1_CH1 通道將使用 PA8 的複用功能作爲輸出。 庫函數使能 TIM3 時鐘的方法是:
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //使能定時器 3 時鐘
設置 PA8 爲複用功能輸,列出 GPIO 初始化的一行代碼即可:
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //複用推輓輸出
2)設置 TIM1 的 ARR 和 PSC。
在開啓了 TIM1 的時鐘之後,我們要設置 ARR 和 PSC 兩個寄存器的值來控制輸出 PWM 的週期。當 PWM 週期太慢(低於 50Hz)的時候,我們就會明顯感覺到閃爍了。因此, PWM 週期在這裏不宜設置的太小。這在庫函數是通過 TIM_TimeBaseInit 函數實現的。
TIM_TimeBaseStructure.TIM_Period = arr; //設置自動重裝載值
TIM_TimeBaseStructure.TIM_Prescaler =psc; //設置預分頻值
TIM_TimeBaseStructure.TIM_ClockDivision = 0; //設置時鐘分割:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上計數模式
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure); //根據指定的參數初始化 TIMx 的
3) 設置 TIM1_CH1 的 PWM 模式及通道方向, 使能 TIM1 的 CH1 輸出。接下來,我們要設置 TIM1_CH1 爲 PWM 模式(默認是凍結的),配置 TIM1_CCMR1 的相關位來控制 TIM1_CH1 的模式。在庫函數中, PWM 通道設置是通過函數 TIM_OC1Init()~TIM_OC4Init()來設置的,不同的通道的設置函數不一樣,這裏我們使用的是通道 1,所以使用的函數是TIM_OC1Init()。
void TIM_OC1Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
直接來看看結構體 TIM_OCInitTypeDef的定義:
t
ypedef struct
{
uint16_t TIM_OCMode;
uint16_t TIM_OutputState;
uint16_t TIM_OutputNState;
uint16_t TIM_Pulse;
uint16_t TIM_OCPolarity;
uint16_t TIM_OCNPolarity;
uint16_t TIM_OCIdleState;
uint16_t TIM_OCNIdleState;
} TIM_OCInitTypeDef;
幾個成員變量:
參數 TIM_OCMode 設置模式是 PWM 還是輸出比較,這裏我們是 PWM 模式。
參數 TIM_OutputState 用來設置比較輸出使能,也就是使能 PWM 輸出到端口。
參數 TIM_OCPolarity 用來設置極性是高還是低。
其他的參數 TIM_OutputNState, TIM_OCNPolarity, TIM_OCIdleState 和 TIM_OCNIdleState 是高級定時器 TIM1 和 TIM8 纔用到的。要實現我們上面提到的場景,方法是:
T
IM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //選擇 PWM 模式 2
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比較輸出使能
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //輸出極性高
TIM_OC1Init(TIM1, &TIM_OCInitStructure); //初始化 TIM1 OC1
4) 使能 TIM1。
在完成以上設置了之後,我們需要使能 TIM1。使能 TIM1 的方法前面已經講解過:
TIM_Cmd(TIM1, ENABLE); //使能 TIM1
5) 設置 MOE 輸出,使能 PWM 輸出。
普通定時器在完成以上設置了之後, 就可以輸出 PWM 了,但是高級定時器,我們還需要使能剎車和死區寄存器(TIM1_BDTR)的 MOE 位,以使能整個 OCx(即 PWM)輸出。數的設置函數爲:
TIM_CtrlPWMOutputs(TIM1,ENABLE);// MOE 主輸出使能
6) 修改 TIM1_CCR1 來控制佔空比。
最後,在經過以上設置之後, PWM 其實已經開始輸出了,只是其佔空比和頻率都是固定的,而我們通過修改 TIM1_CCR1 則可以控制 CH1 的輸出佔空比。繼而控制 PWM輸出。
在庫函數中,修改 TIM1_CCR1 佔空比的函數是:
void TIM_SetCompare1(TIM_TypeDef* TIMx, uint16_t Compare1);
理所當然,對於其他通道,分別有一個函數名字,函數格式爲TIM_SetComparex(x=1,2,3,4)。通過以上 6 個步驟,我們就可以控制 TIM1 的 CH1 輸出 PWM 波了。
main函數
#include "led.h"
#include "delay.h"
#include "sys.h"
#include "pwm.h"
int main(void)
{
u16 led0pwmval=0;
u8 dir=1;
delay_init(); //延時函數初始化
LED_Init(); //初始化與LED連接的硬件接口
TIM1_PWM_Init(899,0);//不分頻。PWM頻率=72000/(899+1)=80Khz
while(1)
{
delay_ms(10);
if(dir)led0pwmval++;
else led0pwmval--;
if(led0pwmval>300)dir=0;
if(led0pwmval==0)dir=1;
TIM_SetCompare1(TIM1,led0pwmval); //通道比較值 修改TIM1_CCR1 佔空比
}
}
pwm.c
#include "pwm.h"
#include "led.h"
//PWM輸出初始化
//arr:自動重裝值
//psc:時鐘預分頻數
void TIM1_PWM_Init(u16 arr,u16 psc)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);// 使能定時器1
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE); //使能GPIO外設時鐘使能
//設置該引腳爲複用輸出功能,輸出TIM1 CH1的PWM脈衝波形
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; //TIM_CH1
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //複用推輓輸出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
TIM_TimeBaseStructure.TIM_Period = arr; //設置在下一個更新事件裝入活動的自動重裝載寄存器週期的值 80KHZ
TIM_TimeBaseStructure.TIM_Prescaler =psc; //設置用來作爲TIMx時鐘頻率除數的預分頻值 不分頻
TIM_TimeBaseStructure.TIM_ClockDivision = 0; //設置時鐘分割:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上計數模式
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure); //根據TIM_TimeBaseInitStruct中指定的參數初始化TIMx的時間基數單位
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //選擇定時器模式:TIM脈衝寬度調製模式2
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比較輸出使能
TIM_OCInitStructure.TIM_Pulse = 0; //設置待裝入捕獲比較寄存器的脈衝值
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //輸出極性:TIM輸出比較極性高
TIM_OC1Init(TIM1, &TIM_OCInitStructure); //根據TIM_OCInitStruct中指定的參數初始化外設TIMx 通道1
TIM_CtrlPWMOutputs(TIM1,ENABLE); //MOE 主輸出使能
TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable); //CH1預裝載使能
TIM_ARRPreloadConfig(TIM1, ENABLE); //使能TIMx在ARR上的預裝載寄存器
TIM_Cmd(TIM1, ENABLE); //使能TIM1
}
pwm.h
#ifndef __PWM_H
#define __PWM_H
#include "sys.h"
void TIM1_PWM_Init(u16 arr,u16 psc);
#endif
注:代碼來源,正點原子。