阻塞方式
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;
}
阻塞方式
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;
}
举报