打印
[国产单片机]

如何减少误差:外部中断INT0触发定时器T0,计数器T1的频率计

[复制链接]
4687|6
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
ANSI_gao|  楼主 | 2010-8-3 10:14 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 ANSI_gao 于 2010-8-3 10:18 编辑

如何减少误差:外部中断INT0
发定时器T0,计数器T1的频率计
      这几天我做了一个外部中断信号INT0中断触发Timer0计时,Timer1计数 的仿真。做倒是做出来了但误差很大。不知各位大侠有何减少误差的方法。
     关于LCD显示的函数和初始化函数、延时函数太繁琐就不一一列出了
     现在我把主函数和三个中断函数列出来:
/*********************************************************
程序功能:计数两个负边缘触发信号时间间隔T内的外部脉冲个数P
              并在LCD上显示出时间间隔T和脉冲数P
**********************************************************/
.................
/*******************************************************
函数功能:主函数
********************************************************/
void main(void)
{
   LcdInitiate();            //调用LCD初始化函数
  display_sym();             //在LCD上显示时间和脉冲提示符“T=”和“P=”
  display_val1(000);         //初始时在LCD上显示器工作正常标志“0.000”和“00000”
  display_val2(00000);
  display_unit();            //LCD显示时间单位“S”      
   TMOD=0x51;                //定时器T1工作于计数模式1,定时器T0工作于计时模式1;
    EA=1; EX0=1;               //开总中断,
    ET0=1;  
    IT0=1;
     while(1)                 //无限循环
      {
      while(flag==0);    //第一个下降沿启动T0,T1
          TH1=0;            //定时器T1高8位赋初值0
          TL1=0;            //定时器T1低8位赋初值0
          TR1=1;            //定时器T1启动 INT0下降沿触发
      count=0;                    //再赋初值
      TH0=-0x03;
        TL0=-0xe8;
      TR0=1;                    //启动定时器T0         
         while(flag==1);     //第二个下降沿关闭T0,T1
         TR0=0;                         //终止Timer0
         TR1=0;
         flag=0;
         pulse=(unsigned int)(TH1*256+TL1);
         pulse=65536*T1count+pulse;  //脉冲数
         display_val2(pulse);        //显示脉冲数
         display_val1(count);         //显示时间
         T1count=0;           
    }           
}
/*******************************************************
函数功能:定时器T0的中断服务函数
********************************************************/
void Time0(void ) interrupt 1  //定时器T0的中断编号为1,使用第1组工作寄存器
  {
    count++;          //T0每中断1次,count加1
    TH0=-0x03;       /1ms中断一次;
    TL0=-0xe8;
    }

void Int0(void) interrupt 0
  {
    flag++;
   }

void Time1(void) interrupt 3
  {
    T1count++;
    }
------------------------------------------------------------------------------------------------------
用脉冲数pulse除以(countX0.001)S得到脉冲的频率
但是仿真结果误差很大,而且我发现把TH0=-0x03;TL0=-0xe8;改为TH0=TH_M1;TL0=TL_M1;
(#define TH_M1 (65536-1000)/256
#define TL_M1 (65536-1000)%256   结果又不一样)
请各位大侠给点建议怎样才能减小误差

相关帖子

沙发
McuPlayer| | 2010-8-3 14:34 | 只看该作者
你这样计数会计多的

消除误差,有几个方法,我说下我想到的
一个方法是把导致时间拉长的代码浪费的时间算出来,然后从Timer溢出时间中扣除,这个是补偿法
另一个方法是是,Timer第一次溢出中断中启动外部计数,Tmier第二次溢出中断停止外部计数,这个叫做误差消除法

使用特权

评论回复
板凳
必有我师| | 2010-12-15 15:38 | 只看该作者
学习,单片机的东西还真是多呀。

使用特权

评论回复
地板
fulin1314168| | 2011-5-12 10:07 | 只看该作者
看看找些资料来着!

使用特权

评论回复
5
airwill| | 2011-5-13 13:47 | 只看该作者
既然是频率计, 那么只要记下两次中断的时间差就可以实现了.
因此, 只要定时器自由运行, 由 INT0 中断读取计时器的值, 再加上高位值(如 timer1 的溢出累计器),减去上次中断保存的计数器值, 通过这个时间计算频率, 理论上就不会有错.
当然还有一个中断嵌套问题, int 和 timer 中断同时出现的时候, 要判断一下(这也不难, 只是个注意点)
最后滤波运算, 主程序把 INT 中断里记录下的时间差, 进行滤波计算, 然后再变换成要显示的频率值.

;楼主程序的最大毛病在这里:  
        while(flag==1);     //第二个下降沿关闭T0,T1
         TR0=0;                         //终止Timer0
         TR1=0;
         flag=0;
         pulse=(unsigned int)(TH1*256+TL1);
         pulse=65536*T1count+pulse;  //脉冲数
         display_val2(pulse);        //显示脉冲数
         display_val1(count);         //显示时间
         T1count=0;      
   
随便关闭定时器, 没有让它自由运行, 这就错过了(少计了)很多的时间, 导致统计计算出现大量误差.

使用特权

评论回复
6
ABCDELF| | 2013-1-28 23:21 | 只看该作者
这个还真没研究过啊,看来学的不是太扎实啊:(

使用特权

评论回复
7
uet_cache| | 2013-1-30 15:35 | 只看该作者
你的变量定义是不是32位的,16位的,脉冲计数值可能会超过,另个,TR0,TR1应该同时启动,即两条语句可以用一个寄存器赋值。这样时间和频率计算是对应的。
最重要的,你的边沿检测最好加延时,如果你用按键模拟,可能受抖动影响。如果不消抖,就要保证信号的纯净。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

0

主题

11

帖子

1

粉丝