本文共 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/