博客
关于我
2017年嵌入式第八届省赛真题解析
阅读量:798 次
发布时间:2023-04-16

本文共 7659 字,大约阅读时间需要 25 分钟。

一、题目分析

本文将围绕状态机的设计与应用,重点分析电梯控制系统的实现逻辑。通过对现有外设的使用与状态机的结合,展现如何将复杂的逻辑控制过程分解为多个状态机进行管理。

状态机的基本概念

状态机是系统设计中常用的模型,它通过将系统划分为多个状态,实现对复杂逻辑的分步管理。状态机的核心要素包括:

  • 状态:系统在某一时刻所处的稳定工作情况。
  • 迁移:系统从一个状态转移到另一个状态的过程,迁移通常需要外界施加条件或事件触发。
  • 事件:引发状态迁移的外部或内部信号。
  • 动作:状态迁移时执行的操作行为。
  • 条件:决定是否发生状态迁移的判定依据。

状态机的设计过程需要明确每个状态的初始条件、迁移条件以及对应的动作。

状态机的应用

以电梯控制系统为例,状态机可以很好地实现电梯运行的逻辑控制。通过将电梯运行分为多个状态,系统能够根据当前状态、输入事件和条件,判断下一步动作,从而完成特定的功能。

二、程序实现

按键扫描

按键扫描是系统的基础功能,用于获取用户输入。以下是按键扫描的实现逻辑:

void Key_Proc(void) {    if ((uwTick - uwTick_Key_Set_Point) < 50) {        return; //减速函数    }    uwTick_Key_Set_Point = uwTick;    ucKey_Val = Key_Scan();    unKey_Down = ucKey_Val & (ucKey_Old ^ ucKey_Val);    ucKey_Up = ~ucKey_Val & (ucKey_Old ^ ucKey_Val);    ucKey_Old = ucKey_Val;    if (state == 0) { //初始状态,按键有效        if (unKey_Down == 1) { //第1键按下            if (platform != 1) {                layer_set &= ~(1 << 0); //清第1位                layer_set |= (1 << 0); //置第1位            }        }        if (unKey_Down == 2) { //第2键按下            if (platform != 2) {                layer_set &= ~(1 << 1); //清第2位                layer_set |= (1 << 1); //置第2位            }        }        if (unKey_Down == 3) { //第3键按下            if (platform != 3) {                layer_set &= ~(1 << 2); //清第3位                layer_set |= (1 << 2); //置第3位            }        }        if (unKey_Down == 4) { //第4键按下            if (platform != 4) {                layer_set &= ~(1 << 3); //清第4位                layer_set |= (1 << 3); //置第4位            }        }        ucLed = 0xF0; //清低4位        ucLed |= layer_set; //合并层设置        if (unKey_Down != 0) { //按键按下,开始计时            uwTick_Set_Point = uwTick;        }    }}

状态机设计

状态机是电梯控制系统的核心,通过分步处理不同状态,实现电梯运行的逻辑控制。以下是状态机的实现逻辑:

void run(void) {    if (layer_set) { //检测是否有层设置        switch (state) {            case 0: { //初始状态                if ((uwTick - uwTick_Set_Point) >= 1000) { //1秒后进入状态1                    state = 1;                }                break;            case 1: { //运行中,关闭门                HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET); //关门                uwTick_Set_Point = uwTick;                //启动电机                HAL_TIM_PWM_Start(&htim17, TIM_CHANNEL_1);                __HAL_TIM_SET_COMPARE(&htim17, TIM_CHANNEL_1, 300); //设置占空比                state = 2;                break;            case 2: { //门关闭                if ((uwTick - uwTick_Set_Point) >= 4000) { //4秒后进入状态3                    HAL_TIM_PWM_Stop(&htim17, TIM_CHANNEL_1); //停止电机                    state = 3;                }                break;            case 3: { //选择运行方向                if (layer_set > (1 << (platform - 1))) { //上行                    dir = 1;                    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET); //上行信号                    HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1);                    __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, 800); //设置占空比                } else if (layer_set < (1 << (platform - 1))) { //下行                    dir = 2;                    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET); //下行信号                    HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1);                    __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, 600); //设置占空比                }                uwTick_Set_Point = uwTick;                state = 4;                break;            case 4: { //运行到目标层                if ((uwTick - uwTick_Set_Point) >= 6000) { //6秒后进入状态5                    HAL_TIM_PWM_Stop(&htim3, TIM_CHANNEL_1); //停止电机                    if (dir == 1) {                        platform++;                    } else if (dir == 2) {                        platform--;                    }                    ucLed = 0x0F; //清高4位                    LED_Disp(ucLed);                    sprintf((char *)Lcd_Disp_String, "         %d   ", platform);                    LCD_DisplayStringLine(Line2, Lcd_Disp_String);                    sprintf((char *)Lcd_Disp_String, "Elev Runned 1 Floor        ");                    LCD_DisplayStringLine(Line8, Lcd_Disp_String);                    state = 5;                } else { //流水灯显示                    if (dir == 1) { //上行                        if (led_set == 0x08) {                            led_set = 0x80;                        }                        LED_Disp(ucLed);                        HAL_Delay(300);                        led_set = led_set >> 1;                    } else if (dir == 2) { //下行                        if (led_set2 == 0x00) {                            led_set2 = 0x10;                        }                        LED_Disp(ucLed);                        HAL_Delay(300);                        led_set2 = led_set2 << 1;                    }                }                break;            case 5: { //判断目标层                if ((1 << (platform - 1)) & layer_set) { //已到达目标层                    //显示闪烁效果                    sprintf((char *)Lcd_Disp_String, "              ");                    LCD_DisplayStringLine(Line2, Lcd_Disp_String);                    HAL_Delay(300);                    sprintf((char *)Lcd_Disp_String, "         %d   ", platform);                    LCD_DisplayStringLine(Line2, Lcd_Disp_String);                    HAL_Delay(300);                    sprintf((char *)Lcd_Disp_String, "              ");                    LCD_DisplayStringLine(Line2, Lcd_Disp_String);                    HAL_Delay(300);                    sprintf((char *)Lcd_Disp_String, "         %d   ", platform);                    LCD_DisplayStringLine(Line2, Lcd_Disp_String);                    HAL_Delay(300);                    //停止电机并开门                    HAL_TIM_PWM_Stop(&htim3, TIM_CHANNEL_1);                    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);                    HAL_TIM_PWM_Start(&htim17, TIM_CHANNEL_1);                    __HAL_TIM_SET_COMPARE(&htim17, TIM_CHANNEL_1, 300);                    sprintf((char *)Lcd_Disp_String, "Comed , Door Opening            ");                    LCD_DisplayStringLine(Line8, Lcd_Disp_String);                    state = 6;                } else { //继续运行                    uwTick_Set_Point = uwTick;                    state = 4;                }                break;            case 6: { //开门                if ((uwTick - uwTick_Set_Point) >= 4000) { //4秒后进入状态7                    HAL_TIM_PWM_Stop(&htim17, TIM_CHANNEL_1);                    //清除目标层设置                    layer_set &= ~(1 << (platform - 1));                    ucLed = 0xF0;                    ucLed |= layer_set;                    LED_Disp(ucLed);                    state = 7;                }                break;            case 7: { //等待                if (layer_set) { //有设置                    uwTick_Set_Point = uwTick;                    sprintf((char *)Lcd_Disp_String, "Waitting 2s           ");                    LCD_DisplayStringLine(Line8, Lcd_Disp_String);                    state = 8;                } else { //无设置,回到初始状态                    state = 0;                    sprintf((char *)Lcd_Disp_String, "                  ");                    LCD_DisplayStringLine(Line8, Lcd_Disp_String);                    break;                }            }            case 8: { //等待结束后重复                if ((uwTick - uwTick_Set_Point) >= 2000) { //2秒后回到状态1                    sprintf((char *)Lcd_Disp_String, "                  ");                    LCD_DisplayStringLine(Line8, Lcd_Disp_String);                    state = 1;                }                break;            }        }    }}

状态机优化

通过状态机设计,系统能够更清晰地分解电梯运行的逻辑流程。每个状态代表一个功能模块,状态迁移则由输入事件和条件决定。这种设计方式有助于提升系统的可维护性和扩展性。

三、总结

状态机是处理复杂逻辑控制系统的有效方法。在本文中,通过将电梯控制系统分解为多个状态机,实现了对复杂逻辑的分步管理。状态机的设计需要结合实际应用场景,明确各个状态的定义、迁移条件和动作响应。通过合理的状态机设计,可以显著提升系统的可靠性和可维护性。

转载地址:http://xygfk.baihongyu.com/

你可能感兴趣的文章
Mysql InnoDB存储引擎 —— 数据页
查看>>
Mysql InnoDB存储引擎中的checkpoint技术
查看>>
Mysql InnoDB存储引擎中缓冲池Buffer Pool、Redo Log、Bin Log、Undo Log、Channge Buffer
查看>>
MySQL InnoDB引擎的锁机制详解
查看>>
Mysql INNODB引擎行锁的3种算法 Record Lock Next-Key Lock Grap Lock
查看>>
mysql InnoDB数据存储引擎 的B+树索引原理
查看>>
mysql innodb通过使用mvcc来实现可重复读
查看>>
mysql insert update 同时执行_MySQL进阶三板斧(三)看清“触发器 (Trigger)”的真实面目...
查看>>
mysql interval显示条件值_MySQL INTERVAL关键字可以使用哪些不同的单位值?
查看>>
Mysql join原理
查看>>
MySQL Join算法与调优白皮书(二)
查看>>
Mysql order by与limit混用陷阱
查看>>
Mysql order by与limit混用陷阱
查看>>
mysql order by多个字段排序
查看>>
MySQL Order By实现原理分析和Filesort优化
查看>>
mysql problems
查看>>
mysql replace first,MySQL中处理各种重复的一些方法
查看>>
MySQL replace函数替换字符串语句的用法(mysql字符串替换)
查看>>
mysql replace用法
查看>>
Mysql Row_Format 参数讲解
查看>>