基于状态机控制 Led(QT实现)

2022-04-27 17:22:23 浏览数 (2)

在现实生活中,我们在不同的状态,对于相同的事,会有不同的反应,就拿天气对上班的影响。可以例举下图:

天气

上班方式

晴朗

走路

下雨

打伞上班

台风

不上班

还有,我们学硬件时的点亮Led,也会有以下操作:

源状态

目标状态

事件

常亮(Light)

熄灭(close)

close

常亮(Light)

闪烁 (Blink)

blink

熄灭(Close )

常亮(Light)

light

熄灭(Close )

闪烁(Blink)

blink

闪烁(Blink)

熄灭(close)

close

闪烁(Blink)

常亮(Light)

light

按照上图,我们可以看出:

当发出 close 事件时,Led 有可能处于不同状态,如常亮,或者闪烁状态,这里面还是省略了,如果目标状态与当前状态一样应该要怎么办。在下面代码中实现了。

这里将演示如何实现上述表格的状态,视频如下:

http://mpvideo.qpic.cn/0bc32iaegaaanuangw6igvqvbuwdipjaaqya.f10002.mp4?

其中主要的代码如下:

1. LedController 控制类 的头文件

以下主要看注释部分:

代码语言:javascript复制
class LedController : public QObject
{
    Q_OBJECT
public:
    typedef enum {
        LIGHT,
        BLINK,
        CLOSE
    }eLedState,eLedCmd; // Led 的状态枚举

    typedef struct {
        eLedCmd cmd;
        QString msg;
    }eLedEvent;

    explicit LedController(QObject *parent = nullptr);
    explicit LedController(Ui::Widget *ui, QObject *parent = nullptr);

private:
    eLedState m_ledState = CLOSE; // 记录 Led 状态
    QQueue<eLedEvent> m_cmdQueue;
    bool m_handleMessage = false;
    QTimer *timer;
    Ui::Widget *m_ui;
    QPixmap *ledLightPic;
    QPixmap *ledClosePic;

signals:
    void controlLedState(eLedEvent enent);
     ...
     ...
}

2. 根据当前 Led 状态进行转换(在控制类 的源文件中)

代码语言:javascript复制
void LedController::onHandleLedEvent()
{
    if (!m_cmdQueue.empty()) {
        //说明正在处理信息,获取事件
        m_handleMessage = true;
        eLedEvent ledEvent = m_cmdQueue.dequeue();
        QString  msg = ledEvent.msg;

        //根据 Led 状态散转
        switch(m_ledState)
        {
            case LIGHT:   //当前 Led 已经被点亮
                switch (ledEvent.cmd)
                {
                    case LIGHT:
                        qDebug() << "当前 Led 已经为点亮状态";
                    break;
                    case BLINK:
                        qDebug() << "当前 Led 为点亮状态, 转换为闪烁状态";
                        m_ledState = BLINK;
                        startBlink(1000);
                    break;
                    case CLOSE:
                        qDebug() << "当前 Led 为点亮状态, 转换为关闭状态";
                        m_ledState = CLOSE;
                        closeLed();
                    break;

                    default:
                    break;
                }
            break;
            case BLINK:   //当前 Led 已经是闪烁状态
                switch (ledEvent.cmd)
                {
                    case LIGHT:
                        qDebug() << "当前 Led 为闪烁状态,转换为点亮状态";
                        m_ledState = LIGHT;
                        stopBlink();
                        lightLed();
                    break;
                    case BLINK:
                        qDebug() << "当前 Led 为闪烁状态,修改闪烁间隔为 "  msg   " ms";
                        startBlink(msg.toInt());
                        m_ledState = BLINK;
                    break;
                    case CLOSE:
                        qDebug() << "当前 Led 为闪烁状态,转换为关闭状态";
                        m_ledState = CLOSE;
                        stopBlink();
                        closeLed();
                    break;

                    default:
                    break;
                }
            break;
            case CLOSE:   //当前 Led 已经是关闭状态
                switch (ledEvent.cmd)
                {
                    case LIGHT:
                        qDebug() << "当前 Led 为关闭状态,转换为点亮状态";
                        m_ledState = LIGHT;
                        lightLed();
                    break;
                    case BLINK:
                        qDebug() << "当前 Led 为关闭状态,转换为闪烁状态,间隔为 "   msg   " ms";
                        m_ledState = BLINK;
                        startBlink(msg.toInt());
                    break;
                    case CLOSE:
                        qDebug() << "当前 Led 已经为关闭状态";
                    break;

                    default:
                    break;
                }
            break;
        }
         m_handleMessage = false;
    }
}

3. 最终结果如开头视频所示

4. 源代码

后台回复:状态机

如果你还是没看懂,建议把代码运行跑跑看。

0 人点赞