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