按键控制 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 足矣,如果状态多的话,可以考虑封装成状态和函数指针,再复杂就可以搞设计模式的那一套了。自己决定吧!