佳礼资讯网

 找回密码
 注册

ADVERTISEMENT

查看: 1579|回复: 8

中断程序内呼叫不到其他副程序

[复制链接]
发表于 25-11-2012 08:07 PM | 显示全部楼层 |阅读模式
为了方便,我会把修改过的program放在一楼。
1。 应用 :控制relay闭合
2。用途:个人

3。需要效果 :控制relay闭合间隔的时间
  • relay每隔一段时间(30sec~2minutes)就会闭合一次。
  • 每发生一次中断,间隔时间+30秒。间隔时间最大不超过2分钟。
  • 中断发生后,LCD即刻更新当前间隔时间。
4。遇到的问题:
  • 中断程序内呼叫不到其他副程序(已解决)
  • 中断发生后,LCD不能即刻更新当前间隔时间。
5。经过什么试验/检查 :
如果中断程序内尝试呼叫其他副程序,output msg:No enough RAM for call stack.
如果没在中断程序内呼叫其他副程序就没问题

6. 电路图 :买的是成品套件。
7。 对于问题的头绪/见解:
  • 不了解,程式是照着书本修改的
  • 16f877a ram不多


8。对于问题需要的解决方案:
  • 程式问题修改程式

9。资金/资源:RM120,cytron产品。

程式源码如下,使用MikroC编写,PIC是16F877A。如果把interrupt内的display()副程序删掉就能compile成功。
/*-------------------版本(1)-----------------------------------*/
void display()
{
Lcd_Cmd(_LCD_CLEAR);
Lcd_Out(1,1,"Well Done";
}

void camera()
{
PORTB.B7=0;
PORTB.B6=1;
VDelay_ms(a);
PORTB.B7=1;
PORTB.B6=1;
VDelay_ms(a);
PORTB.B7=0;
PORTB.B6=0;
VDelay_ms(a);
}

void interrupt()
{
if(INTCON.B1==1)
{
  a=a+10000;
  if(a>=58000)
     {
     a=8000;
     }
  INTCON.B1=0;
     display();
}
}

void main()
{
CCP1CON=CCP2CON=0;
PORTB=0;
TRISB=0b0000001;
TRISD=0;
ADCON0=0;
INTCON.INTF=0;
INTCON.INTE=1;
INTCON.GIE=1;
Lcd_Init();
Lcd_Cmd(_LCD_CLEAR);
Lcd_Cmd(_LCD_CURSOR_OFF);
Lcd_Out(1,1,"Well Come";
Delay_ms(1000);

while(1)
camera();

}
  1. /*------------------------版本(2)--------------------------------*/
  2. void relaycont()
  3. {
  4. PORTB.B7=0;PORTB.B6=1;    PORTB.B2=1;PORTB.B1=0;
  5. Delay_ms(1000);
  6. PORTB.B7=1;PORTB.B6=1;    PORTB.B2=0;PORTB.B1=0;
  7. Delay_ms(1000);
  8. PORTB.B7=0;PORTB.B6=0;    PORTB.B2=1;PORTB.B1=1;
  9. VDelay_ms(a);
  10. }

  11. void display()
  12. {
  13.    if(a==28000)             {Lcd_Out(1,2,"30 Seconds");}
  14.    if(a==58000)             {Lcd_Out(1,2,"1 Minute");}
  15.    if(a==88000)             {Lcd_Out(1,2,"1 Min 30 Sec");}
  16.    if(a==118000)            {Lcd_Out(1,2,"2 Minutes");}
  17.    WordToStr(b,count1); Lcd_Out(2,1,count1); Lcd_Out(2,8,"Times");
  18. }

  19. void timecount()
  20. {
  21.       b++;
  22.       if(b>50000)
  23.       {
  24.       b=1;
  25.       }
  26. }

  27. void interrupt()
  28. {
  29.    if(INTCON.B1==1)
  30.    {
  31.      a=a+30000;
  32.      if(a>118000)
  33.         {
  34.         a=28000;
  35.         }
  36.      INTCON.B1=0;
  37.    }
  38. }

  39. void main()
  40. {
  41.    CCP1CON=CCP2CON=0;
  42.    PORTB=0b00000110;
  43.    TRISB=0b00000001;
  44.    TRISD=0;
  45.    ADCON0=0;
  46.    Lcd_Init();
  47.    Lcd_Cmd(_LCD_CLEAR);
  48.    Lcd_Cmd(_LCD_CURSOR_OFF);
  49.    Lcd_Out(1,1,"Welcome");
  50.    Delay_ms(2000);
  51.    Lcd_Cmd(_LCD_CLEAR);
  52.    INTCON.INTF=0;
  53.    INTCON.INTE=1;
  54.    INTCON.GIE=1;

  55.    while(1)
  56.    {
  57.       display();       //LCD display counting times
  58.       relaycont();   //on off relay
  59.       timecount();     //b++;
  60.    }
  61. }
复制代码
我要的效果是每发生中断一次,LCD都能及时更新当前的状态。
现在问题是LCD不会及时更新。蒙受大大们的指教~小弟获益不浅~感谢感谢~ =D




本帖最后由 FakeSheep 于 28-11-2012 09:57 AM 编辑

回复

使用道具 举报


ADVERTISEMENT

发表于 26-11-2012 10:37 AM | 显示全部楼层
MicroC 我 不会。。
但是, 一般我们不在中断程序再呼叫其他程序。
另一个方法是设定一个flag。

  1. /*---------------------------------------------------------*/
  2. int fDisplay=0;
  3. void display()
  4. {
  5.    Lcd_Cmd(_LCD_CLEAR);
  6.    Lcd_Out(1,1,"Well Done");
  7. }


  8. void interrupt()
  9. {
  10.    if(INTCON.B1==1)
  11.    {
  12.      a=a+10000;
  13.      if(a>=58000)
  14.         {
  15.         a=8000;
  16.         }
  17.      INTCON.B1=0;
  18.       //  display();
  19.       fDisplay=1;
  20.    }
  21. }

  22. void main()
  23. {
  24.    CCP1CON=CCP2CON=0;
  25.    PORTB=0;
  26.    TRISB=0b0000001;
  27.    TRISD=0;
  28.    ADCON0=0;
  29.    INTCON.INTF=0;
  30.    INTCON.INTE=1;
  31.    INTCON.GIE=1;
  32.    Lcd_Init();
  33.    Lcd_Cmd(_LCD_CLEAR);
  34.    Lcd_Cmd(_LCD_CURSOR_OFF);
  35.    Lcd_Out(1,1,"Welcome");
  36.    Delay_ms(1000);
  37.    
  38.    while(1)
  39.    {
  40.       camera();
  41.       if(fDisplay)
  42.       {
  43.          Display();      
  44.          fDisplay=0;
  45.       }
  46.    }
  47. }
复制代码
回复

使用道具 举报

发表于 26-11-2012 10:45 PM | 显示全部楼层
在interrupt里面好像是不可以用call functions 的。
回复

使用道具 举报

发表于 27-11-2012 12:37 AM | 显示全部楼层
ram 不够, 加上你的function 需要大量的stack,所以你不能在interrupt call function.
pic 大大建议的方法, 可以是看。 一般上写program也不会在interrupt call function。简化interrupt,把需要的东西在main 执行, program 比较organize, 也比较tracable.


回复

使用道具 举报

发表于 27-11-2012 12:42 AM | 显示全部楼层
keat88 发表于 26-11-2012 10:45 PM
在interrupt里面好像是不可以用call functions 的。

没遇过这种问题。
不过一般上是避免这样做。 万一function不是reentrant, 恰好遇到同一个function在main & interrupt 同时呼叫, 麻烦就来了。 不过这是个别案件,不是每一个mcu & compiler会有这样的case.

有时候我也是会在interrupt call function 地说。



回复

使用道具 举报

发表于 27-11-2012 11:45 AM | 显示全部楼层
fritlizt 发表于 27-11-2012 12:42 AM
没遇过这种问题。
不过一般上是避免这样做。 万一function不是reentrant, 恰好遇到同一个function在ma ...

如果在main用interrupt bit 来detect interrupt ,这样用call function 就没有问题。
但是他的是interrupt call 里面再call. 更何况在interrupt bit clear 过后才call
这是不能的,万一如果他的interrupt 来得太快,这样不是call还没走完又interrupt?。。。stack爆定啦

还有啊,
Lcd_Cmd(_LCD_CLEAR);
Lcd_Out(1,1,"Well Done");  是用compiler 的service吧?里面也很多call的.
还有:
Lcd_Cmd(_LCD_CLEAR);
Lcd_Cmd(_LCD_CURSOR_OFF);
Lcd_Out(1,1,"Well Come");
过后又,
Lcd_Cmd(_LCD_CLEAR);
Lcd_Out(1,1,"Well Done");
何不在display()里:Lcd_Out(6,1,"Done"); //or LCD_Out(1,6,"Done");
够快。。。。更快还可以LCD_Out(6,1,"Don");  
回复

使用道具 举报

Follow Us
发表于 27-11-2012 12:43 PM | 显示全部楼层
keat88 发表于 27-11-2012 11:45 AM
如果在main用interrupt bit 来detect interrupt ,这样用call function 就没有问题。
但是他的是interrup ...

这个分区好久都没人进来讨论mcu的咚咚了。lol.

mcu 在interrupt subroutine不会被同一个interrupt 打断, 会等到现在这个interrupt走完, 再来进回同一个interrupt function.
所以,如果interrupt (同一个) 来得太快, 会变成main function无效, 因为根本不会return回去main. 一直在loop interrupt而已。
所以如果是这种情况, ram未必会不够, 不过你的program hang掉了。
所以在interrupt function是可以call function的, 取决于你的stack够不够罢了。

楼主的情况, 我猜是interrupt call的那个routine,需要太多的stack,导致的, 877的ram又那么少。

楼主现在什么情况了?


本帖最后由 fritlizt 于 27-11-2012 12:47 PM 编辑

回复

使用道具 举报

 楼主| 发表于 28-11-2012 09:54 AM | 显示全部楼层
小弟大概明白大大们的意思了~程序修改了一些,新的问题来了~

据我了解interrupt可以发生在任何时候,
如果根据pic大大的建议设定flag,
mcu会先处理interrupt,再回去interrupt发生点处理剩下的服务,最后才去处理那个flag

我问题是如何确保当flag=1的时候,mcu马上去处理那个flag?
回复

使用道具 举报


ADVERTISEMENT

发表于 29-11-2012 10:00 AM | 显示全部楼层
FakeSheep 发表于 28-11-2012 09:54 AM
小弟大概明白大大们的意思了~程序修改了一些,新的问题来了~

据我了解interrupt可以发生在任何时候,
据我了解interrupt可以发生在任何时候,
如果根据pic大大的建议设定flag,
mcu会先处理interrupt,再回去interrupt发生点处理剩下的服务,最后才去处理那个flag

我问题是如何确保当flag=1的时候,mcu马上去处理那个flag?
我不知道你的真正应用是什么, 你非要立刻处理不可?
如果你的信号是很快速的, 你错过就没有了的, 那么这种我不会用中断, 我会直接专注在这个信号, MCU 的大部分时间都在main() 等这种很急很急的信号。 要知道, 进一次interrupt,出一次interrupt, 就需要耗费一些时间了。


有时编程, 是讲究技巧。。
如果在很慢的MCU 上, 怎样实现读取很快的信号?可能那个MCU 只能有一个专注的功能了。。

PIC MCU 的clock 可以去到32Mhz , /4= 8MIPS, 一秒8百万次。。
用快的MCU, RAM, ROM, Stack 足够的情况下, 基本随便写都可以了。。
但是这样就没有挑战了。。。

另外, MicroC compiler 也是有所限制。

我使用CCS C, 但是如果遇到我在中断时必须要马上处理的信号时, 就直接在中断里完成一些Flag, 或variable数字的更新,I/O 的更新, 我绝对不会在中断里去更新我LCD 的显示, 因为完全没有这种必要, 我也不认为我的眼睛能分辨出那种快速的更新。

写程序, 也要合理, 当然你可以去挑战 , 去学习。
写程序, 可以很活的, 你甚至可以建立自己的简单系统, 比如Round Robin ,Time schedule 这种简单的框架, 复杂一些的是RTOS, 但是RTOS 不是所有小MCU 受的了的。
Delay_ms(1000); 这种指令尽量的少用。。


我问题是如何确保当flag=1的时候,mcu马上去处理那个flag?
回答你, 如果你有充分的理由必须要马上处理时, 你不要用中断了。。你应该在main 等那个信号然后马上处理

不然, 你就用CCS C, 你在interrupt 里能够合理的call 一些副程序, 前题是你的Stack 足够, 还有你允许耗费》40 的instruction 时间进入interrupt, 再 》40 个instruction 的时间退出 interrupt。






回复

使用道具 举报

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

本版积分规则

 

ADVERTISEMENT



ADVERTISEMENT



ADVERTISEMENT

ADVERTISEMENT


版权所有 © 1996-2023 Cari Internet Sdn Bhd (483575-W)|IPSERVERONE 提供云主机|广告刊登|关于我们|私隐权|免控|投诉|联络|脸书|佳礼资讯网

GMT+8, 24-4-2024 03:24 PM , Processed in 0.063429 second(s), 28 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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