单片机学习笔记9.数码管

0到99计数 ,段选共阴极

html 复制代码
;0到99计数 
ORG 0000H
LJMP MAIN
ORG 000BH
LJMP TIMER0_ISR
ORG 0100H

; 定义位选控制位
DISPLAY_SELECT BIT 20H.0

MAIN:
    ; 定时器 0 初始化
    MOV TMOD, #01H ; 设置定时器 0 为模式 1
    MOV TH0, #3CH  ; 定时器 0 高 8 位初值,定时 50ms
    MOV TL0, #0B0H ; 定时器 0 低 8 位初值,定时 50ms
    SETB TR0       ; 启动定时器 0

    ; 中断初始化
    SETB ET0       ; 使能定时器 0 中断
    SETB EA        ; 全局中断使能

    ; 变量初始化
    MOV R0, #0     ; 存储当前秒数,范围 0 - 99
    MOV R1, #0     ; 50ms 计数,20 次为 1 秒
    CLR DISPLAY_SELECT ; 初始化位选控制位为 0

MAIN_LOOP:
    SJMP MAIN_LOOP ; 主循环,等待中断

TIMER0_ISR:
    ; 重新加载定时器初值
    MOV TH0, #3CH
    MOV TL0, #0B0H

    ; 50ms 计数
    INC R1
    CJNE R1, #20, DISPLAY ; 未到 1 秒,直接进行显示操作

    ; 1 秒时间到,重置计数
    MOV R1, #0
    ; 秒数加 1
    INC R0
    CJNE R0, #100, DISPLAY ; 未到 100 秒,进行显示操作

    ; 秒数达到 100,重置为 0
    MOV R0, #0

DISPLAY:
    ; 分离十位和个位
    MOV A, R0
    MOV B, #10
    DIV AB ; A 为十位,B 为个位

    ; 根据位选控制显示
    JB DISPLAY_SELECT, DISPLAY_LOW ; 若 DISPLAY_SELECT 为 1,显示个位
    MOV P2, #0FEH       ; 十位位选,假设通过 P2.0 控制
    SJMP COMMON_DISPLAY

DISPLAY_LOW:
    MOV P2, #0FDH       ; 个位位选,假设通过 P2.1 控制
    MOV A, B            ; A 中为个位数字

COMMON_DISPLAY:
    MOV DPTR, #SEG_CODE_TABLE
    MOVC A, @A+DPTR     ; 从段码表获取段码
    MOV P0, A           ; 段码输出到 P0 口

    ; 切换位选控制
    CPL DISPLAY_SELECT

    RETI                ; 中断返回

SEG_CODE_TABLE:
    DB 3FH, 06H, 5BH, 4FH, 66H, 6DH, 7DH, 07H, 7FH, 6FH

END

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 为模式 1
    MOV TH0, #3CH  ; 定时器 0 高 8 位初值,定时 50ms
    MOV TL0, #0B0H ; 定时器 0 低 8 位初值,定时 50ms
    SETB TR0       ; 启动定时器 0

    ; 中断初始化
    SETB ET0       ; 使能定时器 0 中断
    SETB EA        ; 全局中断使能

    ; 变量初始化
    MOV R0, #0     ; 存储当前秒数,范围 0 - 99
    MOV R1, #0     ; 50ms 计数,20 次为 1 秒
    CLR DISPLAY_SELECT ; 初始化位选控制位为 0

MAIN_LOOP:
    SJMP MAIN_LOOP ; 主循环,等待中断
定时器 0 初始化
  • MOV TMOD, #01H:将 TMOD 寄存器设置为 01H,使定时器 0 工作在模式 1(16 位定时器模式)。
  • MOV TH0, #3CHMOV 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, #3CH
    MOV TL0, #0B0H

    ; 50ms 计数
    INC R1
    CJNE R1, #20, DISPLAY ; 未到 1 秒,直接进行显示操作

    ; 1 秒时间到,重置计数
    MOV R1, #0
    ; 秒数加 1
    INC R0
    CJNE R0, #100, DISPLAY ; 未到 100 秒,进行显示操作

    ; 秒数达到 100,重置为 0
    MOV R0, #0

DISPLAY:
    ; 分离十位和个位
    MOV A, R0
    MOV B, #10
    DIV AB ; A 为十位,B 为个位

    ; 根据位选控制显示
    JB DISPLAY_SELECT, DISPLAY_LOW ; 若 DISPLAY_SELECT 为 1,显示个位
    MOV P2, #0FEH       ; 十位位选,假设通过 P2.0 控制
    SJMP COMMON_DISPLAY

DISPLAY_LOW:
    MOV P2, #0FDH       ; 个位位选,假设通过 P2.1 控制
    MOV A, B            ; A 中为个位数字

COMMON_DISPLAY:
    MOV DPTR, #SEG_CODE_TABLE
    MOVC A, @A+DPTR     ; 从段码表获取段码
    MOV P0, A           ; 段码输出到 P0 口

    ; 切换位选控制
    CPL DISPLAY_SELECT

    RETI                ; 中断返回
重新加载定时器初值
  • MOV TH0, #3CHMOV TL0, #0B0H:每次定时器 0 溢出产生中断后,重新给 TH0TL0 赋初值,以便下一次计时。
50ms 计数和秒数更新
  • INC R1R1 寄存器的值加 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 秒的计时功能。

相关推荐
雾削木28 分钟前
mAh 与 Wh:电量单位的深度解析
开发语言·c++·单片机·嵌入式硬件·算法·电脑
PLUS_WAVE1 小时前
CogCoM: A Visual Language Model with Chain-of-Manipulations Reasoning 学习笔记
学习·语言模型·大模型·cot·vlm·推理模型·reasoning
绵绵细雨中的乡音1 小时前
Linux进程学习【环境变量】&&进程优先级
linux·运维·学习
贺函不是涵1 小时前
【沉浸式求职学习day27】
学习
努力奋斗的小杨1 小时前
学习MySQL的第十二天
数据库·笔记·学习·mysql·navicat
AiFlutter1 小时前
低代码平台开发手机USB-HID调试助手
单片机·游戏·计算机外设
枫叶20002 小时前
OceanBase数据库-学习笔记1-概论
数据库·笔记·学习·oceanbase
一点.点2 小时前
李沐动手深度学习(pycharm中运行笔记)——04.数据预处理
pytorch·笔记·python·深度学习·pycharm·动手深度学习
一点.点2 小时前
李沐动手深度学习(pycharm中运行笔记)——07.自动求导
pytorch·笔记·python·深度学习·pycharm·动手深度学习
你可以叫我仔哥呀2 小时前
k8s学习记录(五):Pod亲和性详解
学习·容器·kubernetes