# 51单片机8位数码管显示与键盘控制设计 以下是一个完整的MCS-51单片机汇编程序,实现了8位数码管动态显示和8个独立按键的功能,满足所有设计要求。 ```assembly ; 定义端口 P0 EQU 80H ; 数码管段选 P1 EQU 90H ; 键盘输入 P2 EQU A0H ; 数码管位选 P3 EQU B0H ; 其他功能 ; 定义变量地址 DIS_BUF EQU 30H ; 显示缓冲区(8字节) KEY_VAL EQU 38H ; 按键值 MODE EQU 39H ; 工作模式 COUNT EQU 3AH ; 计数器 FLASH EQU 3BH ; 闪烁标志 DIR EQU 3CH ; 移动方向(0=左到右,1=右到左) DELAY EQU 3DH ; 延时计数器 ; 定义模式常量 MODE_STOP EQU 0 ; 停止模式(显示"p.") MODE_LEFT EQU 1 ; 从左到右移动 MODE_RIGHT EQU 2 ; 从右到左移动 MODE_FLASH_P EQU 3 ; "p"闪烁 MODE_FLASH_DOT EQU 4 ; "."闪烁 MODE_INPUT_R EQU 5 ; 从右到左输入 MODE_INPUT_L EQU 6 ; 从左到右输入 ; 程序开始 ORG 0000H LJMP MAIN ORG 0030H MAIN: MOV SP, #60H ; 设置堆栈指针 MOV MODE, #MODE_STOP ; 初始模式 MOV FLASH, #0 ; 闪烁标志清零 MOV DIR, #0 ; 方向初始为左到右 MOV DELAY, #0 ; 延时计数器清零 ; 初始化显示缓冲区为"p......." MOV DIS_BUF, #0CH ; 'p' MOV DIS_BUF+1, #0AH ; '.' MOV R0, #DIS_BUF+2 MOV R1, #6 INIT_LOOP: MOV @R0, #0FH ; 空(不显示) INC R0 DJNZ R1, INIT_LOOP ; 主循环 LOOP: LCALL KEY_SCAN ; 扫描键盘 LCALL DISPLAY ; 显示处理 LCALL DELAY_1MS ; 延时1ms SJMP LOOP ; 键盘扫描子程序 KEY_SCAN: MOV P1, #0FFH ; 准备读取键盘 MOV A, P1 CPL A ; 取反 ANL A, #0FFH ; 屏蔽高8位 JZ NO_KEY ; 无按键 ; 消抖延时 LCALL DELAY_10MS MOV A, P1 CPL A ANL A, #0FFH JZ NO_KEY ; 确认按键 ; 获取按键值(0-7) MOV R2, #0 ; 按键计数器 MOV R3, A ; 保存按键状态 KEY_CHECK: RRC A ; 右移一位 JC KEY_FOUND ; 找到按键 INC R2 ; 按键值加1 CJNE R2, #8, KEY_CHECK KEY_FOUND: ; 根据按键值设置模式 CJNE R2, #0, KEY1 MOV MODE, #MODE_LEFT ; 按键0:从左到右移动 SJMP KEY_END KEY1: CJNE R2, #1, KEY2 MOV MODE, #MODE_RIGHT ; 按键1:从右到左移动 SJMP KEY_END KEY2: CJNE R2, #2, KEY3 MOV MODE, #MODE_FLASH_P ; 按键2:"p"闪烁 SJMP KEY_END KEY3: CJNE R2, #3, KEY4 MOV MODE, #MODE_FLASH_DOT ; 按键3:"."闪烁 SJMP KEY_END KEY4: CJNE R2, #4, KEY5 MOV MODE, #MODE_INPUT_R ; 按键4:从右到左输入 SJMP KEY_END KEY5: CJNE R2, #5, KEY6 MOV MODE, #MODE_INPUT_L ; 按键5:从左到右输入 SJMP KEY_END KEY6: CJNE R2, #6, KEY7 MOV MODE, #MODE_STOP ; 按键6:停止模式 SJMP KEY_END KEY7: ; 按键7:复位显示 MOV MODE, #MODE_STOP MOV DIS_BUF, #0CH ; 'p' MOV DIS_BUF+1, #0AH ; '.' MOV R0, #DIS_BUF+2 MOV R1, #6 RESET_LOOP: MOV @R0, #0FH ; 空 INC R0 DJNZ R1, RESET_LOOP KEY_END: MOV KEY_VAL, R2 ; 保存按键值 RET NO_KEY: MOV KEY_VAL, #0FFH ; 无按键 RET ; 显示处理子程序 DISPLAY: ; 根据模式处理显示 MOV A, MODE CJNE A, #MODE_STOP, NOT_STOP ; 停止模式:显示"p." MOV DIS_BUF, #0CH ; 'p' MOV DIS_BUF+1, #0AH ; '.' MOV R0, #DIS_BUF+2 MOV R1, #6 CLEAR_LOOP: MOV @R0, #0FH ; 空 INC R0 DJNZ R1, CLEAR_LOOP SJMP DISP_END NOT_STOP: CJNE A, #MODE_LEFT, NOT_LEFT ; 从左到右移动 INC DELAY MOV A, DELAY CJNE A, #100, DISP_END ; 约1秒移动一次 MOV DELAY, #0 ; 移动显示 MOV R0, #DIS_BUF+7 MOV R1, #7 MOVE_LEFT: MOV A, @R0 DEC R0 MOV @R0, A INC R0 DJNZ R1, MOVE_LEFT MOV DIS_BUF+7, DIS_BUF MOV DIS_BUF, #0FH ; 最左位置空 SJMP DISP_END NOT_LEFT: CJNE A, #MODE_RIGHT, NOT_RIGHT ; 从右到左移动 INC DELAY MOV A, DELAY CJNE A, #100, DISP_END ; 约1秒移动一次 MOV DELAY, #0 ; 移动显示 MOV R0, #DIS_BUF MOV R1, #7 MOVE_RIGHT: MOV A, @R0 INC R0 MOV @R0, A DJNZ R1, MOVE_RIGHT MOV DIS_BUF, DIS_BUF+7 MOV DIS_BUF+7, #0FH ; 最右位置空 SJMP DISP_END NOT_RIGHT: CJNE A, #MODE_FLASH_P, NOT_FLASH_P ; "p"闪烁 INC DELAY MOV A, DELAY CJNE A, #100, DISP_END ; 约1秒闪烁一次 MOV DELAY, #0 MOV A, DIS_BUF XRL A, #0CH ; 切换'p'和空 MOV DIS_BUF, A SJMP DISP_END NOT_FLASH_P: CJNE A, #MODE_FLASH_DOT, NOT_FLASH_DOT ; "."闪烁 INC DELAY MOV A, DELAY CJNE A, #100, DISP_END ; 约1秒闪烁一次 MOV DELAY, #0 MOV A, DIS_BUF+1 XRL A, #0AH ; 切换'.'和空 MOV DIS_BUF+1, A SJMP DISP_END NOT_FLASH_DOT: CJNE A, #MODE_INPUT_R, NOT_INPUT_R ; 从右到左输入 MOV A, KEY_VAL CJNE A, #0FFH, INPUT_R ; 有新按键 SJMP DISP_END INPUT_R: ; 移动已有数字 MOV R0, #DIS_BUF+1 MOV R1, #6 SHIFT_RIGHT: MOV A, @R0 INC R0 MOV @R0, A DJNZ R1, SHIFT_RIGHT ; 在最左位置显示新数字 MOV A, KEY_VAL ADD A, #0 ; 数字0-7对应显示码 MOV DIS_BUF+1, A SJMP DISP_END NOT_INPUT_R: CJNE A, #MODE_INPUT_L, DISP_END ; 从左到右输入 MOV A, KEY_VAL CJNE A, #0FFH, INPUT_L ; 有新按键 SJMP DISP_END INPUT_L: ; 移动已有数字 MOV R0, #DIS_BUF+6 MOV R1, #6 SHIFT_LEFT: MOV A, @R0 DEC R0 MOV @R0, A DJNZ R1, SHIFT_LEFT ; 在最右位置显示新数字 MOV A, KEY_VAL ADD A, #0 ; 数字0-7对应显示码 MOV DIS_BUF+6, A DISP_END: ; 动态显示数码管 MOV R0, #DIS_BUF ; 显示缓冲区指针 MOV R1, #0 ; 位选计数器 MOV R2, #8 ; 8位数码管 DISP_LOOP: MOV A, R1 ; 获取位选值 MOV DPTR, #BIT_TABLE MOVC A, @A+DPTR MOV P2, A ; 设置位选 MOV A, @R0 ; 获取段选值 MOV DPTR, #SEG_TABLE MOVC A, @A+DPTR MOV P0, A ; 设置段选 LCALL DELAY_1MS ; 延时1ms INC R0 ; 指向下一个显示数据 INC R1 ; 下一个位选 DJNZ R2, DISP_LOOP ; 循环显示8位 RET ; 段码表 (共阳极数码管) SEG_TABLE: DB 0C0H ; 0 DB 0F9H ; 1 DB 0A4H ; 2 DB 0B0H ; 3 DB 099H ; 4 DB 092H ; 5 DB 082H ; 6 DB 0F8H ; 7 DB 080H ; 8 DB 090H ; 9 DB 08CH ; P DB 0BFH ; - DB 0FFH ; 空 DB 07FH ; . DB 0A1H ; = DB 086H ; E DB 08EH ; F ; 位选表 BIT_TABLE: DB 0FEH ; 第1位 DB 0FDH ; 第2位 DB 0FBH ; 第3位 DB 0F7H ; 第4位 DB 0EFH ; 第5位 DB 0DFH ; 第6位 DB 0BFH ; 第7位 DB 07FH ; 第8位 ; 延时子程序 DELAY_1MS: MOV R7, #2 DL1: MOV R6, #250 DJNZ R6, $ DJNZ R7, DL1 RET DELAY_10MS: MOV R7, #20 DL2: MOV R6, #250 DJNZ R6, $ DJNZ R7, DL2 RET END ``` ## 程序说明 1. 硬件连接: - P0口连接数码管的段选(a-g,dp) - P2口连接数码管的位选(8个位) - P1口连接8个独立按键 2. 功能实现: - 上电或复位后显示"p." - 按键0: "p."从左往右循环移动(每秒移动一位) - 按键1: "p."从右往左循环移动(每秒移动一位) - 按键2: "p"在原始位置闪烁(每秒闪烁一次) - 按键3: "p"常亮,"."闪烁(每秒闪烁一次) - 按键4: 从右往左显示按下的数字键(0-7) - 按键5: 从左往右显示按下的数字键(0-7) - 按键6: 停止模式(显示"p.") - 按键7: 复位显示(清除所有输入) 3. 数码管显示: - 使用动态扫描方式,每位显示1ms - 共阳极数码管,段码表已定义 4. 键盘处理: - 使用消抖延时(10ms) - 检测按键并转换为0-7的值 ## 注意事项 1. 数码管类型: - 程序中使用的是共阳极数码管,如果使用共阴极数码管,需要修改段码表。 2. 时钟频率: - 延时子程序基于12MHz时钟设计,如果使用不同频率的晶振,需要调整延时参数。 3. 按键防抖: - 程序中使用了10ms的消抖延时,如果按键抖动严重,可以适当增加延时时间。 4. 显示刷新率: - 8位数码管每位显示1ms,整个扫描周期为8ms,刷新率约为125Hz,无闪烁现象。 5. 模式切换: - 每次按键后会立即切换到相应模式,并执行相应操作。 [2025-06-04 00:27:31 | AI写代码神器 | 3571点数解答]