找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 2769|回复: 12
打印 上一主题 下一主题
收起左侧

单片机红外遥控控制继电器 为什么led()子程序无法跳出

[复制链接]
跳转到指定楼层
楼主
这是一个红外遥控控制继电器RELAY,并在液晶上显示遥控编码,在if(Y0==0x10){RELAY=1;P2=0xff;} else {RELAY=0;led();}中,我设定当遥控按下关闭键时关闭继电器,同时P2全部LED灯关闭,但程序却无法返回P2=0xff;,我自己大概分析原因应该是led();子函数正常运行,while(1)无法跳出。我用过do while也不行。请问各大神应该怎么修改呢?
  1. #include <intrins.h>
  2. #define  NOP()   _nop_()   /* 定义空指令 */

  3. #define uchar unsigned char
  4. #define uint  unsigned int
  5. #define delayNOP(); {_nop_();_nop_();_nop_();_nop_();};

  6. void delay(uchar x);  //x*0.14MS
  7. void delay1(int ms);
  8. void beep(void);
  9. void led();

  10. sbit IRIN = P3^2;         //红外接收器数据线
  11. sbit RELAY= P1^4;         //继电器驱动线
  12. sbit BEEP = P1^5;         //蜂鸣器驱动线

  13. uchar IRCOM[7];

  14. uchar cdis1[] = {" REMOTE CONTROL "};
  15. uchar cdis2[] = {"  IR-CODE: --H"};

  16. //LCD IO
  17. sbit LCD_RW = P2^5;
  18. sbit LCD_RS = P2^6;            
  19. sbit LCD_EN = P2^7;


  20. unsigned char Y0;

  21. /*******************************************************************/
  22. /*                                                                 */
  23. /*检查LCD忙状态                                                    */
  24. /*lcd_busy为1时,忙,等待。lcd-busy为0时,闲,可写指令与数据。      */
  25. /*                                                                 */
  26. /*******************************************************************/

  27. bit lcd_busy()
  28. {                          
  29.     bit result;
  30.     LCD_RS = 0;
  31.     LCD_RW = 1;
  32.     LCD_EN = 1;
  33.     delayNOP();
  34.     result = (bit)(P0&0x80);
  35.     LCD_EN = 0;
  36.     return(result);
  37. }

  38. /*******************************************************************/
  39. /*                                                                 */
  40. /*写指令数据到LCD                                                  */
  41. /*RS=L,RW=L,E=高脉冲,D0-D7=指令码。                             */
  42. /*                                                                 */
  43. /*******************************************************************/

  44. void lcd_wcmd(uchar cmd)

  45. {                          
  46.    while(lcd_busy());
  47.     LCD_RS = 0;
  48.     LCD_RW = 0;
  49.     LCD_EN = 0;
  50.     _nop_();
  51.     _nop_();
  52.     P0 = cmd;
  53.     delayNOP();
  54.     LCD_EN = 1;
  55.     delayNOP();
  56.     LCD_EN = 0;  
  57. }

  58. /*******************************************************************/
  59. /*                                                                 */
  60. /*写显示数据到LCD                                                  */
  61. /*RS=H,RW=L,E=高脉冲,D0-D7=数据。                               */
  62. /*                                                                 */
  63. /*******************************************************************/

  64. void lcd_wdat(uchar dat)
  65. {                          
  66.    while(lcd_busy());
  67.     LCD_RS = 1;
  68.     LCD_RW = 0;
  69.     LCD_EN = 0;
  70.     P0 = dat;
  71.     delayNOP();
  72.     LCD_EN = 1;
  73.     delayNOP();
  74.     LCD_EN = 0;
  75. }

  76. /*******************************************************************/
  77. /*                                                                 */
  78. /*  LCD初始化设定                                                  */
  79. /*                                                                 */
  80. /*******************************************************************/

  81. void lcd_init()
  82. {
  83.     delay1(15);                  
  84.     lcd_wcmd(0x38);      //16*2显示,5*7点阵,8位数据
  85.     delay1(5);
  86.     lcd_wcmd(0x38);         
  87.     delay1(5);
  88.     lcd_wcmd(0x38);         
  89.     delay1(5);

  90.     lcd_wcmd(0x0c);      //显示开,关光标
  91.     delay1(5);
  92.     lcd_wcmd(0x06);      //移动光标
  93.     delay1(5);
  94.     lcd_wcmd(0x01);      //清除LCD的显示内容
  95.     delay1(5);
  96. }

  97. /*******************************************************************/
  98. /*                                                                 */
  99. /*  设定显示位置                                                   */
  100. /*                                                                 */
  101. /*******************************************************************/

  102. void lcd_pos(uchar pos)
  103. {                          
  104.   lcd_wcmd(pos | 0x80);  //数据指针=80+地址变量
  105. }

  106. /*******************************************************************/
  107. main()
  108. {
  109.         uchar m;
  110.     IE = 0x81;                 //允许总中断中断,使能 INT0 外部中断
  111.     TCON = 0x01;               //触发方式为脉冲负边沿触发

  112.     IRIN=1;                    //I/O口初始化
  113.     BEEP=1;
  114.     RELAY=1;
  115.         
  116.     delay1(10);                 //延时
  117.     lcd_init();                //初始化LCD            

  118.     lcd_pos(0);                //设置显示位置为第一行的第1个字符
  119.      m = 0;
  120.     while(cdis1[m] != '\0')
  121.      {                         //显示字符
  122.        lcd_wdat(cdis1[m]);
  123.        m++;
  124.      }

  125.     lcd_pos(0x40);             //设置显示位置为第二行第1个字符
  126.      m = 0;
  127.     while(cdis2[m] != '\0')
  128.      {
  129.        lcd_wdat(cdis2[m]);      //显示字符
  130.        m++;
  131.      }

  132.    while(1);

  133. } //end main
  134. /**********************************************************/
  135. void IR_IN(void) interrupt 0          //外部中断服务程序
  136. {
  137.   unsigned char j,k,N=0;
  138.      EX0 = 0;   
  139.          delay(15);
  140.          if (IRIN==1)
  141.      { EX0 =1;
  142.            return;
  143.           }
  144.                            //确认IR信号出现
  145.   while (!IRIN)            //等IR变为高电平,跳过9ms的前导低电平信号。
  146.     {delay(1);}

  147. for (j=0;j<4;j++)         //收集四组数据
  148. {
  149.   for (k=0;k<8;k++)        //每组数据有8位
  150.   {
  151.    while (IRIN)            //等 IR 变为低电平,跳过4.5ms的前导高电平信号。
  152.      {delay(1);}
  153.     while (!IRIN)          //等 IR 变为高电平
  154.      {delay(1);}
  155.      while (IRIN)           //计算IR高电平时长
  156.       {
  157.     delay(1);
  158.     N++;           
  159.     if (N>=30)
  160.          { EX0=1;
  161.          return;}                  //0.14ms计数过长自动离开。
  162.       }                        //高电平计数完毕               
  163.      IRCOM[j]=IRCOM[j] >> 1;                  //数据最高位补“0”
  164.      if (N>=8) {IRCOM[j] = IRCOM[j] | 0x80;}  //数据最高位补“1”
  165.      N=0;
  166.   }//end for k
  167. }//end for j

  168.    if (IRCOM[2]!=~IRCOM[3])
  169.    { EX0=1;
  170.      return; }

  171.    IRCOM[5]=IRCOM[2] & 0x0F;     //取键码的低四位
  172.    IRCOM[6]=IRCOM[2] >> 4;       //右移4次,高四位变为低四位

  173.    if(IRCOM[5]>9)
  174.     { IRCOM[5]=IRCOM[5]+0x37;}
  175.    else
  176.           IRCOM[5]=IRCOM[5]+0x30;

  177.    if(IRCOM[6]>9)
  178.     { IRCOM[6]=IRCOM[6]+0x37;}
  179.    else
  180.           IRCOM[6]=IRCOM[6]+0x30;

  181.      lcd_pos(0x4b);            
  182.      lcd_wdat(IRCOM[6]);        //第一位数显示
  183.      lcd_pos(0x4c);            
  184.      lcd_wdat(IRCOM[5]);        //第二位数显示

  185.          Y0=0;
  186.          switch(IRCOM[2])
  187.          {
  188.            case 0x09: Y0=0x01; break;
  189.            case 0x1D: Y0=0x02; break;
  190.            case 0x1F: Y0=0x03; break;
  191.            case 0x0D: Y0=0x04; break;
  192.            case 0x19: Y0=0x05; break;
  193.            case 0x1B: Y0=0x06; break;
  194.            case 0x11: Y0=0x07; break;
  195.            case 0x15: Y0=0x08; break;
  196.            case 0x17: Y0=0x09; break;
  197.            case 0x45: Y0=0x10; break;

  198.           case 0x13: RELAY=1; break;
  199.           case 0x14: RELAY=1; break;
  200.           case 0x51: RELAY=0; break;
  201.          }

  202.         if(Y0==0x10){RELAY=1;P2=0xff;} //关闭继电器
  203.         else {RELAY=0;led();}       //打开继电器

  204.     beep();
  205.     EX0 = 1;
  206. }

  207. /**********************************************************/
  208. void beep(void)
  209. {
  210.   unsigned char i;
  211.   for (i=0;i<100;i++)
  212.    {
  213.    delay(4);
  214.    BEEP=!BEEP;                 //BEEP取反
  215.    }
  216.   BEEP=1;                      //关闭蜂鸣器
  217. }
  218. void led()
  219. {
  220.     int i=0;
  221.         uchar a;
  222.     unsigned char ledd[8]={0x7e,0xbd,0xdb,0xe7,0xdb,0xbd,0x7e,0xff};
  223.     //其实就是定义了一个亮灯状态表
  224.    while(1)
  225.         {
  226.         for(i=0;i<8;i++)
  227.             {
  228.                         P2=ledd[i];
  229.                         delay1(50);
  230.                         }
  231.         //中间往两边移动
  232.                 a=0xff;
  233.                 for(i=0;i<=8;i++)
  234.                 {
  235.                         P2=a;
  236.                         delay1(50);
  237.                         a=a>>1;
  238.                         //if(a==0x00)        break;
  239.                 }
  240.          //右移+1
  241.                 a=0xff;
  242.                 for(i=0;i<8;i++)
  243.                 {
  244.                         P2=a;
  245.                         delay1(50);
  246.                         a=a<<1;
  247.                         //if(a==0x00)        break;
  248.                 }
  249.          //左移+1
  250.                 a=0x7f;
  251.                 for (i = 0 ;i < 8 ; i++)
  252.           {
  253.                 P2=a;
  254.                 delay1(50);
  255.                 a=_cror_(a,1);
  256.             if (a == 0xfe)         break;
  257.            }
  258.                    for (i = 0 ;i < 8 ; i++)
  259.           {
  260.                 P2=a;
  261.                 delay1(50);
  262.                 a=_crol_(a,1);
  263.             if (a == 0xff)         break;
  264.            }
  265.         //循环左右移
  266.         }
  267. }
  268. /**********************************************************/
  269. void delay(unsigned char x)    //x*0.14MS
  270. {
  271. unsigned char i;
  272.   while(x--)
  273. {
  274.   for (i = 0; i<13; i++) {}
  275. }
  276. }

  277. /**********************************************************/
  278. void delay1(int ms)
  279. {
  280. unsigned char y;
  281.   while(ms--)
  282. {
  283.   for(y = 0; y<250; y++)
  284.   {
  285.    _nop_();
  286.    _nop_();
  287.    _nop_();
  288.    _nop_();
  289.   }
  290. }
  291. }
复制代码


分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:7485 发表于 2018-1-29 08:26 | 只看该作者
没看到你打开外部中断呢?(EX0=1;)

   “ TCON = 0x01;               //触发方式为脉冲负边沿触发”


是上升沿触发吧。
回复

使用道具 举报

板凳
ID:7485 发表于 2018-1-29 08:27 | 只看该作者
没有详细看其他地方。
回复

使用道具 举报

地板
ID:62355 发表于 2018-1-29 09:08 | 只看该作者
main()
{
        uchar m;
    IE = 0x81;                 //允许总中断中断,使能 INT0 外部中断
    TCON = 0x01;               //触发方式为脉冲负边沿触发

    IRIN=1;                    //I/O口初始化
    BEEP=1;
    RELAY=1;
        
    delay1(10);                 //延时
    lcd_init();                //初始化LCD            

    lcd_pos(0);                //设置显示位置为第一行的第1个字符
     m = 0;
    while(cdis1[m] != '\0')
     {                         //显示字符
       lcd_wdat(cdis1[m]);
       m++;
     }

    lcd_pos(0x40);             //设置显示位置为第二行第1个字符
     m = 0;
    while(cdis2[m] != '\0')
     {
       lcd_wdat(cdis2[m]);      //显示字符
       m++;
     }

   while(1)
{
//你要的循环
}

} //end main
回复

使用道具 举报

5#
ID:213173 发表于 2018-1-29 09:50 | 只看该作者
你在led()里使用死循环while(1),又没有设置强制跳出的条件,程序当然死在这里。
回复

使用道具 举报

6#
ID:258566 发表于 2018-1-29 10:53 | 只看该作者

回复

使用道具 举报

7#
ID:7485 发表于 2018-1-29 17:04 | 只看该作者
没仔细看,好像是靠中断跳出循环的。
你仿真时的中断正常吗?
回复

使用道具 举报

8#
ID:269211 发表于 2018-1-30 22:49 | 只看该作者
流逝记忆 发表于 2018-1-29 09:08
main()
{
        uchar m;

已试过你的方法,不行,不过还是谢谢你
回复

使用道具 举报

9#
ID:269211 发表于 2018-1-30 22:49 | 只看该作者

已试过你的方法,不行,不过还是谢谢你
回复

使用道具 举报

10#
ID:280512 发表于 2018-1-31 09:59 | 只看该作者
中断控制可靠吗?
回复

使用道具 举报

11#
ID:269211 发表于 2018-1-31 12:12 来自手机 | 只看该作者
青桑叶 发表于 2018-1-31 09:59
中断控制可靠吗?

中断可以
回复

使用道具 举报

12#
ID:267330 发表于 2018-1-31 12:23 | 只看该作者
没看到你打开外部中断呢?(EX0=1;) “ TCON = 0x01;               //触发方式为脉冲负边沿触发”是上升沿触发吧
回复

使用道具 举报

13#
ID:281168 发表于 2018-1-31 15:16 | 只看该作者
你在led()的子函数里面,用了while(1),这样程序只会在这里面跑,当然不会跳出。不建议在子函数用while(1),应该用while(条件判断),这样会合理一点
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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