脉冲宽度调制pdm_STM32第七章-脉冲宽度调制
先說在開頭啊,我們學(xué)習(xí)定時(shí)器總感覺它是很難的,這里我就不說他的編程難度,而是對(duì)于它的理解難度。學(xué)習(xí)定時(shí)器你就必須了解他的來龍去脈。
比如說你現(xiàn)在要使用一個(gè)定時(shí)器,那么先要決定你要用哪一個(gè)定時(shí)器,是高級(jí)定時(shí)器還是通用定時(shí)器呢?假如你要用高級(jí)定時(shí)器(TIM1 、TIM8),那他和通用定時(shí)器有啥區(qū)別呢?在程序中我們?nèi)绾蝸眢w現(xiàn)他們的區(qū)別呢?第二個(gè)你要關(guān)心的就是你使用的定時(shí)器是多少位的,一般有16位和32位區(qū)分。比如TIM1就是16位,那么他的最大計(jì)數(shù)個(gè)數(shù)就是2^16=65536-1, 也就是說你的TIM_TimeBaseStructure.TIM_Period = X ;其中X最大值為65535,你不能高于它。但是如果你使用TIM2就是32位,那么他的最大計(jì)數(shù)個(gè)數(shù)就是2^32=4294967296-1,也就是說你的TIM_TimeBaseStructure.TIM_Period = X ;其中X最大值為4294967295,你不能高于它。 第三就是你要清楚你使用的這個(gè)定時(shí)器的時(shí)鐘來源是哪里,一般來說我們高級(jí)定時(shí)器(TIM1、TIM8)的時(shí)鐘來源是來自AHB2,你可以這樣記:高級(jí)定時(shí)器的時(shí)鐘頻率肯定高于通用定時(shí)器的時(shí)鐘頻率對(duì)吧,又因?yàn)?>1,所以高級(jí)定時(shí)器的時(shí)鐘來源是來自AHB2對(duì)吧,那么通用定時(shí)器的時(shí)鐘源就來自AHB1了對(duì)吧。
在這里還要注意的是STM32中除非APB1的時(shí)鐘分頻數(shù)設(shè)置為1,否則通用定時(shí)器TIMx的時(shí)鐘是 APB1時(shí)鐘的2倍,當(dāng) APB1 的時(shí)鐘不分頻的時(shí)候,通用定時(shí)器 TIMx 的時(shí)鐘就等于APB1 的時(shí)鐘。這也就解釋了下面我使用TIM3是通用定時(shí)器,掛載在 APB1上,而 APB1是36MHz,通用定時(shí)器TIMx的時(shí)鐘是 APB1時(shí)鐘的2倍,所以TIM3的定時(shí)器是72MHZ 計(jì)算。只有把這些該清楚了才能續(xù)的下去,當(dāng)然遠(yuǎn)不止這一下。
上一章我們說到了定時(shí)器,這一章稱熱打鐵熱說一說脈沖寬度調(diào)制-PWM。 脈沖寬度調(diào)制(PWM),是英文“Pulse Width Modulation”的縮寫,簡(jiǎn)稱脈寬調(diào)制,是利用微處理器的數(shù)字輸出來對(duì)模擬電路進(jìn)行控制的一種非常有效的技術(shù)。簡(jiǎn)單一點(diǎn),就是對(duì)脈沖寬度進(jìn)行控制。
看到這個(gè)圖,我先想聰明的你馬上會(huì)想到,這個(gè)玩意一定有兩個(gè)寄存器ARR和CRRx,而這兩個(gè)值一定是需要自己設(shè)置的,圖上都標(biāo)出來了,對(duì)吧。 我們假定定時(shí)器工作在向上計(jì)數(shù) PWM模式,且當(dāng) CNT<CCRx 時(shí),輸出 0,當(dāng) CNT>=CCRx 時(shí)輸出 1。那么就可以得到如上的 PWM示意圖:
- 當(dāng) CNT 值小于 CCRx 的時(shí)候,IO 輸出低電平(0),
- 當(dāng) CNT 值大于等于 CCRx 的時(shí)候,IO 輸出高電平(1),
- 當(dāng) CNT 達(dá)到 ARR 值的時(shí)候,重新歸零,然后重新向上計(jì)數(shù),依次循環(huán)。 改變 CCRx 的值,就可以改變 PWM 輸出的占空比,改變 ARR 的值,就可以改變 PWM 輸出的頻率,這就是 PWM 輸出的原理。所以說對(duì)于PWM我們只要在程序中修改這兩個(gè)值就可以了,其他的都一樣。
STM32F429 的定時(shí)器除了 TIM6 和 7。其他的定時(shí)器都可以用來產(chǎn)生 PWM 輸出。 直接開搞,來看一下定時(shí)器的分類,這是F4的定時(shí)器分配圖
這里還要知道一個(gè)概念就是通道:
通道是什么,我們換個(gè)說法,通道=路=引腳,這樣是不是好理解一點(diǎn),也就是說TIM2有4路定時(shí)器。TIM5也有4路,TIM3也有4路,TIM4也有4路。為什么要這么多路呢? 比如我們要產(chǎn)生8路周期,占空比都不同的PWM信號(hào)輸出,那我們可以選TIM2的 CH1/CH2/CH3/CH4 還有TIM3 的CH1,CH2,CH3,CH4 這8路進(jìn)行輸出,需要這么多路,就是為了可以輸出/輸入 更多的信號(hào)。比如你用小舵機(jī)做一個(gè)小機(jī)器人就需要很多的定時(shí)器對(duì)應(yīng)很多的通道也就是對(duì)應(yīng)很多引腳。輸出的信號(hào)分別是哪些管腳呢。很明顯對(duì)F4來說就是 TIM2的 CH1/CH2/CH3/CH4 對(duì)應(yīng) PA5 /PA1/PA2/PA3 這4個(gè)管腳。 TIM5的 CH1/CH2/CH3/CH4 對(duì)應(yīng) PH10/PH11/PH12/PIO 這4個(gè)管腳。
要使 STM32F429 的通用定時(shí)器 TIMx 產(chǎn)生 PWM 輸出,除了上一章介紹的寄存器外,我們還會(huì)用到4個(gè)寄存器,來控制 PWM 的。這三個(gè)寄存器分別是: 捕獲/比較模式寄存器(TIMx_CCMR1/2) 捕獲/比較使能寄存器(TIMx_CCER) 捕獲/比較寄存器(TIMx_CCR1~4) 剎車和死區(qū)寄存器(TIMx_BDTR)這個(gè)寄存器一般在高級(jí)定時(shí)器中使用,就是TIM1和TIM8。如果你沒用到這兩個(gè)定時(shí)器就不要管這個(gè)寄存器了。脈沖寬度調(diào)制模式可以生成一個(gè)信號(hào),該信號(hào)頻率由 TIMx_ARR 寄存器值決定,其占空比則由 TIMx_CCRx 寄存器值決定。
寄存器講解
捕獲/比較模式寄存器(TIMx_CCMR1/2)
該寄存器一般有 2 個(gè):TIMx _CCMR1和 TIMx _CCMR2。TIMx_CCMR1 控制 CH1 和CH2,而 TIMx_CCMR2 控制 CH3 和 CH4
這個(gè)寄存器我們關(guān)心的是 位14 13 12 和 位 9 8,其他的默認(rèn)就可以了。 模式設(shè)置位 OC4M,此部分由 3位組成??偣部梢耘渲贸?7 種模式,我們使用的是 PWM 模式,所以這 3 位必須設(shè)置為 110/111。這兩種 PWM 模式的區(qū)別就是輸出電平的極性相反。另外 CC4S 用于設(shè)置通道的方向(輸入/輸出)默認(rèn)設(shè)置為00,就是設(shè)置通道作為輸出使用。
捕獲/比較使能寄存器(TIM3_CCER)
使能寄存器見名知意,當(dāng)然是使能TIM3定時(shí)器的啊。使CC4E置位為1就可以了。
捕獲/比較寄存器(TIMx_CCR1~4)
該寄存器總共有 4 個(gè),對(duì)應(yīng) 4 個(gè)通道 CH1~4。我們使用的是通道3。在輸出模式下,該寄存器的值與 CNT 的值比較,根據(jù)比較結(jié)果產(chǎn)生相應(yīng)動(dòng)作。利用這點(diǎn),我們通過修改這個(gè)寄存器的值,就可以控制 PWM 的輸出脈寬了。
程序代碼配置
我們文本的例子是定時(shí)器3的通道3,對(duì)應(yīng)PB0管腳。
1.開啟TIM3時(shí)鐘,配置 PB0
要使用 TIM3,我們必須先開啟 TIM3的時(shí)鐘,這點(diǎn)相信大家看了這么多代碼,應(yīng)該明白了。這里我們還要配置 PB0 為復(fù)用輸出(當(dāng)然還要時(shí)能 GPIOB的時(shí)鐘),這是因?yàn)?TIM3_CH3通道將使用 PB0的復(fù)用功能作為輸出,我們配置 PB0為復(fù)用輸出,才可以實(shí)現(xiàn) TIM3_CH3的 PWM 經(jīng)過 PB0輸出。
GPIO_InitTypeDef GPIO_InitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //使能TIM外設(shè)時(shí)鐘 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB , ENABLE); //使能GPIO外設(shè)時(shí)鐘 //設(shè)置該引腳為復(fù)用輸出功能,輸出TIM3 CH3的PWM脈沖波形 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //TIM3_CH3 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //復(fù)用推挽輸出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure);2.設(shè)置 TIM3的ARR和PSC
在開啟了 TIM3的時(shí)鐘之后,我們要設(shè)置 ARR 和 PSC 兩個(gè)寄存器的值來控制輸出 PWM 的周期。這在庫函數(shù)是通過 TIM_TimeBaseInit 函數(shù)實(shí)現(xiàn)的,在上一節(jié)定時(shí)器中斷章節(jié)已經(jīng)有講解過,這里就不詳細(xì)講解,調(diào)用的格式為:
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_TimeBaseStructure.TIM_Period = 100; TIM_TimeBaseStructure.TIM_Prescaler =360-1; 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); //根據(jù)TIM_TimeBaseInitStruct中指定的參數(shù)初始化TIMx的時(shí)間基數(shù)單位對(duì)于上面的參數(shù)解釋一下: ①頻率:我們使用的APB1時(shí)鐘源是72MHz的,在此我們不做分頻,通過配置相關(guān)的參數(shù)來設(shè)置輸入頻率,計(jì)算方法:輸入頻率=APB1時(shí)鐘/(預(yù)分頻系數(shù)+1)=72 000 000Hz/360=200 000Hz =200KHZ。 ②TIM_TImeBaseStructure.TIM_Period參數(shù)決定了輸出PWM波形的頻率,輸出PWM波形的頻率=定時(shí)器的輸入頻率/TIM_TImeBaseStructure.TIM_Period,這里我們?cè)O(shè)置設(shè)置的周期為200 000Hz/100=2000Hz,即0.5ms一個(gè)周期。 如果你想修改你的輸出PWM波形的頻率按我上面自己配置即可。
3.設(shè)置TIM3_CH3的PWM模式及通道方向, 使能 TIM3的CH3輸出
接下來,我們要設(shè)置 TIM3_CH3為 PWM 模式,我們要通過配置 TIM3_CCMR2的相關(guān)位來控制 TIM3_CH3 的模式。在庫函數(shù)中,PWM 通道設(shè)置是通過函數(shù) TIM_OC1Init()~TIM_OC4Init()來設(shè)置的,不同的通道的設(shè)置函數(shù)不一樣,這里我們使用的是通道 3,所以使用的函數(shù)是 TIM_OC3Init()。這里的結(jié)構(gòu)體我就不多少了,自己看一下就可以明白,對(duì)于普通定時(shí)器我們只需要設(shè)置下面這四個(gè)參數(shù)就可以了。
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //選擇定時(shí)器模式:TIM脈沖寬度調(diào)制模式2 TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比較輸出使能 TIM_OCInitStructure.TIM_Pulse = 500; TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //輸出極性:TIM輸出比較極性高 TIM_OC3Init(TIM3, &TIM_OCInitStructure); //根據(jù)TIM_OCInitStruct中指定的參數(shù)初始化外設(shè)TIMx③配置占空比:占空比=配置占空比的值/ TIM_TImeBaseStructure.TIM_Period,這里的占空比為50/100=50% 。50%的占空比那么波形也一定是一半高一半低對(duì)吧,一會(huì)我們仿真看一看。
4使能TIM3
所有的都配置完了,最后能一下TIM3。
TIM_Cmd(TIM3, ENABLE);//使能TIM35.使能基本定時(shí)器3的預(yù)裝載值。
使能TIM3在CCR3上的預(yù)裝載寄存器
TIM_OC3PreloadConfig(TIM3, TIM_OCPreload_Enable); 使能TIM3在CCR3上的預(yù)裝載寄存器,即TIM3_CCR3的預(yù)裝載值在更新事件到來時(shí)才能被傳送至當(dāng)前寄存器中。 TIM_ARRPreloadConfig(TIM3, ENABLE); //使能TIM3在ARR上的預(yù)裝載寄存器 (影子寄存器)這里我們來講一下影子寄存器: 1.有影子寄存器的有3個(gè):分頻寄存器PSC,自動(dòng)重裝載寄存器 ARR,自動(dòng)捕獲CCRx(x是對(duì)應(yīng)的通道),注意,PSC,ARR,CCRx不是影子寄存器,而是它們對(duì)應(yīng)的“預(yù)裝載寄存器”; 2、影子寄存器才是真正起作用的寄存器,但是ST沒有提供這個(gè)寄存器出來,只是提供出與之相對(duì)應(yīng)的預(yù)裝載寄存器,分別為“PSC,ARR,CCRx” 3、我們用戶能接觸到,能修改或讀取的都是預(yù)裝載寄存器,ST只是把它們開放出來(影子寄存器并沒有開放給用戶),其實(shí)就是ARR寄存器,如:TIM3->ARR 4、從預(yù)裝載寄存器ARR傳送到影子寄存器,有兩種方式,一種是立刻更新,一種是等觸發(fā)事件之后更新;這兩種方式主要取決于寄存器TIMx->CR1中的“APRE”位;
- APRE=0,當(dāng)ARR值被修改時(shí),同時(shí)馬上更新影子寄存器的值;
- APRE=1,當(dāng)ARR值被修改時(shí),必須在下一次事件發(fā)生后才能更新影子寄存器的值; 5、怎么樣馬上立刻更改影子寄存器的值,而不是下一個(gè)事件;方法如下:
- 將ARPE=0,TIM_ARRPreloadConfig(TIM3, DISABLE );
- 在ARPE=1,TIM_ARRPreloadConfig(TIM3, ENABLE);
TIM_ARRPreloadConfig設(shè)置為DISABLE 和ENABLE的問題,他的作用只是允許或禁止在定時(shí)器工作時(shí)向ARR的緩沖器中寫入新值,以便在更新事件發(fā)生時(shí)載入覆蓋以前的值。在開始初始化的時(shí)候你已經(jīng)把" TIM_TimeBaseStructure.TIM_Period=100; //ARR的值 ",后來也一直是這個(gè)值,原因是你沒有編寫中斷服務(wù)函數(shù)或者你在中斷服務(wù)函數(shù)中根本就沒有給ARR緩沖器重新寫入新值,所以設(shè)置為DISABLE 和ENABLE都沒有影響,但是最保險(xiǎn)的方法就是是能一下。
匯總一下代碼:
void TIM3_PWM_Init() { GPIO_InitTypeDef GPIO_InitStructure;TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;TIM_OCInitTypeDef TIM_OCInitStructure;RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //使能TIM時(shí)鐘 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB , ENABLE);//使能GPIO外設(shè)時(shí)鐘 //設(shè)置該引腳為復(fù)用輸出功能,輸出TIM3 CH3的PWM脈沖波形GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //TIM3_CH3GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //復(fù)用推挽輸出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStructure); TIM_TimeBaseStructure.TIM_Period = 100; //輸出PWM波形的頻率=定時(shí)器的輸入頻率/TIM_TImeBaseStructure.TIM_Period,200 000Hz/100=2000Hz,即0.5ms一個(gè)周期 TIM_TimeBaseStructure.TIM_Prescaler =360-1;//不分頻 輸入頻率=APB1時(shí)鐘/(預(yù)分頻系數(shù)+1)=72 000 000Hz/360=200 000Hz =200K TIM_TimeBaseStructure.TIM_ClockDivision = 0; //設(shè)置時(shí)鐘分割:TDTS = Tck_timTIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上計(jì)數(shù)模式TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //選擇定時(shí)器模式:TIM脈沖寬度調(diào)制模式2TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比較輸出使能TIM_OCInitStructure.TIM_Pulse = 50; //占空比=配置占空比的值/TIM_TImeBaseStructure.TIM_Period,500/1000=50% TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //輸出極性:TIM輸出比較極性高TIM_OC3Init(TIM3, &TIM_OCInitStructure); TIM_OC3PreloadConfig(TIM3, TIM_OCPreload_Enable); //CH3預(yù)裝載使能 TIM_ARRPreloadConfig(TIM3, ENABLE); //使能TIM3在ARR上的預(yù)裝載寄存器 (影子寄存器) TIM_Cmd(TIM3, ENABLE); //使能TIM3 }6.主函數(shù)的編寫
主函數(shù)就很簡(jiǎn)單,一個(gè)while函數(shù)就可以解決。
int main(void){ SystemInit (); TIM3_PWM_Init();while(1){} }根據(jù)而上一章講到的方法keil中調(diào)試一下,可以清楚地看到周期是0.5ms,跟我們上面設(shè)置的一樣。占空比也是50%,就是1/2。
當(dāng)然我們這里設(shè)置的PWM波是死的,也就是說是固定的50%。那么這實(shí)際項(xiàng)目中我們一般是要求可變的PWM,最典型的就是控制電機(jī)的轉(zhuǎn)速。舉一個(gè)例子,下面是電機(jī)的驅(qū)動(dòng)芯片就是TB6612的管腳分配圖。
TB6612引腳分配: VM PWMA--------->TIM3_CH3(PBO) VCC AIN2--------->GPIOB_12 GND AIN1--------->GPIOB_13 AO1 STBY--------->GPIOB_14 AO2 BIN1--------->GPIOB_15 BO2 BIN2--------->GPIOA_12 BO1 PWMB--------->TIM3_CH4(PB1)在這里我們用GPIOB_12和GPIOB_13的電平高低來控制電機(jī)的前進(jìn)后退,具體的電平高低要看真值表。用TIM3_CH3(PB0)來控制電機(jī)的轉(zhuǎn)速。設(shè)置不同的值,電機(jī)的轉(zhuǎn)速就是有快有慢。那么用哪一個(gè)函數(shù)來控制呢?
void TIM_SetCompare1(TIM_TypeDef* TIMx, uint16_t Compare1);理所當(dāng)然,對(duì)于其他通道,分別有一個(gè)函數(shù)名字,函數(shù)格式為 TIM_SetComparex(x=1,2,3,4)。現(xiàn)在我們就可以控制 TIM3 的 CH3 輸出 PWM 波了。也就是一個(gè)輪子的轉(zhuǎn)速快慢了。這里我用一個(gè)小小的if語句來使定時(shí)器3的通道3的值發(fā)生變化。
int main(void){ u16 i=0; SystemInit (); TIM3_PWM_Init();while(1){i++;TIM_SetCompare3(TIM3,i); //定時(shí)器3的通道3 if(i==100) i=0;} }下面看一下效果:
可以明顯的看到PWM波在不斷地變化,那就對(duì)應(yīng)電機(jī)轉(zhuǎn)速的變化或者小燈的明暗程度。
至此我們就明白是STM32是如何輸出PWM的。這里我們來總結(jié)一下: 我們輸出PWM用到了定時(shí)器3,用TIM_Period 和TIM_Prescaler來確定輸出PWM的頻率和周期.用TIM_Pulse來確定占空比。 如果你單純的使用定時(shí)器3做定時(shí)功能那么TIM_Period 和TIM_Prescaler來確定需要定時(shí)的時(shí)間,也就是多長(zhǎng)時(shí)間進(jìn)入一次中斷服務(wù)函數(shù)執(zhí)行相應(yīng)的指令。只是在不同的地方叫法不同,本質(zhì)還是一樣的。 聰明的你會(huì)了嗎?
總結(jié)
以上是生活随笔為你收集整理的脉冲宽度调制pdm_STM32第七章-脉冲宽度调制的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: yU盘怎么用 如何使用U盘
- 下一篇: 国网待遇怎么样 深入了解国网的薪资福利待