PWM工作步驟解析:
a. CCR1捕獲比較值寄存器設(shè)置比較值,將其與當前值寄存器的值比較,要說明的是修改TIM_CCMR1寄存器的OC1M[2:0]位可控制 PWM模式,方法如下:
- 110:PWM模式1——向上計數(shù)時,一旦TIMx_CNT<TIMx_CCR1時通道1為有效電平,否則為無效電平;在向下計數(shù)時,一旦TIMx_CNT>TIMx_CCR1時通道1為無效電平(OC1REF=0),否則有效電平(OC1REF=1)。
- 111:PWM模式2——在向上計數(shù)時,一旦TIMx_CNT<TIMx_CCR1時通道1為無效電平,否則為有效電平;在向下計數(shù)時,一旦TIMx_CNT>TIMx_CCR1時通道1為有效電平,否則為無效電平。
b. 經(jīng)過輸出控制器后,得到OC1ref電平還要經(jīng)過一個選擇,其由TIMx_CCRE寄存器的CC1P位控制:輸入/捕獲1輸出極性。0:高 電平有效。1:低電平有效
c. 選擇完成后經(jīng)過輸出電路來輸出,輸出電路由TIM_xCCRE寄存器的CC1E位控制。
控制方式為0:關(guān)閉 1:打開。
二、 實驗原理
STM32的定時器有PWM功能,iCore3的三個LED都連接在定時器的輸出接口上,可以通過定時器的PWM輸出控制LED的亮度,從而實現(xiàn)呼吸燈的功能。硬件連接示意圖如下圖所示:

圖8_2 驅(qū)動示意圖
三、源代碼
1、主函數(shù)
- /*
- * Name : main
- * Description : ---
- * Author : ysloveivy.
- *
- * History
- * --------------------
- * Rev : 0.00
- * Date : 11/21/2015
- *
- * create.
- * --------------------
- */
- int main(void)
- {
- int i;
- int brightness = 99;
- pwm.initialize();
- float temp = 0.0;
- int data = 0;
- //紅色LED燈循環(huán)由亮變暗,由暗變亮
- while(1){
- for(i = 0;i < 1000000;i++);
- brightness ++;
- if(brightness == 100){
- brightness = 0;
- }
- temp = sin(PI / 99.0 * brightness) * 0.5 + 0.5;
- temp *= 499;
- data = (int)temp;
- pwm.set_compare(data);
- }
- }
復(fù)制代碼2.PWM初始化
以下是TIM8初始化及PWM設(shè)置程序:
- /*
- * Name : initialize
- * Description : ---
- * Author : ysloveivy.
- *
- * History
- * -------------------
- * Rev : 0.00
- * Date : 11/21/2015
- *
- * create.
- * -------------------
- */
- static int initialize(void)
- {
- GPIO_InitTypeDef GPIO_InitStructure;
- TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
- TIM_OCInitTypeDef TIM_OCInitStructure;
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM8,ENABLE); //開啟TIM8定時器的時鐘
- RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOI, ENABLE); //開啟GPIOI的時鐘
- GPIO_PinAFConfig(GPIOI,GPIO_PinSource5,GPIO_AF_TIM8); //PI5復(fù)用為TIM8
- //GPIO初始化設(shè)置
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //模式設(shè)為復(fù)用
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
- GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //復(fù)用推挽輸出
- GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
- GPIO_Init(GPIOI,&GPIO_InitStructure);
- //TIM8初始化
- TIM_TimeBaseStructure.TIM_Prescaler = 83; //設(shè)置預(yù)分頻值
- TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上計數(shù)模式
- TIM_TimeBaseStructure.TIM_Period = 499; //自動重裝載值
- TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
- //設(shè)置時鐘分割
- TIM_TimeBaseInit(TIM8,&TIM_TimeBaseStructure);
- //TIM8 CH1 LED_RED
- TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //設(shè)置為PWM模式2
- TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比較輸出使能
- TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable; //互補輸出使能
- TIM_OCInitStructure.TIM_Pulse = 0; //設(shè)置待裝入捕獲比較寄存器的脈沖值
- TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; //當定時器的值小于脈沖值時,輸出低電平
- TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;
- TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
- TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Reset;
- TIM_OC1Init(TIM8, &TIM_OCInitStructure);
- TIM_OC1PreloadConfig(TIM8, TIM_OCPreload_Enable); //使能輸出比較預(yù)裝載
- TIM_ARRPreloadConfig(TIM8,ENABLE); //使能TIM8自動重裝載的預(yù)裝載寄存器允許位
- TIM_Cmd(TIM8, ENABLE); //TIM8使能
- TIM_CtrlPWMOutputs(TIM8, ENABLE); //使能主輸出
- return 0;
- }
復(fù)制代碼3.修改占空比函數(shù)
- static int set_compare(int temp)
- {
- TIM_SetCompare1(TIM8,temp); //修改占空比
- return 0;
- }
復(fù)制代碼4.小知識
在上面程序中有一段函數(shù)為:
GPIO_PinAFConfig(GPIOI,GPIO_PinSource5,GPIO_AF_TIM8);
它的功能是將PI5復(fù)用為TIM8_CH1,初學者可能會問了為什么PI5可以復(fù)用為TIM8_CH1,其他引角可不可以。這就要借助該芯片的數(shù)據(jù)手冊了,芯片上眾多引角他們往往帶有自己特殊的使命,如以下從數(shù)據(jù)手冊上的截屏:

圖8_3 芯片引腳功能示意圖
其在數(shù)據(jù)手冊的Pinouts and pin description——STM32F40xxx pin and ball definitions目錄下。前面六列為該芯片手冊包含的芯片類型,接下來第七列是引腳的名稱,第八列是引腳類型如可以輸入輸出的I/O口,第八列中有FT標識的引腳表示能承受5V電壓,第九列是注釋,第十列為可復(fù)用功能如PI5要復(fù)用為TIM8_CH1功能則可通過剛剛介紹的函數(shù)實現(xiàn),第十一列為可重映射功能。
四、 實驗現(xiàn)象:
iCore3 雙核心板紅色LED燈亮度從亮到暗,然后從暗到亮。
五、 代碼包下載鏈接