标题: 想知道怎么用51单片机接收PWM信号 [打印本页]

作者: Ruuci    时间: 2022-4-19 19:12
标题: 想知道怎么用51单片机接收PWM信号
我的二氧化碳传感器MH-Z19输出的是PWM信号,我要用51单片机的I/O口接收这个信号,怎么获得PWM的占空比呢?我听说用一个外部中断和定时器可以实现,我在网上看到了一个接收的方式,用了外部中断0和计数器0,但是他用的STC15F100W-STC15F104W芯片,这个芯片的外部中断0检测到上升沿和下降沿都会进入外部中断,检测到上升沿就开启计数器从零开始计数,检测到下降沿就获取计数值(得到了高电平持续的时间),再将计数器置零等待下一个上升沿。我的芯片是STC89C516RD+,外部中断只能检测到下降沿,所以用不了上述方法。
求问还有什么方式可以检测到PWM的占空比?
(其实二氧化碳传感器MH-Z19也能用串口传输数据,但是我的芯片只有一个串口,而且串口要与上位机通信,所以只能选择PWM的形式了)

作者: 188610329    时间: 2022-4-19 21:22
不在乎性能的话,在外部中断中处理完下降沿的工作后while(p32==0);  等到上升沿后处理完上升沿的活,再退出中断。 在乎性能的话,int0直接接pwm输入,int1通过反向器接pwm,分别处理上升沿和下降沿,当然也可以用npn代替反向器。
作者: 51FAN2020    时间: 2022-4-19 21:31
PWM转换成电压信号给单片机,单片机ADC取值后除以基准,得到占空比。
此方案有微小的误差(~1%),看你的取决了。
作者: npn    时间: 2022-4-20 06:27
51FAN2020 发表于 2022-4-19 21:31
PWM转换成电压信号给单片机,单片机ADC取值后除以基准,得到占空比。
此方案有微小的误差(~1%),看你的 ...

此型号不支持ADC,建议使用STC8系列,其次STC15

作者: wulin    时间: 2022-4-20 09:15
MH-Z19有两种输出:UART和PWM。
1.采用沙发建议。
2.加74157,串口分时复用。
3.换增强型芯片。
作者: Ruuci    时间: 2022-4-20 22:44
188610329 发表于 2022-4-19 21:22
不在乎性能的话,在外部中断中处理完下降沿的工作后while(p32==0);  等到上升沿后处理完上升沿的活,再退 ...

感谢 我的问题已经解决
作者: Ruuci    时间: 2022-4-20 22:44
wulin 发表于 2022-4-20 09:15
MH-Z19有两种输出:UART和PWM。
1.采用沙发建议。
2.加74157,串口分时复用。

感谢 我的问题已经解决
作者: Ruuci    时间: 2022-4-20 22:45
51FAN2020 发表于 2022-4-19 21:31
PWM转换成电压信号给单片机,单片机ADC取值后除以基准,得到占空比。
此方案有微小的误差(~1%),看你的 ...

感谢 我的问题已经解决
作者: Ruuci    时间: 2022-4-20 22:45
npn 发表于 2022-4-20 06:27
此型号不支持ADC,建议使用STC8系列,其次STC15

感谢 我的问题已经解决
作者: Ruuci    时间: 2022-4-20 23:36
我今天突然顿悟,只用STC89C516RD+单片机的定时器1实现了PWM信号的检测。大概是这样的:利用定时器,1ms进入一次中断,在中断函数中,利用if检测上升沿和下降沿,遇到上升沿就用一个变量保存高电平持续时间;遇到下降沿,就继续记录PWM持续时间,直到遇到下一个上升沿,将记录的PWM持续时间存起来。就得到了高电平持续时间和整个PWM持续时间,进而得到占空比。实测可行。
但是每1ms就进入一次中断,可能有点不好,但我说不出来哪不好。
作者: 188610329    时间: 2022-4-21 00:21
Ruuci 发表于 2022-4-20 23:36
我今天突然顿悟,只用STC89C516RD+单片机的定时器1实现了PWM信号的检测。大概是这样的:利用定时器,1ms进 ...

你的思路是对的,
1ms的确不妥, 1ms 的间隔有点太长了误差可能会大。如果只是要得到频占比的话,定时器最好是 8位自动重载模式,定时20us左右, 采样次数尽可能的多一点,10000以上吧,结果会比较精确。程序大致如下(供参考):

#define Duty_Value 50000  //设置量程 (0~65535) 这里定义5万次,20us间隔,大约1秒 计算一次频占比,
bit PWM_Done;            //标志
unsigned short Duty_H,Duty_L,PWM_H,PWM_L,Duty_ount;   //用到的变量
sbit PWM_IO = P3^2;   //定义 PWM输入引脚  (任意引脚)

void PWM_Get_Inti() //初始化
{
Duty_H = 0;
Duty_L = 0;
Duty_count = Duty_Value;
PWM_Done = 0;
//此处定义定时器
}

void T0_Int() interrupt 1     //中断
{
if(PWM_IO)
{
  Duty_H++; //测量高电平比
}
else
{
  Duty_L++; //测量低电平比
}
if(--Duty_count==0)
{
  PWM_H = Duty_H; //保存高电平比
  PWM_L = Duty_L; //保存低电平比
  Duty_H = 0; //复位
  Duty_L = 0;
  Duty_count = Duty_Value;
  PWM_Done = 1;
}
}

//主程序内:
if(PWM_Done)
{
PWM_Done = 0;  //清标志
//计算 频占比  如:    PWM_H * 100/ Duty_Value  得出 x% 高电平比,根据需要拟定
}



作者: datouyuan    时间: 2022-4-21 08:43
楼主这办法,pwm频率越低,精度越高。
假如要达到100的分辨率,要远低于10Hz才行。

芯片是STC89C516RD+,外部中断只能检测到下降沿,

1.通过加反相器(例如一个npn管)来检测上升沿。
2.串口不够,可以考虑用io模拟串口。

我更倾向于用io模拟串口。
作者: Ruuci    时间: 2022-4-21 22:32
188610329 发表于 2022-4-21 00:21
你的思路是对的,
1ms的确不妥, 1ms 的间隔有点太长了误差可能会大。如果只是要得到频占比的话,定时器 ...

其实我1ms进入一次中断,是怕太频繁了,导致其他器件不能正常运行。我的DIY小玩意是检测温度,湿度,和CO2。温度湿度都好说,就是这个CO2的检测麻烦。接受PWM信号用了定时器中断,1ms中断一次,我把检测CO2和温湿度代码合在一起,然后我的我的LCD1602显示就出问题了。
作者: 188610329    时间: 2022-4-21 22:58
Ruuci 发表于 2022-4-21 22:32
其实我1ms进入一次中断,是怕太频繁了,导致其他器件不能正常运行。我的DIY小玩意是检测温度,湿度,和CO ...

你定时器中断 1ms 进入一次,只是读个高低电平,然后  ++ , -- 的话,绝对不会影响 其他程序运行的,所以,你不需要担心 1ms 太短,影响性能, 只需要担心 1ms 太长,准确度太低的问题就可以了。




欢迎光临 (http://www.51hei.com/bbs/) Powered by Discuz! X3.1