基于AT89S52的8051汇编行人过街灯程序问题排查
AT89S52行人过街灯汇编程序错误排查
问题概述
使用MCU 8051 IDE编写AT89S52单片机的行人过街灯汇编程序,需求如下:
- 系统初始处于STOP状态(对应P1.0连接的LED点亮,P1.1熄灭)
- 按下按钮后,延迟切换至GO状态(P1.1点亮,P1.0熄灭)并保持更长时长,随后返回STOP状态循环
但当前代码运行异常:
- 初始时P1.0、P1.1连接的LED均点亮
- 按下按钮后P1.0熄灭且不再亮起,P1.1持续点亮
代码错误分析
1. 初始状态不符合需求
代码开头执行MOV P1,#00H,将P1口所有引脚置为低电平(假设LED为阴极接P1、阳极接VCC的共阳接法,低电平点亮),导致两个LED同时点亮,违背了初始STOP状态仅P1.0点亮的要求。
2. 按键检测逻辑完全颠倒
按键检测部分的条件判断逻辑错误:
JNB P2.0, BUTTON_RELEASED:若P2.0为低电平(按键按下状态,假设按键为下拉式,按下接地),直接跳转到重置计数器的分支,无法正确识别稳定的按键按下动作- 后续的
JB P2.0, CHECK_BUTTON_STATE也对应错误,导致按键检测逻辑完全失效,实际是在等待按键释放而非按下
3. 延时函数不匹配需求
DELAY_SEC实际延时过短:该函数仅循环调用5次DELAY_MS,而DELAY_MS的实际延时远不到1秒,无法满足状态切换的时长要求- GO状态与STOP状态延时相同:需求中GO状态需保持更长时长,但当前代码中两者均调用
DELAY_SEC,时长一致
4. 未处理按键释放,易触发重复执行
检测到按键按下后未等待按键释放,若按键长按会导致程序逻辑混乱,或单次按下触发多次状态切换
修正方案
1. 修正初始状态
将初始P1口设置为STOP状态:若采用共阳LED(低电平点亮),则设置MOV P1,#0FEH(二进制11111110,仅P1.0为低电平点亮,其余引脚高电平熄灭);若为共阴LED(高电平点亮),则设置MOV P1,#01H(仅P1.0为高电平点亮)。
2. 修正按键检测逻辑
调整按键检测的判断条件,确保正确识别稳定的按键按下动作(以下假设按键为下拉式,按下时P2.0为低电平):
- 先检测按键是否按下(P2.0为低),再通过多次检测确认状态稳定,避免抖动
- 检测到稳定按下后,等待按键释放再进入状态循环
3. 调整延时函数,区分GO/STOP时长
- 修正
DELAY_MS的参数,使其接近真实1ms延时(根据AT89S52的12MHz晶振调整) - 新增更长的延时函数
DELAY_LONG_SEC,用于GO状态的长时长保持
4. 优化状态循环逻辑
确保进入循环后严格按照STOP→GO→STOP的顺序执行,且时长符合需求
修正后的完整代码
ORG 00H ; 程序起始地址 ; 初始化端口:假设LED为共阳接法(低电平点亮) MOV P1,#0FEH ; 初始STOP状态:P1.0亮,P1.1灭 MOV P2,#0FFH ; P2口设置为输入,上拉 WAIT_FOR_BUTTON_PRESS: MOV R2, #03H ; 防抖计数器 CHECK_BUTTON_PRESSED: JNB P2.0, CONFIRM_PRESS ; 检测到按键按下(P2.0低),进入确认 MOV R2, #03H ; 未按下,重置计数器 SJMP WAIT_FOR_BUTTON_PRESS CONFIRM_PRESS: CALL DELAY_MS ; 防抖延时 JNB P2.0, DEC_COUNT ; 仍按下,计数器减1 MOV R2, #03H ; 已释放,重置计数器 SJMP WAIT_FOR_BUTTON_PRESS DEC_COUNT: DEC R2 JNZ CONFIRM_PRESS ; 未到稳定次数,继续检测 WAIT_RELEASE: JB P2.0, ENTER_LOOP ; 等待按键释放 SJMP WAIT_RELEASE ENTER_LOOP: ; 按下后先保持STOP状态一段时间 MOV P1,#0FEH CALL DELAY_SEC TRAFFIC_LIGHT_LOOP: ; 切换到GO状态,保持更长时间 MOV P1,#0FDH ; P1.1亮,P1.0灭 CALL DELAY_LONG_SEC ; 返回STOP状态 MOV P1,#0FEH CALL DELAY_SEC SJMP TRAFFIC_LIGHT_LOOP ; 循环执行 ; 约1ms延时(基于12MHz晶振) DELAY_MS: MOV R1, #2 DELAY_MS_LOOP1: MOV R0, #248 DELAY_MS_LOOP2: DJNZ R0, DELAY_MS_LOOP2 DJNZ R1, DELAY_MS_LOOP1 RET ; 约1秒延时 DELAY_SEC: MOV R1, #200 DELAY_SEC_LOOP: CALL DELAY_MS DJNZ R1, DELAY_SEC_LOOP RET ; 约5秒延时(GO状态长时长) DELAY_LONG_SEC: MOV R1, #1000 DELAY_LONG_SEC_LOOP: CALL DELAY_MS DJNZ R1, DELAY_LONG_SEC_LOOP RET END
说明
- 若LED为共阴接法(高电平点亮),需将P1口的设置值对应修改:
- STOP状态:
MOV P1,#01H(P1.0高电平点亮) - GO状态:
MOV P1,#02H(P1.1高电平点亮)
- STOP状态:
- 延时函数参数可根据实际晶振频率微调,确保延时时长符合需求
内容的提问来源于stack exchange,提问作者Dennis
相关产品推荐
相关产品推荐

