91视频免费?看_蜜芽MY188精品TV在线观看_国产免费无遮挡在线观看视频_深夜国产_亚洲精品欧洲精品_欧美黑人粗暴多交

ReCclay
認(rèn)證:VIP會(huì)員
所在專題目錄 查看專題
藍(lán)橋嵌入式之 蜂鳴器
藍(lán)橋嵌入式之 LCD使用
藍(lán)橋嵌入式之 簡(jiǎn)單USART通信實(shí)現(xiàn)LCD顯示
藍(lán)橋嵌入式之 AT24C02
藍(lán)橋嵌入式之 PWM波輸出相關(guān)總結(jié)
藍(lán)橋嵌入式之 輸入捕獲(一)
作者動(dòng)態(tài) 更多
【FPGA基礎(chǔ)】基于 Pango Design Suite(PDS) 的FPGA開發(fā)流程
2021-05-14 11:22
【FPGA基礎(chǔ)】基于Quartus Prime 17.1 的FPGA開發(fā)流程
2021-05-08 17:49
【AD快速入門】8051最小系統(tǒng)繪制
2021-04-22 10:03
藍(lán)橋嵌入式之 ADC電壓采集與顯示
2021-04-14 11:48
藍(lán)橋嵌入式之 實(shí)時(shí)時(shí)鐘RTC
2021-04-13 14:50

藍(lán)橋嵌入式之 PWM波輸出相關(guān)總結(jié)

  1. 通用和高級(jí)定時(shí)器的PWM模式產(chǎn)生PWM
  2. 通用定時(shí)器輸出比較產(chǎn)生PWM

幾個(gè)留待補(bǔ)充的程序:


1、高級(jí)定時(shí)器實(shí)現(xiàn)互補(bǔ)PWM波


2、同一TIM不同通道,產(chǎn)生相位不同的PWM波


3、高級(jí)定時(shí)器的輸出比較產(chǎn)生PWM


之前在藍(lán)橋的單片機(jī)比賽階段對(duì)于PWM的一次又一次深入,印象頗深。而今到了嵌入式,更感覺尤為重要,這里也算做個(gè)小結(jié),如有錯(cuò)誤,不吝指教。


閱讀此篇博文的同時(shí),也可參閱之前寫的一篇ST32之PWM小結(jié)。


幾個(gè)帶著寫博客的問題回答下:

1、關(guān)于PWM的上限頻率呢?

跟周期有關(guān)即PWM模式下的arr和輸出比較中的pulse...,也不太好說,沒具體環(huán)境,具體情況再分析吧。

2、PWM模式下同時(shí)可以幾個(gè)通道輸出呢?

有幾個(gè)通道就能輸出幾個(gè)唄。


一、通用和高級(jí)定時(shí)器的PWM模式產(chǎn)生PWM

PWM模式的特點(diǎn):同一定時(shí)器中,不同的通道下,輸出的頻率固定,占空比可變。

通用定時(shí)器PWM模式,TIM3_CH1 和 TIM3_CH2輸出,引腳為PA6 PA7...工程代碼移步Github<傳送門>

1、通用定時(shí)器PWM模式輸出主要代碼

小于Pluse為高電平,大于Pluse小于ARR為低電平。

main.c

/*******************************************************************************
* 文件名:main.c
* 描  述:
* 作  者:CLAY
* 版本號(hào):v1.0.0
* 日  期: 2019年1月25日
* 備  注:通用定時(shí)器輸出硬件PWM PA6-TIM3_CH1 PA7-TIM3_CH2
*         并通過按鍵4改變占空比,初始占空比40%,每次加10%
*******************************************************************************
*/

#include "config.h"
#include "led.h"
#include "key.h"
#include "timer.h"
#include "beep.h"
#include "lcd.h"
#include "stdio.h"
#include "usart.h"
#include "i2c.h"
#include "eeprom.h"
#include "PWMMode.h"

int main(void)
{
	
	STM3210B_LCD_Init();
	LCD_Clear(Blue);
	LEDInit();
	KeyInit();
	BeepInit();
	TIM2Init(2000, 72);//定時(shí)2ms

	TIM3_PWMInit(1000, 40, 80);//頻率2K CH1占空比40% CH2占空比80%
	
	while(1)
	{	
		KeyDriver();
	}
}

void KeyAction(int code)
{
	static u32 x = 400; 
		
	if(code == 1)//按下B1,切換燈狀態(tài),蜂鳴器鳴叫0.1s
	{
		GPIOC->ODR ^= (1<<8);//PC8不斷取反
		GPIOD->ODR |= (1<<2);//PD2置1,使能573鎖存器
		GPIOD->ODR &= ~(1<<2);//PD2清0,關(guān)閉573鎖存器
		Beep(100);
	}
	else if(code == 2)
	{
		Beep(-1);
	}
	else if(code == 3)
	{
		Beep(0);
	}
	else if(code == 4)
	{
		x += 100;
		TIM_SetCompare1(TIM3, x);//改變占空比
	}
}



PWMMode.c

#include "PWMMode.h"

void TIM3_IOInit(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	
	//***注意這里是APB2***
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能 GPIOA時(shí)鐘
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7; //TIM3通道1-PA6 TIM3通道2-PA7
	//***復(fù)用推挽輸出(PWM模式)***
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; 
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化 GPIO
}

void TIM3Init(u32 arr, u8 ch1_duty, u8 ch2_duty)
{
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
	
	//***注意這里是APB1***
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);  //使能定時(shí)器3時(shí)鐘 
	TIM_TimeBaseStructure.TIM_Period = arr-1; //設(shè)置在自動(dòng)重裝載周期值
	TIM_TimeBaseStructure.TIM_Prescaler = 72-1; //設(shè)置預(yù)分頻值
	TIM_TimeBaseStructure.TIM_ClockDivision = 0; //設(shè)置時(shí)鐘分割:TDTS = Tck_tim
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM 向上計(jì)數(shù)模式
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //初始化 TIM3
}

void TIM3_PWMInit(u32 freq, u8 ch1_duty, u8 ch2_duty)
{
	u32 arr;
	
	TIM_OCInitTypeDef TIM_OCInitStructure;
	arr = 1000000 / freq; 

	TIM3_IOInit();//TIM3通道1-PA6 TIM3通道2-PA7配置
	TIM3Init(arr, ch1_duty, ch2_duty);//TIM3定時(shí)器配置
	
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;//PWM1模式
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;//輸出極性高
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
	TIM_OCInitStructure.TIM_Pulse = (arr - 1) * ch1_duty / 100;
	//TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable);//預(yù)裝載使能位無所謂,不影響
	TIM_OC1Init( TIM3, &TIM_OCInitStructure);
			
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;//PWM2模式
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;//輸出極性低
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//比較輸出使能
	//***(arr-1)是總的計(jì)數(shù)值,而(arr-1)*占空比是電平反轉(zhuǎn)時(shí)的計(jì)數(shù)值,故控制pluse就可以控制占空比***
	TIM_OCInitStructure.TIM_Pulse = (arr - 1) * ch2_duty / 100;
	//TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);//預(yù)裝載使能位無所謂,不影響
	TIM_OC2Init( TIM3, &TIM_OCInitStructure);
	//***高級(jí)定時(shí)器必須有這一句,而通用就不必了***
	//TIM_CtrlPWMOutputs(TIM3, ENABLE);//使能PWM輸出 
	TIM_Cmd(TIM3, ENABLE); //使能 TIM3
}

PWMMode.h

#ifndef _PWMMODE_H
#define _PWMMODE_H

#include "config.h"

void TIM3_PWMInit(u32 freq, u8 ch1_duty, u8 ch2_duty);

#endif

2、通用定時(shí)器PWM模式輸出需要注意的地方

通用定時(shí)器的硬件PWM模式,改變占空比通過TIM_SetCompare1函數(shù),注意最大數(shù)值是等于arr即周期值!

①、我們要用TIM3的CH1和CH2通道,這兩個(gè)可以從數(shù)據(jù)手冊(cè)(P19)查閱到對(duì)應(yīng)的復(fù)用引腳是PA6和PA7。

②、我們要想使用定時(shí)器的PWM模式,配置流程需要遵循 IO引腳配置 -> 定時(shí)器配置 -> PWM模式配置的順序。

③、IO引腳為PA,對(duì)應(yīng)時(shí)鐘總線在APB2,而TIM3對(duì)應(yīng)時(shí)鐘總線是APB1。

④、定時(shí)器配置中的TIM_OCInitStructure結(jié)構(gòu)體,我們通過程序溯源可以找到其成員變量,可以發(fā)現(xiàn)其共有8個(gè),但是其中4個(gè)通用定時(shí)器無需配置,高級(jí)定時(shí)器才需要配置。

⑥、PWM配置中TIM_OCInitStructure結(jié)構(gòu)體的兩個(gè)成員需要注意下,TIM_OCModeTIM_OCPolarity

前者TIM_OCMode取值有兩個(gè)分別為TIM_OCMode_PWM1TIM_OCMode_PWM2。后者取值也有兩個(gè)TIM_OCPolarity_HighTIM_OCPolarity_Low


PWM1和PWM2參考正點(diǎn)原子的《STM32F1開發(fā)指南-寄存器版本_V3.1 》P255....

說白了,這兩個(gè)都是管PWM初始狀態(tài)的,慣用的搭配是TIM_OCMode_PWM1TIM_OCPolarity_High一對(duì),TIM_OCMode_PWM2TIM_OCPolarity_Low一對(duì),這樣搭配是正邏輯,否則為反邏輯。什么意思呢?看下面的圖吧。

主函數(shù)調(diào)用TIM3_PWMInit(1000, 40, 80);

I、CH1為TIM_OCMode_PWM1TIM_OCPolarity_High,CH2為TIM_OCMode_PWM1TIM_OCPolarity_High時(shí):

是符合主函數(shù)調(diào)用邏輯的,故稱之為正邏輯。

II、CH1為TIM_OCMode_PWM2TIM_OCPolarity_High時(shí):

此時(shí)占空比主函數(shù)調(diào)用時(shí)40%,而實(shí)際是60%,故稱之為反邏輯。

III、CH1為TIM_OCMode_PWM2TIM_OCPolarity_Low時(shí):

此時(shí)變又是正邏輯了,所以記住固定搭配就行了。

⑦、關(guān)于PWMMode.c中注釋的一句

	//***高級(jí)定時(shí)器必須有這一句,而通用就不必了***
	//TIM_CtrlPWMOutputs(TIM3, ENABLE);//使能PWM輸出 

參考正點(diǎn)原子的《STM32F1開發(fā)指南-寄存器版本_V3.1 》P318....

只有高級(jí)定時(shí)器PWM輸出時(shí),必須加上這一句,而這里我們是通用定時(shí)器,所以沒有加。

⑧、關(guān)于TIM_OCInitStructure結(jié)構(gòu)體重的TIM_Pulse理解

(arr-1)是總的計(jì)數(shù)值,而(arr-1)*duty是電平反轉(zhuǎn)時(shí)的計(jì)數(shù)值,故pluse = 占空比

⑨、關(guān)于PWMMode.c中的TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);用來使能輸出/比較預(yù)裝載使能位。

輸出比較預(yù)裝載使能位OCxPE位于捕獲/比較模式寄存器TIMx_CCMRx中。

若使能了該位,寫入到TIMx_CCRx寄存器的比較值將在更新事件到來時(shí)才會(huì)傳入到當(dāng)前捕獲/比較寄存器,否則未使能,比較值將立即寫入當(dāng)前捕獲比較寄存器

在PWM模式下,預(yù)裝載使能位無論使能與否都不影響。

哈,注意了,當(dāng)前捕獲比較寄存器是一個(gè)名詞。

每個(gè)通用定時(shí)器擁有4路捕獲/比較寄存器,每路通道都擁有一個(gè)捕獲/比較寄存器TIMx_CCRx用于裝載比較值。該寄存器同樣包括兩個(gè)寄存器,一個(gè)是用戶可以操作的:用于寫入比較值;另一個(gè)是用于和計(jì)數(shù)器CNT進(jìn)行比較的當(dāng)前捕獲比較寄存器

對(duì)了,關(guān)于這個(gè)函數(shù)也有要說的,我們?cè)诔绦蛑许樦@個(gè)函數(shù)尋找它的定義會(huì)找到

也許會(huì)有一個(gè)疑問,CH2的預(yù)裝載使能位在手冊(cè)上寫的不是第11位嗎?

怎么到了庫(kù)函數(shù)里面變成了8,

莫急我們繼續(xù)看看TIM_OCPreload,再尋找這個(gè)的定義

看,

原來使能的時(shí)候不是0x0001啊,而是0x0008,那么這么算起來剛好不就對(duì)應(yīng)11位了么?完美~


附幾個(gè)寄存器名,混個(gè)眼熟

既然上面詳細(xì)介紹了通用定時(shí)器的PWM輸出功能,這里也再附上高級(jí)定時(shí)器的PWM輸出功能吧,方便日后查閱... 工程代碼移步Github<傳送門>

main.c

/*******************************************************************************
* 文件名:main.c
* 描  述:
* 作  者:CLAY
* 版本號(hào):v1.0.0
* 日  期: 2019年1月26日
* 備  注:高級(jí)定時(shí)器PWM輸出 PA9-TIM_CH2 PA10-TIM_CH3
*         并通過按鍵4增加占空比,初始占空比為40%,每次增加10%
*******************************************************************************
*/

#include "config.h"
#include "led.h"
#include "key.h"
#include "timer.h"
#include "beep.h"
#include "lcd.h"
#include "stdio.h"
#include "usart.h"
#include "i2c.h"
#include "eeprom.h"
#include "PWMMode.h"
#include "PWMMode_Advance.h"

int main(void)
{
	STM3210B_LCD_Init();
	LCD_Clear(Blue);
	LEDInit();
	KeyInit();
	BeepInit();
	TIM2Init(2000, 72);//定時(shí)2ms

	TIM3_PWMInit(1000, 40, 80);//頻率2K CH1占空比40% CH2占空比80%
	TIM1_PWMInit(1000, 40, 80);//頻率2K CH2占空比40% CH3占空比80%
	
	while(1)
	{	
		KeyDriver();
	}
}

void KeyAction(int code)
{
	static u32 x = 400;
	
	if(code == 1)//按下B1,切換燈狀態(tài),蜂鳴器鳴叫0.1s
	{
		GPIOC->ODR ^= (1<<8);//PC8不斷取反
		GPIOD->ODR |= (1<<2);//PD2置1,使能573鎖存器
		GPIOD->ODR &= ~(1<<2);//PD2清0,關(guān)閉573鎖存器
		Beep(100);
	}
	else if(code == 2)
	{
		Beep(-1);
	}
	else if(code == 3)
	{
		Beep(0);
	}
	else if(code == 4)
	{
		x += 100;
		TIM_SetCompare2(TIM1, x);//改變TIM1_CH2占空比
	}
}

PWMMode_Advance.c

#include "PWMMode_Advance.h"

void TIM1_IOInit(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	
	//***注意這里是APB2***
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能 GPIOA時(shí)鐘
	//***根據(jù)實(shí)際電路選用了USART1的復(fù)用功能。***(要注意的是,拔掉跳線帽PA9 PA10)
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9|GPIO_Pin_10; //TIM_CH2 - PA9 //TIM_CH3 - PA10
	//***復(fù)用推挽輸出(PWM模式)***
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; 
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化 GPIO
}

void TIM1Init(u32 arr, u8 ch1_duty, u8 ch2_duty)
{
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
	
	//***注意這里是APB2***
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);  //使能定時(shí)器1時(shí)鐘 
	TIM_TimeBaseStructure.TIM_Period = arr-1; //設(shè)置在自動(dòng)重裝載周期值
	TIM_TimeBaseStructure.TIM_Prescaler = 72-1; //設(shè)置預(yù)分頻值
	TIM_TimeBaseStructure.TIM_ClockDivision = 0; //設(shè)置時(shí)鐘分割:TDTS = Tck_tim
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM 向上計(jì)數(shù)模式
	TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure); //初始化 TIM1
}

void TIM1_PWMInit(u32 freq, u8 ch1_duty, u8 ch2_duty)
{
	u32 arr;
	
	TIM_OCInitTypeDef TIM_OCInitStructure;
	arr = 1000000/ freq;
	
	TIM1_IOInit();//TIM1通道2-PA9 TIM1通道3-PA10配置
	TIM1Init(arr, ch1_duty, ch2_duty);//TIM1定時(shí)器配置
	
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;//PWM1模式
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;//輸出極性高
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
	TIM_OCInitStructure.TIM_Pulse = (arr - 1) * ch1_duty / 100;
	//TIM_OC2PreloadConfig(TIM1, TIM_OCPreload_Enable);//預(yù)裝載使能位無所謂,不影響
	TIM_OC2Init( TIM1, &TIM_OCInitStructure);
			
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;//PWM2模式
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;//輸出極性低
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//比較輸出使能
	//***(arr-1)是總的計(jì)數(shù)值,而(arr-1)*占空比是電平反轉(zhuǎn)時(shí)的計(jì)數(shù)值,故控制pluse就可以控制占空比***
	TIM_OCInitStructure.TIM_Pulse = (arr - 1) * ch2_duty / 100;
	//TIM_OC3PreloadConfig(TIM1, TIM_OCPreload_Enable);//預(yù)裝載使能位無所謂,不影響
	TIM_OC3Init( TIM1, &TIM_OCInitStructure);
	
	//***高級(jí)定時(shí)器必須有這一句,而通用就不必了***
	TIM_CtrlPWMOutputs(TIM1, ENABLE);//使能PWM輸出 
	TIM_Cmd(TIM1, ENABLE); //使能 TIM1
}


PWMMode_Advance.h

#ifndef _PWMMODE_ADVANCE_H
#define _PWMMODE_ADVANCE_H

#include "config.h"

void TIM1_PWMInit(u32 freq, u8 ch1_duty, u8 ch2_duty);


#endif


4、高級(jí)定時(shí)器PWM模式輸出需要注意的地方

①、TIM1是高級(jí)定時(shí)器,它是掛載到APB2總線上的.

②、根據(jù)TIM的四個(gè)捕獲比較通道位置:PA8/PA9/PA10/PA11。再結(jié)合實(shí)際電路,確定了選擇CH2-PA9和CH3-PA10作為PWM輸出,但是此時(shí)要注意,拔掉對(duì)應(yīng)的跳線帽。

③、對(duì)應(yīng)的通道初始化應(yīng)為TIM_OC2InitTIM_OC3Init,即對(duì)應(yīng)的通道2和通道3。

④、高級(jí)定時(shí)器必須加這一句TIM_CtrlPWMOutputs(TIM1, ENABLE);//使能PWM輸出

⑤、對(duì)應(yīng)的邏輯分析儀波形

二、通用定時(shí)器輸出比較產(chǎn)生PWM

輸出比較的特點(diǎn):不同通道產(chǎn)生不同頻率不同占空比的方波

理解輸出比較的一張重要圖。

特別感受一種疊加的概念!總的計(jì)數(shù)值是0~0xFFFF(通用定時(shí)器是16位嘛),溢出重新從0開始,再往上加。而Pluse是我們的周期,也就是產(chǎn)生的波形頻率,這個(gè)Pluse并不是對(duì)應(yīng)計(jì)數(shù)器CNT的絕對(duì)范圍,而是相對(duì)CNT的相對(duì)范圍。就是Pluse加到設(shè)定值了,不管此刻對(duì)應(yīng)的CNT是多少,我繼續(xù)從當(dāng)前CNT再計(jì)我的頻率數(shù)。而占空占空比的是其中的Duty,上面這個(gè)示意圖了解了,也就不難理解整個(gè)過程了。

小于Duty為高,大于Duty小于Pluse為低。

工程代碼可見Github<傳送門>

1、主要代碼

main.c

/*******************************************************************************
* 文件名:main.c
* 描  述:
* 作  者:CLAY
* 版本號(hào):v1.0.0
* 日  期: 2019年1月26日
* 備  注:通用定時(shí)器的輸出比較 TIM4_CH1 - PB6    TIM4_CH2 - PB7
*         
*******************************************************************************
*/

#include "config.h"
#include "led.h"
#include "key.h"
#include "timer.h"
#include "beep.h"
#include "lcd.h"
#include "stdio.h"
#include "usart.h"
#include "i2c.h"
#include "eeprom.h"
#include "PWMMode.h"
#include "PWMMode_Advance.h"
#include "PWM_Compare.h"

int main(void)
{
	STM3210B_LCD_Init();
	LCD_Clear(Blue);
	LEDInit();
	KeyInit();
	BeepInit();
	TIM2Init(2000, 72);//定時(shí)2ms

	TIM3_PWMInit(2000, 40, 80);//頻率2K CH1占空比40% CH2占空比80%
	TIM1_PWMInit(2000, 40, 80);//頻率2K CH2占空比40% CH3占空比80%
	TIM4_PWMCompare(2000, 1000, 40, 80);//CH1占空比2K 40% CH2 1K占空比80%
	
	while(1)
	{	
		KeyDriver();
	}
}

void KeyAction(int code)
{
	if(code == 1)//按下B1,切換燈狀態(tài),蜂鳴器鳴叫0.1s
	{
		GPIOC->ODR ^= (1<<8);//PC8不斷取反
		GPIOD->ODR |= (1<<2);//PD2置1,使能573鎖存器
		GPIOD->ODR &= ~(1<<2);//PD2清0,關(guān)閉573鎖存器
		Beep(100);
	}
	else if(code == 2)
	{
		Beep(-1);
	}
	else if(code == 3)
	{
		Beep(0);
	}
}



PWM_Compare.c

#include "PWM_Compare.h"

void TIM4_IOInit(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	
	
	//***注意這里是APB2***
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //使能 GPIOB時(shí)鐘
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7; //TIM4通道1-PB6 TIM4通道2-PB7
	//***復(fù)用推挽輸出(PWM模式)***
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; 
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure); //初始化 GPIO
}

void NVIC_TIM4Enable(void)
{
    NVIC_InitTypeDef NVIC_initstructure;

    NVIC_initstructure.NVIC_IRQChannel = TIM4_IRQn;           //選擇TIM4中斷通道
    NVIC_initstructure.NVIC_IRQChannelCmd = ENABLE;           //使能中斷通道
    NVIC_initstructure.NVIC_IRQChannelPreemptionPriority = 0; //設(shè)定搶占優(yōu)先級(jí)為0
    NVIC_initstructure.NVIC_IRQChannelSubPriority = 0;        //設(shè)定響應(yīng)優(yōu)先級(jí)為0
    NVIC_Init(&NVIC_initstructure);
}

void TIM4Init(void)
{
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
	
	//***注意這里是APB1***
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);  //使能定時(shí)器4時(shí)鐘 
	//***注意這里設(shè)置的是0xFFFF
	TIM_TimeBaseStructure.TIM_Period = 0xFFFF; //設(shè)置計(jì)數(shù)值最大
	TIM_TimeBaseStructure.TIM_Prescaler = 72-1; //設(shè)置預(yù)分頻值
	TIM_TimeBaseStructure.TIM_ClockDivision = 0; //設(shè)置時(shí)鐘分割:TDTS = Tck_tim
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM 向上計(jì)數(shù)模式
	TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure); //初始化 TIM4
	//***別忘了設(shè)置這個(gè)***
	NVIC_TIM4Enable();
}

u32 CH1_Val, CH2_Val, CH1_Duty, CH2_Duty;

void TIM4_PWMCompare(u32 ch1_freq, u32 ch2_freq, u32 ch1_duty, u32 ch2_duty)
{
//	u32 CH1_Val,  CH2_Val;//FUCK!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
	
	TIM_OCInitTypeDef TIM_OCInitStructure;

	CH1_Val = 1000000 / ch1_freq;
	CH2_Val = 1000000 / ch2_freq;
	CH1_Duty = CH1_Val * ch1_duty / 100;
	CH2_Duty = CH2_Val * ch2_duty / 100;
	
	TIM4_IOInit();//TIM4通道1-PB6 TIM4通道2-PB7配置
	TIM4Init();//TIM4定時(shí)器配置
	
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Toggle;//觸發(fā)模式
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;//輸出極性高
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
	TIM_OCInitStructure.TIM_Pulse = CH1_Val;
	TIM_OC1PreloadConfig(TIM4, TIM_OCPreload_Disable);預(yù)裝載使能位失能
	TIM_OC1Init( TIM4, &TIM_OCInitStructure);
			
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Toggle;//觸發(fā)模式
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;//輸出極性高
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//比較輸出使能
	TIM_OCInitStructure.TIM_Pulse = CH2_Val;
	TIM_OC2PreloadConfig(TIM4, TIM_OCPreload_Disable);//預(yù)裝載使能位失能
	TIM_OC2Init( TIM4, &TIM_OCInitStructure);
	
	TIM_SetCounter(TIM4, 0);//定時(shí)器計(jì)數(shù)值清0
	TIM_SetCompare1(TIM4, 0);//定時(shí)器捕獲比較1寄存器值清0
	TIM_SetCompare2(TIM4, 0);//定時(shí)器捕獲比較2寄存器值清0
	
	TIM_ClearITPendingBit(TIM4, TIM_IT_CC1|TIM_IT_CC2);//清除中斷標(biāo)志位 
	TIM_ITConfig(TIM4, TIM_IT_CC1|TIM_IT_CC2, ENABLE);//使能通道比較中斷
	TIM_Cmd(TIM4, ENABLE); //使能 TIM4
}

PWM_Compare.h

#ifndef _PWM_COMPARE_H
#define _PWM_COMPARE_H

#include "config.h"

extern u32 CH1_Val, CH2_Val, CH1_Duty, CH2_Duty;

void TIM4_PWMCompare(u32 ch1_freq, u32 ch2_freq, u32 ch1_duty, u32 ch2_duty);

#endif

2、需要注意的地方

①、查閱數(shù)據(jù)手冊(cè)可知,TIM4的四個(gè)輸出比較通道在PB6/PB7/PB8/PB9,而結(jié)合實(shí)際電路PB6/PB7是接在EEPROM的,而PB8/PB9是用作LCD,LCD顯然使用的較多,我們選擇了犧牲I2C,即TIM3_CH1 - PB6和 TIM3_CH2 - PB7...

②、注意細(xì)節(jié),局部變量和全局變量~~

③、配置好定時(shí)器后別忘了,中斷向量的配置

在這里插入圖片描述

④、關(guān)于TIM_OC1PreloadConfig

前面也有提及如使能了該位,寫入到TIMx_CCRx寄存器的比較值將在更新事件到來時(shí)才會(huì)傳入到當(dāng)前捕獲/比較寄存器,否則未使能,比較值將立即寫入當(dāng)前捕獲比較寄存器

輸出比較模式,當(dāng)然是立即生效了,所以這里TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Disable);為Disable或者不寫。

⑤、TIM_ClearITPendingBit對(duì)輸出極性影響

固件庫(kù)定時(shí)器初始化函數(shù)默認(rèn)會(huì)產(chǎn)生更新事件并觸發(fā)更新事件中斷標(biāo)志位,如果此時(shí)中斷使能,程序會(huì)立即執(zhí)行中斷函數(shù)。

知道了這個(gè)先決條件,再結(jié)合程序就不難理解了,一起來分析分析吧。

當(dāng)有TIM_ClearITPendingBit并且設(shè)置輸出極性為TIM_OCPolarity_High的情況下,設(shè)置2K頻率40%占空比和1K頻率80%占空比的波形如下所示。

2k 40%

1k 80%

契合程序的要求,但是如果現(xiàn)在還是輸出進(jìn)行為TIM_OCPolarity_High沒有了清除中斷標(biāo)志位這一操作。對(duì)應(yīng)的波形又是什么樣子呢?

2K 60%

1K 20%

剛好反過來了,為什么呢?說了半天還在賣關(guān)子,別介咱不是在分析問題么,問題現(xiàn)象出來了,再結(jié)合程序繼續(xù)來看看

定時(shí)器4的中斷源是輸出比較,也就是說計(jì)數(shù)器一直在和輸出比較寄存器的數(shù)進(jìn)行比較,一旦相等就要進(jìn)入中斷。

初始的時(shí)候是計(jì)數(shù)器為0,假如現(xiàn)在初始的時(shí)候清除了中斷標(biāo)志位,一開始計(jì)數(shù)器為0,比較寄存器也是0,相等要進(jìn)入中斷,設(shè)置高電平時(shí)間持續(xù)時(shí)間t1=當(dāng)前比較值(0)+duty,持續(xù)時(shí)間完畢后,計(jì)數(shù)器又和比較器相等,再進(jìn)入中斷,設(shè)置低電平持續(xù)時(shí)間t2 = 當(dāng)前比較值+(pulse-duty)

由于沒有使能預(yù)裝載位,故在中斷里一旦賦值,直接寫入寄存器中。

直到再進(jìn)中斷,即完成了一個(gè)周期的方波輸出,整個(gè)方波是先高后低(設(shè)置TIM_OCPolarity_High的前提下),接著再賦值t3=當(dāng)前比較值+duty,就這樣周而復(fù)始的循環(huán)....便產(chǎn)生了符合我們要求的方波信號(hào)。

說到這就不難立即為什么沒有清除中斷標(biāo)志位就會(huì)剛好相反了,沒有清除中斷標(biāo)志位一上來就直接進(jìn)入中斷(前面說了這是庫(kù)函數(shù)決定了),然后瞬間又發(fā)現(xiàn)計(jì)數(shù)器和比較值一樣,再進(jìn)一次中斷。整個(gè)過程當(dāng)前比較值幾乎沒有更新還是0(整個(gè)過程想成很短的時(shí)間?),相當(dāng)于直接設(shè)置了低電平輸出duty時(shí)間,所以我們看到的波形剛好相反了。

哎呀,想不好想,解釋起來更麻煩,感覺還沒有解釋好,就先這樣吧,如果真有人看到了,有問題再留言交流吧。


聲明:本內(nèi)容為作者獨(dú)立觀點(diǎn),不代表電子星球立場(chǎng)。未經(jīng)允許不得轉(zhuǎn)載。授權(quán)事宜與稿件投訴,請(qǐng)聯(lián)系:editor@netbroad.com
覺得內(nèi)容不錯(cuò)的朋友,別忘了一鍵三連哦!
贊 150
收藏 151
關(guān)注 431
成為作者 賺取收益
全部留言
0/200
  • dy-i2UfRuvP 2021-05-19 13:17
    請(qǐng)教一下
    回復(fù)
  • dy-iipPZRPN 2021-05-13 22:39
    對(duì)我很有幫助
    回復(fù)
  • dy-3EbVR6Ei 2021-05-13 22:27
    感謝分享
    回復(fù)
  • dy-Xq2JxpfN 2021-05-13 22:13
    學(xué)習(xí)了
    回復(fù)
  • dy-9g42stbW 2021-05-13 21:55
    期待繼續(xù)
    回復(fù)
  • dy-mLj7kl5v 2021-05-13 20:31
    圍觀學(xué)習(xí)
    回復(fù)
  • dy-apcih3c1 2021-05-13 20:12
    感謝分享
    回復(fù)
  • dy-k78ZHtFD 2021-05-13 20:02
    比論文強(qiáng)一萬倍
    回復(fù)
  • dy-nAWdnPGS 2021-05-13 18:50
    學(xué)習(xí)了
    回復(fù)
  • dy-prSX6RBY 2021-05-13 18:38
    比論文強(qiáng)一萬倍
    回復(fù)
  • dy-jqGVYqsF 2021-05-13 16:06
    對(duì)我很有幫助
    回復(fù)
  • dy-VIQ9auhf 2021-05-13 14:54
    比論文強(qiáng)一萬倍
    回復(fù)
  • dy-7mura2gg 2021-05-13 14:44
    期待繼續(xù)
    回復(fù)
  • dy-YN3DYTeH 2021-05-13 14:34
    請(qǐng)教一下
    回復(fù)
  • dy-9hjGevyn 2021-05-13 13:33
    思路清晰,受益匪淺
    回復(fù)
  • dy-H1WY5jXH 2021-05-13 13:17
    對(duì)我很有幫助
    回復(fù)
  • dy-wVQjSHHX 2021-05-13 12:59
    不亞于看了一篇高質(zhì)量論文
    回復(fù)
  • dy-88VlYaFf 2021-05-12 15:35
    講的真好!
    回復(fù)
  • dy-9QTV6UZW 2021-05-12 15:23
    感謝分享
    回復(fù)
  • dy-WYS5BCmB 2021-05-12 15:10
    感謝分享
    回復(fù)
主站蜘蛛池模板: 台前县| 凤阳县| 永丰县| 乌鲁木齐市| 梁河县| 景德镇市| 治多县| 涞源县| 封丘县| 沈阳市| 堆龙德庆县| 石台县| 边坝县| 阿拉善左旗| 藁城市| 招远市| 濮阳县| 陵水| 墨玉县| 育儿| 景德镇市| 凌源市| 吐鲁番市| 四平市| 民丰县| 安化县| 临猗县| 沐川县| 准格尔旗| 丹凤县| 木兰县| 萨嘎县| 江都市| 孟津县| 永修县| 莲花县| 夏津县| 乐东| 汽车| 和静县| 临澧县|