51单片机测脉冲速度问题
我的脉冲频率不高,不超过100HZ,硬件电路的脉冲数是来自外部的光电转换器开关,现在的问题是,我要显示外部脉冲的瞬时流速。是这样的,我用单片机89S52的P3.2(外部中...
我的脉冲频率不高,不超过100HZ,硬件电路的脉冲数是来自外部的光电转换器开关,现在的问题是,我要显示外部脉冲的瞬时流速。
是这样的,我用单片机89S52的P3.2(外部中断0)的高电平来启动p3.4脚(T0)对外来脉冲数进行计数,并在程序里参与计算,比如一个脉动冲代表0.0068L气体,然后计算出体积量:体积=0.0068*采集的脉冲个数,通过LCD1602显示出来,但现在是除了计算这个体积量外,我还想测量气体的瞬时流速。也就是:L/H(每小时走了多少升)。我的思路是:先在程序里得到L/S(一秒内多少升)然后再乖以3600得到L/H,关键怎样得到这个数。流速的采集频率一般定为多少(毫秒还是秒)。刚开始我采用中断每50毫秒中断一次,总中断20次,就是一秒,然后计算出当前采集的脉冲个数 — 前一次的肪冲个数=一秒内的脉冲个数,得到一秒内的脉冲个数,然后送流速计算和流速送显函数处理。但这有一个问题,在送显示处理期间,要耽搁不少时间,然后再开中断时,继续定时,但这样的流速变化误差太大。
这是定时中断函数:
void T1ISR(void) interrupt 3 //定时中断入口
{
TH1=0x3c;
TL1=0xb0; //定时50MS
t--;
if(t==0)
{
TR0=0;
count_js();
TR0=1; //开启计数器继续计数,以免遗漏脉冲数
c=a-b;//当前计数值减上一次计数值,为一秒内的计数值。
b=a;//上一次的计数值暂存到b,
t=20; //中断20次为一秒。 lx=1; //流速处理标志位,流速计算处理在主程序中进行
/*************************************/
/* 脉冲个数计算 */
/*************************************/
void count_js()
{
a=(th0*256+tl0)+j*65536; //计数值个数存到a
}
/*************************************/
/* 流速计算 */
/*************************************/
void gas_flow_process()
{
c = c*pls*3600; //流速值存到c
我的程序原体就是这样,而且我也经过验证,出来的流速显示与脉冲数的实际速度还是差不多,但关键是流速在不断变化中始终不断的重复两次变化,比如:1392L/H,1368L/H,就一直在这两个数之间变化。两数之间相差36
不管我的模拟频率怎么变化,流速的最大值与最小值之间始终相差36,而且只有两个数的变化,问题就是,这与实际不太相称啊,
曾有朋友建议我这种,频率不高的脉冲,采用测周的方法, 但我不知道测周的思路是怎样的,还没有更好的办法。 展开
是这样的,我用单片机89S52的P3.2(外部中断0)的高电平来启动p3.4脚(T0)对外来脉冲数进行计数,并在程序里参与计算,比如一个脉动冲代表0.0068L气体,然后计算出体积量:体积=0.0068*采集的脉冲个数,通过LCD1602显示出来,但现在是除了计算这个体积量外,我还想测量气体的瞬时流速。也就是:L/H(每小时走了多少升)。我的思路是:先在程序里得到L/S(一秒内多少升)然后再乖以3600得到L/H,关键怎样得到这个数。流速的采集频率一般定为多少(毫秒还是秒)。刚开始我采用中断每50毫秒中断一次,总中断20次,就是一秒,然后计算出当前采集的脉冲个数 — 前一次的肪冲个数=一秒内的脉冲个数,得到一秒内的脉冲个数,然后送流速计算和流速送显函数处理。但这有一个问题,在送显示处理期间,要耽搁不少时间,然后再开中断时,继续定时,但这样的流速变化误差太大。
这是定时中断函数:
void T1ISR(void) interrupt 3 //定时中断入口
{
TH1=0x3c;
TL1=0xb0; //定时50MS
t--;
if(t==0)
{
TR0=0;
count_js();
TR0=1; //开启计数器继续计数,以免遗漏脉冲数
c=a-b;//当前计数值减上一次计数值,为一秒内的计数值。
b=a;//上一次的计数值暂存到b,
t=20; //中断20次为一秒。 lx=1; //流速处理标志位,流速计算处理在主程序中进行
/*************************************/
/* 脉冲个数计算 */
/*************************************/
void count_js()
{
a=(th0*256+tl0)+j*65536; //计数值个数存到a
}
/*************************************/
/* 流速计算 */
/*************************************/
void gas_flow_process()
{
c = c*pls*3600; //流速值存到c
我的程序原体就是这样,而且我也经过验证,出来的流速显示与脉冲数的实际速度还是差不多,但关键是流速在不断变化中始终不断的重复两次变化,比如:1392L/H,1368L/H,就一直在这两个数之间变化。两数之间相差36
不管我的模拟频率怎么变化,流速的最大值与最小值之间始终相差36,而且只有两个数的变化,问题就是,这与实际不太相称啊,
曾有朋友建议我这种,频率不高的脉冲,采用测周的方法, 但我不知道测周的思路是怎样的,还没有更好的办法。 展开
展开全部
针对你的脉冲速率,的确应该采用“测周”的方法。
你已经注意到了流速不断的重复两次变化,比如:1392L/H,1368L/H,两数之间相差36。
实际上,这是你检测的脉冲个数,在“两个”相邻的数字上变化,如100、101。
你反过来换算一下,36,是不是对应一个脉冲?
这说明,“测频”的方法,精度已经达到极限。
这时,采用“测周”的方法,精度会提高很多。
测周,是测量两个下降(或上升)沿之间的时间,约100Hz的信号,单片机可得到10000的时间数据(12MHz的晶振),考虑到正负1的误差,可能为9999~10001。
换算出“脉冲个数”,就是100.01~99.99,折算成流量,将是0.36的差别。
你已经注意到了流速不断的重复两次变化,比如:1392L/H,1368L/H,两数之间相差36。
实际上,这是你检测的脉冲个数,在“两个”相邻的数字上变化,如100、101。
你反过来换算一下,36,是不是对应一个脉冲?
这说明,“测频”的方法,精度已经达到极限。
这时,采用“测周”的方法,精度会提高很多。
测周,是测量两个下降(或上升)沿之间的时间,约100Hz的信号,单片机可得到10000的时间数据(12MHz的晶振),考虑到正负1的误差,可能为9999~10001。
换算出“脉冲个数”,就是100.01~99.99,折算成流量,将是0.36的差别。
展开全部
89S52单片机我现在也不怎么用了 呵呵 不过你这个还是不难的
首先 分析一下 频率不是很高 100Hz 用单片机捕捉每个脉冲的边缘也是可以的 这样每个边缘的时刻你都清楚了 你说的问题也就解决了 对不对?
说一下具体实现 我记得S52是有T2定时器的 这个定时器应该带捕获模式~ 这样就是可以记录脉冲的精确时间了 具体实现你还是要参照下手册 细节记不清了
如果不用T2 可以用外部中断 每个下降沿进中断 记录下定时器的时刻 也可以~ 但是有点小问题就是如果不停定时器 那么8bit CPU 读16bit数据要两次 碰上正好进位就麻烦了 再就是停定时器 然后软件补偿一下这个误差 还有其他方法~
你的方法相当于 测定时长内的脉冲个数 对脉冲细节不敏感 所以会出现问题 这个方法适合测比较高的频率 比如50ms有5000个脉冲~ 一个一个脉冲去关注你当然受不了了~
应该满意了吧?
首先 分析一下 频率不是很高 100Hz 用单片机捕捉每个脉冲的边缘也是可以的 这样每个边缘的时刻你都清楚了 你说的问题也就解决了 对不对?
说一下具体实现 我记得S52是有T2定时器的 这个定时器应该带捕获模式~ 这样就是可以记录脉冲的精确时间了 具体实现你还是要参照下手册 细节记不清了
如果不用T2 可以用外部中断 每个下降沿进中断 记录下定时器的时刻 也可以~ 但是有点小问题就是如果不停定时器 那么8bit CPU 读16bit数据要两次 碰上正好进位就麻烦了 再就是停定时器 然后软件补偿一下这个误差 还有其他方法~
你的方法相当于 测定时长内的脉冲个数 对脉冲细节不敏感 所以会出现问题 这个方法适合测比较高的频率 比如50ms有5000个脉冲~ 一个一个脉冲去关注你当然受不了了~
应该满意了吧?
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
展开全部
考虑超出取值范围,否则会出现错误的。
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
展开全部
可以试一下这种方法:
在程序的某一位置放一个标志位,例如P1.0,先置1再置0.然后用示波器来测P1.0口的输出频率.这样就可以得到你那段程序所消耗的时间.
在程序的某一位置放一个标志位,例如P1.0,先置1再置0.然后用示波器来测P1.0口的输出频率.这样就可以得到你那段程序所消耗的时间.
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
推荐律师服务:
若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询