找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1272|回复: 13
收起左侧

单片机点灯程序,按键进入中断后,就一直反复执行,跳不出来了

[复制链接]
ID:53813 发表于 2023-11-23 08:55 | 显示全部楼层 |阅读模式
如下,逻辑上感觉没错啊, 10ms ,中断一次,0.5S灯闪一次, temp+1,累计到时间,判断与设定的一样补,一样执行,不一样,判断下一个,都不一样,继续等待 ,找不到问题在哪了,求大佬来了

单片机源程序如下:
#include <STC15.H>  

sbit LED1 = P1^0;  
sbit LED2 = P1^1;  
sbit LED3 = P1^2;  
sbit LED4 = P1^3;  
sbit KEY1 = P3^2;  
sbit KEY2 = P3^3;
sbit Pin2out_H = P1^4;        
sbit Pin4out_H = P1^5;
sbit Pin3out_Delay5s_H = P3^6;        
sbit Beer =        P3^7;


unsigned char key_count = 0; //按键次数,初始值为1  
unsigned char count_status = 0; //倒计时状态,初始值为1,表示倒计时未开始  
unsigned char count_select = 0; //倒计时选择,初始值为1,表示选择1分钟倒计时  
unsigned int count = 0; //计数器,初始值为0,表示倒计时未开始   
unsigned int temp = 0; //计数器值暂存,初始值为0, COUNT计到1000,Ttemp 加1

void delay(unsigned int time) // 延时函数  
{  
    unsigned int i,j;  
    for(i=0;i<time;i++)  
        for(j=0;j<1275;j++);  
}  


void key1_ISR() interrupt 0 //按键1中断服务程序,中断号是0  
{  
    if(key_count < 3)
                { //如果按键次数小于3次  
                key_count++; //按键次数加1  
                if(key_count == 1)
                                { //如果按了一次按键
                                LED1 = 0; LED2 = 1; LED3 = 1;
                    count_select = 2; //选择2分钟倒计时  
                    //count = 120; //设置倒计时为2分钟  
                        }   
                else if(key_count == 2)
                                { //如果按了两次按键
                                LED1 = 1; LED2 = 0; LED3 = 1;
                    count_select = 3; //选择3分钟倒计时  
                    //count = 180; //设置倒计时为3分钟  
                        }   
                else if(key_count == 3)
                                { //如果按了三次按键  
                                LED1 = 1; LED2 = 1; LED3 = 0;
                    count_select = 1; //重置倒计时选择为1分钟  
                    //count = 60; //设置倒计时为1分钟  
                        }  
            }  
    else
                { //如果按键次数超过3次,重置为1次  
        key_count = 1; //重置按键次数为1次
        LED1 = 0; LED2 = 1; LED3 = 1;
            }  
    KEY1 = 1; //按键消抖,防止误操作,这个可以在主循环里面加消抖逻辑或者使用硬件去抖动。具体做法根据你的硬件实现进行编写。  
}  

// KEY2中断服务程序,用于处理倒计时逻辑


void key2_ISR() interrupt 2  
{   
        AUXR |= 0x10;                        //定时器2开始计时
        IE2 |= 0x04;                        //定时器2允许中断
        count_status = 1;                //表示计时开始

}
void Timer2_ISR() interrupt 12  
{        
        
        Pin2out_H = 1;        //先输出低电平
        Pin4out_H = 0;
        
        count++;        //10ms加1次
        if (count == 50) //加到500ms,即0.5S时
                {
                        LED4= ~LED4; //闪灯
                        temp++;  //temp 加1
                        count =0;  // 5次清零一次,重新累计
                }

}
void main()   
{  
        //M1  M0
                //0   0             准双向口--51类型
                //0   1             推挽输出--适合 输出真正的高低电平
                //1   0             高阻输入-- 只能作为  输入:io口被悬空,没有上拉也没有下拉,完全由外部电平驱动
                //1   1             开漏输出--适合线与


        //P1
        //P10,P11,P12,P13,P14,P15设置为推挽输出  
        P1M1 = 0x00;   //0000 0000
        P1M0 = 0x1F;   //0001 1111

        LED1=1;                        //先关灯
        LED2=1;
        LED3=1;
        LED4=1;
        
        
        //P3
        //P30,P31,P32,P33,P36,P37设置为推挽输出
        P3M1 = 0x00; //0000 0000
        P3M0 = 0xCF; //1100 1111

        KEY1 = 1;  //按键先拉高,
        KEY2 = 1;
        Pin2out_H = 0;        //先输出低电平
        Pin4out_H = 1;
        Pin3out_Delay5s_H = 1; //先输出低电平
        Beer = 0;                          //先输出低电平
        
        //10毫秒@12MHz
        AUXR &= 0xFB;                        //定时器时钟12T模式
        T2L = 0xF0;                                //设置定时初始值
        T2H = 0xD8;                                //设置定时初始值
        AUXR |= 0x00;
        //AUXR |= 0x10;                        //定时器2开始计时
        
         
          EA = 1; //开启总中断  
        //IE2 |= 0x04;                        //使能定时器2中断
        IE2 |= 0x00;                        //关闭定时器2中断
         
          IT0 = 1; //设置INT0的中断类型 为下降沿触发
          EX0 = 1; //开启外部中断0 P3.2
         
          IT1 = 1; //设置INT1的中断类型 为下降沿触发
          EX1 = 1; //开启外部中断1 P3.3

        LED1 = 0;
        count_select = 1;
        
       while (1)
                   { // 主循环
                        if (temp < 360 )  //如果时间小于三分钟
                        {
                                //temp++;  //temp 加1
                                if ((temp ==120 ) && (count_select == 1))
                                                {
                                                        IE2 |= 0x00; //关定时器2中断
                                                        AUXR |= 0x00; //定时器2关闭计时
                                                        temp = 0;
                                                        Pin2out_H = 0;        //先输出低电平
                                                        Pin4out_H = 1;
                                                        count_status = 0; //倒计时结束
                                                }
                                
                                else if ((temp ==240 ) && (count_select == 2))
                                                {
                                                        IE2 |= 0x00; //关定时器2中断
                                                        AUXR |= 0x00; //定时器2关闭计时
                                                        temp = 0;
                                                        Pin2out_H = 0;        //先输出低电平
                                                        Pin4out_H = 1;
                                                        count_status = 0; //倒计时结束
                                                }
                                else if( (temp ==360 ) && (count_select == 3))
                                                {
                                                        IE2 |= 0x00; //关定时器2中断
                                                        AUXR |= 0x00; //定时器2关闭计时
                                                        temp = 0;
                                                        Pin2out_H = 0;        //先输出低电平
                                                        Pin4out_H = 1;
                                                        count_status = 0; //倒计时结束
                                                }
                        }
                else  //如果大于三分钟
                        {
                                temp = 0;
                                Pin2out_H = 0;        //先输出低电平
                                Pin4out_H = 1;
                                count_status = 0; //倒计时结束
                        }
               
                if(count_status == 0)
                        {
                                        delay(1);
                                Pin3out_Delay5s_H = 0;
                                }
                }

}
回复

使用道具 举报

ID:161164 发表于 2023-11-23 11:17 | 显示全部楼层
反复执行啥?跳不出来啥?

IE2 |= 0x00; //关定时器2中断
AUXR |= 0x00; //定时器2关闭计时
这两句是没作用的
2023-11-23_111534.png


回复

使用道具 举报

ID:275826 发表于 2023-11-23 11:56 | 显示全部楼层
if(key_count < 3)                 { //如果按键次数小于3次                   key_count++; //按键次数加1                   if(key_count == 1)                                 { //如果按了一次按键                                 LED1 = 0; LED2 = 1; LED3 = 1;                     count_select = 2; //选择2分钟倒计时                       //count = 120; //设置倒计时为2分钟                           }                    else if(key_count == 2)                                 { //如果按了两次按键                                 LED1 = 1; LED2 = 0; LED3 = 1;                     count_select = 3; //选择3分钟倒计时                       //count = 180; //设置倒计时为3分钟                           }                    else if(key_count == 3)                                 { //如果按了三次按键                                   LED1 = 1; LED2 = 1; LED3 = 0;                     count_select = 1; //重置倒计时选择为1分钟                       //count = 60; //设置倒计时为1分钟                           }               }
回复

使用道具 举报

ID:275826 发表于 2023-11-23 12:08 | 显示全部楼层
逻辑错误
回复

使用道具 举报

ID:53813 发表于 2023-11-23 12:31 | 显示全部楼层
lkc8210 发表于 2023-11-23 11:17
反复执行啥?跳不出来啥?

IE2 |= 0x00; //关定时器2中断

就是反复执行 LED4 0.5S闪一下 时间到了也 跳不出中断,  就 不能执行原先设定的倒计时时间,  比如,我上电默认是一分钟, 按KEY2后,定时器中断打开,0.5S灯翻一下, 原本按照逻辑应该是一分钟后,关中断,倒计时结束,对应引脚输出信号。现在就卡在中断里面,一直闪灯,时间到了也不停止。
回复

使用道具 举报

ID:275826 发表于 2023-11-23 12:51 | 显示全部楼层
else if ((temp ==240 ) && (count_select == 2))
                                                {
                                                        IE2 |= 0x00; //关定时器2中断
                                                        AUXR |= 0x00; //定时器2关闭计时
                                                        temp = 0;
                                                        Pin2out_H = 0;        //先输出低电平
                                                        Pin4out_H = 1;
                                                        count_status = 0; //倒计时结束
                                                }
                                else if( (temp ==360 ) && (count_select == 3))
                                                {
                                                        IE2 |= 0x00; //关定时器2中断
                                                        AUXR |= 0x00; //定时器2关闭计时
                                                        temp = 0;
                                                        Pin2out_H = 0;        //先输出低电平
                                                        Pin4out_H = 1;
                                                        count_status = 0; //倒计时结束
                                                } 这些语句都不会执行的
回复

使用道具 举报

ID:161164 发表于 2023-11-23 14:09 | 显示全部楼层
三极管一样的人 发表于 2023-11-23 12:31
就是反复执行 LED4 0.5S闪一下 时间到了也 跳不出中断,  就 不能执行原先设定的倒计时时间,  比如,我 ...

原因就在于我说的那两句
回复

使用道具 举报

ID:53813 发表于 2023-11-23 18:01 | 显示全部楼层

大佬,请指点下,哪里逻辑错了,我实际按键,也可以切换灯,就是,再按K2启动后,这时间就乱套了。
回复

使用道具 举报

ID:53813 发表于 2023-11-23 18:07 | 显示全部楼层
tyrl800 发表于 2023-11-23 12:51
else if ((temp ==240 ) && (count_select == 2))
              &#1 ...

   额... 我屡屡哈, 先0.5S,灯反一下,  然后,temp 存1,  累积120次,就是 60 000ms ,就是一分钟, 然后,240次就是2分钟,360次,就是三分钟, 嗯, 大于3分钟就归零,从新存 。 这个思路没错吧?
回复

使用道具 举报

ID:53813 发表于 2023-11-23 18:08 | 显示全部楼层
lkc8210 发表于 2023-11-23 14:09
原因就在于我说的那两句

我又看了规格书的范例, 改用了  IE2 &= ~0x04;    关掉中断,总算可以结束倒计时了。 现在就是倒计时时间不对, 没有设想的一分钟,2分钟,3分钟如期实现
回复

使用道具 举报

ID:275826 发表于 2023-11-23 18:21 | 显示全部楼层
三极管一样的人 发表于 2023-11-23 18:07
额... 我屡屡哈, 先0.5S,灯反一下,  然后,temp 存1,  累积120次,就是 60 000ms ,就是一分 ...

你temp==120时,后面temp=0; 永远不会出现temp==240了
回复

使用道具 举报

ID:161164 发表于 2023-11-24 09:26 | 显示全部楼层
三极管一样的人 发表于 2023-11-23 18:08
我又看了规格书的范例, 改用了  IE2 &= ~0x04;    关掉中断,总算可以结束倒计时了。 现在就是倒计时时 ...

当一变量会在主循环判断并在中断里更新时
该变量应使用8位数据类型,如char,uchar
原因在我的贴子里有讨论
http://www.51hei.com/bbs/dpj-213547-1.html


回复

使用道具 举报

ID:53813 发表于 2023-11-24 10:32 | 显示全部楼层
tyrl800 发表于 2023-11-23 18:21
你temp==120时,后面temp=0; 永远不会出现temp==240了

额,我是这样想的,   我这temp 一直加加, 加到temp==120 满足时候,同时再去判断 是否还要 同时满足 count_select == 1  ,才会进去执行,执行后,那就归零。也就是停止计时中断了。
相当于要进行下一轮按键选择,和开始
如果不满足 就是去判断下一个条件, ,如果都不满足,这个是temp 已经加到 360以上了,
那就归零,再重头计
(经过改了关定时器2的语句)
现在最新实际情况是,这时间乱倒计。第二轮还不停。
回复

使用道具 举报

ID:53813 发表于 2023-11-24 10:52 | 显示全部楼层
lkc8210 发表于 2023-11-24 09:26
当一变量会在主循环判断并在中断里更新时
该变量应使用8位数据类型,如char,uchar
原因在我的贴子里有 ...

学习了 ,原来还有这种细节问题。而且,帖子提到的那个前辈,看那段话风格,眼熟,一查果然是江湖人称鸿哥的早期经验连载贴
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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