13137|20

71

帖子

0

TA的资源

一粒金砂(初级)

楼主
 

怪现象:keil中return跳不出函数,还在本函数执行 [复制链接]

不知道有哪位仁兄遇到这种情况:
在keil单步调试中,c51语言的return;居然跳不出函数 而是跳到本语句以下的10多行(该语句还属于本函数)去执行,并且执行一句后就跳出来了。
例如:
void function1(uchar i)
{
i=0x00;                           //第一步
if(i==0x00)                      //第二步
  {
    i+=10;                      //3
    fuction2();                //4
    return;
   }

else if(i==0x01)
    {
    fuction3();
    return;
    }

....
else if(i==0x0a)
    {
    fuction2();                    //5
    return;
    }
}                             //6

顺序大概如上面那么怪的!
若哪位仁兄有兴趣帮我克服这个怪现象(对于我来说是怪现象),就联系我吧 QQ:376967502
email:StudyBoy_3w@163.com

thanks for your email and call

最新回复

非常谢谢你的在线回答!thanks  详情 回复 发表于 2007-4-10 19:44
点赞 关注

回复
举报

64

帖子

0

TA的资源

一粒金砂(初级)

沙发
 
补充一下:
听说是优化问题;
嗯我觉得有到了
warring:multiple call to segment
重入问题谁会解决 ??   问题是 不知道我的程序中哪个函数重入了      因为函数1中调用了函数2 函数2又调用了函数3  总之嵌套函数很多层
 
 

回复

93

帖子

0

TA的资源

一粒金砂(初级)

板凳
 
keil有潜逃限制

 
 
 

回复

64

帖子

0

TA的资源

一粒金砂(初级)

4
 
C51默认不允许函数的递归,或是可能造成递归或多次调用的使用

一般有两个方法:
一,确保自己的递归能可靠的跳出来,能做到的话,那就把相关的几个函数声明成可重入的
二,从整逻辑,规划.(推荐这个,为了可靠,应该对执行期可知)
 
 
 

回复

66

帖子

0

TA的资源

一粒金砂(初级)

5
 
lbing7:

看过你很多帖  觉得非常有见地!
我非常赞同“二,从整逻辑,规划.(推荐这个,为了可靠,应该对执行期可知)”
特别是对执行期可知

我在程序中是多次调用一些函数 嗯 还有在时钟中断函数也调用了这些函数
我就关掉中断EA=0;在程序调试中一部分操作程序是执行期可知的 但烧到单片机后这些操作结果是不可知的  是什么原因?

从整逻辑,规划。也要调用他们中一部分程序。
嗯 会好好想想的,谢谢了
 
 
 

回复

64

帖子

0

TA的资源

一粒金砂(初级)

6
 
我在做一个4×4键盘 程序扫描键盘     用lcd 1602显示做菜单
做一个有时钟,闹钟,定时器,秒表功能的菜单  那些功能我都做出来了 就一个菜单结合它们功能做了1个星期都晕死了      不知道各位有什么建议 先说说我的笨方案。

lcd 大概是这样显示:Menu={"set time","set alarm","set timer","stopwatch"};
********************
**    12:00:00  **
**    Menu        **
********************
进入菜单后lcd为:(如进入秒表stopwatch 第一行不变)
********************
**    12:00:00  **
**    00:00:00  **
********************
用2个uchar  Menu,MenuAssi  按位控制菜单 用3个位变量 控制闹钟,定时器,秒表是否设置了
用2个定时器 一个int0是0.01s中断 做时钟和秒表的计算 和秒表在lcd更新   一个int1是0.05秒 做更新第一行时间  为了秒表更精确(不知道可不可以更精确)
程序扫描4×4键盘 处理时间的更改 闹钟,定时,秒表设置 这个函数中频繁调用了跟lcd有关的函数,如WriteData ReadStatus WriteCommand等函数  定时器也调用了这些函数  所以不知道有没有冲突。

 
 
 

回复

69

帖子

0

TA的资源

一粒金砂(初级)

7
 
希望大家提些建议吧
 
 
 

回复

61

帖子

0

TA的资源

一粒金砂(初级)

8
 
系统时钟肯定是独占一个时钟,而且尽可能的放在最高优先级

显示和扫键盘放到一个时钟里

其实的逻辑都可以丢到MAIN里去按层次展开了...

关于显示,觉得用缓冲区方式,反正是液晶,定时好,到时候如果有更新就刷一次
这样挺省资源的

其它的应该模块间的耦合就没有这么严重了...
 
 
 

回复

67

帖子

0

TA的资源

一粒金砂(初级)

9
 
我的程序用计数器0计时和秒表的显示   计数器1 是显示

看了你的方法很好
好方法  在用3天再做一下   
不过还有个疑问       就是用计数器0计时(不显示)   计数器1 显示lcd  main 就是扫键盘和相应位逻辑处理     因为计数器0专门计时  而计数器1 显示lcd    在显示秒表时候 会不会有突变现象 显示00:00:05 中断1(计数器1的中断)继续执行中断处理 而计数器0却频繁中断计时
在计数器1 再次中断时 可能会出现00:00:07的突变现象(虽然很准)

哦 知道了 0.01s很短 给人看起来 那位就是8 应该没关系的!

谢谢你的idea
 
 
 

回复

72

帖子

0

TA的资源

一粒金砂(初级)

10
 
按照本帖的lbing7所说的方案做。有点进步了,显示不会出现乱码。
但是还是有问题请教各位:
在keil调试仿真,程序运行如我所愿。Menu,MenuAssi没有错
但是download后,在硬件运行却不行了 会失效
//************   4*4键盘
//0  1  2  3   
//4  5  6  7
//8  9  ok cancel
//up down left right

问题是 只有cancel有效 ok就才实现了一半功能 其他键却等效cancel键了!
在keil调试仿真不会这样的。扫描键盘程序不会有错的。是什么原因?
 
 
 

回复

77

帖子

0

TA的资源

一粒金砂(初级)

11
 
把去抖弄点试试?

是不是太快了,呵呵
 
 
 

回复

61

帖子

0

TA的资源

一粒金砂(初级)

12
 
对 没去抖是一部分原因
我已经解决了一大部分问题了  其他键如常工作了 就是还有点点 up down left right功能键有点失效
我用控制字来控制的  好像这句不行 MenuAssi=MenuAssi>>1;或者MenuAssi=MenuAssi<<1;
我很希望这句有错。
 
 
 

回复

73

帖子

0

TA的资源

一粒金砂(中级)

13
 
如:               
if(Key==KeyUp&&Menu=0x80)//menu=0x80就是所 在menu等于0x80时keyup才起作用
{
   if(MenuAssi<0x08)    //这个是为了避免MenuAssi移位出界
   {
        ET1=0;      //这个是关掉中断T1  因为T1中断用到了MenuAssi  我怕它们在下一句冲突
        MenuAssi=MenuAssi<<1;  //这个移位后我就可以Menu和MenuAssi结合起来判断显示那个菜单
        ET1=1;       
    }
}
 
 
 

回复

123

帖子

0

TA的资源

一粒金砂(初级)

14
 
给全代码看看...

那两个语句,除非溢出了,否则肯定是没事的,我经常这样用
不过我更喜欢的方式是:

MenuAssi >>= 1;//我觉得这个更漂亮和清晰
 
 
 

回复

71

帖子

0

TA的资源

一粒金砂(初级)

15
 
Menu=0x80

最基本的错误
 
 
 

回复

77

帖子

0

TA的资源

一粒金砂(初级)

16
 
void DealKey(void)             //
{
        unsigned char Key;
        Key=0x00;
        Key=KeyScan();
        //**************************************  make sure whether the LCD run into menu
        if(Key>=0x10)          //没按键
        {
                return;
        }
       
        //*******for test
        //MenuAssi=0x04;
        //Key=KeyUp;//
        //Menu=0x80;
        //***************
        //有按键就灯亮一下       
       
        LED=0;  // 这个按键后亮和响一下 //不是主要问题
        Ring=0;

        if(Menu==0x00) //
        //when the LCD didn't run into menu ,and so just run into it and no action this key press  
        {
                        Menu=0x80;
                        //clear the second row for running into menu
                        //MenuAssi=0x08;
                        return;
       
        }
       
        //*************************************  from here on ,really deal with key press
        //***************************************************************    press OK
        else if(Key==KeyOk)  //press OK 0x0a
        {
                if(Menu==0x80)                        //说明刚进入menu 属于第一层           准备进第二层
                {
                         //移位是为了移到相应的位置置位
                        //表示进入那个菜单 置相应位
                        Menu|=(MenuAssi<<3);  
                        if(Menu==0x88)  //run into 4.stopwatch
                        {
                                min_Stop=0;
                                sec_Stop=0;
                                us_Stop=0; //进入重新置0
                                return;
                        }
                        Address=0xc4;                       
                        if(Menu==0xc0)    //         进入 第一菜单 1.set time
                        {
                        //为了避免与中断冲突 关中断
                                EA=0;
                                C_hour=T_hour;
                                C_min=T_min;
                                C_sec=T_sec;
                                EA=1;                         
                                //在第二行显示当前时间 给用户修改
                                return;
                        }       
                        else if(Menu==0xa0)   //run into 2.set alarm
                        {
                                ET1=0;
                                C_hour=hour_Alarm;
                                C_min=min_Alarm;
                                C_sec=sec_Alarm;
                                ET1=1;                         
                                return;
                        }
                       
                        else if(Menu==0x90)  //run into 3.set timer
                        {
                                ET1=0;
                                C_hour=hour_Timer;
                                C_min=min_Timer;
                                C_sec=sec_Timer;
                                ET1=1;                         
                                return;
                       
                        }        
                        return;               
                }//the end if(Menu==0x80)
                                       
                //以下为已经是第二层了
                else if(Menu==0x88) //when be in the 4.stopwatch  save stopwatch 并相关置位        //为了省空间
                {
                        b_stop=!b_stop;           //取反 使它可以控制秒表的暂停和继续计时        不用返回工作 因为可以由cancl做   
                        return;
                }
                else if(Menu==0xc0)          //when be in the  1.set time   press OK  so save time;
                {
                        //保存时间
                        EA=0;
                        T_hour=C_hour;
                        T_min=C_min;
                        T_sec=C_sec;
                        EA=1;
                        //////////////**************  返回工作
                        //暂时 不允许time1中断
                        ET1=0;
                        MenuAssi=Menu&0x7f;
                        MenuAssi=MenuAssi>>3;
                        Menu=0x80;
                        ET1=1;
                        return;               
                }
                else if(Menu==0xa0)        //when be in the 2.set alarm  press OK and so save alarm time        并相关置位  
                {
                        b_alarm=1;
                        //////////////**************  返回工作
                        //暂时 不允许time1中断
                        ET1=0;
                        MenuAssi=Menu&0x7f;
                        MenuAssi=MenuAssi>>3;
                        Menu=0x80;
                        ET1=1;
                        return;
                }
                else if(Menu==0x90) //when be in the 3.set timer  save timer time                并相关置位
                {
                        b_timer=1;
                        //////////////**************  返回工作
                        //暂时 不允许time1中断
                        ET1=0;
                        MenuAssi=Menu&0x7f;
                        MenuAssi=MenuAssi>>3;
                        Menu=0x80;
                        ET1=1;
                        return;        
                }
        }// here   the end of   if(Key==0x0a)  //press OK
        //*************************************************************** press cancel
        else if(Key==KeyCancel)  // press Cancel
        {
                if(Menu==0x80)  //在第一层 that action press cancel donnot work
                {
                        return;
                }

                else if(Menu==0x88)        //stopwatch
                //这个比较特殊 因为它的退出必须对Tool相应位复位
                {
                        b_stop=0;//对相应位复位                       
                }                                       
                //////////////**************  返回工作
                //暂时 不允许time1中断
                ET1=0;
                MenuAssi=Menu&0x7f;
                MenuAssi=MenuAssi>>3;
                Menu=0x80;
                ET1=1;

                return;       
        }//the end Key==0x0b  end deal with Cancel
        //**********************************************       press up                 *   press down
        //************************************************
        //                          就是这里不行 和下面的left right 也不行
        //
        //*************************************************
        else if((Key==KeyUp||Key==KeyDown)&&Menu==0x80)
        //in the class 1 menu  it can work . others don't work
        //注意MenuAssi的移位溢出
        {       
                //******  for test key
                //Key=0x0d;
                //Menu=0x80;
                //MenuAssi=0x08;
                //******
                if(Key==KeyUp)
                {
                        if(MenuAssi<0x08)
                        {
                                ET1=0;
                                MenuAssi=MenuAssi<<1;
                                ET1=1;       
                        }
                }
                if(Key==KeyDown)
               
                {
                        if(MenuAssi>0x01)
                        {
                                ET1=0;
                                MenuAssi=MenuAssi>>1;
                                ET1=1;       
                        }
                }
                return;
        }
        //*******************************************  press left or right
        else if((Key==KeyLeft||Key==KeyRight)&&(Menu==0xc0||Menu==0xa0||Menu==0x90))
        //in the class 2 menu except Stopwatch it can work . others don't work
        {
                if(Key==KeyLeft&&Address>0xc4)//left
                {
                        Address--;
                }
                if(Key==KeyRight&&Address<0xcb)//right
                {
                        Address++;
                }
                return;
                       
        }//the end of press left or right
        //****************************************************** press number key
        else if(Key>=Key0||Key<=Key9&&(Menu==0xc0||Menu==0xa0||Menu==0x90))
        {
                ET1=0;
                if(Address==0xc4)                        //改变hour的十位
                        C_hour=Key*10+C_hour%10;
                else if(Address==0xc5)                         //改变hour的个位
                        C_hour=Key+(C_hour/10)*10;       

                else if(Address==0xc7)                        //改变min的十位
                        C_min=Key*10+C_min%10;
                else if(Address==0xc8)                         //改变min的个位
                        C_min=Key+(C_min/10)*10;       

                else if(Address==0xca)                        //改变sec的十位
                        C_sec=Key*10+C_min%10;
                else if(Address==0xcb)                         //改变sec的个位
                        C_sec=Key+(C_min/10)*10;       
                ET1=1;
                return;
                       
        }
 
 
 

回复

54

帖子

0

TA的资源

一粒金砂(初级)

17
 
很长 在发个T1的:
void Timer1(void) interrupt 3 using 3
{
        unsigned char B_hour=0,B_min=0,B_sec=0;//B_inter=0;
         //目的为了在下面的语句中不允许timer0中断 影响sec min或者hour的突变。所以就用变量保存起来!
        ET0=0;
        B_hour=T_hour;
        B_min=T_min;
        B_sec=T_sec;
        //B_inter=T_inter;
        ET0=1;
        while(IsBusy_LCD());
        WriteCommand_LCD(0xc4);
        while(IsBusy_LCD());
        WriteCommand_LCD(0x0c);    //开显示 不显示光标 光标不闪烁
        //*****************************************************中断更新时间显示
        WFormatTime(0x84,B_hour,B_min,B_sec);
        //****************************************************
        //*****************************************************************  判断闹钟 定时器 到否
        if(b_alarm) //闹钟开动了
        {
                if(B_hour==hour_Alarm&&B_min==min_Alarm&&B_sec==sec_Alarm)
                {
                        Buzzer=1;//         蜂鸣器 工作
                }
        }
        if(b_timer)        //定时器开动了
        {
                if((B_hour-hourT)==hour_Timer&&(B_min-minT)==min_Timer&&(B_sec-secT)==sec_Timer)
                {
                        Buzzer=1;        //         蜂鸣器 工作
                }
        }


        //**************************************************** 真正menu的开始画面 判断控制字 要显示什么
        //*******for test
        //Menu=0xa0;
        //MenuAssi=0x02;
        //Address=0xc6;
        //b_stop=0;
        //***************
        if(Menu!=0x00)
        {
            
                if(Menu==0x80)                //run into class 1 of Menu and judge which menu it should show
                {
                        JudgeMenu();//这个函数判断根据MenuAssi显示那个菜单的
                }


                //****************  run into class 2 of menu
       
                else if(Menu==0x88)        //show stopwatch
                {
                        ET0=0;
                        B_hour=min_Stop;
                        B_min=sec_Stop;
                        B_sec=us_Stop;
                        ET0=1;

                        DisplayData_LCD(16,0,' '); //这个函数是清空LCD第2行数据
                        WFormatTime(0xc4,B_hour,B_min,B_sec);//是按时间格式写在LCD第二行               
                }        
               
                else if(Menu==0xc0)  //show time
                {
                        B_hour=C_hour;
                        B_min=C_min;
                        B_sec=C_sec;
                        DisplayData_LCD(16,0,' ');//这个函数是清空LCD第2行数据
                        WFormatTime(0xc4,B_hour,B_min,B_sec););//是按时间格式写在LCD第二行               
                               
                        while(IsBusy_LCD());
                        WriteCommand_LCD(Address); //是显示光标在第2行第几位置 根据Left right控制Address
                        while(IsBusy_LCD());
                        WriteCommand_LCD(0x0f);    //开显示 显示光标 光标闪烁       
                }
                       
                else if(Menu==0xa0)                //show  alarm
                {
                        B_hour=C_hour;
                        B_min=C_min;
                        B_sec=C_sec;
                        DisplayData_LCD(16,0,' ');
                        WFormatTime(0xc4,B_hour,B_min,B_sec);       

                        while(IsBusy_LCD());
                        WriteCommand_LCD(Address);
                        while(IsBusy_LCD());
                        WriteCommand_LCD(0x0f);    //开显示 显示光标 光标闪烁       
                }
                                                                          
                else if(Menu==0x90)                           //show timer
                {
                        B_hour=C_hour;
                        B_min=C_min;
                        B_sec=C_sec;
                       
                        DisplayData_LCD(16,0,' ');
                        WFormatTime(0xc4,B_hour,B_min,B_sec);

                        while(IsBusy_LCD());
                        WriteCommand_LCD(Address);
                        while(IsBusy_LCD());
                        WriteCommand_LCD(0x0f);    //开显示 显示光标 光标闪烁
                }
        }




        //*****************************************************重装计数器
        TH1=H_Timer1;
        TL1=L_Timer1;       
}
 
 
 

回复

86

帖子

0

TA的资源

一粒金砂(初级)

18
 
刚学不久 写了10多天 写得很乱 命名也很烂  不要见怪!
 
 
 

回复

75

帖子

0

TA的资源

一粒金砂(初级)

19
 
感觉,一个中断里做的事情还是太多了...

另外,事件的处理尽可能用状态机来描述逻辑关系,这样就不乱了

关于状态机的思路,你可以去看一下编译原理,里面有很详细的阐述.

<现代编译原理--C语言描述>作者:ANDREW W.APPEL 译者:赵克佳,黄春,沈志学.人民邮电出版社

用状态机是对底层事务状态描述相当漂亮的工具.嘿嘿
 
 
 

回复

75

帖子

0

TA的资源

一粒金砂(初级)

20
 
哈哈 现在大致搞好了 只是一些小部分和细节部分了 很高兴  一个人完成电子设计题目 不过用了10多天 晕死了
你这是高手  真的是那个去抖问题  我的时间不够长  够长就可以了!

哦 好的 我也要去学那个编译原理了

对于这个方案 我感觉到T1的中断任务太重了! 我的那个方案一不就在main函数来 可我不会处理main和时间中断共同调用子函数的冲突啊!

lbing7(向青润老大学习!!!)
你对单片机很熟悉 对keil的编译也很熟悉   不知道能否介绍几本关于这些的书给我呢?
 
 
 

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

查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/9 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表