用定時器生成PWM波
????PWM全稱是Pulse Width Modulation,通過控制高頻信號的占空比,眼睛當(dāng)成低通濾波器,可以控制亮暗。再循環(huán)更改pwm的閾值,就弄出了呼吸的效果。
????這里采用一個比較簡單的方法生成PWM波:設(shè)置定時器中斷然后根據(jù)閾值判斷置高和置低。
?
void TIM3_IRQHandler(void) { ????????TIM_ClearITPendingBit(TIM3,TIM_IT_Update);?? if(counter==255) counter = 0; else ????????????counter?+=1; if(mode == 0){ if(counter < pwm) GPIO_SetBits(GPIOA,GPIO_Pin_0|GPIO_Pin_1); else GPIO_ResetBits(GPIOA,GPIO_Pin_0|GPIO_Pin_1); ????????} if(mode == 1) { if(counter < pwm) GPIO_SetBits(GPIOA,GPIO_Pin_1|GPIO_Pin_2); else ????????????????GPIO_ResetBits(GPIOA,GPIO_Pin_1|GPIO_Pin_2);????? ????????}?? if(mode ==2){ if(counter < pwm) GPIO_SetBits(GPIOA,GPIO_Pin_2|GPIO_Pin_0); else GPIO_ResetBits(GPIOA,GPIO_Pin_2|GPIO_Pin_0); } }
?
程序流程
開啟外設(shè)時鐘(GPIO和TIM)
?
void RCC_Configuration(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC|RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4|RCC_APB1Periph_TIM3, ENABLE); }
?
配置GPIO
配置時鐘, 使能中斷(計數(shù)閾值,預(yù)分頻,時鐘分頻,計數(shù)模式)
?
void tim3() //配置TIM3為基本定時器模式 ,約10us觸發(fā)一次,觸發(fā)頻率約100kHz { TIM_TimeBaseInitTypeDef??TIM_TimeBaseStructure;???//定義格式為TIM_TimeBaseInitTypeDef的結(jié)構(gòu)體的名字為TIM_TimeBaseStructure?? TIM_TimeBaseStructure. TIM_Period =9; //配置計數(shù)閾值為9,超過時,自動清零,并觸發(fā)中斷 TIM_TimeBaseStructure.TIM_Prescaler?=71;?????//????時鐘預(yù)分頻值,除以多少 TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; // 時鐘分頻倍數(shù) TIM_TimeBaseStructure.TIM_CounterMode?=?TIM_CounterMode_Up;??//?計數(shù)方式為向上計數(shù) TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); // 初始化tim3 TIM_ClearITPendingBit(TIM3,TIM_IT_Update); //清除TIM3溢出中斷標(biāo)志 TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE); // 使能TIM3的溢出更新中斷 TIM_Cmd(TIM3,ENABLE); // 使能TIM3 }
?
配置中斷優(yōu)先級
?
void nvic() //配置中斷優(yōu)先級 { ?NVIC_InitTypeDef?NVIC_InitStructure;??//????//???命名一優(yōu)先級變量 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); // 將優(yōu)先級分組方式配置為group1,有2個搶占(打斷)優(yōu)先級,8個響應(yīng)優(yōu)先級 NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn; //該中斷為TIM4溢出更新中斷 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;//打斷優(yōu)先級為1,在該組中為較低的,0優(yōu)先級最高 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; // 響應(yīng)優(yōu)先級0,打斷優(yōu)先級一樣時,0最高 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // 設(shè)置使能 ?NVIC_Init(&NVIC_InitStructure);????????????????????????//??初始化 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); //要用同一個Group NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; //TIM3 溢出更新中斷 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;// 打斷優(yōu)先級為1,與上一個相同,不希望中斷相互打斷對方 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; // 響應(yīng)優(yōu)先級1,低于上一個,當(dāng)兩個中斷同時來時,上一個先執(zhí)行 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); }
?
寫中斷服務(wù)函數(shù)
代碼實現(xiàn)
????為了方便按鍵檢測,除了TIM3配置PWM波之外,TIM4用來檢測是否有輸入。由于使用開漏輸出,這里使用5V電源。
?
#include "stm32f10x.h" #include "math.h" #include?"stdio.h" u8 counter=0; int pwm=100; int flag=0; int mode =0; int velocity =0; int turning=1; void RCC_Configuration(void); //時鐘初始化,開啟外設(shè)時鐘 void GPIO_Configuration(void); //IO口初始化,配置其功能 void tim3(void); //定時器tim4初始化配置 void tim4(void); //定時器tim4初始化配置 void nvic(void); //中斷優(yōu)先級等配置 void exti(void); //外部中斷配置 void delay_nus(u32); //72M時鐘下,約延時us void delay_nms(u32); //72M時鐘下,約延時ms void breathing(int velocity){ switch(velocity){ case 0: if(flag) pwm +=1; if(pwm>240) flag=0; if(flag == 0){ pwm -=1; if(pwm<10) flag=1; } ????????????????????break; case 1: if(flag) pwm +=2; if(pwm>240) flag=0; if(flag == 0){ pwm -=2; if(pwm<10) flag=1; } ????????????????????break; case 2: if(flag) pwm +=3; if(pwm>240) flag=0; if(flag == 0){ pwm -=3; if(pwm<10) flag=1; } break; } } void assert_failed(uint8_t* file, uint32_t line) { printf("Wrong parameters value: file %s on line %d ", file, line); while(1); } void TIM4_IRQHandler(void) //TIM4的溢出更新中斷響應(yīng)函數(shù) ,讀取按鍵輸入值,根據(jù)輸入控制pwm波占空比 { u8 key_in1=0x01,key_in2=0x01; ????????TIM_ClearITPendingBit(TIM4,TIM_IT_Update);//?????清空TIM4溢出中斷響應(yīng)函數(shù)標(biāo)志位 key_in1= GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_12); // 讀PC12的狀態(tài) ????????key_in2=?GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_13);//?讀PC13的狀態(tài) ????????if(key_in1?&&?key_in2)?turning?=1; ????????breathing(velocity); if(key_in1==0 && turning){ turning =0; velocity = (velocity + 1) % 3; ????}//調(diào)速度 if(key_in2==0 && turning){ turning =0; mode = (mode + 1) % 3; }//調(diào)顏色 } void TIM3_IRQHandler(void) // //TIM3的溢出更新中斷響應(yīng)函數(shù),產(chǎn)生pwm波 { ????????TIM_ClearITPendingBit(TIM3,TIM_IT_Update);??//???//??清空TIM3溢出中斷響應(yīng)函數(shù)標(biāo)志位 if(counter==255) //counter 從0到255累加循環(huán)計數(shù),每進(jìn)一次中斷,counter加一 counter = 0; else ????????????counter?+=1; if(mode == 0){ if(counter < pwm) //當(dāng)counter值小于pwm值時,將IO口設(shè)為高;當(dāng)counter值大于等于pwm時,將IO口置低 GPIO_SetBits(GPIOA,GPIO_Pin_0|GPIO_Pin_1); //將PC14 PC15置為高電平 else GPIO_ResetBits(GPIOA,GPIO_Pin_0|GPIO_Pin_1); // 將PC14 PC15置為低電平 ????????} if(mode == 1) { if(counter < pwm) //當(dāng)counter值小于pwm值時,將IO口設(shè)為高;當(dāng)counter值大于等于pwm時,將IO口置低 GPIO_SetBits(GPIOA,GPIO_Pin_1|GPIO_Pin_2); //將PC14 PC15置為高電平 else ????????????????????????GPIO_ResetBits(GPIOA,GPIO_Pin_1|GPIO_Pin_2);?????//?將PC14?PC15置為低電平 ????????}?? if(mode ==2){ if(counter < pwm) //當(dāng)counter值小于pwm值時,將IO口設(shè)為高;當(dāng)counter值大于等于pwm時,將IO口置低 GPIO_SetBits(GPIOA,GPIO_Pin_2|GPIO_Pin_0); //將PC14 PC15置為高電平 else GPIO_ResetBits(GPIOA,GPIO_Pin_2|GPIO_Pin_0); // 將PC14 PC15置為低電平 } } int main(void) { RCC_Configuration(); GPIO_Configuration(); tim4(); tim3(); ??nvic();? while(1) { ????}??? } void delay_nus(u32 n) //72M時鐘下,約延時us { u8 i; while(n--) { i=7; while(i--); } } void delay_nms(u32 n) //72M時鐘下,約延時ms { while(n--) delay_nus(1000); } void RCC_Configuration(void) //使用任何一個外設(shè)時,務(wù)必開啟其相應(yīng)的時鐘 { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC|RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO, ENABLE); //使能APB2控制外設(shè)的時鐘,包括GPIOC, 功能復(fù)用時鐘AFIO等, RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4|RCC_APB1Periph_TIM3, ENABLE); //使能APB1控制外設(shè)的時鐘,定時器tim3、4,其他外設(shè)詳見手冊 } void GPIO_Configuration(void) //使用某io口輸入輸出時,請務(wù)必對其初始化配置 { GPIO_InitTypeDef GPIO_InitStructure; //定義格式為GPIO_InitTypeDef的結(jié)構(gòu)體的名字為GPIO_InitStructure ??????????????????????????????????????????//typedef?struct?{?u16?GPIO_Pin;?GPIOSpeed_TypeDef?GPIO_Speed;?GPIOMode_TypeDef?GPIO_Mode;?}?GPIO_InitTypeDef; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //配置IO口的工作模式為上拉輸入(該io口內(nèi)部外接電阻到電源) GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //配置IO口最高的輸出速率為50M GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12|GPIO_Pin_13; //配置被選中的管腳,|表示同時被選中 ????GPIO_Init(GPIOC,?&GPIO_InitStructure);??????????????????//初始化GPIOC的相應(yīng)IO口為上述配置,用于按鍵檢測 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; //配置IO口工作模式為 推挽輸出(有較強(qiáng)的輸出能力) GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //配置IO口最高的輸出速率為50M GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2; //配置被選的管腳,|表示同時被選中 GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化GPIOA的相應(yīng)IO口為上述配置 GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE); //失能STM32 JTAG燒寫功能,只能用SWD模式燒寫,解放出PA15和PB中部分IO口 } void tim4() //配置TIM4為基本定時器模式,約10ms觸發(fā)一次,觸發(fā)頻率約100Hz { ????TIM_TimeBaseInitTypeDef??TIM_TimeBaseStructure;???//定義格式為TIM_TimeBaseInitTypeDef的結(jié)構(gòu)體的名字為TIM_TimeBaseStructure?? TIM_TimeBaseStructure. TIM_Period =9999; // 配置計數(shù)閾值為9999,超過時,自動清零,并觸發(fā)中斷 ????TIM_TimeBaseStructure.TIM_Prescaler?=71;?????????//??時鐘預(yù)分頻值,除以多少 TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; // 時鐘分頻倍數(shù) ????TIM_TimeBaseStructure.TIM_CounterMode?=?TIM_CounterMode_Up;?//?計數(shù)方式為向上計數(shù) TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure); // 初始化tim4 TIM_ClearITPendingBit(TIM4,TIM_IT_Update); //清除TIM4溢出中斷標(biāo)志 TIM_ITConfig(TIM4,TIM_IT_Update,ENABLE); // 使能TIM4的溢出更新中斷 TIM_Cmd(TIM4,ENABLE); // 使能TIM4 } void tim3() //配置TIM3為基本定時器模式 ,約10us觸發(fā)一次,觸發(fā)頻率約100kHz { ????TIM_TimeBaseInitTypeDef??TIM_TimeBaseStructure;???//定義格式為TIM_TimeBaseInitTypeDef的結(jié)構(gòu)體的名字為TIM_TimeBaseStructure?? TIM_TimeBaseStructure. TIM_Period =9; //配置計數(shù)閾值為9,超過時,自動清零,并觸發(fā)中斷 ????TIM_TimeBaseStructure.TIM_Prescaler?=71;?????//????時鐘預(yù)分頻值,除以多少 TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; // 時鐘分頻倍數(shù) ????TIM_TimeBaseStructure.TIM_CounterMode?=?TIM_CounterMode_Up;??//?計數(shù)方式為向上計數(shù) TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); // 初始化tim3 TIM_ClearITPendingBit(TIM3,TIM_IT_Update); //清除TIM3溢出中斷標(biāo)志 TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE); // 使能TIM3的溢出更新中斷 TIM_Cmd(TIM3,ENABLE); // 使能TIM3 } void nvic() //配置中斷優(yōu)先級 { ?????NVIC_InitTypeDef?NVIC_InitStructure;??//????//???命名一優(yōu)先級變量 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); // 將優(yōu)先級分組方式配置為group1,有2個搶占(打斷)優(yōu)先級,8個響應(yīng)優(yōu)先級 NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn; //該中斷為TIM4溢出更新中斷 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;//打斷優(yōu)先級為1,在該組中為較低的,0優(yōu)先級最高 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; // 響應(yīng)優(yōu)先級0,打斷優(yōu)先級一樣時,0最高 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // 設(shè)置使能 ?????NVIC_Init(&NVIC_InitStructure);????????????????????????//??初始化 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); //要用同一個Group NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; //TIM3 溢出更新中斷 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;// 打斷優(yōu)先級為1,與上一個相同,不希望中斷相互打斷對方 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; // 響應(yīng)優(yōu)先級1,低于上一個,當(dāng)兩個中斷同時來時,上一個先執(zhí)行 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; ?????NVIC_Init(&NVIC_InitStructure); }
?
評論
查看更多