汇编语言Day_01:汇编中常用的寄存器简单介绍

本文详细介绍了8086处理器中的各类寄存器及其用途,包括数据寄存器(如累加器AX)、地址寄存器(如堆栈指针SP)、段寄存器(如代码段CS)及专用寄存器(如指令指针IP)。同时对标志寄存器FLAGS的状态标志和控制标志进行了说明,并解释了BP和SP寄存器的区别。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

数据寄存器:(4个16位):

AX:也成累加器,一般保存目的操作数;
BX:基址寄存器,除了可以存放数据以外,还可以存放首地址;
CX:一般用于计数,如循环中的loop就用CX来控制循环次数;
DX:有时可以用来存放端口地址;

地址寄存器:(4个16位):

SP:堆栈指针,存放栈顶的偏移地址
BP:基址指针,存放堆栈数据的偏移地址
SI:源变址寄存器:源数据的偏移地址
DI:目的变址寄存器:

段寄存器:(4个16位):

CS:代码段的基址;
SS:堆栈段的基址;
DS:数据段的基址;
ES:目的数的基址,同DS;

专用寄存器:(2个16位)

IP:指令指针,存放即将执行的指令的便宜地址
FLAGS:标志寄存器,存放CPU的状态标志控制标志

FLAGS:状态标志:

OF:溢出标志,对于有符号数可以判断结果是否正确,无符号数不用关心
CF:进/借位标志,无符号数的加减法是否产生进/借位
SF:符号标志,运算结果的最高位
ZF:零标志
AF:辅助进位标志:
PF:奇偶标志,可以根据这个进行数据校验

FLAGS:控制标志:

IF:中断允许标志
TF:单步标志
DF:方向标志

注:
BP和SP的区别:
BP虽主要用于指向堆栈段,但它是一个通用寄存器,需要程序中设置需要的值。SP虽可以象通用寄存器一样设置数值,但实质上是一个专用寄存器,其数值的含义就是堆栈的顶部;进行堆栈操作时,处理器自动修改SP数值。所以BP和SP根本就是两种不同类型的寄存器

; 8051电子时钟汇编程序 ; 功能:LCD显示时间(时::秒)、日期(年-月-日)、星期、闹钟 ; 硬件:AT89C51, LCD1602, 按键(P1.0-P1.3), 蜂鸣器(P3.7) ; 按键功能:SET(设置模式)、INC(加)、DEC(减)、ALM(闹钟开关) ; 寄存器定义 SEC EQU 30H ; 秒存储位置 MIN EQU 31H ; 分 HOUR EQU 32H ; 时 DAY EQU 33H ; 日 MONTH EQU 34H ; 月 YEAR EQU 35H ; 年(00-99) WEEK EQU 36H ; 星期(0-6=Sun-Sat) ALM_H EQU 37H ; 闹钟时 ALM_M EQU 38H ; 闹钟分 ALM_FLAG EQU 39H ; 闹钟标志(0=关,1=开) MODE EQU 3AH ; 当前模式(0=正常,1=设置时间,2=设置日期) ; LCD控制引脚 RS BIT P2.0 RW BIT P2.1 EN BIT P2.2 ; 按键引脚 SET_KEY BIT P1.0 INC_KEY BIT P1.1 DEC_KEY BIT P1.2 ALM_KEY BIT P1.3 ; 蜂鸣器 BUZZER BIT P3.7 ORG 0000H LJMP MAIN ORG 000BH ; 定时器T0中断入口 LJMP TIMER0_ISR ORG 0030H MAIN: MOV SP, #60H ; 初始化堆栈 CALL INIT_VAR ; 初始化变量 CALL LCD_INIT ; 初始化LCD CALL TIMER_INIT ; 初始化定时器 LOOP: CALL KEY_SCAN ; 按键扫描 CALL DISPLAY ; 更新显示 CALL ALARM_CHECK ; 检查闹钟 SJMP LOOP ; 变量初始化 INIT_VAR: MOV SEC, #0 ; 初始时间00:00:00 MOV MIN, #0 MOV HOUR, #0 MOV DAY, #1 ; 初始日期2000-01-01 MOV MONTH, #1 MOV YEAR, #0 MOV WEEK, #6 ; 2000-01-01是星期六 MOV ALM_H, #7 ; 默认闹钟07:00 MOV ALM_M, #0 MOV ALM_FLAG, #0 ; 闹钟关闭 MOV MODE, #0 ; 正常显示模式 RET ; 定时器初始化(50ms中断) TIMER_INIT: MOV TMOD, #01H ; T0模式1 MOV TH0, #3CH ; 50ms定时初值 MOV TL0, #0B0H SETB TR0 ; 启动T0 SETB ET0 ; 允许T0中断 SETB EA ; 开总中断 RET ; 定时器0中断服务程序 TIMER0_ISR: CLR TR0 MOV TH0, #3CH ; 重装初值 MOV TL0, #0B0H SETB TR0 INC SEC ; 秒加1 MOV A, SEC CJNE A, #60, TIMER_END ; 不到60秒返回 MOV SEC, #0 ; 秒清零 INC MIN ; 分加1 MOV A, MIN CJNE A, #60, TIMER_END ; 不到60分返回 MOV MIN, #0 ; 分清零 INC HOUR ; 时加1 MOV A, HOUR CJNE A, #24, TIMER_END ; 不到24时返回 MOV HOUR, #0 ; 时清零 CALL UPDATE_DATE ; 更新日期 TIMER_END: RETI ; 日期更新函数 UPDATE_DATE: INC DAY MOV A, DAY ; 检查每月天数 MOV R0, MONTH CJNE R0, #2, NOT_FEB ; 非2月 ; 2月处理(简化版,不考虑闰年) CJNE A, #29, FEB_OK MOV DAY, #1 INC MONTH SJMP WEEK_UPDATE FEB_OK: RET NOT_FEB: CJNE R0, #4, CHECK_30 CJNE A, #31, DAY_OK SJMP MONTH_INC CHECK_30: CJNE R0, #6, CHECK_31 CJNE A, #31, DAY_OK SJMP MONTH_INC CHECK_31: CJNE R0, #9, DAY_31 CJNE A, #31, DAY_OK SJMP MONTH_INC DAY_31: CJNE R0, #11, DAY_31_OK CJNE A, #31, DAY_OK SJMP MONTH_INC DAY_31_OK: CJNE A, #32, DAY_OK MONTH_INC: MOV DAY, #1 INC MONTH MOV A, MONTH CJNE A, #13, DAY_OK MOV MONTH, #1 INC YEAR ; 年份增加 MOV A, YEAR CJNE A, #100, DAY_OK MOV YEAR, #0 ; 年份归零 DAY_OK: ; 更新星期(每周7天循环) INC WEEK MOV A, WEEK CJNE A, #7, WEEK_UPDATE MOV WEEK, #0 WEEK_UPDATE: RET ; 按键扫描函数 KEY_SCAN: JB SET_KEY, KEY_INC ; SET键未按下 CALL DELAY_10MS JB SET_KEY, KEY_INC ; 消抖 WAIT_SET: JNB SET_KEY, WAIT_SET ; 模式切换 MOV A, MODE CJNE A, #0, SET_MODE1 MOV MODE, #1 ; 进入时间设置 SJMP KEY_RET SET_MODE1: CJNE A, #1, SET_MODE2 MOV MODE, #2 ; 进入日期设置 SJMP KEY_RET SET_MODE2: MOV MODE, #0 ; 返回正常模式 KEY_RET: RET KEY_INC: JB INC_KEY, KEY_DEC CALL DELAY_10MS JB INC_KEY, KEY_DEC WAIT_INC: JNB INC_KEY, WAIT_INC ; 根据模式增加数值 MOV A, MODE JZ KEY_RET ; 正常模式不操作 DEC A JZ INC_TIME ; 时间设置模式 ; 日期设置模式 MOV A, DAY INC A CJNE A, #32, DAY_INC_OK ; 最大31天 MOV A, #1 DAY_INC_OK: MOV DAY, A RET INC_TIME: MOV A, HOUR INC A CJNE A, #24, HOUR_INC_OK MOV A, #0 HOUR_INC_OK: MOV HOUR, A RET KEY_DEC: JB DEC_KEY, KEY_ALM CALL DELAY_10MS JB DEC_KEY, KEY_ALM WAIT_DEC: JNB DEC_KEY, WAIT_DEC ; 减少数值 MOV A, MODE JZ KEY_RET DEC A JZ DEC_TIME ; 日期减少 MOV A, DAY DEC A JNZ DAY_DEC_OK MOV A, #31 DAY_DEC_OK: MOV DAY, A RET DEC_TIME: MOV A, HOUR DEC A CJNE A, #0FFH, HOUR_DEC_OK MOV A, #23 HOUR_DEC_OK: MOV HOUR, A RET KEY_ALM: JB ALM_KEY, KEY_EXIT CALL DELAY_10MS JB ALM_KEY, KEY_EXIT WAIT_ALM: JNB ALM_KEY, WAIT_ALM ; 切换闹钟开关 MOV A, ALM_FLAG CPL A MOV ALM_FLAG, A KEY_EXIT: RET ; 闹钟检查函数 ALARM_CHECK: MOV A, ALM_FLAG JZ ALM_OFF ; 闹钟关闭 MOV A, HOUR CJNE A, ALM_H, ALM_OFF MOV A, MIN CJNE A, ALM_M, ALM_OFF ; 触发闹钟(蜂鸣器响1秒) SETB BUZZER CALL DELAY_1S CLR BUZZER ALM_OFF: RET ; LCD显示函数 DISPLAY: CALL LCD_CLEAR ; 第一行显示时间 MOV A, #80H ; 第一行起始地址 CALL LCD_CMD MOV A, HOUR CALL DISP_2DIGIT MOV A, #':' CALL LCD_DATA MOV A, MIN CALL DISP_2DIGIT MOV A, #':' CALL LCD_DATA MOV A, SEC CALL DISP_2DIGIT ; 第二行显示日期和星期 MOV A, #0C0H ; 第二行起始地址 CALL LCD_CMD MOV A, #20H ; "20"前缀 CALL LCD_DATA MOV A, #'0' CALL LCD_DATA MOV A, YEAR CALL DISP_2DIGIT MOV A, #'-' CALL LCD_DATA MOV A, MONTH CALL DISP_2DIGIT MOV A, #'-' CALL LCD_DATA MOV A, DAY CALL DISP_2DIGIT ; 显示星期 MOV A, #0CAH ; 第二行第11列 CALL LCD_CMD MOV DPTR, #WEEK_TAB MOV A, WEEK MOV B, #3 MUL AB ADD A, DPL MOV DPL, A MOV A, DPH ADDC A, #0 MOV DPH, A CALL LCD_STR ; 显示闹钟状态 MOV A, #0CDH CALL LCD_CMD MOV A, ALM_FLAG JNZ SHOW_ALM_ON MOV DPTR, #ALM_OFF_STR SJMP SHOW_ALM SHOW_ALM_ON: MOV DPTR, #ALM_ON_STR SHOW_ALM: CALL LCD_STR ; 设置模式显示光标 MOV A, MODE JZ DISP_EXIT ; 正常模式不显示光标 MOV A, #80H ; 第一行起始 JB MODE.0, SET_DATE_POS ; 时间设置模式(光标在小时位置) ADD A, #0 CALL LCD_CMD MOV A, #0FH ; 开启光标闪烁 CALL LCD_CMD RET SET_DATE_POS: ; 日期设置模式(光标在年份位置) ADD A, #40H ; 第二行起始+3 ADD A, #3 CALL LCD_CMD MOV A, #0FH CALL LCD_CMD DISP_EXIT: MOV A, #0CH ; 关闭光标 CALL LCD_CMD RET ; 显示两位数字 DISP_2DIGIT: MOV B, #10 DIV AB ADD A, #'0' CALL LCD_DATA MOV A, B ADD A, #'0' CALL LCD_DATA RET ; LCD初始化 LCD_INIT: CALL DELAY_20MS MOV A, #38H ; 8位模式,2行显示 CALL LCD_CMD MOV A, #0CH ; 开显示,关光标 CALL LCD_CMD MOV A, #06H ; 增量不移位 CALL LCD_CMD CALL LCD_CLEAR RET ; LCD写命令 LCD_CMD: MOV P0, A CLR RS CLR RW SETB EN CALL DELAY_2MS CLR EN RET ; LCD写数据 LCD_DATA: MOV P0, A SETB RS CLR RW SETB EN CALL DELAY_2MS CLR EN RET ; LCD清屏 LCD_CLEAR: MOV A, #01H CALL LCD_CMD CALL DELAY_2MS RET ; LCD显示字符串(DPTR指向字符串) LCD_STR: CLR A MOVC A, @A+DPTR JZ STR_END CALL LCD_DATA INC DPTR SJMP LCD_STR STR_END: RET ; 延时函数 DELAY_20MS: MOV R6, #40 DL1: MOV R7, #250 DJNZ R7, $ DJNZ R6, DL1 RET DELAY_2MS: MOV R7, #10 DL2: MOV R6, #100 DJNZ R6, $ DJNZ R7, DL2 RET DELAY_10MS: MOV R6, #20 DL3: MOV R7, #250 DJNZ R7, $ DJNZ R6, DL3 RET DELAY_1S: MOV R5, #10 DL4: CALL DELAY_100MS DJNZ R5, DL4 RET DELAY_100MS: MOV R4, #200 DL5: MOV R3, #250 DJNZ R3, $ DJNZ R4, DL5 RET ; 字符串数据表 WEEK_TAB: DB "Sun",0 DB "Mon",0 DB "Tue",0 DB "Wed",0 DB "Thu",0 DB "Fri",0 DB "Sat",0 ALM_ON_STR: DB "ALM ON ",0 ALM_OFF_STR: DB "ALM OFF",0 END 搭建对应的电路
07-04
; C51???????? ; ????: ; LCD??? = P0 ; LCD???: RS=P2.0, RW=P2.1, EN=P2.2 ; ??: SET=P3.0, INC=P3.1, DEC=P3.2, MODE=P3.3 ; ??RAM?? SECOND EQU 30H ; ? MINUTE EQU 31H ; ? HOUR EQU 32H ; ? DAY EQU 33H ; ? MONTH EQU 34H ; ? YEAR EQU 35H ; ? WEEKDAY EQU 36H ; ??(0=??,1=??...6=??) ALARM_H EQU 37H ; ??? ALARM_M EQU 38H ; ??? MODE_FLAG EQU 39H ; ????(0=??,1=????,2=????,3=????) CURSOR EQU 3AH ; ?????? TICK_CNT EQU 3BH ; 50ms?? SEC_FLAG EQU 3CH ; ???? ORG 0000H LJMP MAIN ORG 000BH ; ???0???? LJMP TIMER0_ISR MAIN: MOV SP, #60H ; ?????? LCALL INIT_VARS ; ????? LCALL LCD_INIT ; ???LCD LCALL TIMER_INIT ; ?????? MAIN_LOOP: LCALL KEY_SCAN ; ???? LCALL DISPLAY_TIME ; ???? LCALL CHECK_ALARM ; ???? SJMP MAIN_LOOP ; ????? INIT_VARS: MOV SECOND, #00H ; ???? 00:00:00 MOV MINUTE, #00H MOV HOUR, #00H MOV DAY, #01H ; ???? 01/01/00 MOV MONTH, #01H MOV YEAR, #00H MOV WEEKDAY, #01H ; ?? MOV ALARM_H, #07H ; ??07:00 MOV ALARM_M, #00H MOV MODE_FLAG, #00H MOV CURSOR, #00H MOV TICK_CNT, #00H MOV SEC_FLAG, #00H RET ; ?????? TIMER_INIT: MOV TMOD, #01H ; ???0??1 MOV TH0, #3CH ; 50ms??(11.0592MHz) MOV TL0, #0B0H SETB TR0 ; ????? SETB ET0 ; ??????? SETB EA ; ???? RET ; ???0?????? TIMER0_ISR: PUSH ACC MOV TH0, #3CH ; ???? MOV TL0, #0B0H INC TICK_CNT MOV A, TICK_CNT CJNE A, #20, TIMER_EXIT ; 50ms*20=1s MOV TICK_CNT, #00H SETB SEC_FLAG ; ????? ; ???? INC SECOND MOV A, SECOND CJNE A, #60, TIMER_EXIT MOV SECOND, #00H INC MINUTE MOV A, MINUTE CJNE A, #60, TIMER_EXIT MOV MINUTE, #00H INC HOUR MOV A, HOUR CJNE A, #24, TIMER_EXIT MOV HOUR, #00H ; ??????? INC DAY INC WEEKDAY MOV A, WEEKDAY CJNE A, #7, CHECK_DAY MOV WEEKDAY, #0 CHECK_DAY: MOV A, MONTH CJNE A, #2, NOT_FEB ; ??2? MOV A, YEAR ANL A, #03H ; ??????(??4??) JNZ FEB_28 MOV A, DAY CJNE A, #30, TIMER_EXIT SJMP MONTH_END FEB_28: MOV A, DAY CJNE A, #29, TIMER_EXIT SJMP MONTH_END NOT_FEB: MOV A, MONTH CJNE A, #4, CHECK_30 SJMP CHECK_31 CHECK_30: CJNE A, #6, CHECK_31 SJMP CHECK_31 ; 30??? MOV A, DAY CJNE A, #31, TIMER_EXIT SJMP MONTH_END CHECK_31: ; 31??? MOV A, DAY CJNE A, #32, TIMER_EXIT MONTH_END: MOV DAY, #01H INC MONTH MOV A, MONTH CJNE A, #13, TIMER_EXIT MOV MONTH, #01H INC YEAR MOV A, YEAR CJNE A, #100, TIMER_EXIT MOV YEAR, #00H TIMER_EXIT: POP ACC RETI ; LCD??? LCD_INIT: LCALL DELAY ; ??LCD???? MOV A, #38H ; 8???,2???,5x7?? LCALL LCD_CMD MOV A, #0CH ; ???,??? LCALL LCD_CMD MOV A, #06H ; ????,??? LCALL LCD_CMD MOV A, #01H ; ?? LCALL LCD_CMD RET ; LCD?????? LCD_CMD: MOV P0, A ; ????P0 CLR P2.0 ; RS=0(??) CLR P2.1 ; RW=0(?) SETB P2.2 ; EN=1 LCALL DELAY ; ??? CLR P2.2 ; EN=0 LCALL DELAY RET ; LCD?????? LCD_DATA: MOV P0, A ; ????P0 SETB P2.0 ; RS=1(??) CLR P2.1 ; RW=0(?) SETB P2.2 ; EN=1 LCALL DELAY ; ??? CLR P2.2 ; EN=0 LCALL DELAY RET ; ?????? DISPLAY_TIME: MOV A, #80H ; ??????? LCALL LCD_CMD ; ???? HH:MM:SS MOV A, HOUR LCALL DISP_BCD MOV A, #':' ; ???? LCALL LCD_DATA MOV A, MINUTE LCALL DISP_BCD MOV A, #':' LCALL LCD_DATA MOV A, SECOND LCALL DISP_BCD ; ???? YY/MM/DD MOV A, #0C0H ; ??????? LCALL LCD_CMD MOV A, YEAR LCALL DISP_BCD MOV A, #'/' LCALL LCD_DATA MOV A, MONTH LCALL DISP_BCD MOV A, #'/' LCALL LCD_DATA MOV A, DAY LCALL DISP_BCD ; ???? MOV A, #0CAH ; ????11? LCALL LCD_CMD MOV A, WEEKDAY ADD A, #'0' ; ???ASCII LCALL LCD_DATA ; ?????? MOV A, #8FH ; ????? LCALL LCD_CMD MOV A, #'A' ; ??A?????? LCALL LCD_DATA RET ; ??BCD?(????) DISP_BCD: MOV R0, A SWAP A ; ????? ANL A, #0FH ADD A, #'0' LCALL LCD_DATA MOV A, R0 ; ????? ANL A, #0FH ADD A, #'0' LCALL LCD_DATA RET ; ???? KEY_SCAN: JB P3.0, KEY_INC ; SET???? LCALL DELAY_10MS JB P3.0, KEY_INC JNB P3.0, $ ; ???? ; ???? MOV A, MODE_FLAG INC A CJNE A, #4, SET_MODE MOV A, #0 SET_MODE: MOV MODE_FLAG, A MOV CURSOR, #0 ; ?????? RET KEY_INC: JB P3.1, KEY_DEC ; INC???? LCALL DELAY_10MS JB P3.1, KEY_DEC JNB P3.1, $ ; ???? ; ????????? MOV A, MODE_FLAG JZ KEY_EXIT ; ??????? ; ?????? CJNE A, #1, CHK_DATE LCALL INC_TIME RET CHK_DATE: CJNE A, #2, CHK_ALARM LCALL INC_DATE RET CHK_ALARM: CJNE A, #3, KEY_EXIT LCALL INC_ALARM RET KEY_DEC: JB P3.2, KEY_MODE ; DEC???? LCALL DELAY_10MS JB P3.2, KEY_MODE JNB P3.2, $ ; ???? ; ????????? MOV A, MODE_FLAG JZ KEY_EXIT ; ?????? CJNE A, #1, DEC_DATE LCALL DEC_TIME RET DEC_DATE: CJNE A, #2, DEC_ALARM LCALL DEC_DATE RET DEC_ALARM: CJNE A, #3, KEY_EXIT LCALL DEC_ALARM RET KEY_MODE: JB P3.3, KEY_EXIT ; MODE?(?????) LCALL DELAY_10MS JB P3.3, KEY_EXIT JNB P3.3, $ ; ???? MOV A, MODE_FLAG JZ KEY_EXIT ; ??????? ; ?????????? INC CURSOR MOV A, CURSOR CJNE A, #3, KEY_EXIT ; ??/???3? MOV CURSOR, #0 KEY_EXIT: RET ; ????? INC_TIME: MOV A, CURSOR JZ INC_HOUR CJNE A, #1, INC_SEC ; ???? INC MINUTE MOV A, MINUTE CJNE A, #60, INC_EXIT MOV MINUTE, #0 RET INC_HOUR: INC HOUR MOV A, HOUR CJNE A, #24, INC_EXIT MOV HOUR, #0 RET INC_SEC: INC SECOND MOV A, SECOND CJNE A, #60, INC_EXIT MOV SECOND, #0 INC_EXIT: RET ; ????? INC_DATE: MOV A, CURSOR JZ INC_YEAR CJNE A, #1, INC_DAY ; ???? INC MONTH MOV A, MONTH CJNE A, #13, INC_EXIT MOV MONTH, #1 RET INC_YEAR: INC YEAR MOV A, YEAR CJNE A, #100, INC_EXIT MOV YEAR, #0 RET INC_DAY: INC DAY MOV A, DAY CJNE A, #32, INC_EXIT MOV DAY, #1 RET ; ????? INC_ALARM: MOV A, CURSOR JZ INC_ALARM_H ; ???? INC ALARM_M MOV A, ALARM_M CJNE A, #60, INC_EXIT MOV ALARM_M, #0 RET INC_ALARM_H: INC ALARM_H MOV A, ALARM_H CJNE A, #24, INC_EXIT MOV ALARM_H, #0 RET ; ?????(??????,?) DEC_TIME: ; ????INC_TIME???? RET ; ???? CHECK_ALARM: MOV A, HOUR CJNE A, ALARM_H, ALARM_EXIT MOV A, MINUTE CJNE A, ALARM_M, ALARM_EXIT ; ????(?????LED??) CPL P1.7 ; ??P1.7??LED ALARM_EXIT: RET ; ????? DELAY: MOV R6, #50 DL1: MOV R7, #200 DL2: DJNZ R7, DL2 DJNZ R6, DL1 RET DELAY_10MS: MOV R5, #20 DL3: MOV R6, #250 DL4: DJNZ R6, DL4 DJNZ R5, DL3 RET END 这段代码烧录后9到0时出现;=?>等符号,且减法无用,修改代码
最新发布
07-04
; C51电子时钟汇编程序 ; 硬件连接: ; LCD数据口 = P0 ; LCD控制线: RS=P2.0, RW=P2.1, EN=P2.2 ; 按键: SET=P3.0, INC=P3.1, DEC=P3.2, MODE=P3.3 ; 内部RAM分配 SECOND EQU 30H ; 秒 MINUTE EQU 31H ; 分 HOUR EQU 32H ; 时 DAY EQU 33H ; 日 MONTH EQU 34H ; 月 YEAR EQU 35H ; 年 WEEKDAY EQU 36H ; 星期(0=周日,1=周一…6=周六) ALARM_H EQU 37H ; 闹钟时 ALARM_M EQU 38H ; 闹钟分 MODE_FLAG EQU 39H ; 模式标志(0=正常,1=设置时间,2=设置日期,3=设置闹钟) CURSOR EQU 3AH ; 当前设置位置 TICK_CNT EQU 3BH ; 50ms计数 SEC_FLAG EQU 3CH ; 秒标志位 ORG 0000H LJMP MAIN ORG 000BH ; 定时器0中断入口 LJMP TIMER0_ISR MAIN: MOV SP, #60H ; 设置堆栈指针 LCALL INIT_VARS ; 初始化变量 LCALL LCD_INIT ; 初始化LCD LCALL TIMER_INIT ; 初始化定时器 MAIN_LOOP: LCALL KEY_SCAN ; 扫描按键 LCALL DISPLAY_TIME ; 显示时间 LCALL CHECK_ALARM ; 检查闹钟 SJMP MAIN_LOOP ; 初始化变量 INIT_VARS: MOV SECOND, #00H ; 初始时间 00:00:00 MOV MINUTE, #00H MOV HOUR, #00H MOV DAY, #01H ; 初始日期 01/01/00 MOV MONTH, #01H MOV YEAR, #00H MOV WEEKDAY, #01H ; 周一 MOV ALARM_H, #07H ; 闹钟07:00 MOV ALARM_M, #00H MOV MODE_FLAG, #00H MOV CURSOR, #00H MOV TICK_CNT, #00H MOV SEC_FLAG, #00H RET ; 初始化定时器 TIMER_INIT: MOV TMOD, #01H ; 定时器0模式1 MOV TH0, #3CH ; 50ms定时(11.0592MHz) MOV TL0, #0B0H SETB TR0 ; 启动定时器 SETB ET0 ; 允许定时器中断 SETB EA ; 开总中断 RET ; 定时器0中断服务程序 TIMER0_ISR: PUSH ACC MOV TH0, #3CH ; 重装初值 MOV TL0, #0B0H INC TICK_CNT MOV A, TICK_CNT CJNE A, #20, TIMER_EXIT ; 50ms*20=1s MOV TICK_CNT, #00H SETB SEC_FLAG ; 置位秒标志 ; 更新时间 INC SECOND MOV A, SECOND CJNE A, #60, TIMER_EXIT MOV SECOND, #00H INC MINUTE MOV A, MINUTE CJNE A, #60, TIMER_EXIT MOV MINUTE, #00H INC HOUR MOV A, HOUR CJNE A, #24, TIMER_EXIT MOV HOUR, #00H ; 更新日期和星期 INC DAY INC WEEKDAY MOV A, WEEKDAY CJNE A, #7, CHECK_DAY MOV WEEKDAY, #0 CHECK_DAY: MOV A, MONTH CJNE A, #2, NOT_FEB ; 检查2月 MOV A, YEAR ANL A, #03H ; 简单闰年判断(能被4整除) JNZ FEB_28 MOV A, DAY CJNE A, #30, TIMER_EXIT SJMP MONTH_END FEB_28: MOV A, DAY CJNE A, #29, TIMER_EXIT SJMP MONTH_END NOT_FEB: MOV A, MONTH CJNE A, #4, CHECK_30 SJMP CHECK_31 CHECK_30: CJNE A, #6, CHECK_31 SJMP CHECK_31 ; 30天月份 MOV A, DAY CJNE A, #31, TIMER_EXIT SJMP MONTH_END CHECK_31: ; 31天月份 MOV A, DAY CJNE A, #32, TIMER_EXIT MONTH_END: MOV DAY, #01H INC MONTH MOV A, MONTH CJNE A, #13, TIMER_EXIT MOV MONTH, #01H INC YEAR MOV A, YEAR CJNE A, #100, TIMER_EXIT MOV YEAR, #00H TIMER_EXIT: POP ACC RETI ; LCD初始化 LCD_INIT: LCALL DELAY ; 等待LCD上电稳定 MOV A, #38H ; 8位数据,2行显示,5x7点阵 LCALL LCD_CMD MOV A, #0CH ; 开显示,关光标 LCALL LCD_CMD MOV A, #06H ; 地址递增,不移屏 LCALL LCD_CMD MOV A, #01H ; 清屏 LCALL LCD_CMD RET ; LCD写命令子程序 LCD_CMD: MOV P0, A ; 命令送到P0 CLR P2.0 ; RS=0(命令) CLR P2.1 ; RW=0(写) SETB P2.2 ; EN=1 LCALL DELAY ; 短延时 CLR P2.2 ; EN=0 LCALL DELAY RET ; LCD写数据子程序 LCD_DATA: MOV P0, A ; 数据送到P0 SETB P2.0 ; RS=1(数据) CLR P2.1 ; RW=0(写) SETB P2.2 ; EN=1 LCALL DELAY ; 短延时 CLR P2.2 ; EN=0 LCALL DELAY RET ; 显示时间日期 DISPLAY_TIME: MOV A, #80H ; 第一行起始地址 LCALL LCD_CMD ; 显示时间 HH:MM:SS MOV A, HOUR LCALL DISP_BCD MOV A, #':' ; 显示冒号 LCALL LCD_DATA MOV A, MINUTE LCALL DISP_BCD MOV A, #':' LCALL LCD_DATA MOV A, SECOND LCALL DISP_BCD ; 显示日期 YY/MM/DD MOV A, #0C0H ; 第二行起始地址 LCALL LCD_CMD MOV A, YEAR LCALL DISP_BCD MOV A, #'/' LCALL LCD_DATA MOV A, MONTH LCALL DISP_BCD MOV A, #'/' LCALL LCD_DATA MOV A, DAY LCALL DISP_BCD ; 显示星期 MOV A, #0CAH ; 第二行第11位 LCALL LCD_CMD MOV A, WEEKDAY ADD A, #'0' ; 转换为ASCII LCALL LCD_DATA ; 显示闹钟标志 MOV A, #8FH ; 第一行末尾 LCALL LCD_CMD MOV A, #'A' ; 显示A表示闹钟开启 LCALL LCD_DATA RET ; 显示BCD码(两位数字) DISP_BCD: MOV R0, A SWAP A ; 显示十位数 ANL A, #0FH ADD A, #‘0’ LCALL LCD_DATA MOV A, R0 ; 显示个位数 ANL A, #0FH ADD A, #‘0’ LCALL LCD_DATA RET ; 按键扫描 KEY_SCAN: JB P3.0, KEY_INC ; SET键按下? LCALL DELAY_10MS JB P3.0, KEY_INC JNB P3.0, $ ; 等待释放 ; 模式切换 MOV A, MODE_FLAG INC A CJNE A, #4, SET_MODE MOV A, #0 SET_MODE: MOV MODE_FLAG, A MOV CURSOR, #0 ; 重置光标位置 RET KEY_INC: JB P3.1, KEY_DEC ; INC键按下? LCALL DELAY_10MS JB P3.1, KEY_DEC JNB P3.1, $ ; 等待释放 ; 根据模式增加当前值 MOV A, MODE_FLAG JZ KEY_EXIT ; 正常模式不处理 ; 设置时间模式 CJNE A, #1, CHK_DATE LCALL INC_TIME RET CHK_DATE: CJNE A, #2, CHK_ALARM LCALL INC_DATE RET CHK_ALARM: CJNE A, #3, KEY_EXIT LCALL INC_ALARM RET KEY_DEC: JB P3.2, KEY_MODE ; DEC键按下? LCALL DELAY_10MS JB P3.2, KEY_MODE JNB P3.2, $ ; 等待释放 ; 根据模式减少当前值 MOV A, MODE_FLAG JZ KEY_EXIT ; 设置时间模式 CJNE A, #1, DEC_DATE LCALL DEC_TIME RET DEC_DATE: CJNE A, #2, DEC_ALARM LCALL DEC_DATE RET DEC_ALARM: CJNE A, #3, KEY_EXIT LCALL DEC_ALARM RET KEY_MODE: JB P3.3, KEY_EXIT ; MODE键(切换设置项) LCALL DELAY_10MS JB P3.3, KEY_EXIT JNB P3.3, $ ; 等待释放 MOV A, MODE_FLAG JZ KEY_EXIT ; 正常模式不处理 ; 在设置模式下移动光标 INC CURSOR MOV A, CURSOR CJNE A, #3, KEY_EXIT ; 时间/日期有3项 MOV CURSOR, #0 KEY_EXIT: RET ; 增加时间值 INC_TIME: MOV A, CURSOR JZ INC_HOUR CJNE A, #1, INC_SEC ; 增加分钟 INC MINUTE MOV A, MINUTE CJNE A, #60, INC_EXIT MOV MINUTE, #0 RET INC_HOUR: INC HOUR MOV A, HOUR CJNE A, #24, INC_EXIT MOV HOUR, #0 RET INC_SEC: INC SECOND MOV A, SECOND CJNE A, #60, INC_EXIT MOV SECOND, #0 INC_EXIT: RET ; 增加日期值 INC_DATE: MOV A, CURSOR JZ INC_YEAR CJNE A, #1, INC_DAY ; 增加月份 INC MONTH MOV A, MONTH CJNE A, #13, INC_EXIT MOV MONTH, #1 RET INC_YEAR: INC YEAR MOV A, YEAR CJNE A, #100, INC_EXIT MOV YEAR, #0 RET INC_DAY: INC DAY MOV A, DAY CJNE A, #32, INC_EXIT MOV DAY, #1 RET ; 增加闹钟值 INC_ALARM: MOV A, CURSOR JZ INC_ALARM_H ; 增加分钟 INC ALARM_M MOV A, ALARM_M CJNE A, #60, INC_EXIT MOV ALARM_M, #0 RET INC_ALARM_H: INC ALARM_H MOV A, ALARM_H CJNE A, #24, INC_EXIT MOV ALARM_H, #0 RET ; 减少时间值(类似增加函数,略) DEC_TIME: ; 实现类似INC_TIME但减少值 RET ; 检查闹钟 CHECK_ALARM: MOV A, HOUR CJNE A, ALARM_H, ALARM_EXIT MOV A, MINUTE CJNE A, ALARM_M, ALARM_EXIT ; 触发闹钟(此处简化为LED闪烁) CPL P1.7 ; 翻转P1.7控制LED ALARM_EXIT: RET ; 延时子程序 DELAY: MOV R6, #50 DL1: MOV R7, #200 DL2: DJNZ R7, DL2 DJNZ R6, DL1 RET DELAY_10MS: MOV R5, #20 DL3: MOV R6, #250 DL4: DJNZ R6, DL4 DJNZ R5, DL3 RET END这段有如下问题 1、9之后出现?;等字符 2,按键无反应 在原来的基础上修改代码,给我完整的改后的代码
07-04
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值