打印
[51单片机]

关于在中断函数里面使用不了全局变量,求解、

[复制链接]
7218|18
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
tanxin2721|  楼主 | 2014-1-2 22:58 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 tanxin2721 于 2014-1-2 22:59 编辑

最近在用89c52做一个通过按键输入,数码管显示数值,来控制步进电机转动时间的程序,在用到中断函数的时候遇到了点问题,就是在中断3里面重新设置初值的时候有用到全局变量s,但是用了之后没有作用。如果把s改成常数的话,那又正常的了。比如我把s改成20,那么P1_0灯亮2秒是正常的,但是如果改成s的话,灯一直是亮的。不知道是怎么回事,我查了一下,说中断函数里的变量需用volatile定义,我也定义了,但是没有作用.都快崩溃了,调了4,5个晚上了,还是没有调出来,只有来求助各位达人了。
数码管显示部分可以不用看,主要是在按键扫描里面关于中断的问题。直白点可以关注灯P1_0亮的时间是否准确。
#include <reg52.h>
#include <string.h>
unsigned char num[11]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x7f}; //共阳极LED段码0~9
unsigned char a,k,m,H[50];
volatile unsigned char s,p,q,biaozi,time;
sbit P1_0=P1^0;
sbit P3_4=P3^4;
sbit P3_2=P3^2;
/*************延时Xms*****************/
void Delay_nms(unsigned int n) //延时程序
{ unsigned int i,j;
for(i=n;i>0;i--)
for(j=100;j>0;j--);
}
/*****************键盘扫描函数*************************************/
void GetKey ( )//键盘扫描函数,用于识别哪一个键按下,并读取键值
{
unsigned char X,Y,Z;
   if(P1_0==1)
        {
       P0=0x0f; //先对P3置数 行扫描
       if(P0!=0x0f) //判断是否有键按下
         {
           Delay_nms(5); //延时,软件去干扰
           if(P0!=0x0f) //确认按键按下X = P3;
              {
                X=P0&0x0f; //保存行扫描时有键按下时状态
                P0=0xf0; //列扫描
                Y=P0&0xf0; //保存列扫描时有键按下时状态
                Z=X|Y; //取出键值
                switch ( Z ) //判断键值(那一个键按下)
                  {
                    case 0xd7: k=0; break; //对键值赋值
                    case 0xee: k=1; break;
                    case 0xde: k=2; break;
                    case 0xbe: k=3; break;
                    case 0xed: k=4; break;
                    case 0xdd: k=5; break;
                    case 0xbd: k=6; break;
                    case 0xeb: k=7; break;
                    case 0xdb: k=8; break;
                    case 0xbb: k=9; break;
                    case 0x77: k=10;break;
                          case 0x7b: k=11;break;
                    default  : break;
                   }

                                                 while(P0!=0XF0)     /*等待按键释放*/
                                                  {
                                                  }

                                                 if(k!=10)
                                                 {
                                                            H[m]=k;
                                        m++;
                                        a++;
                                                 }
                                                 else if(k==10)      //若k=10(按键确认键)
                                                 {

/***********************************送给步进电机一段脉冲信号*******************/
                                                   TMOD=0X51;       //设定定时器0方式1和计数器1方式1                                       
                                                        TH0=(65536-1250)/256;   
                                                        TL0=(65536-1250)%256;
                                                        TH1=(65536-100)/256;
                                                        TL1=(65536-100)%256;
                                                        time=0;
                                                        biaozi=0;
                                                        p=0;
                                                        q=0;
                                                        EA=1;
                                                        ET0=1;
                                                        ET1=1;
                                                        TR0=1;                                                
                                                        TR1=1;
                                                        P1_2=0;

/*********************等待第一次脉冲信号输入完全然后电机不转,等待特定秒数后再转动********/
                                                      while(time==0)
                                                                        {}
/****************根据按键得出计时时间值***********************/
                                                        if (a<=1)
                                                         {
                                                         s=20;
                                                         }
                                                         else if(a==2)
                                                                 {
                                                                  if(H[0]>=2)
                                                                   {
                                                                                s=H[0]*10+H[1];
                                                                        }
                                                                else{s=20;}
                                                                }
                                                                else if(a==3)
                                                                 {
                                                                 s=H[0]*100+H[1]*10+H[2];
                                                                 }
                                                                 else if(a>=4)
                                                                  {s=H[m-4]*1000+H[m-3]*100+H[m-2]*10+H[m-1];}
/****************************************************/                                                                        
                                                                        P1_0=0;        //灯P1_0亮                                
                                                                        p=1;
                                                                        q=1;                                       
                                                                        ET0=1;
                                                                        ET1=1;
                                                                        TR0=1;                                                
                                                                        TR1=1;                                                               
                                                                 while(biaozi==0)
                                                                        {}

/***********************电机再次转动**************************/
                                                                         TMOD=0X01;
                                                                                p=0;
                                                                                TR0=0;
                          }        
                                                         
                     }
                                                                 if(k==11)
                                                            {
                                                                memset(H,0,sizeof(H));
                                                                m=0,a=0;
                                                                }
           }
     }
}
/*******************数码管显示*****************************************/
void dispy()
{ int U;
    P0=num[10];
    P2=0XFB;
         Delay_nms(2);
        P2=0XFF;
   if(a==1 )
    {
      U=H[m-1];
      P0=num[U];
      P2=0XF7;
      Delay_nms(2);
      P2=0XFF;
    }
    else if(a==2)
      {
                U=H[m-1];
      P0=num[U];
      P2=0XF7;
      Delay_nms(2);
      P2=0XFF;

       U=H[m-2];
      P0=num[U];
      P2=0XFB;
      Delay_nms(2);
      P2=0XFF;               
       }
     else if(a==3)
       {
                 U=H[m-1];
      P0=num[U];
      P2=0XF7;
      Delay_nms(2);
      P2=0XFF;

                U=H[m-2];
      P0=num[U];
      P2=0XFB;
      Delay_nms(2);
      P2=0XFF;

                U=H[m-3];
      P0=num[U];
      P2=0XFD;
      Delay_nms(2);
      P2=0XFF;
        }
       else if(a>=4)
        {
                  U=H[m-1];
      P0=num[U];
      P2=0XF7;
      Delay_nms(2);
      P2=0XFF;

                U=H[m-2];
      P0=num[U];
      P2=0XFB;
      Delay_nms(2);
      P2=0XFF;
               
                U=H[m-3];
      P0=num[U];
      P2=0XFD;
      Delay_nms(2);
      P2=0XFF;
               
                U=H[m-4];
      P0=num[U];
      P2=0XFE;
      Delay_nms(2);
      P2=0XFF;
                }
}                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               
/**********************中断函数****************************/
timer0() interrupt 1 using 1
{  if(p==0)
        {
                P3_2=!P3_2;    //外部输入给步进电机脉冲信号
                P3_4=!P3_4;                //与P3_5相连,送给计数器脉冲信号
                TH0=(65536-1250)/256;
                TL0=(65536-1250)%256;
         }
    else if(p==1)
                {
                        P3_4=!P3_4;                 //与P3_5相连,送给计数器脉冲信号
                        TH0=(65536-50000)/256;
                TL0=(65536-50000)%256;
                        
                }
}

timer1() interrupt 3 using 3
{  if(q==0)
    {                                
                TR0=0;
                ET0=0;
                ET1=0;
                TR1=0;
                time=1;
        
                        TH1=(65536-s)/256;      
                        TL1=(65536-s)%256;      

        
     }        
                 else if(q==1)
                        {           
                                P1_0=1; //灯P1_0灭
                                TR0=1;
                                biaozi=1;
                        
                        }

}

/**********************主函数******************************/
void main(void)
{ a=0,m=0;
P3_4=1;
P1_0=1;
P3_2=1;


   while(1)
      {  
        GetKey();//得到键值        
        dispy(); //数码管显示   
       }
}
/************************************************************/

相关帖子

沙发
as564335sa| | 2014-1-3 00:24 | 只看该作者
思路不是很明确,中断里的变量要用volatile修饰?没听说过
你这个问题考虑几个问题,S的值是否会超出定时器范围,主程序初始化给S赋个值,另外一个就是S的值是否会被某句程序初始化导致中断不能正常赋值

使用特权

评论回复
板凳
ayb_ice| | 2014-1-3 08:26 | 只看该作者
没有看程序,

但肯定是原子操作的问题

使用特权

评论回复
地板
tanxin2721|  楼主 | 2014-1-3 09:05 | 只看该作者
本帖最后由 tanxin2721 于 2014-1-3 12:32 编辑
as564335sa 发表于 2014-1-3 00:24
思路不是很明确,中断里的变量要用volatile修饰?没听说过
你这个问题考虑几个问题,S的值是否会超出定时器 ...


应该不会,比如我让a<=1,可以s就为20。但是这样运行结果不和预想的一样。而且我在主程序把s设初值为0,仍然不行

使用特权

评论回复
5
tanxin2721|  楼主 | 2014-1-3 09:17 | 只看该作者
ayb_ice 发表于 2014-1-3 08:26
没有看程序,

但肯定是原子操作的问题

我在网上插了下,c语言不能用原子操作,还有没其他的解决办法?

使用特权

评论回复
6
ayb_ice| | 2014-1-3 09:29 | 只看该作者
tanxin2721 发表于 2014-1-3 09:17
我在网上插了下,c语言不能用原子操作,还有没其他的解决办法?

关键地方禁止中断即可

使用特权

评论回复
7
tanxin2721|  楼主 | 2014-1-3 12:22 | 只看该作者
关键的地方是哪里,我在中断3那里设置的关中断,这里不是关键位置吗?

使用特权

评论回复
8
tanxin2721|  楼主 | 2014-1-3 12:24 | 只看该作者
ayb_ice 发表于 2014-1-3 09:29
关键地方禁止中断即可

关键的地方是哪里,我在中断3那里设置的关中断,这里不是关键位置吗?

使用特权

评论回复
9
jiabin1024| | 2014-1-3 15:08 | 只看该作者
在执行过程中不能被中断的代码即为关键地方。程序比较短,你单步调试一下。

使用特权

评论回复
10
lnulibin| | 2014-1-3 19:40 | 只看该作者
个人认为程序写的不太完善。
IF()
{......}
ELSE IF()
{......}
ESLE
{....}
最后的ELSE要写全。不然,可能在编译完成后有些问题的。

使用特权

评论回复
11
ZG11211| | 2014-1-3 20:23 | 只看该作者
把中断函数放到主代码后面试试。

使用特权

评论回复
12
tanxin2721|  楼主 | 2014-1-3 21:21 | 只看该作者
本帖最后由 tanxin2721 于 2014-1-3 21:48 编辑
ZG11211 发表于 2014-1-3 20:23
把中断函数放到主代码后面试试。

试过了不行,呵呵不过我把  if (a<=1)
                                                         {
                                                         s=20;
                                                         }
                                                         else if(a==2)
                                                                 {
                                                                  if(H[0]>=2)
                                                                   {
                                                                                s=H[0]*10+H[1];
                                                                        }
                                                                else{s=20;}
                                                                }
                                                                else if(a==3)
                                                                 {
                                                                 s=H[0]*100+H[1]*10+H[2];
                                                                 }
                                                                 else if(a>=4)
                                                                  {s=H[m-4]*1000+H[m-3]*100+H[m-2]*10+H[m-1];}
要算s的值的式子放在了设置TMOD前面,就行了,但是出现了一个新问题,就是在第二次进入定时中断(定时器0: TH0=(65536-50000)/256,TL0=(65536-50000)%256, 计数器1:TH1=(65536-s)/256,TL1=(65536-s)%256,当s=1到255之间(定时25.5秒内)是正常的,但是超过256后,它又从0开始,比如所我按键输入26.0(数码管显示26.0)应该定时26s(灯P1_0亮26s),但是结果它只亮1s,不知道哪里出现了问题。。。。

使用特权

评论回复
13
sfpxfpcfp| | 2014-1-3 21:43 | 只看该作者
volatile 以前有个贴子是专门讲这个的呢

使用特权

评论回复
14
tanxin2721|  楼主 | 2014-1-3 21:47 | 只看该作者
sfpxfpcfp 发表于 2014-1-3 21:43
volatile 以前有个贴子是专门讲这个的呢

但是我在s前面加过volatile的呀?

使用特权

评论回复
15
guanhe| | 2014-1-3 23:05 | 只看该作者
volatile只是说明每次读取数据的时候,是重新从内存里面读取,不要编译器进行相关的优化,你这个我估计可能是因为终端中会有数据进行改变,也就是说主程序和中断的话两个进程会对数据有读写的话是要进行临界资源的保护的。。好像操作系统里面是这么说的。。而且,你这个还有中断嵌套,也要考虑到另一个中断可能对此中断的影响。。

使用特权

评论回复
16
cuilaiabc| | 2014-1-4 09:58 | 只看该作者
你查一下其他上面地方有没有用到S,值有没有被冲掉。中断中用全局变量是可以的。

使用特权

评论回复
17
sunhq02| | 2014-1-4 10:00 | 只看该作者
这是因为你把s到定时器重置值的计算放在中断里面
这个计算用到了 除法和整除
这两个运算速度非常慢
干扰了中断的运行

如果一定要计算的话
可以外部计算好后在中断里面用
使用右移和掩码操作代替除法和整除

使用特权

评论回复
评分
参与人数 1威望 +1 收起 理由
tanxin2721 + 1 非常感谢,我想我的第一个问题,估计就是全.
18
南宫云明| | 2014-1-4 11:39 | 只看该作者
本帖最后由 南宫云明 于 2014-1-4 11:40 编辑

这问题当时我在大学里用c8051f020做频率测量的一个小项目的时候也碰到过,也是对定时器赋初值,初值赋不了,当时找了很久原因找不到。。。后来就没后来了。。。到现在我也不知道。。。


这时候突然想起来,现在手上没板子,等有空再去试试看。


使用特权

评论回复
19
gx_huang| | 2014-1-4 17:44 | 只看该作者
1、中断要大致算一下程序执行的时间,除法需要比较长的时间。
2、中断里操作全局变量,只要是长度2字节以上的,可能会错误。
   比如变量S,主程序里,S=12345,实际是1个字节1个字节的赋值,中断程序里调用,可能刚好是错误的。

使用特权

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

本版积分规则

9

主题

33

帖子

1

粉丝