打印
[STC单片机]

我这个定时器为什么误差这么大?一分钟误差有20秒!

[复制链接]
5126|29
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
xichandoujigu|  楼主 | 2018-1-3 09:19 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
之前没用中断的时候有误差,想减少误差用了中断,不知道哪里不对,误差更大了。谢谢!
                                                                                 
#include <REG51.H>
unsigned char Tab[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};

sbit P37=P3^3;
sbit P36=P3^4;
sbit P35=P3^5;
sbit P34=P3^7;
sbit beep=P3^2;
char zhongduan_cnt;

void init()
{   
      TMOD=0x01; //定时器初始化  选择timer0做16位定时器  
       TH0=(65536-50000)/256;  
           TL0=(65536-50000)%256;     
        EA=1;    //开放中断
          ET0=1;  //开放timer0中断  
          TR0=1;  //启动timer0  
}



void timer0(void) interrupt 1 using 1
{
       TH0=(65536-50000)/256+TH0;  
           TL0=(65536-50000)%256+TL0;   
          zhongduan_cnt++;  

}



void Delay_beep(char x)
{   char t;   while(x--) for(t=0;t<120;t++);  }   //按周期t发音

void Play(char t)
{    char i;   for(i=0;i<100;i++)  {   beep=~beep;  Delay_beep(t);  }   beep=0;  }  


  //10ms延时子程序(12MHZ)
   void delay_ms(void)
{  
unsigned char i,j,k;

         for(i=5;i>0;i--)

         for(j=4;j>0;j--)

         for(k=248;k>0;k--);

        }


void display(unsigned int fen_gao,fen_di,miao_gao,miao_di)

{

P1 = 0X00;
P37=1;  
P1=Tab[fen_gao];
delay_ms() ;
P37=0;

P1 = 0X00;
P36=1;  
P1=Tab[fen_di];
delay_ms() ;
P36=0;

P1 = 0X00;
P35=1;  
P1=Tab[miao_gao];
delay_ms() ;
P35=0;

P1 = 0X00;
P34=1;  
P1=Tab[miao_di];
delay_ms() ;
P34=0;

}




  /*********主程序********************/
void main() {

unsigned  int fen_gao;        //分十位
unsigned  int fen_di;        //分个位
unsigned  int miao_gao; //秒十位
unsigned  int miao_di;        // 秒个位





beep=0;
miao_di=0;
miao_gao=0;
fen_di=0;
fen_gao=0;



P35=0;  
P37=0;
P34=0;
P36=0;

init();

while(1)
{

  if         (miao_di==0)
  if         (miao_gao==0)
   if         (fen_di==0)
    if         (fen_gao==5)
        {
        while(1)
        {
                Play(1);
        }
        }

        if(zhongduan_cnt==20) //如果到了1S
            {
                zhongduan_cnt=0; //清零
                 miao_di++; //秒数累加
            }


if (miao_di>9)
{
    miao_gao=miao_gao+1;
    miao_di=0;}


if (miao_gao>5)
{
   fen_di=fen_di+1;
   miao_gao=0;
}



if (fen_di>9)
{
  fen_gao=fen_gao+1;
fen_di=0;}

display(fen_gao,fen_di,miao_gao,miao_di);
                }
                   }


相关帖子

沙发
574007815| | 2018-1-3 09:50 | 只看该作者
中断函数赋初值貌似有问题
void timer0(void) interrupt 1 using 1
{
       TH0=(65536-50000)/256
           TL0=(65536-50000)%256  
          zhongduan_cnt++;  

}

使用特权

评论回复
板凳
xichandoujigu|  楼主 | 2018-1-3 10:00 | 只看该作者
574007815 发表于 2018-1-3 09:50
中断函数赋初值貌似有问题
void timer0(void) interrupt 1 using 1
{

哪里有问题呢?这个是50ms,20次就1秒,应该是这样的吧。

使用特权

评论回复
地板
xichandoujigu|  楼主 | 2018-1-3 10:00 | 只看该作者
刚才又试了用外部的12m晶振,效果一样。

使用特权

评论回复
5
ayb_ice| | 2018-1-3 10:05 | 只看该作者
主循环中的
if(zhongduan_cnt==20) //如果到了1S
逻辑上有问题
应该通过标志来处理
或者改为zhongduan_cnt>=20

使用特权

评论回复
6
ayb_ice| | 2018-1-3 10:08 | 只看该作者
void timer0(void) interrupt 1 using 1
{
        TH0  = (65536-50000)/256;  
        TL0 |= (65536-50000)%256;   
        zhongduan_cnt++;  
}

使用特权

评论回复
评分
参与人数 1威望 +2 收起 理由
xichandoujigu + 2
7
574007815| | 2018-1-3 10:11 | 只看该作者
xichandoujigu 发表于 2018-1-3 10:00
哪里有问题呢?这个是50ms,20次就1秒,应该是这样的吧。

         TH0 ,TL0赋初值不用再次加上TH0,TL0了吧?

          TH0=(65536-50000)/256+TH0;  
           TL0=(65536-50000)%256+TL0;

改成这样试试
          TH0=(65536-50000)/256
           TL0=(65536-50000)%256  

使用特权

评论回复
8
xichandoujigu|  楼主 | 2018-1-3 10:21 | 只看该作者
574007815 发表于 2018-1-3 10:11
TH0 ,TL0赋初值不用再次加上TH0,TL0了吧?

          TH0=(65536-50000)/256+TH0;  

嗯,把加号已经去掉了。

使用特权

评论回复
9
xichandoujigu|  楼主 | 2018-1-3 10:24 | 只看该作者
ayb_ice 发表于 2018-1-3 10:08
void timer0(void) interrupt 1 using 1
{
        TH0  = (65536-50000)/256;  

谢谢,按照你的修改,准确多了,不过还是有些误差,我测了下
2分钟慢6秒
3分钟慢8秒
4分钟慢10秒
5分钟慢13秒
6分钟慢16秒
正在思考如何改进。。。。

使用特权

评论回复
10
xichandoujigu|  楼主 | 2018-1-3 10:24 | 只看该作者
ayb_ice 发表于 2018-1-3 10:08
void timer0(void) interrupt 1 using 1
{
        TH0  = (65536-50000)/256;  

谢谢,按照你的修改,准确多了,不过还是有些误差,我测了下
2分钟慢6秒
3分钟慢8秒
4分钟慢10秒
5分钟慢13秒
6分钟慢16秒
正在思考如何改进。。。。

使用特权

评论回复
11
ayb_ice| | 2018-1-3 10:37 | 只看该作者
再修改下
        if(zhongduan_cnt >= 20) //如果到了1S
        {
                //zhongduan_cnt=0; //清零
                EA = 0;
                zhongduan_cnt -= 20;
                EA = 1;
               
                miao_di++; //秒数累加
        }
另外要看晶振准不准了

使用特权

评论回复
评论
tianqi911 2018-8-29 14:28 回复TA
高人就是高人。 
12
xichandoujigu|  楼主 | 2018-1-3 10:39 | 只看该作者
xichandoujigu 发表于 2018-1-3 10:24
谢谢,按照你的修改,准确多了,不过还是有些误差,我测了下
2分钟慢6秒
3分钟慢8秒

问题解决了,把大于20改成大于19,试了6分钟,没有误差。  :)

使用特权

评论回复
13
xuyaqi| | 2018-1-3 11:12 | 只看该作者
不应该在中断里又做除法又取余,占用太多时间,缺乏实时性,完全可以事先算好直接赋值省时间。

使用特权

评论回复
评论
ayb_ice 2018-1-3 14:59 回复TA
这里的操作是常量,编译器会计算最终的结果,不占用额外时间,这样可读性强 
14
mcu5i51| | 2018-1-3 14:27 | 只看该作者
TR0 = 0;
TL0 += -5000-n;
TH0 += -5000-n;
TR0 = 1;
n为以上指令的周期

使用特权

评论回复
15
mcu5i51| | 2018-1-3 14:31 | 只看该作者
对了数据是负的,要加括号或加上周期数,标准51中为7个周期

使用特权

评论回复
16
xichandoujigu|  楼主 | 2018-1-3 21:05 | 只看该作者
本帖最后由 xichandoujigu 于 2018-1-3 21:39 编辑

大家再帮我看看,又出问题了,我把蜂鸣器也去掉了,就剩单片机(stc12c2052AD)和数码管(5641BH),现在时间还是慢了,比正常慢一倍。
                                                                                 
#include <REG51.H>
unsigned char Tab[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};

sbit P37=P3^3;
sbit P36=P3^4;
sbit P35=P3^5;
sbit P34=P3^7;
char zhongduan_cnt;

void init()
{   
      TMOD=0x01; //定时器初始化  选择timer0做16位定时器  
       TH0=0x3c;//(65536-50000)/256;  
           TL0=0xb0;//(65536-50000)%256;     
        EA=1;    //开放中断
          ET0=1;  //开放timer0中断  
          TR0=1;  //启动timer0  
}

void timer0(void) interrupt 1 using 1
{
           TH0  = 0x3c; //TH0  =(65536-50000)/256;
        TL0 |= 0xb0;//这里写成TL0 = 0x3c效果一样,还有这里我没理解ayb_ice的为什么要写成或的关系。 //TL0=(65536-50000)%256;  
        zhongduan_cnt++;  
}

  //10ms延时子程序(12MHZ)
   void delay_ms(void)
{  
    unsigned char i,j,k;

         for(i=5;i>0;i--)                             
         for(j=4;j>0;j--)
         for(k=248;k>0;k--);

        }

void display(unsigned int fen_gao,fen_di,miao_gao,miao_di)

{
P1 = 0X00;
P37=1;  
P1=Tab[fen_gao];
delay_ms() ;
P37=0;

P1 = 0X00;
P36=1;  
P1=Tab[fen_di];
delay_ms() ;
P36=0;

P1 = 0X00;
P35=1;  
P1=Tab[miao_gao];
delay_ms() ;
P35=0;

P1 = 0X00;
P34=1;  
P1=Tab[miao_di];
delay_ms() ;
P34=0;

}

  /*********主程序********************/
void main() {

unsigned  int fen_gao;        //分十位
unsigned  int fen_di;        //分个位
unsigned  int miao_gao; //秒十位
unsigned  int miao_di;        // 秒个位

miao_di=0;
miao_gao=0;
fen_di=0;
fen_gao=0;
zhongduan_cnt=0;

P35=0;  
P37=0;
P34=0;
P36=0;

init();

while(1)
{
        if(zhongduan_cnt>20) //如果到了1S
            {
               zhongduan_cnt=0; //清零
                miao_di++; //秒数累加

                        /*         EA = 0;
                zhongduan_cnt -= 20;
                EA = 1;
                                miao_di++; //秒数累加
                                */
            }

if (miao_di>9)
{
    miao_gao=miao_gao+1;
    miao_di=0;}

if (miao_gao>5)
{
   fen_di=fen_di+1;
   miao_gao=0;
}

if (fen_di>9)
{
  fen_gao=fen_gao+1;
fen_di=0;}

display(fen_gao,fen_di,miao_gao,miao_di);

if         (miao_di==0)
  if         (miao_gao==0)
   if         (fen_di==0)
    if         (fen_gao==20)
        {
        while(1)
        {
        //        Play(1);
        }
        }

               }
                   }

使用特权

评论回复
17
xichandoujigu|  楼主 | 2018-1-3 21:07 | 只看该作者
本帖最后由 xichandoujigu 于 2018-1-3 21:36 编辑

使用特权

评论回复
18
xichandoujigu|  楼主 | 2018-1-3 22:12 | 只看该作者
最终确定内部晶振误差太大,用外部晶振就行了。

使用特权

评论回复
19
linqing171| | 2018-1-4 13:19 | 只看该作者
你的定时器没有auto reload 模式么? 每次进入中断后重新装载,但是如果主循环关一段时间中断呢? 如果有其它中断呢? 如果进中断之前每次执行的指令都不同导致进入中断的延迟略有变化呢?

使用特权

评论回复
20
gx_huang| | 2018-1-4 13:27 | 只看该作者
关于定时器,都是简单的问题,只有自己反复研究,才会有进步。
进步一,知道准确的定时器原理。
进步二,知道如何分析和解决问题。

使用特权

评论回复
评论
山东电子小菜鸟 2018-1-6 13:11 回复TA
感谢您的进步 
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

31

主题

96

帖子

2

粉丝