性无码一区二区三区在线观看,少妇被爽到高潮在线观看,午夜精品一区二区三区,无码中文字幕人妻在线一区二区三区,无码精品国产一区二区三区免费

  • 回復
  • 收藏
  • 點贊
  • 分享
  • 發(fā)新帖

單片機輸出PWM的簡單總結

PWM的應用可以說非常廣泛,控制電機速度、燈光亮度、通信調制等眾多領域。PWM的問題小伙伴問的比較多,最近也在用PWM,這里就分享一下關于PWM的一些內容。

什么是PWM?

PWM:Pulse Width Modulation,脈沖寬度調制。網上的解釋很多,通過下圖,你就能直觀的理解PWM,其實就是高低電平組成的脈沖信號。

通過改變其中頻率(脈沖周期)、占空比,就能應用在很多場合。

PWM常見輸出方式

通過上面描述,PWM就是一個IO口以不同的時間周期輸出高、低電平。1.新手(菜鳥)級別while循環(huán)中,阻塞延時,控制IO口高低輸出:

while(1)
{
  IO口高電平
  Delay阻塞延時
  IO口低電平
  Delay阻塞延時
}

阻塞延時可以是:軟件模擬延時,定時器阻塞延時等。

2.入門(初級)級別while循環(huán)中,非阻賽延時,控制IO口高低輸出:

while(1)
{
  IO口高電平
  Delay非阻塞延時
  IO口低電平
  Delay非阻塞延時
}

3.熟悉(中級)級別定時器中斷控制IO高低電平輸出:

定時器中斷配置 ,啟動定時器,響應中斷,控制IO口高低電平

void TIM2_IRQHandler(void)   //TIM2中斷
{
  
  if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) //檢查指定的TIM中斷發(fā)生與否:TIM 中斷源 
    {
      TIM_ClearITPendingBit(TIM2, TIM_IT_Update  );  //清除TIMx的中斷待處理位:TIM 中斷源 
      pwmcount++;
      if(pwmcount == 3600)//20ms
     { 
          pwmcount = 0;
          
      }
      if(pwmcount == 500)
      {
          Servo1_High;
          Servo2_High;
          Servo3_High;
          Servo4_High;
          //Servo5_High;
          //Servo6_High;
          Servo7_High;
          Servo8_High;
      }

4.熟練(中級+)級別定時器PWM硬件控制輸出:

配置定時器輸出PWM

void AppTask(void *p_arg)
{
  PWM_TIM_Configuration();

  PWM_Output(頻率, 占空比);

  while(1)
  {
    //自己的應用代碼
  }
}

比較:

上面幾種PWM輸出方式,前面三種都會CPU干預PWM的輸出,也就是會占用CPU資源,特別是前面兩種方式,不僅占用CPU,誤差還比較大。使用第三種中斷方式,如果頻率比較高,CPU消耗的也比較嚴重。這種情況適合于沒有硬件PWM輸出的單片機。第四種就是單片機自帶硬件PWM輸出功能,只需要簡單配置就可以自動輸出PWM波形,無需CPU干預。

硬件輸出PWM例子

這里以大家熟悉的STM32F1為例:為大家簡單分享一下硬件定時器輸出PWM波形。

PWM定時器相關宏定義:

//定時器計數時鐘(1M次/秒)
#define PWM_COUNTER_CLOCK         1000000

//預分頻值(與系統(tǒng)時鐘、計數值有關)
#define PWM_PRESCALER_VALUE       (SystemCoreClock/PWM_COUNTER_CLOCK - 1)

PWM配置:

/**
  * @brief  定時器PWM輸出配置
  * @param  無
  * @retval 無
  */
void PWM_TIM_Configuration(void)
{
  GPIO_InitTypeDef        GPIO_InitStructure;
  TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
  TIM_OCInitTypeDef       TIM_OCInitStructure;

  /* 時鐘配置 */
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

  /* 引腳配置 */
  GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_0;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF_PP;
  GPIO_Init(GPIOA, &GPIO_InitStructure);

  /* 時基配置 */
  TIM_TimeBaseStructure.TIM_Prescaler = PWM_PRESCALER_VALUE;         //預分頻值
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;        //向上計數
  TIM_TimeBaseStructure.TIM_Period = 0xFFFF;                         //定時周期(暫定值)
  TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;            //分頻因子
  TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);

  /* PWM模式配置 */
  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;                  //輸出PWM1模式
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;      //使能輸出
  TIM_OCInitStructure.TIM_Pulse = 0;                                 //脈寬值(暫定值)
  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;          //輸出極性(TIM_OC1對應通道1)
  TIM_OC1Init(TIM2, &TIM_OCInitStructure);
}

PWM輸出函數接口:

/**
  * @brief  輸出PWM
  * @param  Frequency:頻率
            Dutycycle:占空比
  * @retval 無
  */
void PWM_Output(uint32_t Frequency, uint32_t Dutycycle)
{
  uint32_t tim_period;
  uint32_t tim_pulse;

  tim_period = PWM_COUNTER_CLOCK/Frequency - 1;                      //計算出計數周期(決定輸出的頻率)
  tim_pulse  = (tim_period + 1)*Dutycycle / 100;                     //計算出脈寬值(決定PWM占空比)

  TIM_Cmd(TIM2, DISABLE);                                            //失能TIM
  TIM_SetCounter(TIM2, 0);                                           //計數清零
  TIM_SetAutoreload(TIM2, tim_period);                               //更改頻率
  TIM_SetCompare1(TIM2, tim_pulse);                                  //更改占空比(TIM_SetCompare1對應通道1)
  TIM_Cmd(TIM2, ENABLE);                                             //使能TIM
}

本例使用的是STM32標準外設庫,如果要深入理解其中原理,還是建議使用標準外設庫。

當然,如果想要快速使用PWM這個功能,不想理解其原理,可以直接使用STM32CubeMX配置生成代碼

想要更加精確控制,并更加滿足應用層的需求,就需要自己一步一步深入了解原理。下面說幾點常見的問題吧。

1.引腳映射如果你使用的引腳需要映射,就需要配置對應的參數。

需要增加對應的“映射”代碼:

//復用功能
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);

//定時器(PWM)引腳映射
GPIO_PinRemapConfig(GPIO_FullRemap_TIM2, ENABLE);

2.頻率和占空比精度

如果使用32位定時器的話,頻率范圍更寬、精度也可以達到更高。比如:頻率:0.01Hz、 占空比0.01%等。如果是16位的話,其中的參數都不能超過16位(65535):

#define PWM_COUNTER_CLOCK         1000000
#define PWM_PRESCALER_VALUE       (SystemCoreClock/PWM_COUNTER_CLOCK - 1)

tim_period = PWM_COUNTER_CLOCK/Frequency - 1;                      //計算出計數周期(決定輸出的頻率)
tim_pulse  = (tim_period + 1)*Dutycycle / 100;                     //計算出脈寬值(決定PWM占空比)

具體可根據自己情況進行配置,比如PWM(定時器)計數時鐘、分頻值等。實際應用代碼,建議增加各個參數的判斷,以防越界(這里為了方便理解,就寫的比較簡單)。

全部回復(1)
正序查看
倒序查看
2021-11-11 11:58

贊,最后面stm32的代碼完整,可以跑起來。再多加個timer來控制一個duty修改時間線,就能做個簡單的類midi提示音

0
回復
發(fā)