ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

基于单片机的电梯程序控制系统设计:状态机与调度实现

基于单片机的电梯程序控制系统设计:状态机与调度实现 简介一套面向单片机学习者的电梯程序控制系统课程设计资源覆盖需求分析、硬件接口、程序调度与安全机制等完整环节适合嵌入式入门及课程项目参考。压缩包共35个文件包含Keil工程uvproj/uvopt、C语言源码、Hex烧录文件、Proteus仿真DSN/DBK及多段测试视频avi可结合源码与仿真快速理解电梯控制逻辑。资源共30.32MB作者为weixin_44010641目前已有95人学习下载。内容沉淀了主单片机程序、开关门/复位/警报/上下行优先级/极限开关/超重引脚等场景测试录屏以及README说明和仿真设计文件。通过学习可掌握按键输入、数码管/LED显示、电机PWM控制、限位与超重检测等模块设计思路并可直接基于已有源码二次开发用于课程答辩、实验验证或毕业设计基础。1. 基于单片机的电梯程序控制系统从状态机到课程设计很多第一次接触电梯控制课程设计的人会把它当成“用单片机控制一个电机上下转”。真正上手才发现电机反而是最好写的部分楼层检测、按键调度、开关门逻辑、平层减速这些交织在一起才构成完整的电梯程序控制系统。单片机在这里不只是驱动硬件它承担的是一个多条件并发、状态互斥的调度核心——电梯永远知道自己当前在哪、要去哪、途中能不能被“截”。这篇文章以 STC89C5251 内核为主控把电梯程序控制系统拆成任务层、调度层、执行层三层来写。你会看到一套可以抄进 Keil 的 C51 代码骨架也能看到 Proteus 仿真里排查“电梯到站不停”“按键无响应”的经验。学完这套思路换成 STM32 或者换一个电梯模型你改的是引脚和定时器不用重写调度逻辑。2. 电梯程序控制系统的模型先定状态机再谈单片机选型电梯的本质是一个有限状态机轿厢在任意时刻只处于某一种运行状态状态之间由按键请求、楼层传感器、门开关信号触发转移。把这层逻辑想清楚单片机选型才有依据。课程设计里最常见的选型组合是 STC89C52RC L298N 电机驱动 双位数码管Proteus 仿真则常搭配步进电机模型来观察运行方向。2.1 电梯运行状态的六段拆分在写代码之前先把系统状态拆成六段状态编号状态名进入条件关键动作S0IDLE 待机初始化或完成一次运行关闭电机等待请求S1DOOR_OPEN 开门到达目标楼层或检修强制开门延时 5 秒保持开门S2DOOR_CLOSE 关门开门超时或关门按钮按下输出关门信号S3MOVE_UP 上行目标楼层高于当前层正转输出速度分级S4MOVE_DOWN 下行目标楼层低于当前层反转输出速度分级S5DECEL 平层减速接近目标楼层位置换低速准备定位每个状态在 main 主循环里通过 switch 分发为了保证实时性楼层位置和按键状态由定时器中断每 10ms 采集一次主循环只做逻辑判断。这样拆的好处是调试状态下你可以单步看当前状态值一眼定位问题在哪一段。2.2 调度层的分层策略同向优先反向响应电梯只管“当前楼层的目标请求”是远远不够的。课程设计一般要求 6 层以内如果只按请求先后顺序响应会出现电梯从 6 楼下来接 1 楼的请求结果 4 楼有人按了上行乘客要等电梯到底再折返回来——这不符合真实电梯的调度直觉。常见的做法是分层调度先建立一张 6 位的请求登记表每个楼层对应一位。每次运行前调度算法先扫描轿厢内按键和外呼请求按两个优先级处理。第一优先级是当前运行方向上的顺向请求比如电梯在 2 楼向上运行途中经过 3、4 楼这两个楼层的请求要在经过时直接停靠。第二优先级才是反向请求需要等到当前方向所有请求清空后再改变运行方向。2.2.1 方向登记表与优先级判定请求登记表的每一位对应一个楼层置 1 表示有请求。判定是否停靠的逻辑是这样// 0 号位不用1~6 对应物理楼层 unsigned char call_up[7]; // 外呼上行请求 unsigned char call_down[7]; // 外呼下行请求 unsigned char call_car[7]; // 轿厢内楼层请求每一轮主循环扫描这张表根据当前运行方向选择停靠优先级。电梯在上升过程中只处理当前楼层以上的 call_car 和 call_up下降过程只处理当前楼层以下的 call_car 和 call_down。这保证了顺向截梯的实现——只要请求发生在运行方向上电梯经过该楼层时就可靠停靠。2.3 单片机最小系统的资源分配STC89C52 的资源对这门课够用P0 口接数码管段码P2.0 和 P2.1 接电机正反转控制P1 口接按键和楼层传感器定时器 T0 做 10ms 时基T1 做串口调试打印。一个容易被忽略的细节是蜂鸣器不能直接挂在 P3.7 上驱动要加一个三极管放大否则声音非常小。在 Proteus 里仿真时把限位开关模型放在每层的位置用一个小球模拟轿厢触发开关就能复现真实的楼层到位信号。3. 电梯程序控制系统的主循环实现调度代码、按键扫描与楼层显示模型定完代码按模块写。下面是主状态机的 C51 骨架这是电梯程序控制系统的核心也是课程设计报告里分值最高的部分。建议直接建立五个文件main.c 管主循环和状态机key.c 按键扫描car.c 请求登记与调度motor.c 电机执行display.c 数码管动态刷新。3.1 主状态机的骨架代码// main.c 电梯主状态机 void main(void) { init_timer0(); // 10ms 定时中断用于消抖和时基 init_gpio(); // 初始化端口方向和初始电平 current_floor 1; // 电梯初始在 1 楼 state S0; // 初始状态 IDLE while (1) { scan_requests(); // 读取轿厢内按键和外呼信号 update_display(); // 双位数码管动态刷新使用中断标志位 if (flag_10ms) // 每 10ms 处理一次状态机 { flag_10ms 0; switch (state) { case S0: // 待机无请求则睡眠有请求则开门 if (has_request()) state S1; break; case S1: // 开门持续 5 秒 open_door(); if (door_timer 500) { door_timer 0; state S2; } break; case S2: // 关门检测到没有障碍物后判断转向 close_door(); if (door_closed()) { if (target_floor current_floor) state S3; else if (target_floor current_floor) state S4; else state S0; } break; case S3: // 上行运行过程中检查是否到达顺向停靠层 motor_up(); if (current_floor target_floor) state S5; break; case S4: // 下行 motor_down(); if (current_floor target_floor) state S5; break; case S5: // 平层减速短延时后停在目标层 motor_stop(); state S1; break; } } } }这段代码的逻辑主线是“请求 → 开门 → 关门 → 运行 → 平层 → 开门”最关键的参数是 door_timer 和 current_floor。其中 current_floor 不要直接读传感器状态而是用“位置累计值”换算每经过一个限位开关就累加或递减一次楼层计数值这样在运行途中就知道当前在哪一层而不是停在传感器触发时才更新位置。3.2 按键扫描与消抖的参数设计51 单片机的按键扫描常见有两种接法矩阵键盘用于扩展 12 个按键6 层外呼上下按钮加上轿厢内楼层键独立按键用于少量控制。课程设计里推荐 4x4 矩阵键盘占用 P1 口的 8 根线正好覆盖 16 个按键还够用。按键扫描最头疼的问题是抖动。机械按键在按下和释放的瞬间会有 5~10ms 的不稳定电平直接读取会误判成多次触发。这里利用定时器中断做时间片消抖// key.c 按键扫描带 20ms 稳定确认 void scan_requests(void) { unsigned char key_code read_matrix_keyboard(); if (key_code ! 0xFF) // 检测到有键按下 { if (temp_key key_code) // 与上一次扫描结果一致 { press_cnt; if (press_cnt 2) // 连续两次 10ms 扫描结果相同 { register_request(key_code); // 录入请求登记表 press_cnt 0; } } else { temp_key key_code; // 第一次读取不立即确认 press_cnt 0; } } else { temp_key 0xFF; // 无按键清除暂存 press_cnt 0; } }press_cnt 达到 2 意味着同一个键值连续稳定出现 20ms这时才认为是一次有效按键。这个做法比 delay 消抖好得多因为延时消抖会阻塞主循环导致数码管刷新出现闪烁。调用 register_request 时注意在函数内部根据当前运行方向做方向登记上行过程中按了下降按钮该请求先存进 call_down 表等待转向后处理。3.3 数码管楼层显示与定时器刷新楼层显示用动态扫描双位数码管一位一位轮流点亮只要刷新率高于 50Hz 人眼就看不出闪烁。定时器 T0 配置成 2ms 中断每次中断刷新一位两次刷新完成一个完整显示周期// display.c 数码管动态刷新定时器 2ms 中断调用 void display_refresh(void) { unsigned char code table[10] {0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90}; P2 0x0F; // 位选清零防止拖影 P0 table[current_floor / 10]; // 十位 P2 | 0x10; // 选中第一位 delay_short(200); // 让数码管稳定点亮 200us P2 0x0F; P0 table[current_floor % 10]; // 个位 P2 | 0x20; // 选中第二位 delay_short(200); }delay_short(200) 里的时间不能太长单次数码管点亮时间超过 2ms 会明显看到闪烁。如果 Proteus 仿真发现显示有叠字通常是位选和段选的切换时序出了问题在每次切换前先关闭全部位选也就是代码里 P2 0x0F 那行的作用。4. 电梯控制系统的 Proteus 仿真与排错定时器参数、平层减速和状态锁死仿真阶段的故障排查比写代码更耗时。Proteus 8.x 里搭一个电梯模型常见的坑集中在三处电机方向控制逻辑、定时器中断冲突、状态机锁死。下面这套排查思路按出现频率排序直接对着现象查对应模块。4.1 电机方向与速度控制的参数电机控制采用 L298N 双 H 桥驱动ENA 引脚接 PWM 输出控制速度IN1 和 IN2 控制方向。51 单片机没有硬件 PWM 模块时用定时器 T1 生成 PWM频率选 1kHz占空比低档 40%平层减速、高档 90%正常运行。motor_up()和motor_down()的逻辑对应关系是 IN11、IN20 为正转IN10、IN21 为反转。很多人在这里把“电梯上行”和“电机正转”混为一谈。置位 IN1 之前必须先确认 state 已经是 MOVE_UP 状态防止在 S0 待机状态误启动电机。4.2 平层减速的判定条件电梯快到目标楼层时直接切停止会因为惯性冲过楼层。课程设计简化处理采用“两级速度”方案检测到目标楼层前一层时切换成低速低速状态下到达目标楼层才完全停止。判定低速切换点的方式是在定时器中断里累加运行时间// motor.c 运行时间累计 平层减速判断 void motor_up(void) { run_time; if (abs(target_floor - current_floor) 1) set_motor_speed(LOW_SPEED); // 距离目标楼层 1 层以内切换低速 else set_motor_speed(HIGH_SPEED); // 正常速度运行 }run_time 变量每 10ms 加 1用于超时保护如果电梯运行时间超过正常需要时间的两倍还没有触发平层信号说明传感器丢失或目标楼层判断出错立刻停机并报告故障码。这一个保护逻辑在验收演示时非常加分评委提问“电梯卡住怎么办”的时候这就是答案。4.3 状态锁死最常见的课程设计翻车点状态锁死的典型表现是电梯到站开门后不再响应任何请求或者电机持续运行不停。前者的根源多半是 DOOR_CLOSE 状态里的关门确认条件永远不满足 — Proteus 里关门限位开关没有触发state 一直停在 S2。排查手段是在每个 case 分支里向串口打印状态码// 调试辅助用串口输出当前状态9600 8N1 printf(S:%d F:%d T:%d UP:%d DN:%d\r\n, state, current_floor, target_floor, (unsigned int)flag_up_req, (unsigned int)flag_dn_req);运行后在串口助手观察最后一行输出停留在 S2 说明是门限位问题停留在 S3 说明是楼层计数值和实际位置不一致。后者通常发生在通过限位开关累计楼层时产生了重复计数在接近开关位置抖动导致的解决办法和按键消抖一样位置变化也要连续两次确认才更新楼层值。4.4 定时器作用的边界T0 做 10ms 时基、T1 做 1kHz PWM两个定时器同时工作时要注意中断优先级的分配。T1 的中断频率更高应该设置更高的中断优先级避免 PWM 波形在 T0 中断期间被拉长否则电机会发出明显的滋滋声。proteus 仿真时蜂鸣器不响的另一个常见原因是晶振频率设置成 11.0592MHz 但定时器初值按 12MHz 计算时间基准偏差导致持续时间参数比如开门 5 秒全部失真。5. 不靠运气交付用事件日志验证调度正确性再对着答辩清单过一遍程序能编译通过、仿真能跑起来只是第一步。课设验收通常要在现场演示多个场景这两个技巧能帮你提前找出隐蔽问题避免演示时翻车。5.1 优先级的定义与事件日志分析调度逻辑是梯形图还是状态机两者写出来的代码可读性差别很大但验证方式可以统一在每次事件发生的位置请求登记、状态转移、楼层更新往串口打一行时间戳日志事后把日志按时间排序检查是否满足调度规则。一个值得验证的规则是“顺向截梯与反向响应的时序关系”电梯从 1 楼上行目标 5 楼途中 3 楼有人按了上行、4 楼有人按了下行。正确的事件序列应该是在 3 楼停靠、然后继续上行到 5 楼停靠。如果日志显示电梯从 3 楼停靠后直接掉头下行说明方向登记表的清理时机有误。反向请求的登记信息不能立即清除要等电梯换向后到达该楼层才清位。日志验证三步串口打印所有状态转移S2 - S3必须发生在方向判定之后楼层更新记录与运行方向一致上行时楼层只增不减除非平层失败回退每次停靠都必须对应一条请求登记记录不允许电梯在无请求楼层停靠5.2 边界场景测试用例除了常规的 1 楼上 5 楼、逐层停靠测试给课设评分老师展示这三个边界用例通常比功能本身更有说服力。测试场景预期行为关注点电梯在 3 楼静止同时按 1 楼轿厢键和 4 楼外呼上行先向下到 1 楼再向上到 4 楼调度方向切换是否正确电梯满员模式添加超重传感器模拟下按任意楼层键键响应但门不关、电梯不动超重信号是否被纳入状态机条件运行中断电再上电保持断电前所在楼层不执行任何请求位置掉电保存把 current_floor 存在 EEPROM 或 eeprom 仿真块中最后一条是很多人忽略的。51 单片机没有非易失存储器掉电后 current_floor 回归初值 1重启后电梯会误以为自己在 1 楼然后执行请求去错误楼层开门。STC89C52 内部集成 EEPROM掉电前把当前楼层存进 0x2000 地址上电初始化时读回来作为 current_floor 初值。这个处理在答辩时能回答“单片机如何记住电梯位置”的问题。5.3 答辩演示清单演示前把 Proteus 仿真里的电梯模型缩放到合适大小将串口虚拟终端窗口放在旁边打开 9600 波特率。演示顺序固定为空载单层运行 → 顺向截梯 → 反向折返 → 故障停靠。每一步切换场景前先清空请求登记表避免上一次的残留请求干扰演示逻辑。遇到异常不要急着重启仿真先把串口日志里最后 10 行复制到报告中分析状态和事件顺序理清逻辑后再恢复现场。本文还有配套的精品资源点击获取
返回列表