MCU微課堂
CKS32F4xx系列
MCU互補PWM
互補輸出簡介
互補輸出只能在高級控制定時器(TIM1和TIM8)上使用,可以輸出兩路互補信號,包括主輸出OCx和互補輸出OCxN?;诒容^輸出一節(jié)的內(nèi)容,OCx和OCxN都可以輸出一定頻率和占空比的PWM波形,且他們的極性是相反的,如圖1所示,OCxREF是參考信號,OCx輸出信號與參考信號相同,只是它的上升沿相對于參考信號的上升沿有一個延遲,OCxN輸出信號與參考信號相反,只是它的上升沿相對于參考信號的下降沿有一個延遲,這個延遲時間,我們是可以通過死區(qū)寄存器配置的,本節(jié)中我們可以設(shè)置為0。
圖1 帶死區(qū)插入的互補輸出
圖2捕獲比較通道的輸出階段
如圖3所示,因為互補輸出多用于PWM控制電機的項目中,所以緊急情況下的剎車控制是必不可少的,OSSR的含義是運行模式下的關(guān)閉狀態(tài)選擇,OSSI的含義是空閑模式下的關(guān)閉狀態(tài)選擇,MOE的含義是主輸出使能,一般的應(yīng)用模式為,當(dāng)短路輸入為有效狀態(tài),MOE又硬件異步清零,OSSI設(shè)置為0,禁止OCOCN輸出,OSI1OSI1N設(shè)置為0,OC1OC1N輸出為0,達到緊急剎車的目的。
圖3 控制位和輸出狀態(tài)
配置步驟
互補輸出實際跟比較輸出章節(jié)一樣使用的是定時器的功能,所以相關(guān)的函數(shù)設(shè)置同樣在庫函數(shù)文件CKS32f4xx_tim.h和CKS32f4xx_tim.c文件中。 1)開啟TIM1和GPIO時鐘,配置PA7、PA8選擇復(fù)用功能GPIO_AF_TIM1輸出。 要使用TIM1,我們必須先開啟TIM1的時鐘,這點相信大家看了這么多代碼,應(yīng)該明白了。這里我們還要配置PA7、PA8為復(fù)用(GPIO_AF_TIM1)輸出,才可以實現(xiàn)TIM1_CH1的互補PWM經(jīng)過PA7、PA8輸出。庫函數(shù)使能TIM1時鐘的方法是:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE); //>>TIM1 時鐘使能這在前面章節(jié)已經(jīng)提到過。當(dāng)然,這里我們還要使能GPIOA的時鐘。然后我們要配置PA7引腳映射至GPIO_AF_TIM1,復(fù)用為定時器1,調(diào)用的函數(shù)為:
GPIO_PinAFConfig(GPIOA,GPIO_PinSource7,GPIO_AF_TIM1); //>>GPIOA7 復(fù)用為定時器1配置PA8引腳映射至GPIO_AF_TIM1,復(fù)用為定時器1,調(diào)用的函數(shù)為:
GPIO_PinAFConfig(GPIOA,GPIO_PinSource8,GPIO_AF_TIM1); //>>GPIOA8 復(fù)用為定時器1這個方法跟我們串口實驗講解一樣,調(diào)用的同一個函數(shù),最后設(shè)置PA7為復(fù)用功能輸出這里我們只列出GPIO初始化為復(fù)用功能的一行代碼:
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //>>復(fù)用功能這里還需要說明一下,對于定時器通道的引腳關(guān)系,大家可以查看CKS32F4對應(yīng)的數(shù)據(jù)手冊,比如我們PWM實驗,我們使用的是定時器1的通道1,對應(yīng)的引腳PA7可以從數(shù)據(jù)手冊表中查看:
?
?
2)初始化TIM1,設(shè)置TIM1的ARR和PSC等參數(shù)。 在開啟了TIM1的時鐘之后,我們要設(shè)置ARR和PSC兩個寄存器的值來控制輸出PWM的周期。這在庫函數(shù)是通過TIM_TimeBaseInit函數(shù)實現(xiàn)的,在上一節(jié)定時器中斷章節(jié)我們已經(jīng)有講解,這里就不詳細講解,調(diào)用的格式為:
?
TIM_TimeBaseStructure.TIM_Period = arr; //設(shè)置自動重裝載值 TIM_TimeBaseStructure.TIM_Prescaler =psc; //設(shè)置預(yù)分頻值 TIM_TimeBaseStructure.TIM_ClockDivision = 0; //設(shè)置時鐘分割:TDTS = Tck_tim TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上計數(shù)模式 TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure); //根據(jù)指定的參數(shù)初始化 TIMx3)設(shè)置TIM1_CH1的PWM模式,使能TIM1的CH1輸出。 設(shè)置TIM1_CH1為PWM模式(默認是凍結(jié)的)通過配置TIM1_CCMR1的相關(guān)位來控制TIM1_CH1的模式。在庫函數(shù)中,PWM通道設(shè)置是通過函數(shù)TIM_OC1Init()~TIM_OC4Init()來設(shè)置的,不同的通道的設(shè)置函數(shù)不一樣,這里我們使用的是通道1,所以使用的函數(shù)是TIM_OC1Init()。
Void TIM_OC1Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);這種初始化格式大家學(xué)到這里應(yīng)該也熟悉了,所以我們直接來看看結(jié)構(gòu)體TIM_OCInitTypeDef的定義:
typedef 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;這里我們講解一下與我們要求相關(guān)的幾個成員變量: 參數(shù)TIM_OCMode設(shè)置模式是PWM還是輸出比較,這里我們是PWM模式。 參數(shù)TIM_OutputStateOutputNState用來設(shè)置比較輸出使能,也就是使能PWM輸出到端口。參數(shù)TIM_OCPolarityOCNPolarity用來設(shè)置極性是高還是低。參數(shù)TIM_OCIdleState和TIM_OCNIdleState用來設(shè)置空閑時的輸出狀態(tài)。 要實現(xiàn)我們上面提到的場景,方法是:
TIM_OCInitTypeDef TIM_OCInitStructure; TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //>>選擇模式 PWM TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //>>比較輸出使能 TIM_OCInitStructure.TIM_OutputNState = TIM_OutputState_Enable; //>>比較輸出使能 TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCPolarity_High; //>>輸出極性高 TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; //>>輸出極性低 TIM_OCInitStructure. TIM_OCIdleState = TIM_OCNIdleState_Reset; //>>當(dāng)MOE=0重置輸出空閑狀態(tài) TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset; //>>當(dāng)MOE=0重置輸出空閑狀態(tài) TIM_OCInitStruct.TIM_Pulse=100;//待裝入捕獲比較寄存器的脈沖值 TIM_OC1Init(TIM1, &TIM_OCInitStructure); //>>根據(jù)指定的參數(shù)初始化外設(shè)TIM1 OC1 TIM_OC1PreloadConfig(TIM1,TIM_OCPreload_Enable); //使能TIM1在CCR上的預(yù)裝載寄存器4)使能 TIM1。 在完成以上設(shè)置了之后,我們不開啟剎車功能,并使能TIM1,使能TIM1的方法前面已經(jīng)講解過:
TIM_BDTRStructure.TIM_AutomaticOutput=TIM_AutomaticOutput_Enable;//自動輸出功能使能 TIM_BDTRStructure.TIM_Break=TIM_Break_Disable;//失能剎車輸入 TIM_BDTRStructure.TIM_BreakPolarity=TIM_BreakPolarity_High; //剎車輸入管腳極性高 TIM_BDTRStructure.TIM_DeadTime=0; //輸出打開和關(guān)閉狀態(tài)之間的延時 TIM_BDTRStructure.TIM_LOCKLevel=TIM_LOCKLevel_OFF;// 鎖電平參數(shù): 不鎖任何位 TIM_BDTRStructure.TIM_OSSIState=TIM_OSSIState_Disable; //設(shè)置在運行模式下非工作狀態(tài)選項 TIM_BDTRStructure.TIM_OSSRState=TIM_OSSRState_Disable; //設(shè)置在運行模式下非工作狀態(tài)選項 TIM_BDTRConfig(TIM1,&TIM_BDTRStructure); TIM_ARRPreloadConfig(TIM1,ENABLE); //使能TIM1在ARR上的預(yù)裝載寄存器 TIM_CtrlPWMOutputs(TIM1,ENABLE); //PWM使能主輸出MOE=1 TIM_Cmd(TIM1,ENABLE); //打開TIM15)修改TIM1_CCR1來控制占空比。 最后,在經(jīng)過以上設(shè)置之后,PWM其實已經(jīng)開始輸出了,只是其占空比和頻率都是固定的,而我們通過修改TIM1_CCR1則可以控制CH1的輸出占空比。在庫函數(shù)中,修改TIM1_CCR1占空比的函數(shù)是:
void TIM_SetCompare1(TIM_TypeDef* TIMx, uint16_t Compare2);理所當(dāng)然,對于其他通道,分別有一個函數(shù)名字,函數(shù)格式為:
TIM_SetComparex(x=1,2,3,4)
通過以上5個步驟,我們就可以控制TIM1的CH1輸出互補PWM波了。 3代碼示例 添加PWM配置文件pwm.c和pwm.h。 pwm.c源文件代碼如下:
//>>TIM1 PWM 部分初始化 //>>PWM 輸出初始化 //>>arr:自動重裝值 psc:時鐘預(yù)分頻數(shù) void TIM1_PWM_Init(u32 arr,u32 psc) { GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE);//TIM1 時鐘使能 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); //使能 PORTA 時鐘 GPIO_PinAFConfig(GPIOA,GPIO_PinSource7,GPIO_AF_TIM1); //PA7 復(fù)用為 TIM1 GPIO_PinAFConfig(GPIOA,GPIO_PinSource8,GPIO_AF_TIM1); //PA8 復(fù)用為 TIM1 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_8; //GPIOF9 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //復(fù)用功能 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; //速度 100MHz GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽復(fù)用輸出 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉 GPIO_Init(GPIOA,&GPIO_InitStructure); //初始化 PA7PA8 TIM_TimeBaseStructure.TIM_Prescaler=psc; //定時器分頻 TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上計數(shù)模式 TIM_TimeBaseStructure.TIM_Period=arr; //自動重裝載值 TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; TIM_TimeBaseInit(TIM1,&TIM_TimeBaseStructure);//初始化定時器 1 //初始化 TIM1 Channel1 互補PWM 模式 TIM_OCInitTypeDef TIM_OCInitStructure; TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //>>選擇模式 PWM TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //>>比較輸出使能 TIM_OCInitStructure.TIM_OutputNState = TIM_OutputState_Enable; //>>比較輸出使能 TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCPolarity_High; //>>輸出極性低 TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; //>>輸出極性低 TIM_OCInitStructure. TIM_OCIdleState = TIM_OCNIdleState_Reset; //>>當(dāng)MOE=0重置輸出空閑狀態(tài) TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset; //>>當(dāng)MOE=0重置輸出空閑狀態(tài) TIM_OC1Init(TIM1, &TIM_OCInitStructure); //>>根據(jù)指定的參數(shù)初始化外設(shè)TIM1 OC1 TIM_OC1PreloadConfig(TIM1,TIM_OCPreload_Enable); //使能TIM1在CCR上的預(yù)裝載寄存器 TIM_BDTRStructure.TIM_AutomaticOutput=TIM_AutomaticOutput_Enable;//自動輸出功能使能 TIM_BDTRStructure.TIM_Break=TIM_Break_Disable;//失能剎車輸入 TIM_BDTRStructure.TIM_BreakPolarity=TIM_BreakPolarity_High; //剎車輸入管腳極性高 TIM_BDTRStructure.TIM_DeadTime=0; //輸出打開和關(guān)閉狀態(tài)之間的延時 TIM_BDTRStructure.TIM_LOCKLevel=TIM_LOCKLevel_OFF;// 鎖電平參數(shù): 不鎖任何位 TIM_BDTRStructure.TIM_OSSIState=TIM_OSSIState_Disable; //設(shè)置在運行模式下非工作狀態(tài)選項 TIM_BDTRStructure.TIM_OSSRState=TIM_OSSRState_Disable; //設(shè)置在運行模式下非工作狀態(tài)選項 TIM_BDTRConfig(TIM1,&TIM_BDTRStructure); TIM_ARRPreloadConfig(TIM1,ENABLE); //使能TIM1在ARR上的預(yù)裝載寄存器 TIM_CtrlPWMOutputs(TIM1,ENABLE); //PWM使能主輸出MOE=1 TIM_Cmd(TIM1,ENABLE); //打開TIM1 TIM_SetCompare1(TIM1,300); //>>設(shè)置pwm的占空比為300/500 = 60% }此部分代碼包含了上面介紹的PWM輸出設(shè)置的前5個步驟。這里我們關(guān)于TIM1的設(shè)置就不再說了。接下來,我們看看主程序里面的main函數(shù)如下:
int main(void) { NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//>>設(shè)置系統(tǒng)中斷優(yōu)先級分組 2 delay_init(168); //>>初始化延時函數(shù) TIM1_PWM_Init(500-1,84-1); //>>定時器時鐘為 84M,分頻系數(shù)為 84,所以計數(shù)頻率 //>> 84M/84=1Mhz,重裝載值500,所以PWM頻率為1M/500=2Khz. while(1) { } }這里,我們先設(shè)置好了NVIC終端優(yōu)先級,然后初始化延時函數(shù)和timer,在timer的初始化參數(shù)中我們把PWM的頻率設(shè)置成2K,將占空比設(shè)置成60%,完成PWM輸出設(shè)置。
審核編輯:黃飛
評論
查看更多