找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 10282|回复: 17
收起左侧

51单片机定时器中断进不去

  [复制链接]
ID:326418 发表于 2018-5-9 23:12 | 显示全部楼层 |阅读模式
写了一段单片机外部中断计数控制定时器输出0.5khz方波驱动无源蜂鸣器的程序,但是无论下载到开发板上还是isis7模拟,又或者在keil里调试,都无法进入定时器中断。看着想了一天改了一天,实在是不知道为什么,编程能力真的太菜了。。。。刚注册,有什么不知道的规矩没遵守还请见谅,如果帖子违反了版规,我自行删除。
下面是我的程序。。
  1. #include<reg52.h>
  2. #define uchar unsigned char
  3. #define uint unsigned int
  4. void delay(uint z);
  5. sbit k0=P3^2;
  6. sbit spk=P0^0;
  7. uchar a=0;

  8. void int0() interrupt 0
  9. {
  10.        if(k0==0)
  11.       {
  12.             a++;
  13.             if(a>3)
  14.             {
  15.                    a=0;
  16.             }
  17.       }
  18. }
  19. void timer0() interrupt 1
  20. {
  21.        spk=!spk;
  22.        TH0=0xFC;
  23.        TL0=0x18;
  24. }
  25. void delay(uint z)
  26. {
  27.        uint x,y;
  28.        for(x=z;z>0;x--)
  29.        for(y=245;y>0;y--);
  30. }
  31. void main()
  32. {  
  33.        TMOD=0X11;
  34.      //IE=0x83;
  35.        EA=1;
  36.        EX0=1;
  37.        IT0=1;
  38.   
  39.    
  40. ET0=1;
  41.      
  42. PT0=1;
  43.      
  44. PX0=0;
  45.      
  46. TH0=0xFC;
  47.      
  48. TL0=0x18;
  49.      
  50. if(a>2)     //就是这里,keil里调试发现a>2的时候还是无法进入定时。
  51.      
  52. {
  53.            
  54. TR0=1;
  55.            
  56. delay(50000);
  57.            
  58. delay(50000);
  59.            
  60.   delay(50000);
  61.            
  62. delay(50000);
  63.      
  64.      
  65.   TR0=0;
  66.      
  67. }
  68. else TR0=0;
  69. while(1);
  70. }
复制代码


回复

使用道具 举报

ID:326418 发表于 2018-5-10 23:30 | 显示全部楼层
我要再补一段函数的问题。。。
#include <reg52.h>

sbit MDA = P2^0;   //步进电机驱动口
sbit MDB = P2^1;
sbit MDC = P2^2;
sbit MDD = P2^3;
sbit SEN = P3^2;   //传感器接口
sbit BUZ = P3^7;   //蜂鸣器
unsigned char time0 = 0; //定时器溢出次数
unsigned char time1 = 0;
unsigned char wei = 0;  //电机驱动指针
unsigned char num = 0;  //计数值
unsigned char flagd = 0; //方向标志
unsigned char second = 0; //秒数

//延时函数
void delay_ms(unsigned int s)
{                           
   unsigned int k;
   while(s--)
   {
     for(k=0; k<120; k++);
   }
}


void main(void)
{
unsigned char flags = 0;
TMOD = 0X11;     //工作模式1:16位计时器
TH0 = (65536-50000)/256;  //T0初值:50ms
TL0 = (65536-50000)%256;
TH1 = (65536-1000)/256;   //T1初值:1ms
TL1 = (65536-1000)%256;
IT0 = 1;      //外部中断0下降沿触发
      
EA = 1;       //中断初始化
ET0  = 1;
ET1  = 1;
EX0 = 1;
PT0=1;
PT1=1;
PX0=0;

while(1)
{
}
}
//外部中断服务函数
void INT0_ISR(void) interrupt 0
{
EX0 = 0;
delay_ms(10);
if(SEN == 0)  //确认低电平有效
{
  num++;   //递增
  if(num == 3) //达到3次
  {
   TR0 = 1; //开始工作
   TR1 = 1;
   flagd = 0;
   second = 0;
   return;
  }
  else
  {
   EX0 = 1; //未达3次,使能中断
  }
}
}

//T0中断服务函数
void T0_ISR(void) interrupt 1
{
TH0 = (65536-50000)/256;
TL0 = (65536-50000)%256;
time0++;      
if(time0 == 20)    //计时1s
{
  time0 = 0;  
  second++;
  if((second == 60)&&(flagd == 0)) //计时达到60秒
  {
   flagd = 1;     //反向
   second = 0;
  }
  else if((second == 60)&&(flagd == 1)) //反转60秒,关闭
  {
   flagd=0;
   second=0;
   TR0 = 0;
   TR1 = 0;
   num = 0;
   EX0 = 1;
  }
}
}
//T1中断服务函数
void T1_ISR(void) interrupt 3
{
TH1 = (65536-1000)/256;
TL1 = (65536-1000)%256;
BUZ = !BUZ;
time1++;
if(time1 == 10) //10ms输出一个驱动脉冲
{
  time1 = 0;
  if(flagd == 0)  //正转
  {
   wei = (wei+1)%4; //正向输出驱动脉冲
  }
  else if(flagd==1)    //反转
  {
   wei = (wei+3)%4; //反向输出驱动脉冲
  }
  P2 = 0XFF;     //输出驱动脉冲
  P2 &= ~(1<<wei);
}
}
这段程序有一个问题,在keil里调试的时候,发现如果定时器0和1在运行中,P3^2口继续得到信号,EX0在定时器中断程序运行结束后未被置位,这时P3^2口得到信号就无法进入外部中断服务程序。
而如果在定时器0和1运行时不给P3^2口信号,定时器中断程序结束后,这时P3^2口继续得到信号是可以进入外部中断程序的。
还有一点是我把程序下进开发板,发现无法运行,怎么给信号都不驱动蜂鸣器和步进电机,但是在keil里调试或在isis7里模拟,是可以输出方波的。
抓狂中。。。。。

回复

使用道具 举报

ID:213173 发表于 2018-5-10 06:29 | 显示全部楼层
改成这样试试
#include<reg52.h>
#define uchar unsigned char
#define uint unsigned int
void delay(uint z);
sbit k0=P3^2;
sbit spk=P0^0;
uchar a=0;
bit b=0;
void int0() interrupt 0
{
        if(k0==0)
        {
                a++;
                if(a>=3)
                {
                        a=0;
                        b=1;
                }
        }
}
void timer0() interrupt 1
{
        spk=!spk;
//        TH0=0xFC;
//        TL0=0x18;
}

void delay(uint z)
{
        uint x,y;
//        for(x=z;z>0;x--)
        for(x=z;x>0;x--)
                for(y=245;y>0;y--);
}

void main()
{  
        TMOD= 0x02;                //设置定时器模式2,8位自动重载
        TL0 = 0x06;                //设置定时初值,250us
        TH0 = 0x06;                //设置定时重载值
        EA=1;
        EX0=1;
        IT0=1;
        ET0=1;
        PT0=1;
        PX0=0;
//        TH0=0xFC;
//        TL0=0x18;
/*        if(a>2)     //就是这里,keil里调试发现a>2的时候还是无法进入定时。
        {
                TR0=1;
                delay(50000);
                delay(50000);
                delay(50000);
                delay(50000);
                TR0=0;
        }
        else TR0=0;*/
        while(1)
        {
                if(b==1)
                {
                        b=0;
                        TR0=1;
                        delay(50000);
                        delay(50000);
                        delay(50000);
                        delay(50000);
                        TR0=0;
                        spk=1;//恢复初态
                }
        }
}

评分

参与人数 1黑币 +8 收起 理由
DisTanCeRaIn + 8 很给力!

查看全部评分

回复

使用道具 举报

ID:289989 发表于 2018-5-10 08:56 | 显示全部楼层
你这个,我也不是很懂~但是感觉你在第一次判断a>2时是不成立的,进入else  后面有个while(1)这个不就停这了么?

评分

参与人数 1黑币 +8 收起 理由
DisTanCeRaIn + 8 很给力!

查看全部评分

回复

使用道具 举报

ID:164602 发表于 2018-5-10 09:00 | 显示全部楼层
你的程序,我研究了,修改了一下,可以通过外部中断按键让蜂鸣器发声音了。
由于不明白你的a变量是干什么用的,就没有动这个部分。目前的现象是:
先按键,按下第二次,蜂鸣器就开始响了,关不了。不知道你是不是这样设置的。
#include<reg52.h>
#define uchar unsigned char
#define uint unsigned int
void delay(uint z);
sbit k0=P3^2;
sbit spk=P0^0;
uchar a=0;

void int0() interrupt 0
{
       if(k0==0)
      {
            a++;
            if(a>3)
            {
                   a=0;
            }
      }
}
void timer0() interrupt 1
{
       spk=!spk;
       TH0=0xFC;
       TL0=0x18;
}
void delay(uint z)
{
       uint x,y;
       for(x=z;z>0;x--)
       for(y=245;y>0;y--);
}
void main()
{  
       TMOD=0X11;
     //IE=0x83;
       EA=1;
       EX0=1;
       IT0=1;
  
   
ET0=1;
     
PT0=1;
     
PX0=0;
     
TH0=0xFC;
     
TL0=0x18;
     

while(1)
{
if(a>2)     //就是这里,keil里调试发现a>2的时候还是无法进入定时。
     
{
           
TR0=1;
           
delay(50000);
           
delay(50000);
           
  delay(50000);
           
delay(50000);
     
     
  TR0=0;
     
}
else TR0=0;
}
}

这是另外一个修改的程序,可以通过按键,按若干次,可以让蜂鸣器一会儿响,一会儿不响,不知道能你有没有用。也给你吧:
#include<reg52.h>

#define uchar unsigned char
#define uint unsigned int

void delay(uint z);

sbit k0=P3^2;
sbit spk=P0^0;

uchar a=0;

void Delay10ms(unsigned char c)
{
    unsigned char a,b;
    for(;c>0;c--)
        for(b=38;b>0;b--)
            for(a=130;a>0;a--);
}

void main()
{  
        TMOD = 0x01;                //设置定时器模式
        TL0 = 0x30;                //设置定时初值
        TH0 = 0xF8;                //设置定时初值
        TF0 = 0;                //清除TF0标志
        TR0 = 0;                //定时器0开始计时
        ET0=1;
    EA=1;
    EX0=1;
    IT0=1;
          PT0=0;
    PX0=1;
     
        while(1)
        {
        if(a>2)     //就是这里,keil里调试发现a>2的时候还是无法进入定时。
        {
           
                TR0=1;
           
                Delay10ms(100);
           
     
                TR0=0;
     
        }
        else TR0=0;
       
        }
}

void int0() interrupt 0
{
                        Delay10ms(5);
            a++;
            if(a>3)
            {
                   a=0;
            }
                        IE0=0;
}

void timer0() interrupt 1
{
       spk=!spk;
        TL0 = 0x30;                //设置定时初值
        TH0 = 0xF8;                //设置定时初值
       
}




评分

参与人数 2黑币 +68 收起 理由
admin + 60 回帖助人的奖励!
DisTanCeRaIn + 8 很给力!

查看全部评分

回复

使用道具 举报

ID:318783 发表于 2018-5-10 09:57 | 显示全部楼层
程序有错啊
回复

使用道具 举报

ID:326418 发表于 2018-5-10 19:06 来自手机 | 显示全部楼层
wulin 发表于 2018-5-10 06:29
改成这样试试
#include
#define uchar unsigned char

大佬,你改的程序我试了一下,很成功。请教一下,用定时器模式2,进入定时器中断,主程序在运行的同时定时器也在运行吗?
回复

使用道具 举报

ID:326418 发表于 2018-5-10 19:18 来自手机 | 显示全部楼层
Yubug 发表于 2018-5-10 08:56
你这个,我也不是很懂~但是感觉你在第一次判断a>2时是不成立的,进入else  后面有个while(1)这个不就停这 ...

是的,我改了一下程序。
while(1)
{
      if(a>2)
      {
           TR0=1;
           delay(50000);
           delay(50000);
           delay(50000);
           delay(50000);
           TR0=0;
       }
      else TR0=0;
}
这样是会在a累加到3的时候进入定时器中断,但是新问题是进去后出不来了。。。我需要进入定时器中断,运行一段时间后退出中断。二楼用定时器模式二写的程序成功了。
回复

使用道具 举报

ID:326418 发表于 2018-5-10 19:49 来自手机 | 显示全部楼层
HC6800-ES-V2.0 发表于 2018-5-10 09:00
你的程序,我研究了,修改了一下,可以通过外部中断按键让蜂鸣器发声音了。
由于不明白你的a变量是干什么 ...

感谢认真的回复!变量a是计算外部中断次数的,外部中断设置为下降沿触发,每当按下一次k0变量a自加1,加到3清零。你的第一部分确实是解决了进不了定时器中断的问题,但是我发现进去了中断出不来了。。。第二部分我试了一下,看到外部中断优先级高,退出定时器中断是要外部中断打断,如果没有外部中断打断是退出不了定时器0的。我原先的设置是定时器优先级高,外部中断加到3进入定时器中断,延时一会后退出定时器中断。
回复

使用道具 举报

ID:326418 发表于 2018-5-10 20:01 | 显示全部楼层

是的。。。。楼上指出了。。。
回复

使用道具 举报

ID:326418 发表于 2018-5-11 11:03 来自手机 | 显示全部楼层
DisTanCeRaIn 发表于 2018-5-10 23:30
我要再补一段函数的问题。。。
#include


在keil调试模式里仔细研究了一下,发现IT0是置1的,也就是说外部中断用下降沿触发,而外部中断子程序里在进入外部中断后有一个10毫秒的按键防抖,而在定时器中断程序运行时,给P3^2口发信号是会使IE0置1的,等到T0T1的程序运行结束后,因为IE0为1,直接进入了外部中断程序,而这时的SEN是不为0的,所以运行到delay_ms(10);后就直接退出了外部中断,这样外部中断就被关闭而不能再进入了,需要按下复位才能再次开启。
我现在把按键防抖去掉了,再在定时器0中断程序的else if里补上一句IE=0;后,调试成功了。
当然补上IE=0;后不去掉按键防抖也是可以的。
回复

使用道具 举报

ID:326418 发表于 2018-5-11 14:45 来自手机 | 显示全部楼层
又有新问题,我觉得我问题多到爆炸。。。我在调试和模拟控制蜂鸣器和步进电机的程序时是完全没有问题的,达到了我的要求,但是下载进开发板后,刚开始是可以成功运行,等蜂鸣器和电机停止后再怎么给信号都不启动了。我还以为我烧录了改过前的hex文件,仔细排查后确实是改进后的。。
回复

使用道具 举报

ID:327624 发表于 2018-5-11 15:33 | 显示全部楼层
程序问题
回复

使用道具 举报

ID:213173 发表于 2018-5-11 17:51 | 显示全部楼层
DisTanCeRaIn 发表于 2018-5-10 19:06
大佬,你改的程序我试了一下,很成功。请教一下,用定时器模式2,进入定时器中断,主程序在运行的同时定 ...

只要开启定时器,定时器就与主程序分别运行,只有开启了定时器中断,当定时器发生中断请求时CPU才会暂停运行主程序执行中断任务,完成中断任务后再回到暂停点继续运行主程序。所以中断任务里不要执行过多代码。

评分

参与人数 1黑币 +8 收起 理由
DisTanCeRaIn + 8 十分感谢!

查看全部评分

回复

使用道具 举报

ID:327962 发表于 2018-5-12 13:08 来自手机 | 显示全部楼层
你试着把if(a>2)这块写到int0()函数里
回复

使用道具 举报

ID:328160 发表于 2018-5-12 13:44 来自手机 | 显示全部楼层
去单片机小精灵找一下代码
回复

使用道具 举报

ID:328266 发表于 2018-5-12 16:29 | 显示全部楼层
#include <reg52.h>

sbit MDA = P2^0;   //步进电机驱动口
sbit MDB = P2^1;
sbit MDC = P2^2;
sbit MDD = P2^3;
sbit SEN = P3^2;   //传感器接口
sbit BUZ = P3^7;   //蜂鸣器
unsigned char time0 = 0; //定时器溢出次数
unsigned char time1 = 0;
unsigned char wei = 0;  //电机驱动指针
unsigned char num = 0;  //计数值
unsigned char flagd = 0; //方向标志
unsigned char second = 0; //秒数

//延时函数
void delay_ms(unsigned int s)
{                           
   unsigned int k;
   while(s--)
   {
     for(k=0; k<120; k++);
   }
}


void main(void)
{
unsigned char flags = 0;
TMOD = 0X11;     //工作模式1:16位计时器
TH0 = (65536-50000)/256;  //T0初值:50ms
TL0 = (65536-50000)%256;
TH1 = (65536-1000)/256;   //T1初值:1ms
TL1 = (65536-1000)%256;
IT0 = 1;      //外部中断0下降沿触发
      
EA = 1;       //中断初始化
ET0  = 1;
ET1  = 1;
EX0 = 1;
PT0=1;
PT1=1;
PX0=0;

while(1)
{
}
}
//外部中断服务函数
void INT0_ISR(void) interrupt 0
{
EX0 = 0;
delay_ms(10);
if(SEN == 0)  //确认低电平有效
{
  num++;   //递增
  if(num == 3) //达到3次
  {
   TR0 = 1; //开始工作
   TR1 = 1;
   flagd = 0;
   second = 0;
   return;
  }
  else
  {
   EX0 = 1; //未达3次,使能中断
  }
}
}

//T0中断服务函数
void T0_ISR(void) interrupt 1
{
TH0 = (65536-50000)/256;
TL0 = (65536-50000)%256;
time0++;      
if(time0 == 20)    //计时1s
{
  time0 = 0;  
  second++;
  if((second == 60)&&(flagd == 0)) //计时达到60秒
  {
   flagd = 1;     //反向
   second = 0;
  }
  else if((second == 60)&&(flagd == 1)) //反转60秒,关闭
  {
   flagd=0;
   second=0;
   TR0 = 0;
   TR1 = 0;
   num = 0;
   EX0 = 1;
  }
}
}
//T1中断服务函数
void T1_ISR(void) interrupt 3
{
TH1 = (65536-1000)/256;
TL1 = (65536-1000)%256;
BUZ = !BUZ;
time1++;
if(time1 == 10) //10ms输出一个驱动脉冲
{
  time1 = 0;
  if(flagd == 0)  //正转
  {
   wei = (wei+1)%4; //正向输出驱动脉冲
  }
  else if(flagd==1)    //反转
  {
   wei = (wei+3)%4; //反向输出驱动脉冲
  }
  P2 = 0XFF;     //输出驱动脉冲
  P2 &= ~(1<<wei);
}
}
回复

使用道具 举报

ID:304501 发表于 2018-5-12 17:16 | 显示全部楼层
简单回家吧回家吧
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表