单片机学习笔记9.数码管
0到99计数 ,段选共阴极
;0到99计数 
ORG 0000H
LJMP MAIN
ORG 000BH
LJMP TIMER0_ISR
ORG 0100H; 定义位选控制位
DISPLAY_SELECT BIT 20H.0MAIN:; 定时器 0 初始化MOV TMOD, #01H ; 设置定时器 0 为模式 1MOV TH0, #3CH  ; 定时器 0 高 8 位初值,定时 50msMOV TL0, #0B0H ; 定时器 0 低 8 位初值,定时 50msSETB TR0       ; 启动定时器 0; 中断初始化SETB ET0       ; 使能定时器 0 中断SETB EA        ; 全局中断使能; 变量初始化MOV R0, #0     ; 存储当前秒数,范围 0 - 99MOV R1, #0     ; 50ms 计数,20 次为 1 秒CLR DISPLAY_SELECT ; 初始化位选控制位为 0MAIN_LOOP:SJMP MAIN_LOOP ; 主循环,等待中断TIMER0_ISR:; 重新加载定时器初值MOV TH0, #3CHMOV TL0, #0B0H; 50ms 计数INC R1CJNE R1, #20, DISPLAY ; 未到 1 秒,直接进行显示操作; 1 秒时间到,重置计数MOV R1, #0; 秒数加 1INC R0CJNE R0, #100, DISPLAY ; 未到 100 秒,进行显示操作; 秒数达到 100,重置为 0MOV R0, #0DISPLAY:; 分离十位和个位MOV A, R0MOV B, #10DIV AB ; A 为十位,B 为个位; 根据位选控制显示JB DISPLAY_SELECT, DISPLAY_LOW ; 若 DISPLAY_SELECT 为 1,显示个位MOV P2, #0FEH       ; 十位位选,假设通过 P2.0 控制SJMP COMMON_DISPLAYDISPLAY_LOW:MOV P2, #0FDH       ; 个位位选,假设通过 P2.1 控制MOV A, B            ; A 中为个位数字COMMON_DISPLAY:MOV DPTR, #SEG_CODE_TABLEMOVC A, @A+DPTR     ; 从段码表获取段码MOV P0, A           ; 段码输出到 P0 口; 切换位选控制CPL DISPLAY_SELECTRETI                ; 中断返回SEG_CODE_TABLE:DB 3FH, 06H, 5BH, 4FH, 66H, 6DH, 7DH, 07H, 7FH, 6FHEND0-99计数
1. 代码整体结构
ORG 0000H
LJMP MAIN
ORG 000BH
LJMP TIMER0_ISR
ORG 0100H
- ORG 0000H:指定程序的起始地址为- 0000H。
- LJMP MAIN:长跳转指令,跳转到- MAIN标号处开始执行主程序。
- ORG 000BH:定时器 0 中断服务程序的入口地址为- 000BH,当定时器 0 产生中断时,程序会跳转到这个地址执行。
- LJMP TIMER0_ISR:跳转到- TIMER0_ISR标号处执行定时器 0 的中断服务程序。
- ORG 0100H:指定主程序从- 0100H地址开始执行。
2. 位定义
DISPLAY_SELECT BIT 20H.0
- 使用 BIT伪指令将20H字节的第 0 位定义为DISPLAY_SELECT,用于控制数码管显示十位还是个位。
3. 主程序 MAIN
 
MAIN:; 定时器 0 初始化MOV TMOD, #01H ; 设置定时器 0 为模式 1MOV TH0, #3CH  ; 定时器 0 高 8 位初值,定时 50msMOV TL0, #0B0H ; 定时器 0 低 8 位初值,定时 50msSETB TR0       ; 启动定时器 0; 中断初始化SETB ET0       ; 使能定时器 0 中断SETB EA        ; 全局中断使能; 变量初始化MOV R0, #0     ; 存储当前秒数,范围 0 - 99MOV R1, #0     ; 50ms 计数,20 次为 1 秒CLR DISPLAY_SELECT ; 初始化位选控制位为 0MAIN_LOOP:SJMP MAIN_LOOP ; 主循环,等待中断
定时器 0 初始化
- MOV TMOD, #01H:将- TMOD寄存器设置为- 01H,使定时器 0 工作在模式 1(16 位定时器模式)。
- MOV TH0, #3CH和- MOV TL0, #0B0H:给定时器 0 的高 8 位- TH0和低 8 位- TL0赋初值,这样定时器 0 每计数到溢出时,时间间隔约为 50ms。
- SETB TR0:启动定时器 0 开始计数。
中断初始化
- SETB ET0:使能定时器 0 的中断功能,当定时器 0 溢出时会触发中断。
- SETB EA:全局中断使能,允许所有中断源产生中断。
变量初始化
- MOV R0, #0:将- R0寄存器初始化为 0,用于存储当前的秒数,范围是 0 - 99。
- MOV R1, #0:将- R1寄存器初始化为 0,用于对 50ms 的中断次数进行计数,每 20 次中断表示经过了 1 秒。
- CLR DISPLAY_SELECT:将位选控制位- DISPLAY_SELECT清 0,表示初始时显示数码管的十位。
主循环
- SJMP MAIN_LOOP:无限循环,程序会一直停在这里等待定时器 0 中断的发生。
4. 定时器 0 中断服务程序 TIMER0_ISR
 
TIMER0_ISR:; 重新加载定时器初值MOV TH0, #3CHMOV TL0, #0B0H; 50ms 计数INC R1CJNE R1, #20, DISPLAY ; 未到 1 秒,直接进行显示操作; 1 秒时间到,重置计数MOV R1, #0; 秒数加 1INC R0CJNE R0, #100, DISPLAY ; 未到 100 秒,进行显示操作; 秒数达到 100,重置为 0MOV R0, #0DISPLAY:; 分离十位和个位MOV A, R0MOV B, #10DIV AB ; A 为十位,B 为个位; 根据位选控制显示JB DISPLAY_SELECT, DISPLAY_LOW ; 若 DISPLAY_SELECT 为 1,显示个位MOV P2, #0FEH       ; 十位位选,假设通过 P2.0 控制SJMP COMMON_DISPLAYDISPLAY_LOW:MOV P2, #0FDH       ; 个位位选,假设通过 P2.1 控制MOV A, B            ; A 中为个位数字COMMON_DISPLAY:MOV DPTR, #SEG_CODE_TABLEMOVC A, @A+DPTR     ; 从段码表获取段码MOV P0, A           ; 段码输出到 P0 口; 切换位选控制CPL DISPLAY_SELECTRETI                ; 中断返回
重新加载定时器初值
- MOV TH0, #3CH和- MOV TL0, #0B0H:每次定时器 0 溢出产生中断后,重新给- TH0和- TL0赋初值,以便下一次计时。
50ms 计数和秒数更新
- INC R1:- R1寄存器的值加 1,表示又经过了一个 50ms 的时间间隔。
- CJNE R1, #20, DISPLAY:比较- R1的值是否等于 20,如果不等于 20,说明还未经过 1 秒,直接跳转到- DISPLAY处进行显示操作。
- MOV R1, #0:如果- R1的值等于 20,说明经过了 1 秒,将- R1重置为 0,准备下一次的 1 秒计时。
- INC R0:秒数- R0加 1。
- CJNE R0, #100, DISPLAY:比较- R0的值是否等于 100,如果不等于 100,说明还未达到 99 秒,跳转到- DISPLAY处进行显示操作。
- MOV R0, #0:如果- R0的值等于 100,说明秒数达到了 99 秒,将- R0重置为 0,重新开始计时。
显示部分
- 分离十位和个位: - MOV A, R0:将当前秒数- R0送入累加器- A。
- MOV B, #10:将立即数 10 送入寄存器- B。
- DIV AB:执行除法运算,- A中存储商(即十位数字),- B中存储余数(即个位数字)。
 
- 根据位选控制显示: - JB DISPLAY_SELECT, DISPLAY_LOW:判断- DISPLAY_SELECT位是否为 1,如果为 1,跳转到- DISPLAY_LOW处显示个位数字。
- MOV P2, #0FEH:如果- DISPLAY_SELECT位为 0,将- P2口输出- 0FEH,假设通过- P2.0控制数码管的十位显示。
- SJMP COMMON_DISPLAY:跳转到- COMMON_DISPLAY处进行段码显示。
- DISPLAY_LOW:- MOV P2, #0FDH:将- P2口输出- 0FDH,假设通过- P2.1控制数码管的个位显示。
- MOV A, B:将个位数字从- B寄存器送入累加器- A。
 
 
- 获取段码并显示: - MOV DPTR, #SEG_CODE_TABLE:将段码表的起始地址送入数据指针- DPTR。
- MOVC A, @A+DPTR:根据- A中的数字(十位或个位)从段码表中获取对应的段码。
- MOV P0, A:将获取到的段码输出到- P0口,用于驱动数码管显示相应的数字。
 
- 切换位选控制: - CPL DISPLAY_SELECT:对- DISPLAY_SELECT位取反,以便下次中断时显示另一位数字。
 
- 中断返回: - RETI:中断返回指令,结束本次中断服务程序,返回到主程序继续执行。
 
5. 段码表
SEG_CODE_TABLE:DB 3FH, 06H, 5BH, 4FH, 66H, 6DH, 7DH, 07H, 7FH, 6FH
- SEG_CODE_TABLE是一个段码表,存储了数字 0 - 9 对应的数码管段码。- DB是定义字节的伪指令,依次定义了数字 0 - 9 的段码。例如,- 3FH是数字 0 的段码,- 06H是数字 1 的段码,以此类推。
综上所述,整个代码通过定时器 0 产生 50ms 的定时中断,每 20 次中断(即 1 秒)更新一次秒数,同时利用数码管动态显示当前的秒数,实现了 0 - 99 秒的计时功能。
