首先,我想引用一下在一片博文里 看到 的一段話,寫的很詳細,
首先來說,你要使用PWM模式你得先選擇用那個定時器來輸出PWM吧!除了TIM6、TIM7這兩個普通的定時器無法輸出PWM外,其余的定時器都可以輸出PWM,每個通用定時器可以輸出4路PWM,高級定時器TIM1、TIM8每個可輸出7路PWM,這里為了方便起見,我們選擇與實驗相同的TIM3的通道2來說明。選好定時器及通道后,下一步就是要使能定時器的時鍾,根據需要看看是否需要重映射IO,然后就是配置輸出PWM的IO及定時器,到這里原子的視頻及例程都有詳細的介紹,這里只需要提一點有些網友疑惑的TIM_TimeBaseStructure.TIM_ClockDivision = 0;這句話是什么作用?其實仔細看過技術手冊后發現這句話與PWM輸出實驗其實是沒關系的,這句話是設置定時器時鍾(CK_INT)頻率與數字濾波器(ETR,TIx)使用的采樣頻率之間的分頻比例的(與輸入捕獲相關),0表示濾波器的頻率和定時器的頻率是一樣的。至於其余部分,我就不再贅述。
那么,下面就貼上我自己的代碼
這個代碼可是我改了一天的結果啊。。。。
/***************************************** 利用pwm控制led亮度, 其實我們看到的是燈在呼吸,實際上燈是一直在以很高的頻率在閃爍,每次閃爍的亮度都不一樣,越來越亮,或者暗 由於人的視覺暫留效應,我們看到燈一直在亮,而且亮度在漸變。 日期:2016.2.25 ********************************************/ #include "stm32f10x.h" /* LED亮度等級 PWM表 */ uint8_t indexWave[] = {1,1,2,2,3,4,6,8,10,14,19,25,33,44,59,80, 107,143,191,255,255,191,143,107,80,59,44,33,25,19,14,10,8,6,4,3,2,2,1,1}; //函數申明 void Init_LED(void); void NVIC_Config_PWM(void); void Init_TIMER(void); void Init_PWM(void); void Delay_Ms(uint16_t time); void Delay_Us(uint16_t time); int main(void) { SystemInit(); //系統時鍾配置 Init_LED(); //LED初始化 NVIC_Config_PWM(); Init_TIMER(); //定時器初始化 Init_PWM(); //PWM初始化設置 GPIO_SetBits(GPIOG,GPIO_Pin_14); // LED D2 輸出為高 while(1); } void Init_LED(void) { GPIO_InitTypeDef GPIO_InitStructure; //定義一個GPIO結構體變量 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD| RCC_APB2Periph_GPIOG |RCC_APB2Periph_AFIO,ENABLE); //使能各個端口時鍾,重要!!! GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14; //配置LED D2端口掛接到PG14端口 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //通用輸出推挽 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //配置端口速度為50M GPIO_Init(GPIOG, &GPIO_InitStructure); //將端口GPIOD進行初始化配置 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 ; //配置LED D5端口掛接到13端口 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //復用功能輸出推挽,這是重映射必要地,AF表示復用 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //配置端口速度為50M GPIO_Init(GPIOD, &GPIO_InitStructure); //將端口GPIOD進行初始化配置 GPIO_PinRemapConfig(GPIO_Remap_TIM4,ENABLE); //將定時器4通道2重映射到PD13引腳,重要!! } //我看很多資料都是這樣映射的 //還是野火比較專業,人的吸氣呼氣通常用時為3秒,算出來是這樣的 //TIM_BaseInitStructure.TIM_Period = 256-1; //TIM_BaseInitStructure.TIM_Prescaler = 2000-1; void Init_TIMER(void) { TIM_TimeBaseInitTypeDef TIM_BaseInitStructure; //定義一個定時器結構體變量 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); //使能定時器4,重要!! // TIM_DeInit(TIM4); //將TIM4定時器初始化位復位值 // TIM_InternalClockConfig(TIM4); //配置 TIM4 內部時鍾 //TIM_BaseInitStructure.TIM_Period = 7200-1; //設置自動重載寄存器值為最大值 0~65535之間 1000000/1000=1000us=1ms //TIM_Period(TIM1_ARR)=7200,計數器向上計數到7200后產生更新事件, //計數值歸零 也就是 1MS產生更新事件一次 TIM_BaseInitStructure.TIM_Period = 256-1; TIM_BaseInitStructure.TIM_Prescaler = 2000-1; //自定義預分頻系數為0,即定時器的時鍾頻率為72M提供給定時器的時鍾 0~65535之間 TIM_BaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; //時鍾分割為0 TIM_BaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上計數模式 從0開始向上計數,計數到1000后產生更新事件 TIM_TimeBaseInit(TIM4, &TIM_BaseInitStructure); //根據指定參數初始化TIM時間基數寄存器 TIM_ARRPreloadConfig(TIM4, ENABLE); //使能TIMx在 ARR 上的預裝載寄存器 TIM_Cmd(TIM4, ENABLE); //TIM4總開關:開啟 TIM_ITConfig(TIM4,TIM_IT_Update,ENABLE); //使能定時器中斷 NVIC_Config_PWM(); //配置中斷優先級 } void Init_PWM() { TIM_OCInitTypeDef TIM_OCInitStructure; //定義一個通道輸出結構 TIM_OCStructInit(&TIM_OCInitStructure); //設置缺省值 TIM_OCInitStructure.TIM_Pulse = 0; //設置占空比,占空比=(CCRx/ARR)*100%或(TIM_Pulse/TIM_Period)*100% //PWM的輸出頻率為Fpwm=72M/7200=1Mhz; /* 下面五句話就把PWM 基本上配置完成,再加上上面定時器的使能,TIM_Cmd(TIM4,ENABLE) */ TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //PWM 模式 1 輸出 , TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //使能輸出狀態 需要PWM輸出才需要這行代碼 TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //TIM 輸出比較極性高 ,就是開始 計數到ccr之前都是high,因為這里的led是正邏輯點亮 TIM_OC2Init(TIM4, &TIM_OCInitStructure); //根據參數初始化PWM寄存器 ,使能通道CCR2 TIM_OC2PreloadConfig(TIM4,TIM_OCPreload_Enable); //使能 TIMx在 CCR2 上的預裝載寄存器,很關鍵和容易遺漏的一部 //TIM_CtrlPWMOutputs(TIM4,ENABLE); //設置TIM4 的PWM 輸出為使能 } void NVIC_Config_PWM(void) //配置嵌套向量中斷控制器NVIC { NVIC_InitTypeDef NVIC_InitStructure; NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); //設置中斷優先級分組2 NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn; //設定中斷源為PC13 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //中斷占優先級為0 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //副優先級為0 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能中斷 NVIC_Init(&NVIC_InitStructure); //根據參數初始化中斷寄存器 } void TIM4_IRQHandler(void) //中斷入口函數 { static uint8_t pwm_index = 0; //用於PWM查表 static uint8_t period_cnt = 0; //用於計算周期數 if (TIM_GetITStatus(TIM4, TIM_IT_Update) != RESET) //TIM_IT_Update { period_cnt++; if(period_cnt >= 10) //若輸出的周期數大於10,輸出下一種脈沖寬的PWM波,在這里野火說他也不知道為什么大於10 { TIM4->CCR2 = indexWave[pwm_index]; //根據PWM表修改定時器的比較寄存器值 pwm_index++; //標志PWM表的下一個元素 if( pwm_index >= 40) //若PWM脈沖表已經輸出完成一遍,重置PWM查表標志 { pwm_index=0; } period_cnt=0; //重置周期計數標志 } TIM_ClearITPendingBit (TIM4, TIM_IT_Update); //必須要清除中斷標志位 } } /*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ** 函數名稱: Delay_Ms_Ms ** 功能描述: 延時1MS (可通過仿真來判斷他的准確度) ** 參數描述:time (ms) 注意time<65535 ** 作 者: Dream ** 日 期: 2011年6月20日 :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ void Delay_Ms(uint16_t time) //延時函數 { uint16_t i,j; for(i=0;i<time;i++) for(j=0;j<10260;j++); } /*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ** 函數名稱: Delay_Ms_Us ** 功能描述: 延時1us (可通過仿真來判斷他的准確度) ** 參數描述:time (us) 注意time<65535 ** 作 者: Dream ** 日 期: 2011年6月20日 :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ void Delay_Us(uint16_t time) //延時函數 { uint16_t i,j; for(i=0;i<time;i++) for(j=0;j<9;j++); } /*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: End:-D:-D:-D:-D:-D:-D:-D:-D:-D:-D:-D:-D:-D:-D:-D:-D:-D:-D:-D:-D :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/