找回密码
 立即注册

QQ登录

只需一步,快速开始

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

单片机不使用外部中断,如何LED显示程序?

[复制链接]
跳转到指定楼层
楼主
我要实现的是按键按一下LED长亮,第二下显示SOS信号,第三下LED熄灭,但是现在有时按第三下LED并不熄灭,我想是因为我的SOS显示代码没有执行完,所以按键扫描不到,请问这个问题如何解决呢。下面是我的代码# include <STC8.h>
# include <intrins.h>
sbit KEY = P3^5;
sbit LED = P3^4;
unsigned int num=0;
unsigned int LED_flag=0;
void Delay10ms()                //@24.000MHz
{
        unsigned char data i, j, k;

        i = 2;
        j = 56;
        k = 172;
        do
        {
                do
                {
                        while (--k);
                } while (--j);
        } while (--i);
}
void Delay200ms(void)        //@24.000MHz
{
        unsigned char data i, j, k;

        _nop_();
        _nop_();
        i = 25;
        j = 90;
        k = 176;
        do
        {
                do
                {
                        while (--k);
                } while (--j);
        } while (--i);
}

void Delay500ms(void)        //@24.000MHz
{
        unsigned char data i, j, k;

        _nop_();
        _nop_();
        i = 61;
        j = 225;
        k = 62;
        do
        {
                do
                {
                        while (--k);
                } while (--j);
        } while (--i);
}
void Delay2000ms(void)        //@24.000MHz
{
        unsigned char data i, j, k;

        i = 244;
        j = 130;
        k = 4;
        do
        {
                do
                {
                        while (--k);
                } while (--j);
        } while (--i);
}

void Init_IO()               
{
    P0M1 = 0x00;   P0M0 = 0x00;   
    P1M1 = 0x00;   P1M0 = 0x00;   
    P2M1 = 0x00;   P2M0 = 0x00;   
    P3M1 = 0x00;   P3M0 = 0x00;   
    P4M1 = 0x00;   P4M0 = 0x00;   
    P5M1 = 0x00;   P5M0 = 0x00;   
    P6M1 = 0x00;   P6M0 = 0x00;   
    P7M1 = 0x00;   P7M0 = 0x00;   
}
void display_sos()
{
        LED = 1;            
        Delay200ms();
        LED = 0;            
        Delay200ms();
        LED = 1;            
        Delay200ms();
        LED = 0;            
        Delay200ms();
        LED = 1;            
        Delay200ms();
        LED = 0;            
        Delay200ms();

        LED = 1;            
  Delay500ms();
        LED = 0;            
  Delay500ms();
        LED = 1;            
  Delay500ms();
        LED = 0;           
  Delay500ms();
        LED = 1;            
  Delay500ms();
        LED = 0;            
  Delay500ms();

        LED = 1;            
        Delay200ms();
        LED = 0;            
        Delay200ms();
        LED = 1;           
        Delay200ms();
        LED = 0;            
        Delay200ms();
        LED = 1;            
        Delay200ms();
        LED = 0;            
        Delay200ms();
        
        Delay2000ms();
}
void display()
{
        if(LED_flag==0)
        {
                LED=0;
        }
        else if(LED_flag==1)
        {
                LED=1;
        }
        else if(LED_flag==2)
        {
                while(LED_flag==2)
                {
                        display_sos();
                }        
        }
        else if(LED_flag==3)
        {
                LED=0;
        }
}        
void KeyScan()
{
        if(KEY == 0)
        {
                Delay10ms();                        
                if(KEY == 0)
                {
                        LED_flag++;
                        display();
                        if(LED_flag==3)
                        {
                                LED_flag=0;
                        }                        
                }
                while(!KEY);                                
        }
}
void main()
{
  LED = 0;
        Init_IO();
        while(1)
        {
                KeyScan();               
        }
}


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

使用道具 举报

来自 2#
ID:633559 发表于 2024-8-10 08:58 | 只看该作者
/*
什么状不状态不态,太远了。在你基础上改了下,思路是没问题的,代码还没测试过,你看看有没有有没有参考价值吧。
*/
sbit KEY = P3 ^ 5;
sbit LED = P3 ^ 4;
unsigned int num = 0;
unsigned int LED_flag = 0;
void Delay10ms()                //@24.000MHz
{
    unsigned char data i, j, k;

    i = 2;
    j = 56;
    k = 172;
    do
    {
        do
        {
            while (--k);
        }
        while (--j);
    }
    while (--i);
}

void Init_IO()
{
    P0M1 = 0x00;
    P0M0 = 0x00;
    P1M1 = 0x00;
    P1M0 = 0x00;
    P2M1 = 0x00;
    P2M0 = 0x00;
    P3M1 = 0x00;
    P3M0 = 0x00;
    P4M1 = 0x00;
    P4M0 = 0x00;
    P5M1 = 0x00;
    P5M0 = 0x00;
    P6M1 = 0x00;
    P6M0 = 0x00;
    P7M1 = 0x00;
    P7M0 = 0x00;
}
void display_sos(unsigned char state)
{
    static unsigned int cnt = 0;
    if (state == 0)
    {
        cnt = 0;
    }
/*
下面其实可以写的漂亮点,用结构体数组for循环处理
*/
    if (cnt < 540)
    {
        cnt++;
    }  
    if (cnt < 20)
    {
        LED = 1;
    }
    else if (cnt < 40)
    {
        LED = 0;
    }
    else if (cnt < 60)
    {
        LED = 1;
    }
    else if (cnt < 80)
    {
        LED = 0;
    }
    else if (cnt < 100)
    {
        LED = 1;
    }
    else if (cnt < 120)
    {
        LED = 0;
    }
   
    else if (cnt < 170)
    {
        LED = 1;
    }
    else if (cnt < 220)
    {
        LED = 0;
    }
    else if (cnt < 270)
    {
        LED = 1;
    }
    else if (cnt < 320)
    {
        LED = 0;
    }
    else if (cnt < 370)
    {
        LED = 1;
    }
    else if (cnt < 420)
    {
        LED = 0;
    }

    else if (cnt < 440)
    {
        LED = 1;
    }
    else if (cnt < 460)
    {
        LED = 0;
    }
    else if (cnt < 480)
    {
        LED = 1;
    }
    else if (cnt < 500)
    {
        LED = 0;
    }
    else if (cnt < 520)
    {
        LED = 1;
    }
    else if (cnt < 540)
    {
        LED = 0;
    }
}
void display()
{
    static unsigned char state = 0;
    if (LED_flag == 0)
    {
        LED = 0;
        state = 0;
    }
    else if (LED_flag == 1)
    {
        LED = 1;
        state = 0;
    }
    else if (LED_flag == 2)
    {
        display_sos(state);
        state = 1;
    }
    else if (LED_flag == 3)
    {
        LED = 0;
        state = 0;
    }
}

void KeyScan()
{
    static unsigned char last_key_state = 1;
    static unsigned char cnt = 0;   

    if (KEY != last_key_state)
    {
        if (++cnt >= 3)
        {
            if (last_key_state == 1)
            {
                if (++LED_flag >= 3)
                {
                    LED_flag = 0;
                }              
            }                        
            cnt = 0;
            last_key_state = KEY;
        }
    }
    else
    {
        cnt = 0;
    }
}
void main()
{
    LED = 0;
    Init_IO();
    while (1)
    {
        KeyScan();
        display();   
        Delay10ms();            
    }
}
回复

使用道具 举报

板凳
ID:866313 发表于 2024-8-9 21:41 | 只看该作者
以下回答来自GPT-4o

  • 你所遇到的问题的确可能是因为在执行 display_sos() 函数时,按键扫描没有被及时处理,导致按第三下按键时,LED没有熄灭。这个问题的根本原因是按键处理函数在 display_sos() 运行时没有机会执行,因为你的代码是单线程顺序执行的。display_sos() 函数中包含了长时间的延时操作,导致在这段时间内程序不能响应按键的变化。
    要解决这个问题,可以采用中断处理或者使用一个状态机来管理LED的状态,而不是在 display_sos() 函数中使用阻塞延时。以下是使用状态机的方法的简化思路:
    1. 移除阻塞的延时
    将阻塞延时改为非阻塞计数器方式,这样主循环可以继续检查按键状态。
    2. 使用状态机
    使用状态机来管理LED的不同状态(比如长亮、SOS、熄灭),并根据按键的状态来切换。
    代码实现 #include <STC8.h>
    #include <intrins.h>
    sbit KEY = P3^5;
    sbit LED = P3^4;

    unsigned int LED_flag = 0;
    unsigned int sos_step = 0;
    unsigned int delay_counter = 0;

    void Init_IO()
    {
         P0M1 = 0x00;   P0M0 = 0x00;   
         P1M1 = 0x00;   P1M0 = 0x00;   
         P2M1 = 0x00;   P2M0 = 0x00;   
         P3M1 = 0x00;   P3M0 = 0x00;   
         P4M1 = 0x00;   P4M0 = 0x00;   
         P5M1 = 0x00;   P5M0 = 0x00;   
         P6M1 = 0x00;   P6M0 = 0x00;   
         P7M1 = 0x00;   P7M0 = 0x00;   
    }

    void Delay10ms()
    {
         unsigned char i, j, k;
         i = 2; j = 56; k = 172;
         do { do { while (--k); } while (--j); } while (--i);
    }

    void LED_SOS_Handler()
    {
         switch (sos_step)
         {
             case 0: case 2: case 4:
                 LED = 1; delay_counter = 20; sos_step++; break; // LED on for 200ms
             case 1: case 3: case 5:
                 LED = 0; delay_counter = 20; sos_step++; break; // LED off for 200ms
             case 6: case 8: case 10:
                 LED = 1; delay_counter = 50; sos_step++; break; // LED on for 500ms
             case 7: case 9: case 11:
                 LED = 0; delay_counter = 50; sos_step++; break; // LED off for 500ms
             case 12: case 14: case 16:
                 LED = 1; delay_counter = 20; sos_step++; break; // LED on for 200ms
             case 13: case 15: case 17:
                 LED = 0; delay_counter = 20; sos_step++; break; // LED off for 200ms
             case 18:
                 delay_counter = 200; sos_step = 0; LED_flag = 3; break; // Wait 2s, then turn off LED
         }
    }

    void display()
    {
         if (LED_flag == 1)
         {
             LED = 1;  // Turn on LED
         }
         else if (LED_flag == 2)
         {
             LED_SOS_Handler();  // Handle SOS signal
         }
         else if (LED_flag == 3)
         {
             LED = 0;  // Turn off LED
         }
    }

    void KeyScan()
    {
         if(KEY == 0)
         {
             Delay10ms();
             if(KEY == 0)
             {
                 LED_flag++;
                 if (LED_flag > 3) LED_flag = 0;
             }
             while (!KEY);
         }
    }

    void main()
    {
         Init_IO();
         LED = 0;
         while (1)
         {
             KeyScan();
             if (delay_counter > 0)
             {
                 delay_counter--;
             }
             else
             {
                 display();
             }
         }
    }解释:
    • LED_SOS_Handler() 函数按步骤控制LED闪烁,实现SOS信号。
    • display() 函数根据 LED_flag 的值控制LED行为。
    • 延时计数器 delay_counter 用于代替阻塞延时,让主循环能继续执行按键扫描。

    这种设计能够在处理LED行为的同时,继续监控按键输入,避免按键在特定情况下失效。


回复

使用道具 举报

地板
ID:1130376 发表于 2024-8-9 22:05 | 只看该作者
延时过多,这种造成单片机内部资源消耗一直延时你的SOS信号,这种没什么太好的解决办法,建议你学一下中断函数吧
回复

使用道具 举报

5#
ID:628113 发表于 2024-8-9 23:00 | 只看该作者
建议使用状态机。
按键切换 状态机的 状态, 然后 用状态去驱动 三个不同显示函数。
这样程序很清晰 , 模块化 很强 .
回复

使用道具 举报

6#
ID:1012735 发表于 2024-8-9 23:11 | 只看该作者
死循环了:
        else if(LED_flag==2)
         {
                 while(LED_flag==2)              <----如何跳出这个循环的???
                 {
                         display_sos();
                 }        
         }
         else if(LED_flag==3)
回复

使用道具 举报

7#
ID:1130312 发表于 2024-8-10 09:00 | 只看该作者
cedtek 发表于 2024-8-9 21:41
以下回答来自GPT-4o

您好,我下载您的程序之后发现SOS信号并不能实现(LED完全不亮),请问这是什么原因呀
回复

使用道具 举报

8#
ID:1130312 发表于 2024-8-10 09:02 | 只看该作者
1754232 发表于 2024-8-9 22:05
延时过多,这种造成单片机内部资源消耗一直延时你的SOS信号,这种没什么太好的解决办法,建议你学一下中断 ...

嗯嗯,感谢
回复

使用道具 举报

9#
ID:1130312 发表于 2024-8-10 09:03 | 只看该作者
ppcbug 发表于 2024-8-9 23:00
建议使用状态机。
按键切换 状态机的 状态, 然后 用状态去驱动 三个不同显示函数。
这样程序很清晰 ,  ...

好的,感谢
回复

使用道具 举报

10#
ID:1130312 发表于 2024-8-10 16:05 | 只看该作者
想进步要学习 发表于 2024-8-10 08:58
/*
什么状不状态不态,太远了。在你基础上改了下,思路是没问题的,代码还没测试过,你看看有没有有没有参 ...

非常感谢您,参考您的代码解决了我的问题
回复

使用道具 举报

11#
ID:161164 发表于 2024-8-10 18:15 | 只看该作者
请善用主循环
  1. #include <STC8H.H>
  2. # include <intrins.h>
  3. sbit KEY = P3^5;
  4. sbit LED = P3^4;
  5. unsigned int num=0;
  6. unsigned int LED_flag=0;
  7. void Delay10ms()                //@24.000MHz
  8. {
  9.         unsigned char data i, j, k;

  10.         i = 2;
  11.         j = 56;
  12.         k = 172;
  13.         do
  14.         {
  15.                 do
  16.                 {
  17.                         while (--k);
  18.                 }
  19.                 while (--j);
  20.         }
  21.         while (--i);
  22. }

  23. void Init_IO()
  24. {
  25.         P3M1 = 0x00;
  26.         P3M0 = 0x00;
  27. }
  28. void display_sos()
  29. {
  30.         static unsigned char Step=0, delay=0,repeat = 0;
  31.         if(Step==0)
  32.         {
  33.                 LED = 1;
  34.                 repeat = 6;               
  35.                 Step= 1;
  36.         }
  37.         if(Step==1)
  38.         {
  39.                 if(++delay>=20)
  40.                 {
  41.                         delay=0;
  42.                         repeat--;
  43.                         if(repeat==0)
  44.                         {
  45.                                 Step=2;
  46.                                 repeat = 6;
  47.                         }else{
  48.                                 if(LED)
  49.                                         LED=0;
  50.                                 else
  51.                                         LED=1;                               
  52.                         }
  53.                        
  54.                 }
  55.         }
  56.         if(Step==2)
  57.         {
  58.                 if(++delay>=50)
  59.                 {
  60.                         delay=0;
  61.                         repeat--;
  62.                         if(repeat==0)
  63.                         {
  64.                                 Step=3;
  65.                                 LED=0;
  66.                         }else{
  67.                                 if(LED)
  68.                                         LED=0;
  69.                                 else
  70.                                         LED=1;                               
  71.                         }
  72.                 }
  73.         }
  74.         if(Step==3)
  75.         {
  76.                 if(++delay>=200)
  77.                 {
  78.                         Step=0;
  79.                         delay=0;
  80.                 }
  81.         }
  82.         Delay10ms();
  83. }
  84. void display()
  85. {
  86.         if(LED_flag==0)
  87.         {
  88.                 LED=0;
  89.         }
  90.         else if(LED_flag==1)
  91.         {
  92.                 LED=1;
  93.         }
  94.         else if(LED_flag==2)
  95.         {
  96.                 display_sos();
  97.         }
  98. }
  99. void KeyScan()
  100. {
  101.         if(KEY == 0)
  102.         {
  103.                 Delay10ms();
  104.                 if(KEY == 0)
  105.                 {
  106.                         LED_flag++;
  107.                         if(LED_flag==3)
  108.                         {
  109.                                 LED_flag=0;
  110.                         }
  111.                 }
  112.                 while(!KEY);
  113.         }
  114. }
  115. void main()
  116. {
  117.         LED = 0;
  118.         Init_IO();
  119.         while(1)
  120.         {
  121.                 display();
  122.                 KeyScan();
  123.         }
  124. }
复制代码



回复

使用道具 举报

12#
ID:123917 发表于 2024-8-10 23:30 | 只看该作者
太复杂了。
计算按键次数保存在R0,然后判断R0=1,2,3去执行相应的动作即可
回复

使用道具 举报

13#
ID:123917 发表于 2024-8-11 20:29 | 只看该作者
;==================================
;----不用中断,按一次LED亮,按两次SOS,按三次LED灭,按四次全灭
;==================================
;====淄博金峰电子科技==============
     ORG   0000H
;====初始化========================
     MOV   R0,  #00H
     MOV   P1,  #0FFH
     MOV   P3,  #0FFH
     K1    EQU  P3.0  ;定义P3.0为K1
     LED   EQU  P1.0  ;定义P1.0为LED
     SOS   EQU  P1.3  ;定义P1.3为SOS
;====主程序=========================
MAIN:
     JNB   K1,  JIA
     LCALL OUT
     JMP   MAIN
;====记录按键次数程序=============
JIA:
     LCALL DELAY
     JNB   K1,$
     LCALL DELAY
     INC   R0
     LJMP  MAIN
;====输出子程序===================   
OUT:
     MOV  A,R0
OUT1:   
     CJNE A,#01,OUT2
     CLR  LED
     RET
OUT2:
     CJNE A,#02,OUT3
     CLR  SOS
     RET
OUT3:
     CJNE A,#03,OUT4
     SETB LED
     RET
OUT4:
     CJNE A,#04,OUT5
OUT5:     
     SETB SOS
     MOV  R0,#00H
     RET   
;====延时子程序=====================
DELAY:
     MOV  R6,#255
L1: MOV  R7,#248
     DJNZ R7,$
     DJNZ R6,L1
     RET   
END 按3次.rar (3.81 KB, 下载次数: 1)
回复

使用道具 举报

14#
ID:123917 发表于 2024-8-11 20:52 | 只看该作者
使用汇编形成的代码很小的
回复

使用道具 举报

15#
ID:1130414 发表于 2024-8-11 23:16 | 只看该作者
你的DELAY延时太长了,有200ms,甚至500ms,在延时过程中是不能处理按键的。
回复

使用道具 举报

16#
ID:1130414 发表于 2024-8-11 23:21 | 只看该作者
你的DELAY延时时间太长了,200ms已经很长了,还有500ms的。
有两种解决方案:
一、放弃延时,用定时器中断计数,比如1ms触发一次,主循环中识别按键,识别计数值,计数达到设定时间后,显示下一个内容。此方案的优点是定时精度高,缺点是你需要管理多个状态变量,我的程序都是用的这种方式;
二、将延时切割小,用循环控制延时时间,在循环中调用按键识别程序。此方案程序修改量小,但是定时的精度会有影响。
回复

使用道具 举报

17#
ID:332444 发表于 2024-8-12 20:09 | 只看该作者
典型的阻塞延时造成的案例,解决方案有放弃阻塞延时,改用询问延时,改用中断延时。
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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