电力电子技术
直播中

李明

7年用户 1314经验值
私信 关注
[问答]

PWM占空比的测量方法

PWM(Pulse Width Modulation),一般指脉冲宽度调节,是利用微处理器的数字输出来对模拟威廉希尔官方网站 进行控制的一种非常有效的技术,广泛应用在从测量、通信到功率控制与变换的许多领域中,比如LED亮度调节、电机转速控制等。
而在某些特殊应用中,我们也需要通过测量输入PWM的占空比,来实现不同的输出控制,这就需要使用到PWM占空比的测量方法。这里介绍三种不同的测量方法:阻塞方式、中断方式以及定时器捕获功能。

回帖(4)

马聪

2021-2-3 16:38:08
  阻塞方式
  MCU阻塞方式测量PWM占空比的原理比较简单,也只需要使用到一个普通的IO端口(设置为输入模式,对于51而言那就是一个普通的双向口)。具体实现流程为:
  等待上升沿到来,然后开启定时器,开始计时;
  等待下降沿到来,记录下定时器的计数值,即得到PWM的高电平时间H;
  同时,清零定时器,重新开始计数;
  等待上升沿到来,记录下定时器的计数值,即得到PWM的低电平时间L;
  计算得出占空比:duty = H / (H + L);
  阻塞方式原理简单,而且只需要MCU有一个定时器的资源即可实现;但采集时阻塞CPU运行,阻塞的时间和输入PWM的周期相关,只适用于实时性较低的系统。
  另外,上述流程中存在着一个严重的BUG,即当输入的PWM占空比为0%或者100%时,程序会被一直阻塞,等待上升沿/下降沿的到来。所以解决方法是,在等待上升沿/下降沿的过程中,实时提取定时器的值,一旦定时时间超过1个周期的限定(一般可定义为2-3个周期时间),即退出等待,并根据端口电平判断此时占空比为0%(低电平)或100%(高电平)。
  示例代码,仅供参考:
  //获取PWM输入脚的电平
  #define PWM_IN() xxxxxx
  //定义超时时间(如2-3倍PWM周期)
  #define T1_TIMEOUT xxxxxx
  uint8_t PWM_Analyse(void)
  {
  uint8_t duty = 0xFF;
  uint16_t pwm_H = 0;
  uint16_t pwm_L = 0;
  if (PWM_IN()) //初始为高电平,则开始等待低电平
  {
  TH1 = 0;
  while (PWM_IN()) //等待下降沿
  {
  if (TH1 》= T1_TIMEOUT) //下降沿没有到来,判定为100%占空比
  {
  duty = 100;
  return duty;
  }
  }
  TH1 = 0;
  TL1 = 0;
  while (!PWM_IN()) //等待上升沿
  {
  if (TH1 》= T1_TIMEOUT) //上升沿没有到来,判定为0%占空比
  {
  duty = 0;
  return duty;
  }
  }
  pwm_L = (TH1 《《 8) | TL1;
  TH1 = 0;
  TL1 = 0;
  while (PWM_IN()) //等待下降沿
  {
  if (TH1 》= T1_TIMEOUT) //下降沿没有到来,判定为100%占空比
  {
  duty = 100;
  return duty;
  }
  }
  pwm_H = (TH1 《《 8) | TL1;
  duty = pwm_H * 100 / (pwm_H + pwm_L);
  return duty;
  }
  else //当前为低电平,则开始等待高电平
  {
  TH1 = 0;
  while (!PWM_IN()) //等待上升沿
  {
  if (TH1 》= T1_TIMEOUT) //上升沿没有到来,判定为0%占空比
  {
  duty = 0;
  return duty;
  }
  }
  TH1 = 0;
  TL1 = 0;
  while (PWM_IN()) //等待下降沿
  {
  if (TH1 》= T1_TIMEOUT) //下降沿没有到来,判定为100%占空比
  {
  duty = 100;
  return duty;
  }
  }
  pwm_H = (TH1 《《 8) | TL1;
  TH1 = 0;
  TL1 = 0;
  while (!PWM_IN()) //等待上升沿
  {
  if (TH1 》= T1_TIMEOUT) //上升沿没有到来,判定为0%占空比
  {
  duty = 0;
  return duty;
  }
  }
  pwm_L = (TH1 《《 8) | TL1;
  duty = pwm_H * 100 / (pwm_H + pwm_L);
  return duty;
  }
  return 0xFF;
  }
举报

万腾龙

2021-2-3 16:38:20
  中断方式
  中断方式的PWM采集原理与阻塞方式相同,只是将判定移动至外部中断中。开启MCU端口的外部中断(上升沿和下降沿中断);如果MCU外部中断触发不支持上升和下降沿中断,则先开启上升沿中断,在中断处理中切换中断触发条件。
  处理方法:在中断处理函数中,根据当前电平状态,记录下定时器的值,并清零定时器的值,重新开始下一轮计时。
  0%和100%的处理:设定一个定时递增的变量,同时在外部中断中执行清零操作。若该变量超过一定值(说明外部中断有较长时间没有触发),则判定为0%或100%。
  uint16_t pwm_H = 0;
  uint16_t pwm_L = 0;
  uint16_t pwm_time_out = 0;
  void EXT1_ISR(void) interrupt EXTI1_VECTOR
  {
  if (PWM_IN())
  {
  pwm_L = (TH1 《《 8) | TL1; //记录低电平时间
  TH1 = 0;
  TL1 = 0;
  }
  else
  {
  pwm_H = (TH1 《《 8) | TL1; //记录高电平时间
  TH1 = 0;
  TL1 = 0;
  }
  //该变量定时递增(如1ms递增1),在外部中断中清零
  //在主程序中判断,超过一定值时认为PWM占空比为0%或100%
  pwm_time_out = 0;
  return;
  }
  123456789101112131415161718192021222324
  注:使用中断方式,则占空比计算不建议放在中断中处理;同时,为了保证占空比的准确性,可以连续2-3次计算结果一致时,再确定当前占空比的结果。
举报

张英

2021-2-3 16:38:31
  MCU捕获方式
  采用捕获方式的前提是MCU支持捕获功能。当前部分厂家推出的51内核单片机,会包含一个定时器2,其拥有捕获功能;或者采用32位单片机,一般都带有捕获功能。捕获的原理很简单,当上升沿或下降沿来临时,MCU硬件将定时器/计数器的值保存在一个影子寄存器中,并产生捕获中断。
  通过固定每次上升/下降沿的计数器值,相减即可分别得出高电平值和低电平值,从而计算出占空比。
  
  下面以某颗51内核的MCU为例,提供示例代码:
  unsigned int pwm_fall = 0, pwm_rise = 0;
  volatile unsigned int pwm_H;
  volatile unsigned int pwm_L;
  volatile unsigned char pwm_time_out;
  //------------------------------------------------------------
  void T2_interrupt(void) interrupt 5 //定时器2中断;
  {
  if (CCCON & 0x02) //CC1中断标志位
  {
  CCCON &= 0xFD; //清除中断标志
  if (PWM_IN()) //上升沿触发
  {
  pwm_rise = CC1; //获取捕获寄存器中的值
  pwm_L = pwm_rise - pwm_fall;
  }
  else
  {
  pwm_fall = CC1; //获取捕获寄存器中的值
  pwm_H = pwm_fall - pwm_rise;
  }
  //该变量定时递增(如1ms递增1),在外部中断中清零
  //在主程序中判断,超过一定值时认为PWM占空比为0%或100%
  pwm_time_out = 0;
  }
  }
  123456789101112131415161718192021222324252627282930
  注: pwm_rise/pwm_fall/pwm_L/pwm_H都必须使用无符号数,否则相减时可能得到错误的值。
举报

陈亮

2021-2-3 16:38:41
  方式一任何单片机都可以实现,但是阻塞方式会使系统的实时性变差;
  方式二在使用时,需要保证外部中断的最高优先级,不可以被其他中断打断,以保证其准确性;
  方式三的稳定性和准确性都较高,但是需要MCU硬件支持。
举报

更多回帖

发帖
×
20
完善资料,
赚取积分