STM32F103 使用TIM3產生四路PWM
程序如下:
/******************************************************************************* * 程序說明 : 思路PWM波生成函數 * 函數功能 : 使用TIM3的PWM功能生成思路PWM, * 輸 入 : 無 * 輸 出 : 四路PWM,通過GPIO引腳復用,對TIM3的四個輸出通道引腳重映射為PC6、PC7、PC8、PC9 *******************************************************************************/ #include"stm32f10x.h" void RCC_Cfg(void); void GPIO_Cfg(void); void TIM_Cfg(void); void NVIC_Cfg(void); void delay_ms(u32 i); void PWM_Cfg(float dutyfactor1,float dutyfactor2,float dutyfactor3,float dutyfactor4); int main() { u8 flag = 1; float ooo=0.5; RCC_Cfg(); NVIC_Cfg(); GPIO_Cfg(); TIM_Cfg(); //開啟定時器2 TIM_Cmd(TIM3,ENABLE); //呼吸燈 while(1){ PWM_Cfg(ooo,10,50+0.5*ooo,200-2*ooo); if(flag == 1) { ooo=ooo+0.002; } if(flag == 0) { ooo=ooo-0.002; } if(ooo>100){ flag = 0; } if(ooo<0.5) { flag = 1; } } } void GPIO_Cfg(void) { GPIO_InitTypeDef GPIO_InitStructure; //RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC|RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO,ENABLE); //全部映射,將TIM3_CH2映射到PB5 //根據STM32中文參考手冊2010中第第119頁可知: //當沒有重映射時,TIM3的四個通道CH1,CH2,CH3,CH4分別對應PA6,PA7,PB0,PB1 //當部分重映射時,TIM3的四個通道CH1,CH2,CH3,CH4分別對應PB4,PB5,PB0,PB1 //當完全重映射時,TIM3的四個通道CH1,CH2,CH3,CH4分別對應PC6,PC7,PC8,PC9 //也即是說,完全重映射之后,四個通道的PWM輸出引腳分別為PC6,PC7,PC8,PC9,我們用到了通道1和通道2,所以對應引腳為PC6,PC7,PC8,PC9,我們用到了通道1和通道2,所以對應引腳為 GPIO_PinRemapConfig(GPIO_FullRemap_TIM3, ENABLE); //部分重映射的參數 //GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE); //設置PC6、PC7、PC8、PC9為復用輸出,輸出4路PWM GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9; GPIO_Init(GPIOC,&GPIO_InitStructure); } void TIM_Cfg(void) { //定義結構體 TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; //重新將Timer設置為缺省值 TIM_DeInit(TIM3); //采用內部時鍾給TIM2提供時鍾源 TIM_InternalClockConfig(TIM3); //預分頻系數為0,即不進行預分頻,此時TIMER的頻率為72MHzre.TIM_Prescaler =0; TIM_TimeBaseStructure.TIM_Prescaler = 0; //設置計數溢出大小,每計20000個數就產生一個更新事件 TIM_TimeBaseStructure.TIM_Period = 7200 - 1; //設置時鍾分割 TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //設置計數器模式為向上計數模式 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //將配置應用到TIM2中 TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStructure); //清除溢出中斷標志 //TIM_ClearFlag(TIM2, TIM_FLAG_Update); //禁止ARR預裝載緩沖器 //TIM_ARRPreloadConfig(TIM2, DISABLE); //開啟TIM2的中斷 //TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE); } /******************************************************************************* * 函 數 名 : PWM波產生配置函數 * 函數功能 : PWM_Cfg * 輸 入 : dutyfactor 占空比數值,大小從0.014到100 * 輸 出 : 無 *******************************************************************************/ void PWM_Cfg(float dutyfactor1,float dutyfactor2,float dutyfactor3,float dutyfactor4) { TIM_OCInitTypeDef TIM_OCInitStructure; //設置缺省值 TIM_OCStructInit(&TIM_OCInitStructure); //TIM3的CH1輸出 TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //設置是PWM模式還是比較模式 TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比較輸出使能,使能PWM輸出到端口 TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //設置極性是高還是低 //設置占空比,占空比=(CCRx/ARR)*100%或(TIM_Pulse/TIM_Period)*100% TIM_OCInitStructure.TIM_Pulse = dutyfactor1 * 7200 / 100; TIM_OC1Init(TIM3, &TIM_OCInitStructure); //TIM3的CH2輸出 TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //設置是PWM模式還是比較模式 TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比較輸出使能,使能PWM輸出到端口 TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //設置極性是高還是低 //設置占空比,占空比=(CCRx/ARR)*100%或(TIM_Pulse/TIM_Period)*100% TIM_OCInitStructure.TIM_Pulse = dutyfactor2 * 7200 / 100; TIM_OC2Init(TIM3, &TIM_OCInitStructure); //TIM3的CH3輸出 TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //設置是PWM模式還是比較模式 TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比較輸出使能,使能PWM輸出到端口 TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //設置極性是高還是低 //設置占空比,占空比=(CCRx/ARR)*100%或(TIM_Pulse/TIM_Period)*100% TIM_OCInitStructure.TIM_Pulse = dutyfactor3 * 7200 / 100; TIM_OC3Init(TIM3, &TIM_OCInitStructure); //TIM3的CH4輸出 TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //設置是PWM模式還是比較模式 TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比較輸出使能,使能PWM輸出到端口 TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //設置極性是高還是低 //設置占空比,占空比=(CCRx/ARR)*100%或(TIM_Pulse/TIM_Period)*100% TIM_OCInitStructure.TIM_Pulse = dutyfactor4 * 7200 / 100; TIM_OC4Init(TIM3, &TIM_OCInitStructure); //使能輸出狀態 TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //設置TIM3的PWM輸出為使能 TIM_CtrlPWMOutputs(TIM3,ENABLE); } void NVIC_Cfg(void) { //定義結構體 NVIC_InitTypeDef NVIC_InitStructure; //選擇中斷分組1 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); //選擇TIM2的中斷通道 NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; //搶占式中斷優先級設置為0 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //響應式中斷優先級設置為0 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //使能中斷 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); } void RCC_Cfg(void) { //定義錯誤狀態變量 ErrorStatus HSEStartUpStatus; //將RCC寄存器重新設置為默認值 RCC_DeInit(); //打開外部高速時鍾晶振 RCC_HSEConfig(RCC_HSE_ON); //等待外部高速時鍾晶振工作 HSEStartUpStatus = RCC_WaitForHSEStartUp(); if(HSEStartUpStatus == SUCCESS) { //設置AHB時鍾(HCLK)為系統時鍾 RCC_HCLKConfig(RCC_SYSCLK_Div1); //設置高速AHB時鍾(APB2)為HCLK時鍾 RCC_PCLK2Config(RCC_HCLK_Div1); //設置低速AHB時鍾(APB1)為HCLK的2分頻 RCC_PCLK1Config(RCC_HCLK_Div2); //設置FLASH代碼延時 FLASH_SetLatency(FLASH_Latency_2); //使能預取指緩存 FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); //設置PLL時鍾,為HSE的9倍頻 8MHz * 9 = 72MHz RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9); //使能PLL RCC_PLLCmd(ENABLE); //等待PLL准備就緒 while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET); //設置PLL為系統時鍾源 RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); //判斷PLL是否是系統時鍾 while(RCC_GetSYSCLKSource() != 0x08); } //允許TIM2的時鍾 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE); //允許GPIO的時鍾 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOC|RCC_APB2Periph_AFIO,ENABLE); } void TIM2_IRQHandler(void) { u16 aa=10; if(TIM_GetFlagStatus(TIM2,TIM_IT_Update)!=RESET) { //清除TIM2的中斷待處理位 TIM_ClearITPendingBit(TIM2 , TIM_FLAG_Update); TIM_Cmd(TIM2,DISABLE); //通過循環讓燈閃爍 while (aa){ GPIO_SetBits(GPIOC,GPIO_Pin_3); delay_ms(10); GPIO_ResetBits(GPIOC,GPIO_Pin_3); delay_ms(10); aa--; } //使燈的狀態為滅 GPIO_SetBits(GPIOC,GPIO_Pin_3); TIM_Cmd(TIM2,ENABLE); } } void delay_ms(u32 i) { u32 temp; SysTick->LOAD=9000*i; //設置重裝數值, 72MHZ時 SysTick->CTRL=0X01; //使能,減到零是無動作,采用外部時鍾源 SysTick->VAL=0; //清零計數器 do { temp=SysTick->CTRL; //讀取當前倒計數值 } while((temp&0x01)&&(!(temp&(1<<16)))); //等待時間到達 SysTick->CTRL=0; //關閉計數器 SysTick->VAL=0; //清空計數器 }
在產生PWM時,如果輸出引腳已經被使用,就要對引腳進行重映射,閱讀《STM32中文參考手冊2010》第119頁可知:
對TIM3而言:
1、當沒有重映射時,TIM3的四個通道CH1,CH2,CH3,CH4分別對應PA6,PA7,PB0,PB1
2、當部分重映射時,TIM3的四個通道CH1,CH2,CH3,CH4分別對應PB4,PB5,PB0,PB1
3、當完全重映射時,TIM3的四個通道CH1,CH2,CH3,CH4分別對應PC6,PC7,PC8,PC9
為了整齊,我們選擇完全重映射,使用的函數是:
GPIO_PinRemapConfig(GPIO_FullRemap_TIM3, ENABLE);
如果想使用部分映射,參數用GPIO_PartialRemap_TIM3:
GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE);