分享到plurk 分享到twitter 分享到facebook

版本 39ea17c62218ce018f2a8279e125b9314a21b9f0

Pulse-width modulation(PWM)

Introduction

又稱pulse-duration modulation(PDM),是將類比信號轉為脈波的一種技術。

為何需要PWM?雖然類比電壓可直接用來控制,但類比電路控制信號容易隨時間漂移,功耗大。

.. image:: /pwm.png

如圖所示,PWM 電路主要功能是將輸入電壓的振幅轉換成脈衝寬度。一般轉換後脈波的週期固定,脈波的占空比(duty cycle)會依類比信號的大小而改變,可用來控制燈泡亮度、馬達轉速等等,脈波寬度越大燈泡亮度越亮、馬達轉速越快。

Implementation

PWM需要透過Timer來實現,STM32的Timer可分為以下幾種

  • 基本定時器(TIM6 和 TIM7)
  • 高級控制定時器(TIM1 和 TIM8)
  • 通用定時器(TIMx):具有測量輸入信號的脈衝長度、產生輸出波形和PWM的功能。
    • clock來源 : 內部clock(CK_INT)、外部clock模式1(TIx)、外部clock模式2(ETR)、內部觸發輸入(ITRx)。
    • CK_INT -> AHB Prescaler(/1、2、…、512) -> APB1 Prescaler(/1、2、4、8、16) or APB2 Prescaler(/1、2、4、8、16)。
    • Time Base Configuration :
    .. image:: /up mode.bmp

.. image:: /down mode.bmp


.. image:: /center aligned.jpg

- TIM_ClockDivision  - 採樣頻率基準,當連續採樣到N個有效電平時,才當作一次有效電平。
- TIM_Prescaler  -  將TIMxCLK除以(TIM_Prescaler+1)
- TIM_CounterMode  -  選擇計數模式
- TIM_Period  -  TIMx_ARR,counter 週期
  • 輸出脈波週期 = (TIM_Period+1) * (TIM_Prescaler+1) * (TIM_ClockDivision+1) / TIMxCLK
  • PWM configuration
    • TIM_OCMode - PWM模式
      • PWM 1 Mode : 在向上計數,TIMx_CNT<TIMx_CCRx時,輸出為1,否則輸出為0;在向下計數,TIMx_CNT>TIMx_CCRx時,輸出為0,否則輸出為1。
      • PWM 2 Mode : 在向上計數,TIMx_CNT<TIMx_CCRx時,輸出為0,否則輸出為1;在向下計數,TIMx_CNT>TIMx_CCRx時,輸出為1,否則輸出為0。
    • TIM_Pulse - TIMx_CCRx,脈衝寬度
    • TIM_OCPolarity - 設置輸出極性,例如:TIM_OCPolarity_High PWM輸出關閉時默認為低電位。

以LED為例:

.. image:: /timer.png

TIM_Prescaler = 499,TIM_ClockDivision=0,TIMxCLK=84MHz

輸出脈波週期 = (TIM_Period+1) * (TIM_Prescaler+1) * (TIM_ClockDivision+1) / TIMxCLK

       = (1999+1) * (499+1) * (0+1)/84000000 ≒ 0.012 s

0.012 s 遠小於人眼視覺暫留的時間(0.1~0.4s),因此上圖的PWM 1 duty cycle(75%)>PWM 2 duty cycle(25%),PWM 1 Mode看起來會比PWM 2 Mode亮。


Code_section

//====set pin enable=====================================

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD | RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOA, ENABLE ); //開啟Pin腳 D B E提供使用

RCC_APB1PeriphClockCmd( RCC_APB1Periph_TIM4 | RCC_APB1Periph_TIM3, ENABLE ); //開啟Timer

  • GPIO_PinAFConfig(GPIOD, GPIO_PinSource12, GPIO_AF_TIM4);

  • GPIO_PinAFConfig(GPIOD, GPIO_PinSource13, GPIO_AF_TIM4);

  • GPIO_PinAFConfig(GPIOD, GPIO_PinSource14, GPIO_AF_TIM4);

  • GPIO_PinAFConfig(GPIOD, GPIO_PinSource15, GPIO_AF_TIM4);

  • /* GPIOA Configuration: CH1 (PB4) and CH2 (PB5) */ //設定PB4 5為輸出模式 提供模擬中斷來源

  • GPIO_InitStructure2.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 ;

  • GPIO_InitStructure2.GPIO_Mode = GPIO_Mode_OUT; //輸出信號模式

  • GPIO_InitStructure2.GPIO_OType = GPIO_OType_PP;

  • GPIO_InitStructure2.GPIO_Speed = GPIO_Speed_100MHz;

  • GPIO_InitStructure2.GPIO_PuPd = GPIO_PuPd_UP;

  • GPIO_Init(GPIOB, &GPIO_InitStructure2);

  • /* GPIOA Configuration: (PA2) and (PA3) */ //設定PA2 3為輸入模式 提供接收中斷來源

  • GPIO_InitStructure2.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3 ;

  • GPIO_InitStructure2.GPIO_Mode = GPIO_Mode_IN;

  • GPIO_InitStructure2.GPIO_Speed = GPIO_Speed_100MHz;

  • GPIO_InitStructure2.GPIO_OType = GPIO_OType_PP;

  • GPIO_InitStructure2.GPIO_PuPd = GPIO_PuPd_DOWN ;

  • GPIO_Init(GPIOA, &GPIO_InitStructure2);

  • // Setup Blue & Green LED on STM32-Discovery Board to use PWM. / //PD與LED3456相連實作PWM

  • GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13| GPIO_Pin_14| GPIO_Pin_15;

  • GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; // Alt Function - Push Pull

  • GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;

  • GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;

  • GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;

  • GPIO_Init( GPIOD, &GPIO_InitStructure );

//======================================================

//====Interrupt set section==============================

  • //==清空中斷標誌==

  • EXTI_ClearITPendingBit(EXTI_Line2);

  • EXTI_ClearITPendingBit(EXTI_Line3);

  • //==選擇中斷PIN腳 A2 A3======

  • SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource2);

  • SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource3);

  • //==

  • EXTI_InitStructure.EXTI_Line = EXTI_Line2 ; //選擇中斷線路2

  • EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //設置為中斷請求,非事件請求

  • EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling //設置中斷觸發方式為 下降沿觸發

  • EXTI_InitStructure.EXTI_LineCmd = ENABLE; //外部中斷enable

  • EXTI_Init(&EXTI_InitStructure);

  • EXTI_GenerateSWInterrupt(EXTI_Line2);

  • EXTI_InitStructure.EXTI_Line = EXTI_Line3 ; //選擇中斷線路3

  • EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //设設置為中斷請求,非事件請求

  • EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //設置中斷觸發方式為 下降沿觸發

  • EXTI_InitStructure.EXTI_LineCmd = ENABLE; //外部中斷enable

  • EXTI_Init(&EXTI_InitStructure);

  • EXTI_GenerateSWInterrupt(EXTI_Line3);

  • //===給予中斷分組與優先權的設定===

  • NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); //選擇中斷分組2

  • NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQn ; //選擇中斷通道2

  • NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //搶占式中斷優先級設置為0

  • NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //響應式中斷優先級設置為0

  • NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //enable中断

  • NVIC_Init(&NVIC_InitStructure);

//========================================================

//===Timer set section========================================

  • PrescalerValue = (uint16_t) ((SystemCoreClock /4) / 100000) - 1; //算脈衝周期的時間

  • //==TIMER 4 設定

  • TIM_TimeBaseStructInit( &TIM_TimeBaseInitStruct );

  • TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;

  • TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up; //上數模式

  • TIM_TimeBaseInitStruct.TIM_Period = 2000 - 1; // 0..2000 //周期

  • TIM_TimeBaseInitStruct.TIM_Prescaler = PrescalerValue;

  • TIM_TimeBaseInit( TIM4, &TIM_TimeBaseInitStruct );

  • //==TIMER 4 CCRx 暫存器設定

  • TIM_OCStructInit( &TIM_OCInitStruct );

  • TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;

  • TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;

  • // Initial duty cycle equals 0%. Value can range from zero to 1000.

  • TIM_OCInitStruct.TIM_Pulse = 1000-1; // 0 .. 1000 (0=Always Off, 1000=Always On)

  • //==TIMER channel init

  • TIM_OC1Init( TIM4, &TIM_OCInitStruct ); // Channel 1 LED

  • TIM_OC2Init( TIM4, &TIM_OCInitStruct ); // Channel 2 LED

  • TIM_OC3Init( TIM4, &TIM_OCInitStruct ); // Channel 3 LED

  • TIM_OC4Init( TIM4, &TIM_OCInitStruct ); // Channel 4 LED

  • TIM_Cmd( TIM4, ENABLE );

  • TIM4->CCR1 = 500-1;

  • TIM4->CCR2 = 500-1;

  • TIM4->CCR3 = 500-1;

  • TIM4->CCR4 = 500-1;

//================================================================

//====中斷subroutine===============================================

void EXTI2_IRQHandler(void) //加長脈波頻寬的中斷subroutine

{

if(EXTI_GetITStatus(EXTI_Line2) != 0)

{ EXTI_ClearITPendingBit(EXTI_Line2);

if (brightness <= 1999 - 100)
    brightness +=100;

TIM4->CCR1 = brightness;

TIM4->CCR2 = brightness;

TIM4->CCR3 = brightness;

TIM4->CCR4 = brightness;

EXTI_ClearITPendingBit(EXTI_Line2);

EXTI_ClearITPendingBit(EXTI_Line3);

} }

void EXTI3_IRQHandler(void) //減少脈波頻寬的中斷subroutine {

if(EXTI_GetITStatus(EXTI_Line3) != 0)

{ EXTI_ClearITPendingBit(EXTI_Line3);

if (brightness >= 199)
    brightness -=100;

TIM4->CCR1 = brightness;

TIM4->CCR2 = brightness;

TIM4->CCR3 = brightness;

TIM4->CCR4 = brightness;

EXTI_ClearITPendingBit(EXTI_Line2);

EXTI_ClearITPendingBit(EXTI_Line3);
}

}

//============================================================

Demo

http://youtu.be/RHzLguvuOKY

http://youtu.be/guG6MdLIwfI

http://youtu.be/jJfebbbMDPw

補充

  1. PWM較省電?

    因為一般類比電壓要降低電壓輸出需靠增加電阻,源頭輸出電壓“持續”都為同一電壓,不過利用電阻改變最後輸出電壓,而PWM他靠的是一段時間內輸出的頻率來模擬類比電壓,“不需要持續的輸出”,故不會降電浪費在電阻上,即可達到省電效果。

  2. overflow 和 UEV UIF的關係

UEV occurs everytime an overflow occurs, and UIF is a flag triggered when overflow occurs , if you don’t clean the flag, it will remain triggered. Reference

  1. 向上計數和向下計數的差別

  2. timer 和 RTC的差別

The system timer is what makes everything in the computer run at the same speed. For example, your CPU won’t look for a fresh batch of data while the Memory is still trying to feed it the last batch.

The Real Time Clock tells the system what day/time it is.

  1. TIM_OCMode (timer output compare mode)

.. image:: /TIM_OCMode.png

  1. PWM先高後低和先低後高 在步進馬達上表現有什麼差別?
  2. 改成中央對齊計數方式會怎麼樣?
  3. Nyquist-Shannon Sampling Theorem 如果信號是帶限(某個頻率以上及以下~0)的,並且採樣頻率高於信號帶寬的一倍,那麼,原來的連續信號可以從採樣樣本中完全重建出來。

============= - http://zh.wikipedia.org/zh-tw/%E8%84%88%E8%A1%9D%E5%AF%AC%E5%BA%A6%E8%AA%BF%E8%AE%8A - http://ppt.cc/nIAF - http://www.google.com.tw/url?sa=t&rct=j&q=pwm&source=web&cd=10&cad=rja&ved=0CFMQFjAJ&url=http%3A%2F%2Fwww.vr.ncue.edu.tw%2Fesa%2Fa1001%2FPWM.pdf&ei=S3OoUO6pOafcmAWWiIGQDw&usg=AFQjCNE_7pw6paGQzH7kSwkwD2witqcC-A - http://hi.baidu.com/snic_k/item/0f045e3288e6683d2e20c42b - 陳志旺(2012),STM32 嵌入式微控制器快速上手,中國:電子工業出版社。