C51 单片机开发记录状态位控制 LED 的亮与灭

2024-04-18 16:14:20 浏览数 (2)

按键控制 LED 灯的文章写了好几篇了,这篇是最后一篇关于按键控制 LED 灯的文章了。本章仍然没有新的关于单片机开发的知识,只是再来写一篇关于代码技巧的文章。

0x01:状态机的介绍

状态机是软件开发中一种较为高效管理状态的代码组织结构。在 UML 中有相应的 “状态图”;在设计模式中,关于状态转化与处理的设计模式有 状态模式、观察者模式 和 命令模式。我个人觉得这些都是和状态机相关的概念,只是从不同的角度去认识和抽象吧。

状态机有 5 个要素,分别是:状态、迁移、事件、动作 和 条件。状态机通过这 5 个要素,可以解决程序中多种状态变化逻辑的完备性。

  • 状态:指当前所处的状态。
  • 迁移:指状态之间的转换。
  • 条件:指状态迁移的条件或触发动作的条件。
  • 事件:又称为条件,当条件被满足时,可能会触发一个动作或执行一次状态的迁移。
  • 动作:指条件满足后执行的动作行为。动作执行完毕后,可以迁移到新的状态,也可以保持原状态。

这些要素共同构成了状态机编程的基础,通过合理地组合和使用这些要素,可以实现复杂的逻辑控制和行为决策。(有些状态机的文章介绍,状态机有 4 个要素,状态机在有的文章中称为有限状态机)

当然了,无论是状态机,还是和其类似的设计模式,都是一个比较大的话题,这里就不具体讨论了。

0x02:用状态控制 LED 的实现

这里同样是使用两个按键控制一个 LED 灯的亮与灭,不过使用了一个状态变量进行记录。看完代码,你可能会觉得我骗人,如此简陋的代码还把说什么状态机。先看代码吧!

代码语言:javascript复制
#include <intrins.h>
#include "reg52.h"

sbit led1 = P3 ^ 7;
sbit key1 = P2 ^ 1;
sbit key2 = P2 ^ 0;

#define ON_STATUS 1
#define OFF_STATUS 0

void Delay2000ms()    //@11.0592MHz
{
  unsigned char i, j, k;

  _nop_();
  i = 15;
  j = 2;
  k = 235;
  do
  {
    do
    {
      while (--k);
    } while (--j);
  } while (--i);
}



void main()
{
    int ledMark = OFF_STATUS;
    led1 = 1;
    
    while (1)
    {
        if (key1 == 0)
        {
            Delay2000ms();
            if (key1 == 0)
            {
                ledMark = ON_STATUS;
            }
        }

        if (key2 == 0)
        {
            Delay2000ms();
            if (key2 == 0)
            {
                ledMark = OFF_STATUS;
            }
        }
        
        if (ledMark == OFF_STATUS)
        {
            led1 = 1;
        }
        else
        {
            led1 = 0;
        }
    }
}

是不是有一种上当的感觉?貌似和状态机没有半毛钱的关系?的确是没有感觉到状态机的存在,确实是没有!但是当按键控制的 LED 灯亮多了,且让 LED 灯更有 “节奏” 的亮起时(比如控制两个 LED 灯,然后两个 LED 灯的状态是 灭灭、灭亮、亮灭、亮亮…… 类似这样),使用类似的状态管理配合一定的逻辑判断,可读性将会好一些。这里,只是想把这种以状态是方式管理的思路进行引出。

更进一步来说,状态机是一种管理代码的思路,设计模式也是管理代码的一种模式(当然了,设计模式除了有效的组织代码,还可以有效的隔离变化点,比如里面的开闭思想),让代码更具可读性和维护性。因此,当状态少且逻辑简单的时候,使用 if/else 足矣,如果状态多的话,可以考虑封装成状态和函数指针,再复杂就可以搞设计模式的那一套了。自己决定吧!

0 人点赞