简介:这份文档资料是面向电气工程及其自动化、单片机原理及系统课程设计场景的完整设计报告,适合正在做课程设计或需要参考自动门控制方案的学生与初学者。内容围绕基于AT89C51单片机的车库自动门展开,涵盖硬件总体设计、红外检测电路、门行程检测、步进电机控制、故障检测与显示、控制方式切换等模块,并给出软件流程图、开门与关门子程序、T0/T1中断服务程序及外部中断设计思路,还包含原理图、仿真图与主程序附录,可帮助读者理解从需求分析到软硬件联调的完整过程。资源包共1个doc文件,约555KB,结构紧凑,便于直接查阅与借鉴。目前已有430人学习下载,适合作为课程设计报告撰写、单片机应用系统入门与自动门控制逻辑梳理的参考材料。
1. 自动门控制器的核心矛盾:为什么 AT89C51 加步进电机是课程设计里最稳的选型
自动门看起来简单,做起来最容易翻车的地方不在门体机械,而在“什么时候开、开多大、什么时候停”。红外检测给出的是开关量,步进电机要的是脉冲序列,中间隔着一个必须自己写的状态机。AT89C51 这类 51 单片机没有硬件 PWM,也没有比较捕获单元,所有时序都得靠定时器中断硬算,这恰恰是它适合教学场景的原因:资源少,逼着人把时序算清楚。
选 AT89C51 而不是 STC 或 STM32,主要理由是课程设计通常要求可仿真、可烧录、资料齐全。Proteus 元件库里有 AT89C51 和 ULN2003、L297/L298 模型,红外对管也能用开关代替,整条链路能在电脑上跑通再上实物。步进电机选 42 两相四线或 28BYJ-48,前者扭矩够推小门,后者便宜好驱动。红外检测用一对 E18-D80NK 或简单的反射式对管,输出直接进单片机 IO。
真正要解决的是三件事:红外信号去抖后如何触发开门状态、步进电机如何按加减速曲线走完行程、门开到位后如何保持并等待关门条件。这三件事在 51 上分别对应外部中断、定时器中断和主循环状态判断。把这三块拆开写,代码就不会乱。
2. AT89C51 最小系统与红外检测电路的硬件落地
2.1 最小系统里必须接对的 4 个部分
AT89C51 最小系统不是“能跑就行”,自动门场景下有几个引脚必须处理干净。晶振用 11.0592MHz 或 12MHz,前者串口波特率更准,后者定时器算整数更方便。复位电路用 10uF 电容加 10K 电阻,EA 引脚接高电平表示从内部 ROM 执行。P0 口做输出时一定要接 10K 上拉排阻,否则驱动能力不够,ULN2003 输入端会浮空。
| 部分 | 元件 | 参数 | 注意点 |
|---|---|---|---|
| 晶振 | 石英晶体 | 12MHz | 配 30pF 瓷片电容 |
| 复位 | 电解电容+电阻 | 10uF/10K | 复位脚保持两个机器周期高电平 |
| 上拉 | 排阻 | 10K×8 | P0 口做输出必接 |
| 驱动 | ULN2003 | 达林顿阵列 | 每路 500mA,带续流二极管 |
2.2 红外检测的两种接法与去抖参数
红外检测分遮挡式和反射式。遮挡式对管输出干净,反射式受门体颜色影响大。接法上,NPN 输出型红外模块可以直接进 P3.2 外部中断 0,配置为下降沿触发。如果模块输出是模拟量,中间加 LM393 比较器整形成开关量。
// 红外检测初始化:外部中断0下降沿触发 void IR_Init(void) { IT0 = 1; // 下降沿触发 EX0 = 1; // 使能外部中断0 EA = 1; // 开总中断 } // 中断服务函数里只置标志,不做延时 void IR_ISR(void) interrupt 0 { static unsigned int last = 0; unsigned int now = TH0 * 256 + TL0; if (now - last > 200) { // 软件去抖,约20ms door_state = OPENING; } last = now; }逻辑说明:中断里只改状态标志,避免在中断中做长延时导致主循环卡死。参数说明:IT0=1是边沿触发,比电平触发抗干扰;去抖阈值 200 个定时器计数对应约 20ms,实际按门体抖动情况调到 10~50ms。注意红外模块供电要和单片机共地,否则中断会乱触发。
2.3 步进电机驱动电路:ULN2003 与 L298N 怎么选
28BYJ-48 自带减速箱,用 ULN2003 驱动即可,四相八拍,每拍走 5.625/64 度。42 两相四线步进电机电流大,必须用 L298N 或 DRV8833 这类 H 桥驱动,ENA 使能脚接单片机 PWM 或普通 IO 拉高。常见做法是 L298N 的 IN1~IN4 接 P1.0~P1.3,ENA 接 P1.4 做使能控制。
// 28BYJ-48 四相八拍正转序列 unsigned char code FWD[8] = {0x01,0x03,0x02,0x06,0x04,0x0C,0x08,0x09}; void Step_Run(unsigned char dir, unsigned int steps) { unsigned int i; for (i = 0; i < steps; i++) { P1 = FWD[i % 8]; // 输出拍序 Delay_ms(2); // 控制转速,2ms对应约300pps } }逻辑说明:FWD数组是八拍顺序,每次输出一个字节到 P1 口。参数说明:Delay_ms(2)决定步进速度,改小加速但可能失步,改大减速。注意 42 步进电机不能直接用这个序列,需要按两相励磁写0x03,0x06,0x0C,0x09四拍。
3. 自动门状态机与步进电机加减速的代码实现
3.1 用定时器中断生成步进脉冲
51 单片机没有硬件 PWM,步进脉冲靠定时器中断翻转 IO。Timer0 设 1ms 中断,在中断里计数,计到设定值就输出下一拍。这样主循环只负责状态判断,脉冲时序不受影响。
volatile unsigned int step_cnt = 0; volatile unsigned int step_period = 2; // 单位ms volatile unsigned char step_idx = 0; void Timer0_ISR(void) interrupt 1 { TH0 = (65536 - 1000) / 256; // 1ms 重装 TL0 = (65536 - 1000) % 256; step_cnt++; if (step_cnt >= step_period) { step_cnt = 0; P1 = FWD[step_idx % 8]; step_idx++; } }逻辑说明:定时器固定 1ms,step_period决定多少毫秒走一拍。参数说明:step_period=2对应 500pps,28BYJ-48 在这个速度下扭矩尚可。注意中断里不要放浮点运算,51 跑不动。
3.2 开门、保持、关门的完整状态迁移
状态机用枚举定义四个状态:IDLE、OPENING、HOLD、CLOSING。红外触发进 OPENING,走到设定步数进 HOLD,HOLD 计时到进 CLOSING,关到位回 IDLE。
typedef enum { IDLE, OPENING, HOLD, CLOSING } DoorState; DoorState door_state = IDLE; unsigned int hold_timer = 0; void Door_Task(void) { switch (door_state) { case IDLE: if (ir_flag) { ir_flag = 0; door_state = OPENING; step_idx = 0; } break; case OPENING: if (step_idx >= OPEN_STEPS) { door_state = HOLD; hold_timer = 0; } break; case HOLD: hold_timer++; if (hold_timer > 500) { door_state = CLOSING; step_idx = 0; } break; case CLOSING: if (step_idx >= OPEN_STEPS) { door_state = IDLE; } break; } }逻辑说明:OPEN_STEPS是门从关到开需要的总步数,按门宽和传动比算。参数说明:hold_timer > 500对应保持 5 秒,按场景调。注意 CLOSING 时如果红外再次触发,要能切回 OPENING,这是防夹的关键。
3.3 加减速曲线:为什么不能全程匀速
步进电机启动频率有限,直接给 500pps 可能失步。常见做法是前 20% 行程用梯形加速,中间匀速,后 20% 减速。在定时器中断里动态改step_period即可。
| 阶段 | 步数范围 | step_period | 效果 |
|---|---|---|---|
| 加速 | 0~20% | 4→2 | 避免启动失步 |
| 匀速 | 20%~80% | 2 | 最快通过 |
| 减速 | 80%~100% | 2→4 | 到位不冲过头 |
void Update_Speed(unsigned int idx, unsigned int total) { if (idx < total / 5) { step_period = 4 - (idx * 2) / (total / 5); } else if (idx > total * 4 / 5) { step_period = 2 + ((idx - total * 4 / 5) * 2) / (total / 5); } else { step_period = 2; } }逻辑说明:按当前步数占总步数比例调整周期。参数说明:加速段从 4ms 降到 2ms,减速段反过来。注意total/5不能为 0,门行程太短时直接跳过加减速。
4. Proteus 仿真与实物联调的排错清单
4.1 Proteus 里跑通自动门的最小配置
Proteus 仿真 51 自动门,元件清单:AT89C51、ULN2003、MOTOR-STEPPER、IR 对管用 SWITCH 代替、LED 指示状态。晶振频率在属性里设 12MHz,程序加载 .hex 文件。常见问题是步进电机模型不转,多半是拍序和模型励磁方式不匹配,把 MOTOR-STEPPER 属性里的 Step Angle 改成 5.625 再试。
# 编译生成 hex(以 SDCC 为例) sdcc -mmcs51 --model-small main.c packihx main.ihx > main.hex逻辑说明:SDCC 是开源 51 编译器,--model-small对应小内存模型。参数说明:生成 .ihx 后用 packihx 转 .hex 给 Proteus 用。注意 Keil 用户直接勾选 Create HEX File 即可。
4.2 实物联调最常见的 5 个坑
第一,红外模块输出和单片机电平不匹配,3.3V 模块接 5V 单片机要加电平转换。第二,步进电机电源和单片机电源共地但没隔离,电机启动瞬间拉低电压导致单片机复位,加 1000uF 电解电容在电机电源端。第三,ULN2003 输出没接续流二极管,电机断电反电动势打坏芯片。第四,定时器中断里执行时间过长,主循环状态机响应慢,把耗时操作移出中断。第五,门到位检测只靠步数,没有限位开关,丢步后门会撞框,加光电限位做校准。
注意:步进电机丢步是渐进的,第一次跑可能正常,跑几十次后门位置偏移。每次上电先回零到限位开关,再按步数走,能消除累积误差。
4.3 用串口打印状态做在线调试
51 串口用 Timer1 做波特率发生器,9600bps 下 TH1=0xFD。在状态切换时打印当前状态和步数,能快速定位卡在哪个环节。
void UART_Init(void) { TMOD |= 0x20; // Timer1 模式2 TH1 = 0xFD; // 9600bps @11.0592MHz TL1 = 0xFD; TR1 = 1; SCON = 0x50; // 模式1,允许接收 } void UART_Send(char *s) { while (*s) { SBUF = *s++; while (!TI); TI = 0; } }逻辑说明:Timer1 模式 2 是自动重装,适合做波特率。参数说明:TH1=0xFD对应 11.0592MHz 晶振下 9600bps,用 12MHz 会有误差。注意串口打印不要放在中断里,会阻塞时序。
5. 从课程设计到可交付:自动门方案的扩展技巧
5.1 用 EEPROM 保存开门行程参数
AT89C51 没有内部 EEPROM,外挂 AT24C02 用 I2C 保存OPEN_STEPS和hold_timer,换门体后不用重新烧程序。I2C 用普通 IO 模拟,SCL 接 P2.0,SDA 接 P2.1,加 4.7K 上拉。
void I2C_Write(unsigned char addr, unsigned char dat) { I2C_Start(); I2C_Send(0xA0); // 器件地址+写 I2C_Send(addr); I2C_Send(dat); I2C_Stop(); Delay_ms(5); // 等待写入周期 }逻辑说明:标准 I2C 时序,0xA0是 AT24C02 写地址。参数说明:Delay_ms(5)是 EEPROM 写周期等待,不能省。注意每次只写一个字节,页写要自己拼。
5.2 防夹与断电记忆的两个实用改法
防夹用红外在 CLOSING 状态再次触发时立即切 OPENING,同时把当前步数存 EEPROM,断电重启后从记忆位置继续。另一个改法是加电流检测,步进电机堵转时电流上升,用采样电阻加比较器给单片机一个中断,比红外更早发现夹人。
| 功能 | 实现方式 | 关键参数 |
|---|---|---|
| 防夹 | 红外中断切状态 | 响应<50ms |
| 断电记忆 | EEPROM 存步数 | 每 100 步存一次 |
| 堵转检测 | 采样电阻+比较器 | 阈值按电机额定电流 1.5 倍 |
5.3 用 STC 单片机做在线升级的替换思路
如果课程设计允许换芯片,STC 系列自带 ISP 串口下载,不用编程器,调试效率高很多。代码层面 51 内核兼容,把 AT89C51 换成 STC89C52RC,定时器和中断写法不变,只多一个串口下载电路。常见做法是保留 AT89C51 做 Proteus 仿真,实物用 STC 烧录,两边代码共用一份。
提示:STC 下载时 P3.0/P3.1 被占用,如果这两个脚接了红外或串口打印,下载前要断开,否则握手失败。
5.4 步进电机闭环的入门做法
开环丢步是自动门的老问题。入门级闭环不加编码器,用光电限位做位置校准:每次开门前先向关门方向走 10 步碰限位,把步数清零,再执行开门。这样每次行程起点一致,累积误差被限制在单次行程内。成本最低,效果比纯开环稳得多。
本文还有配套的精品资源,点击获取