打印
[51单片机]

循环等待定时器中断后,累加次数只要一多,时间就不准,这是为什么?

[复制链接]
2582|4
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
zy02752003|  楼主 | 2015-10-31 12:39 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
循环等待定时器中断后,累加次数只要一多,时间就不准,这是为什么?
HI,ALL
     本来是红外发射码,但是发现只要定时器用得多了,就有问题,只能将代码一点一点删除,现在就剩下发38K脉冲持续500次,延时一段时间,再循环。实测38K持续时间忽长忽短,不知所以,请大侠解释一下。。
#include <reg51.h>
//#include <C51_ZY.h>
sbit P1_1=P1^1;     //  LED
static bit OP;                 //the turn on or off of the IR led
sbit P1_3=P1^3;      // IR pin
static unsigned char flag;     //the flag of IR emission
static unsigned int lead_high;
static unsigned int lead_low;
static unsigned int count;     //delay count
static unsigned int endcount;   //terminate count
void   SendIRdata(void);
void timer0_int(void);
void IR_transfer_test(void);
void delay_100ms(int);
void main(void)  
{
  IE=0x0;
        P1_1=0;
        //AUXR |= 0x80;         //SET TIMER0 1T MODE
  P1M1 &= 0xF7;
  P1M0 |= 0x08;        //SET P1_3 PUSH-PULL MODE
       
               
  timer0_int();
         
        IR_transfer_test();
       
}   
void IR_transfer_test()
{          

                //int i;
//        int j;
        count=0;   
  flag=0;   
        OP=0;   
        P1_3=0;                                       
        lead_high=500;   
        lead_low=500;
       
        do{  
   EA=1;
   SendIRdata();
                EA=0;       
                P1_3=0;
         delay_100ms(1);
                
  } while(1);

}
void SendIRdata()
{         
       
        endcount=lead_high;  
  flag=1;  
  count=0;   
  //ET0=1;TR0 = 1;
       
  do{}while(count<endcount);  

                   
        //TR0 = 0;ET0=0;
        //endcount=lead_low;  
  //flag=0;  
// count=0;   
        //ET0=1;TR0 = 1;
               
  //do{}while(count<endcount);
        // TR0 = 0;ET0=0;
        }
      
void timer0_int()
{                    

  EA=1;
        AUXR |= 0x80;                //定时器时钟1T模式
        TMOD &= 0xF0;                //设置定时器模式
        TMOD |= 0x02;                //设置定时器模式
        TL0 = 0x64;                //设置定时初值
        TH0 = 0x64;                //设置定时重载值
        TF0 = 0;                //清除TF0标志
        ET0=1;
        TR0 = 1;                //定时器0开始计时
   
}
void timeint(void) interrupt 1
{   
       
        count++;          
        if (flag==1)  
         {
                OP=~OP;  
                  
         }
        else   
         {
                 OP = 0;
                 
          }
          P1_3 = OP;
       
}   
void delay_100ms(int k)
{     
  int i,j;   
  for(k;k>0;k--)
{  
  for(i=0;i<150;i++)   
     {
                        for(j=0;j<100;j++);
     }
        }                 
                 
}

相关帖子

沙发
NE5532| | 2015-10-31 21:22 | 只看该作者
你怎么保证中断标志建立的时候主循环不在那个100毫秒延时里?

使用特权

评论回复
板凳
dirtwillfly| | 2015-10-31 22:11 | 只看该作者
边界代码

使用特权

评论回复
地板
无量寿经| | 2015-11-1 23:28 | 只看该作者
对于STC15单片机,38K可用PCA模块实现,只要设置好后,它就不再占用CPU时间。
一下代码来源于
《51单片机轻松入门—基于STC15W4K系列》
例3.8  假设R/C时钟频率Fosc=11.0592MHz,设计程序实现6路时钟输出口输出100Hz~11.0592MHz频率范围的信号。实验代码如下:
// 功能:输出P5.4(MCLKO)——11.0592MHz
//       输出P3.5(T0_CLKO)——5M
//       输出P3.4(T1_CLKO)——38.4KHz
//       输出P3.0(T2_CLKO)——500Hz
//       输出P0.4(T3_CLKO)——200Hz
//       输出P0.6(T4_CLKO)——100Hz

#include"STC15W4K.H"           // 包含 "STC15W4K.H"寄存器定义头文件
#defineFOSC 11059200L          // 假设振荡时钟为11.0592MHz
#defineF5MHz (65536-11059200/2/5000000)   //5MHz
#defineF38_4KHz (65536-11059200/2/38400)  //38.4KHz
#defineF500Hz (65536-11059200/2/500)      //500Hz
#defineF200Hz (65536-11059200/2/200)      //200Hz
#defineF100Hz (65536-11059200/2/100)      //100Hz
voidmain(void)
{
    port_mode();      // 所有IO口设为准双向弱上拉方式。
//*****************  设置主时钟输出,不分频*****************   
    CLK_DIV = 0x40;     // 当使用内部R/C时钟时,R/C时钟频率要求不大于12MHz。
//*****************设置T0和T1时钟输出 *************************
    TMOD = 0x00;        // T0和T1工作在方式0,16位自动重装计数器
    AUXR = AUXR | 0x80;      // T0工作在1T模式(建议使用1T模式,高低频率都方便输出)
    AUXR = AUXR | 0x40;      // T1工作在1T模式(建议使用1T模式,高低频率都方便输出)
// 设置T0的8位自动重装计数初值,输出频率=11059200/2/74约为1MHz
    TL0 = F5MHz;
    TH0 = F5MHz>>8;     
// 设置T1的8位自动重装计数初值,输出时钟频率18432000/2/240= 38400Hz
    TL1 = F38_4KHz;
    TH1 = F38_4KHz>>8;   
    TR0 = 1;           // 启动T0开始计数,对系统时钟进行分频输出
    TR1 = 1;           // 启动T1开始计数,对系统时钟进行分频输出
    INT_CLKO =INT_CLKO|0x03;  //允许T0与T1时钟输出
//*****************设置T2时钟输出*************************
    AUXR = AUXR | 0x04; // T2工作在1T模式(建议使用1T模式,高低频率都方便输出)
    T2L = F500Hz;       // 设置T2重装时间常数的低字节
    T2H = F500Hz>>8;    // 设置T2重装时间常数的高字节     
    AUXR = AUXR |0x10;  // 启动定时器T2
    INT_CLKO |= 0x04;   // 允许T2时钟输出
//*****************设置T3、T4时钟输出 *************************
    T3L = F200Hz;       // 设置T3重装时间常数的低字节
    T3H = F200Hz>>8;    // 设置T3重装时间常数的高字节
    T4L = F100Hz;       // 设置T4重装时间常数的低字节
    T4H = F100Hz>>8;    // 设置T4重装时间常数的高字节
    T4T3M=0xbb;        // T3、T4工作在1T模式并立即运行(建议使用1T模式,高低频率都方便输出)
// 至此时钟已经输出,用户可以通过示波器观看到输出的时钟频率
    while(1);
}
使用VC97万用表测量输出,结果如下:P5.4(MCLKO)=11.07MHz, P3.5(T0_CLKO)=5.535MHz,P3.4(T1_CLKO)=38.44KHz,P3.0(T2_CLKO)=501Hz,P0.4(T3_CLKO)=201Hz,P0.6(T4_CLKO)=100.1Hz
我们发现P3.5=5.535M与标准值5M相比误差较大,不过也是符号我们前面分析结果的。

使用特权

评论回复
5
ayb_ice| | 2015-11-2 08:56 | 只看该作者
本帖最后由 ayb_ice 于 2015-11-2 09:00 编辑

已经有人说了是临界代码的问题,估计LZ也不明白什么叫临界代码,此处类似于计数器飞读

原代码当count值达到256以上就很容易出问题,小于此值不出问题,此时相当于U8变量(高字节固定为0),访问本身是有原子操作的
修改如下

void SendIRdata()
{
        bit b = EA;

        endcount=lead_high;
        flag=1;

        EA = 0;
        count=0;
        EA = b

        while(1)
        {
                U16 t;
                EA = 0;
                t = count;
                EA = b;

                if(t >= endcount){
                        break;
                }
        }
}

使用特权

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

本版积分规则

3

主题

4

帖子

0

粉丝