单片机学习笔记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, 6FHEND
0-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 秒的计时功能。