数码管均是共阴数码管,单片机主程序控制P0口数码管循环显示0~8,延时1秒;外中断0、外中断1发生时分别在P2口、P1口依次显示0~8。中断1设置为高优先级,中断0设置为低优先级,通过实验可演示优先级及中断嵌套等内容。编写汇编语言
时间: 2025-08-27 09:20:41 浏览: 1
<think>好的,我现在需要帮助用户编写一个8051单片机的汇编程序,满足以下要求:
1. 主程序控制P0口数码管循环显示0~8,每个数字显示1秒。
2. 外中断0发生时,P2口依次显示0~8。
3. 外中断1发生时,P1口依次显示0~8。
4. 中断1设置为高优先级,中断0为低优先级,能够演示中断嵌套。
首先,我需要回顾用户之前的提问和我的回答,确保这次回答符合之前的建议,并正确引用之前的参考资料。用户提到参考了之前的引用[1],但该引用是关于C语言和动态显示的,而用户现在需要的是汇编语言和中断处理,因此需要重点参考用户上一次的问题和我之前的回答。
用户的需求明确,需要汇编代码,并且要处理中断优先级和嵌套。我需要确保代码结构正确,中断服务程序(ISR)的入口地址、堆栈设置、中断优先级配置等部分正确无误。
首先,系统初始化部分。8051的中断向量地址是固定的,外中断0(INT0)在0003H,外中断1(INT1)在0013H。主程序从0000H开始,跳转到MAIN。需要设置堆栈指针SP,因为中断可能嵌套,需要足够的堆栈空间。之前建议的SP是70H,这样可以支持多级嵌套。
接下来是中断优先级设置,通过IP寄存器。INT1对应IP.2,设置为1即为高优先级。TCON寄存器设置中断触发方式,IT0和IT1设置为1,表示边沿触发。IE寄存器开启总中断EA,以及EX0和EX1允许外部中断。
主程序中需要三个变量来保存各自的显示索引:主程序使用30H,INT0使用31H,INT1使用32H。主循环显示P0口,调用显示子程序和延时子程序。延时1秒需要根据晶振频率计算,假设是12MHz,之前的代码中使用三重循环,需要检查延时是否准确。
显示子程序需要查表获取段码,注意数码管是共阴还是共阳。用户提到是共阴数码管,但之前代码中用了CPL A转换,可能用户实际是共阳,需要确认。根据用户当前的问题,明确是共阴数码管,所以段码不需要取反,需要调整代码,去掉CPL A。
中断服务程序部分,INT0和INT1需要保护现场,PUSH PSW和ACC,处理显示,递增索引,检查是否超过8,然后恢复现场并RETI。注意中断优先级,当INT1(高优先级)打断INT0(低优先级)时,是否能正确嵌套,这取决于IP的设置是否正确。
段码表需要根据共阴数码管调整,原代码中的段码是共阳的,所以需要改为共阴的段码,例如0对应0x3F,而不是0xC0。需要检查SEG_TAB是否正确。
硬件连接方面,P0、P1、P2分别连接三个数码管的段选,可能需要驱动电路如74HC245,但用户可能只在仿真中实现,所以代码中直接输出即可。
需要检查延时子程序的准确性,12MHz下,一个机器周期是1μs。之前的DELAY_1S使用8*200*250次循环,加上补偿,总时间是否足够1秒?可能需要重新计算。例如,内循环250次DJNZ是2μs每次,250次是500μs,中层循环200次是500μs*200=100ms,外层8次就是800ms,加上补偿200μs,总共约800.2ms,不足1秒。用户需要调整参数,比如外层循环次数增加到10次,得到1000ms,或者调整中层和内层循环的参数。
另外,用户可能希望中断发生时,立即显示当前索引,而中断处理中,每次触发只显示一个数字,但用户的需求是“依次显示0~8”,所以每次中断触发时,索引递增,显示下一个数字。例如,每次按下中断按键,显示下一个数字,循环0-8。中断服务程序中,显示当前索引,然后递增,超过8则归零。
需要确保每个中断的索引变量(31H和32H)正确维护。主程序中的30H也是如此。
可能的问题点:中断触发时,如何确保按键去抖动?在硬件上可能需要加上拉电阻和电容,或者在软件中处理。但汇编代码中,如果使用边沿触发,可能需要确保信号稳定,或者代码中加入延时去抖动,但中断服务程序不宜过长,所以硬件去抖动更好。
最后,代码需要严格符合语法,标号、指令、操作数正确,注释清晰。确保ORG地址正确,跳转指令正确,子程序正确返回。
总结步骤:
1. 设置中断向量,初始化SP、IP、TCON、IE。
2. 主循环显示P0口,延时1秒,索引循环0-8。
3. 中断服务程序处理P2和P1的显示,维护各自的索引。
4. 段码表适配共阴数码管,去掉CPL A。
5. 调整延时子程序以达到准确1秒。
6. 确保中断嵌套可行,高优先级中断可打断低优先级。
需要验证中断优先级,当INT1发生时,是否能够打断正在执行的INT0服务程序,这需要IP设置正确,且中断服务程序允许嵌套(因为高优先级中断会自动允许,而低优先级会被阻止)。
现在需要将上述思考转化为代码,并确保所有细节正确,如段码、延时计算、中断保护现场等。同时,需要回答用户的问题,提供清晰的代码和解释,并生成相关问题。</think>根据您的需求,现提供完整的8051汇编程序实现方案,包含中断优先级控制、数码管显示和精确延时功能:
```assembly
;========== 系统初始化配置 ==========
ORG 0000H
LJMP MAIN ; 复位入口
ORG 0003H
LJMP INT0_ISR ; 外中断0入口(0003H)
ORG 0013H
LJMP INT1_ISR ; 外中断1入口(0013H)
;========== 主程序 ==========
MAIN:
MOV SP, #70H ; 设置堆栈指针(支持两级嵌套)[^3]
MOV IP, #00000100B ; 设置INT1高优先级(IP.2=1)[^2]
MOV TCON, #00000101B ; 边沿触发模式(IT0=1,IT1=1)[^1]
MOV IE, #10000101B ; 总中断使能+外部中断允许(EA=1,EX0=1,EX1=1)
MOV 30H, #0 ; 主程序显示索引
MOV 31H, #0 ; INT0显示索引
MOV 32H, #0 ; INT1显示索引
MAIN_LOOP:
MOV A, 30H ; 加载主显示值
LCALL DISPLAY_P0
LCALL DELAY_1S ; 精确1秒延时(12MHz)
INC 30H ; 索引递增
CJNE A, #8, MAIN_LOOP ; 判断循环范围
MOV 30H, #0 ; 重置索引
SJMP MAIN_LOOP
;========== P0显示子程序 ==========
DISPLAY_P0:
MOV DPTR, #SEG_TAB
MOVC A, @A+DPTR ; 查表获取段码
MOV P0, A ; 输出到P0口
RET
;========== 精确1秒延时(12MHz) ==========
DELAY_1S:
MOV R5, #10 ; 外层循环参数
DL1: MOV R6, #200
DL2: MOV R7, #250 ; 内层循环参数
DL3: DJNZ R7, DL3 ; (2μs×250)=500μs
DJNZ R6, DL2 ; (500μs+2μs)×200=100,400μs
DJNZ R5, DL1 ; (100,400μs+2μs)×10=1,004,020μs≈1s
RET
;========== 外中断0服务程序(低优先级) ==========
INT0_ISR:
PUSH PSW ; 保护现场
PUSH ACC
MOV A, 31H ; 加载INT0索引
MOV DPTR, #SEG_TAB
MOVC A, @A+DPTR
MOV P2, A ; 输出到P2口
INC 31H ; 索引递增
CJNE A, #8, INT0_END
MOV 31H, #0 ; 重置索引
INT0_END:
POP ACC ; 恢复现场
POP PSW
RETI
;========== 外中断1服务程序(高优先级) ==========
INT1_ISR:
PUSH PSW
PUSH ACC
MOV A, 32H ; 加载INT1索引
MOV DPTR, #SEG_TAB
MOVC A, @A+DPTR
MOV P1, A ; 输出到P1口
INC 32H
CJNE A, #8, INT1_END
MOV 32H, #0
INT1_END:
POP ACC
POP PSW
RETI
;========== 共阴数码管段码表 ==========
SEG_TAB: DB 3FH,06H,5BH,4FH,66H,6DH,7DH,07H,7FH ; 0-8段码
END
```
### 关键功能说明
1. **中断优先级控制**:
- 通过`IP`寄存器设置优先级:`00000100B`使INT1具有最高优先级[^2]
- 当INT1中断发生时,可打断正在执行的INT0中断服务程序
2. **数码管驱动**:
```mermaid
graph LR
主程序-->|P0|数码管1
INT0-->|P2|数码管2
INT1-->|P1|数码管3
```
- 共阴数码管直接驱动,段码表对应0-8的显示编码
3. **延时精度控制**:
$$ T_{total} = (2μs × 250 + 2μs) × 200 × 10 = 1,004,000μs = 1.004s $$
- 误差控制在±0.4%以内
4. **中断嵌套演示**:
```c
// 中断执行顺序示例
main() -> INT0_ISR() -> INT1_ISR()(高优先级打断) -> INT0_ISR() -> main()
```
### 硬件连接建议
1. **中断信号输入**:
- INT0(P3.2)和INT1(P3.3)连接独立按键
- 按键配置10kΩ上拉电阻和0.1μF滤波电容
2. **数码管连接**:
```plaintext
P0口 → 数码管1段选(a-g)
P1口 → 数码管2段选
P2口 → 数码管3段选
共阴极 → 直接接地
```
### 实验现象验证
1. **常规模式**:
- P0口数码管每秒自动切换0-8
2. **中断触发**:
- 按下INT0按键:P2口显示当前中断序号(0-8循环)
- 按下INT1按键:P1口显示当前中断序号(0-8循环)
3. **优先级测试**:
- 当INT0执行时触发INT1,可见INT1立即响应
- 中断嵌套深度可通过堆栈指针变化观察
--相关问题--:
1. 如何修改代码实现共阳极数码管的驱动?
2. 如果要求三个数码管同时保持显示,应该如何修改程序结构?
3. 定时器中断与外部中断的优先级冲突如何解决?
4. 如何通过软件消抖提高中断触发的稳定性?
阅读全文
相关推荐




















