用定時器生成PWM波
PWM全稱是Pulse Width Modulation,通過控制高頻信號的占空比,眼睛當成低通濾波器,可以控制亮暗。再循環(huán)更改PWM的閾值,就弄出了呼吸的效果,相關文章推薦:STM32中PWM的配置與應用詳解。
這里采用一個比較簡單的方法生成PWM波:設置定時器中斷然后根據閾值判斷置高和置低。
void TIM3_IRQHandler(void){TIM_ClearITPendingBit(TIM3,TIM_IT_Update);if(counter==255)counter = 0;elsecounter+=1;if(mode == 0){if(counter < pwm)GPIO_SetBits(GPIOA,GPIO_Pin_0|GPIO_Pin_1);elseGPIO_ResetBits(GPIOA,GPIO_Pin_0|GPIO_Pin_1);}if(mode == 1){if(counter < pwm)GPIO_SetBits(GPIOA,GPIO_Pin_1|GPIO_Pin_2);elseGPIO_ResetBits(GPIOA,GPIO_Pin_1|GPIO_Pin_2);}if(mode ==2){if(counter < pwm)GPIO_SetBits(GPIOA,GPIO_Pin_2|GPIO_Pin_0);elseGPIO_ResetBits(GPIOA,GPIO_Pin_2|GPIO_Pin_0);}}
程序流程
-
開啟外設時鐘(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
-
配置時鐘, 使能中斷(計數閾值,預分頻,時鐘分頻,計數模式)
void tim3() //配置TIM3為基本定時器模式 ,約10us觸發(fā)一次,觸發(fā)頻率約100kHz{TIM_TimeBaseInitTypeDefTIM_TimeBaseStructure;//定義格式為TIM_TimeBaseInitTypeDef的結構體的名字為TIM_TimeBaseStructureTIM_TimeBaseStructure. TIM_Period =9; //配置計數閾值為9,超過時,自動清零,并觸發(fā)中斷TIM_TimeBaseStructure.TIM_Prescaler=71;//時鐘預分頻值,除以多少TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; // 時鐘分頻倍數TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;//計數方式為向上計數TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); // 初始化tim3TIM_ClearITPendingBit(TIM3,TIM_IT_Update); //清除TIM3溢出中斷標志TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE); // 使能TIM3的溢出更新中斷TIM_Cmd(TIM3,ENABLE); // 使能TIM3}
-
配置中斷優(yōu)先級
void nvic() //配置中斷優(yōu)先級{NVIC_InitTypeDefNVIC_InitStructure;////命名一優(yōu)先級變量NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); // 將優(yōu)先級分組方式配置為group1,有2個搶占(打斷)優(yōu)先級,8個響應優(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ōu)先級0,打斷優(yōu)先級一樣時,0最高NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // 設置使能NVIC_Init(&NVIC_InitStructure);//初始化NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); //要用同一個GroupNVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; //TIM3 溢出更新中斷NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;// 打斷優(yōu)先級為1,與上一個相同,不希望中斷相互打斷對方NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; // 響應優(yōu)先級1,低于上一個,當兩個中斷同時來時,上一個先執(zhí)行NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);}
-
寫中斷服務函數
代碼實現
為了方便按鍵檢測,除了TIM3配置PWM波之外,TIM4用來檢測是否有輸入。由于使用開漏輸出,這里使用5V電源。
u8 counter=0;int pwm=100;int flag=0;int mode =0;int velocity =0;int turning=1;void RCC_Configuration(void); //時鐘初始化,開啟外設時鐘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時鐘下,約延時usvoid delay_nms(u32); //72M時鐘下,約延時msvoid 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的溢出更新中斷響應函數 ,讀取按鍵輸入值,根據輸入控制pwm波占空比{u8 key_in1=0x01,key_in2=0x01;TIM_ClearITPendingBit(TIM4,TIM_IT_Update);//清空TIM4溢出中斷響應函數標志位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;}//調速度if(key_in2==0 && turning){turning =0;mode = (mode + 1) % 3;}//調顏色}void TIM3_IRQHandler(void) // //TIM3的溢出更新中斷響應函數,產生pwm波{TIM_ClearITPendingBit(TIM3,TIM_IT_Update);////清空TIM3溢出中斷響應函數標志位if(counter==255) //counter 從0到255累加循環(huán)計數,每進一次中斷,counter加一counter = 0;elsecounter+=1;if(mode == 0){if(counter < pwm) //當counter值小于pwm值時,將IO口設為高;當counter值大于等于pwm時,將IO口置低GPIO_SetBits(GPIOA,GPIO_Pin_0|GPIO_Pin_1); //將PC14 PC15置為高電平elseGPIO_ResetBits(GPIOA,GPIO_Pin_0|GPIO_Pin_1); // 將PC14 PC15置為低電平}if(mode == 1){if(counter < pwm) //當counter值小于pwm值時,將IO口設為高;當counter值大于等于pwm時,將IO口置低GPIO_SetBits(GPIOA,GPIO_Pin_1|GPIO_Pin_2); //將PC14 PC15置為高電平elseGPIO_ResetBits(GPIOA,GPIO_Pin_1|GPIO_Pin_2);//將PC14PC15置為低電平}if(mode ==2){if(counter < pwm) //當counter值小于pwm值時,將IO口設為高;當counter值大于等于pwm時,將IO口置低GPIO_SetBits(GPIOA,GPIO_Pin_2|GPIO_Pin_0); //將PC14 PC15置為高電平elseGPIO_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) //使用任何一個外設時,務必開啟其相應的時鐘{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC|RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO, ENABLE); //使能APB2控制外設的時鐘,包括GPIOC, 功能復用時鐘AFIO等,RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4|RCC_APB1Periph_TIM3, ENABLE); //使能APB1控制外設的時鐘,定時器tim3、4,其他外設詳見手冊}void GPIO_Configuration(void) //使用某io口輸入輸出時,請務必對其初始化配置{GPIO_InitTypeDef GPIO_InitStructure; //定義格式為GPIO_InitTypeDef的結構體的名字為GPIO_InitStructure//typedefstruct{u16GPIO_Pin;GPIOSpeed_TypeDefGPIO_Speed;GPIOMode_TypeDefGPIO_Mode;}GPIO_InitTypeDef;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //配置IO口的工作模式為上拉輸入(該io口內部外接電阻到電源)GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //配置IO口最高的輸出速率為50MGPIO_InitStructure.GPIO_Pin = GPIO_Pin_12|GPIO_Pin_13; //配置被選中的管腳,|表示同時被選中GPIO_Init(GPIOC,&GPIO_InitStructure);//初始化GPIOC的相應IO口為上述配置,用于按鍵檢測GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; //配置IO口工作模式為 推挽輸出(有較強的輸出能力)GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //配置IO口最高的輸出速率為50MGPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2; //配置被選的管腳,|表示同時被選中GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化GPIOA的相應IO口為上述配置GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE); //失能STM32 JTAG燒寫功能,只能用SWD模式燒寫,解放出PA15和PB中部分IO口}void tim4() //配置TIM4為基本定時器模式,約10ms觸發(fā)一次,觸發(fā)頻率約100Hz{TIM_TimeBaseInitTypeDefTIM_TimeBaseStructure;//定義格式為TIM_TimeBaseInitTypeDef的結構體的名字為TIM_TimeBaseStructureTIM_TimeBaseStructure. TIM_Period =9999; // 配置計數閾值為9999,超過時,自動清零,并觸發(fā)中斷TIM_TimeBaseStructure.TIM_Prescaler=71;//時鐘預分頻值,除以多少TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; // 時鐘分頻倍數TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;//計數方式為向上計數TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure); // 初始化tim4TIM_ClearITPendingBit(TIM4,TIM_IT_Update); //清除TIM4溢出中斷標志TIM_ITConfig(TIM4,TIM_IT_Update,ENABLE); // 使能TIM4的溢出更新中斷TIM_Cmd(TIM4,ENABLE); // 使能TIM4}void tim3() //配置TIM3為基本定時器模式 ,約10us觸發(fā)一次,觸發(fā)頻率約100kHz{TIM_TimeBaseInitTypeDefTIM_TimeBaseStructure;//定義格式為TIM_TimeBaseInitTypeDef的結構體的名字為TIM_TimeBaseStructureTIM_TimeBaseStructure. TIM_Period =9; //配置計數閾值為9,超過時,自動清零,并觸發(fā)中斷TIM_TimeBaseStructure.TIM_Prescaler=71;//時鐘預分頻值,除以多少TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; // 時鐘分頻倍數TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;//計數方式為向上計數TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); // 初始化tim3TIM_ClearITPendingBit(TIM3,TIM_IT_Update); //清除TIM3溢出中斷標志TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE); // 使能TIM3的溢出更新中斷TIM_Cmd(TIM3,ENABLE); // 使能TIM3}void nvic() //配置中斷優(yōu)先級{NVIC_InitTypeDefNVIC_InitStructure;////命名一優(yōu)先級變量NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); // 將優(yōu)先級分組方式配置為group1,有2個搶占(打斷)優(yōu)先級,8個響應優(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ōu)先級0,打斷優(yōu)先級一樣時,0最高NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // 設置使能NVIC_Init(&NVIC_InitStructure);//初始化NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); //要用同一個GroupNVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; //TIM3 溢出更新中斷NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;// 打斷優(yōu)先級為1,與上一個相同,不希望中斷相互打斷對方NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; // 響應優(yōu)先級1,低于上一個,當兩個中斷同時來時,上一個先執(zhí)行NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);}
審核編輯:湯梓紅
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規(guī)問題,請聯(lián)系本站處理。
舉報投訴
-
PWM
+關注
關注
116文章
5869瀏覽量
225584 -
STM32
+關注
關注
2309文章
11162瀏覽量
373396 -
定時器
+關注
關注
23文章
3368瀏覽量
123566
原文標題:STM32呼吸燈的PWM原理與代碼實現
文章出處:【微信號:單片機與嵌入式,微信公眾號:單片機與嵌入式】歡迎添加關注!文章轉載請注明出處。
發(fā)布評論請先 登錄
相關推薦
熱點推薦
定時器輸出PWM波
定時器輸出PWM波什么是PWM脈沖寬度調制(PWM),是英文“Pulse Width Modulation”的縮寫,簡稱脈寬調制,是利用微處
發(fā)表于 01-05 07:05
定時器輸出PWM實驗
定時器輸出PWM 實驗
一. 實驗目的利用定時器控制產生占空比可變的PWM 波。二. 實驗設備及器件IBM PC 機 一臺DP-51PRO
發(fā)表于 09-22 10:49
?7813次閱讀
51單片機定時器實現PWM波
51單片機是可以實現PWM波輸出的,原理其實都是一樣的。說白了,PWM波就是讓某一個引腳輸出周期性連續(xù)高低電平變化的信號。那么如何用51單片機實現周期性的高低電平呢?答案就是
發(fā)表于 11-12 10:36
?13次下載
STM8學習筆記---定時器輸出7路PWM波
STM8S003F3P6單片機共有三個定時器定時器1、定時器2、定時器4。其中定時器1為16位高級定時器
發(fā)表于 11-26 16:06
?9次下載
步進電機-STM32高級定時器輸出正弦波pwm控制四相五線步進電機
前面的文章介紹了單片機控制步進電機四相四拍、四相八拍的方式。用的是持續(xù)電平驅動,這種驅動方式電機的噪音大,震動明顯,正弦波驅動方式,這種方式能很好的解決噪音和震動問題。前面的文章也介紹了使用定時器
發(fā)表于 12-02 19:36
?29次下載
STM32CubeMX_定時器中斷_PWM
文章目錄前言STM32CubeMX新建工程基本定時器配置生成代碼定時器中斷PWM配置工程代碼前言STM32CubeMX_環(huán)境搭建_GPIO_外部中斷上節(jié)整理的是GPIO和外部中斷, 這
發(fā)表于 12-05 13:51
?13次下載
用定時器生成PWM波的原理和方法
PWM全稱是Pulse Width Modulation,通過控制高頻信號的占空比,眼睛當成低通濾波器,可以控制亮暗。再循環(huán)更改pwm的閾值,就弄出了呼吸的效果。
利用通用定時器輸出PWM(附示例驅動直流電機)
上一節(jié)講述了時鐘樹和基本定時器的配置方法,本節(jié)先介紹通用定時器和基本定時器的差異,然后粗略講述PWM波
發(fā)表于 04-03 14:56
?0次下載
一文詳解HPM6000系列PWM定時器模塊
在進行電機類、電源類應用開發(fā)時,如何使用PWM定時器模塊靈活、高效的實現所需 PWM波形的輸出,是眾多開發(fā)者關注的問題。在上篇文章里,我們介紹了PWM
用定時器生成PWM波的方法
評論