基于51单片机的八位数码管测温时钟实例(汇编)
本例提供了一个基于汇编程序实现的51单片机实例,通过八个七段数码管显示时、分、秒的走时,能设置闹铃,能显示当前温度。以下是本例所依赖的电路原理图,系统使用11.0592MHz晶振。
以上是八个数码管的电路,段码和位码共用了P0端口,使用两片锁存器芯片来分时实现传送数据。
以上是十六个按键的矩阵键盘,使用了P3口来扫描并获取键值。
以上是蜂鸣器和温度传感器电路。蜂鸣器通过PNP三极管驱动,P2.3为低电平时响。温度传感器使用的是单总线DS18B20芯片,数据线接在P2.2口。
本例一共使用了六个按键(S1~S6),其功能如下:
S1:增加
S2:减小
S3:调校(包括时钟和闹钟,调校时相应的位会闪烁)
S4:时钟/闹铃(显示切换)
S5:时钟/温度(显示切换,在闹铃显示状态不响应)
S6:闹铃开/关(闹铃生效时第三位数码管会显示小数点)
当检测到DB18B20时点亮P1.7的LED,未检测到点亮P1.0,测温时点亮P1.6,每次温度转换完成取反P1.5引脚电平。
以下是本例的全部汇编代码,为了方便大家学习参考,每行代码都进行了详细注释。
KEY EQU 7FH ;键值 H_S EQU 7EH ;时的十位 H_G EQU 7DH ;时的个位 M_S EQU 7BH ;分的十位 M_G EQU 7AH ;分的个位 S_S EQU 78H ;秒的十位 S_G EQU 77H ;秒的个位 CNT EQU 76H ;调校闪烁速度控制 SCT EQU 75H ;调校状态(时、分、秒、不调校) _H EQU 74H ;时 _M EQU 73H ;分 _S EQU 72H ;秒 A_H_S EQU 71H ;闹铃时的十位 A_H_G EQU 70H ;闹铃时的个位 A_M_S EQU 6EH ;闹铃分的十位 A_M_G EQU 6DH ;闹铃分的个位 A_S_S EQU 6BH ;闹铃秒的十位 A_S_G EQU 6AH ;闹铃秒的个位 A_SCT EQU 69H ;闹铃调校状态(时、分、秒、不调校) A_H EQU 68H ;闹铃时 A_M EQU 67H ;闹铃分 A_S EQU 66H ;闹铃秒 T_S EQU 65H ;温度的十位 T_G EQU 64H ;温度的个位 T_L EQU 23H ;温度低位数据(位寻址区) T_H EQU 22H ;温度高位数据(位寻址区) FLG_H BIT 00H ;时闪烁标志 FLG_M BIT 01H ;分闪烁标志 FLG_S BIT 02H ;秒闪烁标志 AFLG_H BIT 03H ;闹铃时闪烁标志 AFLG_M BIT 04H ;闹铃分闪烁标志 AFLG_S BIT 05H ;闹铃秒闪烁标志 A_SHOW_FLAG BIT 06H ;显示时间还是闹铃标志 DS18B20 BIT 07H ;发现DS18B20标志 TMP BIT 08H ;温度转换延时标志 T_SHOW_FLAG BIT 09H ;温度显示标志 A_SET BIT 0AH ;闹铃控制开关 ;*****************************程序开始********************************* ORG 0000H AJMP START ORG 000BH AJMP T0_SRV ;T0中断产生时钟 ORG 001BH AJMP T1_SVR ;T1中断实现数码管扫描 ORG 0030H START: MOV SP, #30H ;初始化堆栈指针 MOV 7CH, #16 ;显示“-” MOV 79H, #16 ;显示“-” MOV 6FH, #17 ;显示黑屏 MOV 6CH, #17 ;显示黑屏 MOV SCT, #00H ;调校状态初始为不调校 MOV A_SCT, #00H ;闹铃调校状态初始为不调校 MOV R0, #7EH ;显示内容首地址 MOV R1, #71H ;闹铃内容首地址 MOV R2, #0FEH ;动态扫描控制 MOV R3, #00H ;软件计数器初始值 MOV R7, #09H ;按键响应时间控制 MOV _S, #00H ;秒初始值 MOV _M, #00H ;分初始值 MOV _H, #00H ;时初始值 CLR FLG_H ;时初始状态不闪烁 CLR FLG_M ;分初始状态不闪烁 CLR FLG_S ;秒初始状态不闪烁 CLR AFLG_H ;闹铃时初始状态不闪烁 CLR AFLG_M ;闹铃分初始状态不闪烁 CLR AFLG_S ;闹铃秒初始状态不闪烁 CLR A_SHOW_FLAG ;初始状态显示时钟(不显示闹铃) CLR TMP ;初始状态为未读取温度 CLR T_SHOW_FLAG ;初始状态为不显示温度 CLR A_SET ;初始状态为闹铃关闭 MOV TMOD, #11H ;T0、T1工作在16位模式下 MOV TH0, #4CH MOV TL0, #00H ;50ms的初始值 MOV TH1, HIGH(65536-2000) MOV TL1, LOW(65536-2000);2ms初始值 MOV IE, #8AH ;使能T0、T1及总中断 SETB TR0 ;启动T0 SETB TR1 ;启动T1 ;*****************************主循环开始******************************* LOOP: ;==============================判断按键6=============================== MOV A, KEY ;读取键值 CJNE A, #06H, T_N ;判断键值是否为6,为6顺序执行,否则跳转 MOV KEY, #00H ;键值清零 DJNZ R7, T_N ;连续读取9次键值,若都为6证明该按键被按下 MOV R7, #09H ;恢复按键响应时间控制初始值 JB A_SHOW_FLAG, T_NS ;若在闹铃显示状态下则闹铃设置不生效 JB T_SHOW_FLAG, T_NS ;若在温度显示状态下则闹铃设置不生效 MOV A, SCT CJNE A, #00, T_NS ;若在时钟调校状态下则闹铃设置不生效 CPL A_SET ;按键按下开/关闹铃交替 JB A_SET, T_N ;判断是否设置为闹铃响,若不是则不显示“.” MOV 7CH, #16 ;恢复显示“-” ;==============================判断按键5=============================== T_N: MOV A, KEY ;读取键值 CJNE A, #05H, T_NS ;判断键值是否为5,为5顺序执行,否则跳转 MOV KEY, #00H ;键值清零 DJNZ R7, ALM_SHOW ;连续读取9次键值,若都为5证明该按键被按下 MOV R7, #09H ;恢复按键响应时间控制初始值 JB A_SHOW_FLAG, T_NS ;若在闹铃显示状态下则温度显示不生效 MOV SCT, #00H ;按下键则时间调校结束 CPL T_SHOW_FLAG ;按键按下时间/温度功能交替 ;===========================时间显示状态=============================== ;---------------------------判断按键3---------------------------------- T_NS: JB A_SHOW_FLAG, N_A ;判断闹铃显示标志,时钟则顺序执行,闹铃则跳转 MOV A, KEY ;读取键值 CJNE A, #03H, ALM_SHOW ;判断键值是否为3,为3顺序执行,否则跳转 MOV KEY, #00H ;键值清零 DJNZ R7, ALM_SHOW ;连续读取9次键值,若都为3证明该按键被按下 MOV R7, #09H ;恢复按键响应时间控制初始值 JB T_SHOW_FLAG, LOOP ;若在温度显示状态下则按键3不生效 INC SCT ;调校状态加1 MOV A, SCT CJNE A, #4,ALM_SHOW ;判断调校状态是否已到4 MOV SCT, #00H ;调校状态恢复0 AJMP ALM_SHOW ;跳转到下一个按键状态判别 ;===========================闹铃显示状态=============================== ;---------------------------判断按键3---------------------------------- N_A: ;在闹铃状态调校 MOV A, KEY ;读取键值 CJNE A, #03H, ALM_SHOW ;判断键值是否为3,为3顺序执行,否则跳转 MOV KEY, #00H ;键值清零 DJNZ R7, ALM_SHOW ;连续读取9次键值,若都为3证明该按键被按下 MOV R7, #09H ;恢复按键响应时间控制初始值 INC A_SCT ;闹铃调校状态加1 MOV A, A_SCT CJNE A, #4, ALM_SHOW ;判断闹铃调校状态是否已到4 MOV A_SCT, #00H ;闹铃调校状态恢复0 ;==============================判断按键4================================ ALM_SHOW: MOV A, KEY ;读取键值 CJNE A, #04H, H_N1 ;判断键值是否为4,为4顺序执行,否则跳转 MOV KEY, #00H ;键值清零 DJNZ R7, H_N1 ;连续读取9次键值,若都为4证明该按键被按下 MOV R7, #09H ;恢复按键响应时间控制初始值 JB T_SHOW_FLAG, L_GO ;若在温度显示状态下则按键4不生效 CPL A_SHOW_FLAG ;按键按下时间/闹铃功能交替 JB A_SHOW_FLAG, A_OK ;判断闹铃显示标志,时钟则顺序执行,闹铃则跳转 MOV A_SCT, #00H ;按下时闹铃调校结束 AJMP H_N1 ;跳转到下一个按键状态判别 A_OK: MOV SCT, #00H ;按下时间调校结束 AJMP H_N1 ;跳转到下一个按键状态判别 L_GO: AJMP LOOP ;跳回主循环开始 ;==========================以下为“时”调校状态=========================== ;-----------------------------判断按键1--------------------------------- H_N1: JB A_SHOW_FLAG, GO_AH_N1;判断闹铃显示标志,时钟则顺序执行,闹铃则跳转(接力跳) MOV A, SCT ;获取当前调校状态 CJNE A, #01H, M_N1 ;当前调校“时” MOV A, KEY ;读取键值 CJNE A, #01H, H_N2 ;判断键值是否为1,为1顺序执行,否则跳转 MOV KEY, #00H ;键值清零 DJNZ R7, H_N2 ;连续读取9次键值,若都为1证明该按键被按下 INC _H ;“时”加一 MOV A, _H CJNE A, #24,H_INC ;判断“时”是否加到24 MOV _H, #00H ;到24则恢复0 H_INC: MOV R7, #09H ;恢复按键响应时间控制初始值 ;----------------------------判断按键2---------------------------------- H_N2: MOV A, KEY ;读取键值 CJNE A, #02H, M_N1 ;判断键值是否为2,为2顺序执行,否则跳转 MOV KEY, #00H ;键值清零 DJNZ R7, M_N1 ;连续读取9次键值,若都为2证明该按键被按下 DEC _H ;“时”减一 MOV A, _H CJNE A, #0FFH,H_DEC ;判断“时”是否减到负值 MOV _H, #23 ;到负值则恢复23 H_DEC: MOV R7, #09H ;恢复按键响应时间控制初始值 AJMP M_N1 ;跳转到下一个按键状态判别 GO_AH_N1: AJMP AH_N1 ;跳转接力 ;==========================以下为“分”调校状态=========================== ;----------------------------判断按键1---------------------------------- M_N1: MOV A, SCT ;获取当前调校状态 CJNE A, #02H, S_N1 ;当前调校“分” MOV A, KEY ;读取键值 CJNE A, #01H, M_N2 ;判断键值是否为1,为1顺序执行,否则跳转 MOV KEY, #00H ;键值清零 DJNZ R7, M_N2 ;连续读取9次键值,若都为1证明该按键被按下 INC _M ;“分”加一 MOV A, _M CJNE A, #60,M_INC ;判断“分”是否加到60 MOV _M, #00H ;到60则恢复0 M_INC: MOV R7, #09H ;恢复按键响应时间控制初始值 ;----------------------------判断按键2---------------------------------- M_N2: MOV A, KEY ;读取键值 CJNE A, #02H, S_N1 ;判断键值是否为2,为2顺序执行,否则跳转 MOV KEY, #00H ;键值清零 DJNZ R7, S_N1 ;连续读取9次键值,若都为2证明该按键被按下 DEC _M ;“分”减一 MOV A, _M CJNE A, #0FFH,M_DEC ;判断“分”是否减到负值 MOV _M, #59 ;到负值则恢复59 M_DEC: MOV R7, #09H ;恢复按键响应时间控制初始值 ;==========================以下为“秒”调校状态=========================== ;----------------------------判断按键1---------------------------------- S_N1: MOV A, SCT ;获取当前调校状态 CJNE A, #03H, GO_ON ;当前调校“秒” MOV A, KEY ;读取键值 CJNE A, #01H, S_N2 ;判断键值是否为1,为1顺序执行,否则跳转 MOV KEY, #00H ;键值清零 DJNZ R7, S_N2 ;连续读取9次键值,若都为1证明该按键被按下 INC _S ;“秒”加一 MOV A, _S CJNE A, #60,S_INC ;判断“秒”是否加到60 MOV _S, #00H ;到60则恢复0 S_INC: MOV R7, #09H ;恢复按键响应时间控制初始值 ;---------------------------判断按键2---------------------------------- S_N2: MOV A, KEY ;读取键值 CJNE A, #02H, GO_ON ;判断键值是否为2,为2顺序执行,否则跳转 MOV KEY, #00H ;键值清零 DJNZ R7, GO_ON ;连续读取9次键值,若都为2证明该按键被按下 DEC _S ;“秒”减一 MOV A, _S CJNE A, #0FFH,S_DEC ;判断“秒”是否减到负值 MOV _S, #59 ;到负值则恢复59 S_DEC: MOV R7, #09H ;恢复按键响应时间控制初始值 GO_ON: AJMP CLOCK ;跳转到时间显示拆分程序 ;======================以下为闹铃“时”调校状态=========================== ;-----------------------------判断按键1--------------------------------- AH_N1: MOV A, A_SCT ;获取当前闹铃调校状态 CJNE A, #01H, AM_N1 ;当前闹铃调校“时” MOV A, KEY ;读取键值 CJNE A, #01H, AH_N2 ;判断键值是否为1,为1顺序执行,否则跳转 MOV KEY, #00H ;键值清零 DJNZ R7, AH_N2 ;连续读取9次键值,若都为1证明该按键被按下 INC A_H ;闹铃“时”加一 MOV A, A_H CJNE A, #24,AH_INC ;判断闹铃“时”是否加到24 MOV A_H, #00H ;到24则恢复0 AH_INC: MOV R7, #09H ;恢复按键响应时间控制初始值 ;----------------------------判断按键2---------------------------------- AH_N2: MOV A, KEY ;读取键值 CJNE A, #02H, AM_N1 ;判断键值是否为2,为2顺序执行,否则跳转 MOV KEY, #00H ;键值清零 DJNZ R7, AM_N1 ;连续读取9次键值,若都为2证明该按键被按下 DEC A_H ;闹铃“时”减一 MOV A, A_H CJNE A, #0FFH, AH_DEC ;判断闹铃“时”是否减到负值 MOV A_H, #23 ;到负值则恢复23 AH_DEC: MOV R7, #09H ;恢复按键响应时间控制初始值 ;======================以下为闹铃“分”调校状态=========================== ;-----------------------------判断按键1--------------------------------- AM_N1: MOV A, A_SCT ;获取当前闹铃调校状态 CJNE A, #02H, AS_N1 ;当前闹铃调校“分” MOV A, KEY ;读取键值 CJNE A, #01H, AM_N2 ;判断键值是否为1,为1顺序执行,否则跳转 MOV KEY, #00H ;键值清零 DJNZ R7, AM_N2 ;连续读取9次键值,若都为1证明该按键被按下 INC A_M ;闹铃“分”加一 MOV A, A_M CJNE A, #60,AM_INC ;判断闹铃“分”是否加到60 MOV A_M, #00H ;到60则恢复0 AM_INC: MOV R7, #09H ;恢复按键响应时间控制初始值 ;----------------------------判断按键2---------------------------------- AM_N2: MOV A, KEY ;读取键值 CJNE A, #02H, AS_N1 ;判断键值是否为2,为2顺序执行,否则跳转 MOV KEY, #00H ;键值清零 DJNZ R7, AS_N1 ;连续读取9次键值,若都为2证明该按键被按下 DEC A_M ;闹铃“分”减一 MOV A, A_M CJNE A, #0FFH, AM_DEC ;判断闹铃“分”是否减到负值 MOV A_M, #59 ;到负值则恢复59 AM_DEC: MOV R7, #09H ;恢复按键响应时间控制初始值 ;======================以下为闹铃“秒”调校状态=========================== ;-----------------------------判断按键1--------------------------------- AS_N1: MOV A, A_SCT ;获取当前闹铃调校状态 CJNE A, #03H, CLOCK ;当前闹铃调校“秒” MOV A, KEY ;读取键值 CJNE A, #01H, AS_N2 ;判断键值是否为1,为1顺序执行,否则跳转 MOV KEY, #00H ;键值清零 DJNZ R7, AS_N2 ;连续读取9次键值,若都为1证明该按键被按下 INC A_S ;闹铃“秒”加一 MOV A, A_S CJNE A, #60,AS_INC ;判断闹铃“秒”是否加到60 MOV A_S, #00H ;到60则恢复0 AS_INC: MOV R7, #09H ;恢复按键响应时间控制初始值 ;----------------------------判断按键2---------------------------------- AS_N2: MOV A, KEY ;读取键值 CJNE A, #02H, CLOCK ;判断键值是否为2,为2顺序执行,否则跳转 MOV KEY, #00H ;键值清零 DJNZ R7, CLOCK ;连续读取9次键值,若都为2证明该按键被按下 DEC A_S ;闹铃“秒”减一 MOV A, A_S CJNE A, #0FFH, AS_DEC ;判断闹铃“秒”是否减到负值 MOV A_S, #59 ;到负值则恢复59 AS_DEC: MOV R7, #09H ;恢复按键响应时间控制初始值 ;========================以下为时间显示拆分============================ ;----------------------------“秒”拆分---------------------------------- CLOCK: JB A_SHOW_FLAG, ALARM ;判断闹铃显示标志,时钟则顺序执行,闹铃则跳转 MOV A, _S ;读取“秒” MOV B, #10 ;加载被除数10 DIV AB ;“秒”除以10 JB FLG_S, S_OFF ;判断秒显示标志,若为1则显示黑屏,否则正常显示 MOV S_S, A ;十位数部分 MOV S_G, B ;个位数部分 AJMP M_ON ;跳到“分”拆分部分 S_OFF: MOV S_S, #17 ;显示黑屏 MOV S_G, #17 ;显示黑屏 ;----------------------------“分”拆分---------------------------------- M_ON: MOV A, _M ;读取“分” MOV B, #10 ;加载被除数10 DIV AB ;“分”除以10 JB FLG_M, M_OFF ;判断秒显示标志,若为1则显示黑屏,否则正常显示 MOV M_S, A ;十位数部分 MOV M_G, B ;个位数部分 AJMP H_ON ;跳到“时”拆分部分 M_OFF: MOV M_S, #17 ;显示黑屏 MOV M_G, #17 ;显示黑屏 ;----------------------------“时”拆分---------------------------------- H_ON: MOV A, _H ;读取“时” MOV B, #10 ;加载被除数10 DIV AB ;“时”除以10 JB FLG_H, H_OFF ;判断秒显示标志,若为1则显示黑屏,否则正常显示 MOV H_S, A ;十位数部分 MOV H_G, B ;个位数部分 AJMP LOOP ;跳回主循环开始 H_OFF: MOV H_S, #17 ;显示黑屏 MOV H_G, #17 ;显示黑屏 AJMP LOOP ;跳回主循环开始 ;========================以下为闹铃显示拆分============================ ;----------------------------闹铃“秒”拆分------------------------------ ALARM: MOV A, A_S ;读取闹铃“秒” MOV B, #10 ;加载被除数10 DIV AB ;闹铃“秒”除以10 JB AFLG_S, AS_OFF ;判断秒显示标志,若为1则显示黑屏,否则正常显示 MOV A_S_S, A ;十位数部分 MOV A_S_G, B ;个位数部分 AJMP AM_ON ;跳到闹铃“分”拆分部分 AS_OFF: MOV A_S_S, #17 ;显示黑屏 MOV A_S_G, #17 ;显示黑屏 ;----------------------------闹铃“分”拆分------------------------------ AM_ON: MOV A, A_M ;读取闹铃“分” MOV B, #10 ;加载被除数10 DIV AB ;闹铃“分”除以10 JB AFLG_M, AM_OFF ;判断秒显示标志,若为1则显示黑屏,否则正常显示 MOV A_M_S, A ;十位数部分 MOV A_M_G, B ;个位数部分 AJMP AH_ON ;跳到闹铃“时”拆分部分 AM_OFF: MOV A_M_S, #17 ;显示黑屏 MOV A_M_G, #17 ;显示黑屏 ;----------------------------闹铃“时”拆分------------------------------ AH_ON: MOV A, A_H ;读取闹铃“时” MOV B, #10 ;加载被除数10 DIV AB ;闹铃“时”除以10 JB AFLG_H, AH_OFF ;判断秒显示标志,若为1则显示黑屏,否则正常显示 MOV A_H_S, A ;十位数部分 MOV A_H_G, B ;个位数部分 AJMP LOOP ;跳回主循环开始 AH_OFF: MOV A_H_S, #17 ;显示黑屏 MOV A_H_G, #17 ;显示黑屏 AJMP LOOP ;跳回主循环开始 ;*****************************定时器T1******************************** T1_SVR: PUSH ACC ;累加器压栈 PUSH PSW ;程序状态字压栈 MOV TH1, HIGH(65536-2000) MOV TL1, LOW(65536-2000);重载2ms初始值 MOV A, R2 ;读取当前的位扫描值 MOV P0, A ;输出当前位扫描值 SETB P2.7 ;设置位锁存器高电平(直通) CLR P2.7 ;设置位锁存器低电平(锁住) JB A_SHOW_FLAG, A_SH ;判断闹铃显示标志,时钟则顺序执行,闹铃则跳转 JNB T_SHOW_FLAG, T_GO ;判断温度显示模块,显示温度则顺序,否则跳转 JNB ACC.7, ACC_7 ;判断数码管扫描位置是否为倒数第1位 JNB ACC.6, ACC_6 ;判断数码管扫描位置是否为倒数第2位 MOV H_S, #16 ;原时间“时”的十位部分显示“-” MOV H_G, #16 ;原时间“时”的个位部分显示“-” MOV M_S, #16 ;原时间“分”的十位部分显示“-” MOV M_G, #16 ;原时间“分”的个位部分显示“-” AJMP T_GO ACC_7: MOV R0, #T_G ;显示温度个位 AJMP T_GO ACC_6: MOV R0, #T_S ;显示温度十位 T_GO: MOV A, @R0 ;读取“时” AJMP SH ;跳转到查表部分 A_SH: MOV A, @R1 ;读取闹铃“时” SH: MOV DPTR, #TABLE ;获取字形码存放地址 MOVC A, @A+DPTR ;查表获得字形码 MOV P0, A ;输出字形码 SETB P2.6 ;设置段锁存器高电平(直通) CLR P2.6 ;设置段锁存器低电平(锁住) ;========================调用矩阵键盘扫描============================ MOV A, R2 ;读取当前的位扫描值 ORL A, #0F0H ;高四位置1(作为输入) MOV P3, A ;输出到矩阵键盘接口进行扫描 ACALL KEY_SCAN ;调用矩阵键盘子程序 ;==================================================================== MOV A, R2 ;读取当前的位扫描值 RL A ;左移 JB A_SHOW_FLAG, A_DEC ;判断闹铃显示标志,时钟则顺序执行,闹铃则跳转 DEC R0 ;时间显示内容的地址减一 AJMP OK A_DEC: DEC R1 ;闹铃显示内容的地址减一 OK: JB ACC.0, N_1 ;判断是否8位数码管全部扫描完毕 JB A_SHOW_FLAG, A_OUT ;判断闹铃显示标志,时钟则顺序执行,闹铃则跳转 MOV R0, #H_S ;全部扫描完毕则恢复时间显示内容的地址 AJMP N_1 A_OUT: MOV R1, #A_H_S ;全部扫描完毕则恢复闹铃显示内容的地址 N_1: MOV R2, A ;回存左移后的位扫描值 POP PSW ;弹出程序状态字 POP ACC ;弹出累加器 RETI ;中断返回 ;***************************矩阵键盘扫描****************************** KEY_SCAN: PUSH ACC ;累加器压栈 PUSH PSW ;程序状态字压栈 MOV A, P3 ;读取矩阵键盘接口 JNB ACC.4, L_4 ;判断第一列是否有低电平出现 JNB ACC.5, L_5 ;判断第二列是否有低电平出现 JNB ACC.6, L_6 ;判断第三列是否有低电平出现 JNB ACC.7, L_7 ;判断第四列是否有低电平出现 AJMP OUT ;都没有低电平则退出(无键按下) ;==========================第一列有键按下============================= L_4: MOV A, R2 ;读取当前的位扫描值 JNB ACC.0, K_1 ;判断是否第一行输出了低电平 JNB ACC.1, K_5 ;判断是否第二行输出了低电平 JNB ACC.2, K_9 ;判断是否第三行输出了低电平 JNB ACC.3, K_13 ;判断是否第四行输出了低电平 AJMP OUT ;都没有低电平则退出(干扰) ;-------------------------第一行输出了低电平-------------------------- K_1: MOV KEY, #01H ;编码键值为1 AJMP OUT ;跳转到退出子程序 ;-------------------------第二行输出了低电平-------------------------- K_5: MOV KEY, #05H ;编码键值为5 AJMP OUT ;跳转到退出子程序 ;-------------------------第三行输出了低电平-------------------------- K_9: MOV KEY, #09H ;编码键值为9 AJMP OUT ;跳转到退出子程序 ;-------------------------第四行输出了低电平-------------------------- K_13: MOV KEY, #0DH ;编码键值为13 AJMP OUT ;跳转到退出子程序 ;==========================第二列有键按下============================= L_5: MOV A, R2 ;读取当前的位扫描值 JNB ACC.0, K_2 ;判断是否第一行输出了低电平 JNB ACC.1, K_6 ;判断是否第二行输出了低电平 JNB ACC.2, K_10 ;判断是否第三行输出了低电平 JNB ACC.3, K_14 ;判断是否第四行输出了低电平 AJMP OUT ;都没有低电平则退出(干扰) ;-------------------------第一行输出了低电平-------------------------- K_2: MOV KEY, #02H ;编码键值为2 AJMP OUT ;跳转到退出子程序 ;-------------------------第二行输出了低电平-------------------------- K_6: MOV KEY, #06H ;编码键值为6 AJMP OUT ;跳转到退出子程序 ;-------------------------第三行输出了低电平-------------------------- K_10: MOV KEY, #0AH ;编码键值为10 AJMP OUT ;跳转到退出子程序 ;-------------------------第四行输出了低电平-------------------------- K_14: MOV KEY, #0EH ;编码键值为14 AJMP OUT ;跳转到退出子程序 ;==========================第三列有键按下============================= L_6: MOV A, R2 ;读取当前的位扫描值 JNB ACC.0, K_3 ;判断是否第一行输出了低电平 JNB ACC.1, K_7 ;判断是否第二行输出了低电平 JNB ACC.2, K_11 ;判断是否第三行输出了低电平 JNB ACC.3, K_15 ;判断是否第四行输出了低电平 AJMP OUT ;都没有低电平则退出(干扰) ;-------------------------第一行输出了低电平-------------------------- K_3: MOV KEY, #03H ;编码键值为3 AJMP OUT ;跳转到退出子程序 ;-------------------------第二行输出了低电平-------------------------- K_7: MOV KEY, #07H ;编码键值为7 AJMP OUT ;跳转到退出子程序 ;-------------------------第三行输出了低电平-------------------------- K_11: MOV KEY, #0BH ;编码键值为11 AJMP OUT ;跳转到退出子程序 ;-------------------------第四行输出了低电平-------------------------- K_15: MOV KEY, #0FH ;编码键值为15 AJMP OUT ;跳转到退出子程序 ;==========================第四列有键按下============================= L_7: MOV A, R2 ;读取当前的位扫描值 JNB ACC.0, K_4 ;判断是否第一行输出了低电平 JNB ACC.1, K_8 ;判断是否第二行输出了低电平 JNB ACC.2, K_12 ;判断是否第三行输出了低电平 JNB ACC.3, K_16 ;判断是否第四行输出了低电平 AJMP OUT ;都没有低电平则退出(干扰) ;-------------------------第一行输出了低电平-------------------------- K_4: MOV KEY, #04H ;编码键值为4 AJMP OUT ;跳转到退出子程序 ;-------------------------第二行输出了低电平-------------------------- K_8: MOV KEY, #08H ;编码键值为8 AJMP OUT ;跳转到退出子程序 ;-------------------------第三行输出了低电平-------------------------- K_12: MOV KEY, #0CH ;编码键值为12 AJMP OUT ;跳转到退出子程序 ;-------------------------第四行输出了低电平-------------------------- K_16: MOV KEY, #10H ;编码键值为16 OUT: POP PSW ;弹出程序状态字 POP ACC ;弹出累加器 RET ;子程序返回 ;*****************************定时器T0******************************** T0_SRV: PUSH ACC ;累加器压栈 PUSH PSW ;程序状态字压栈 MOV TL0, #00H MOV TH0, #4CH ;重载50ms初始值 CJNE R3, #19, N_2 ;软件计数值20次到达1秒 MOV R3, #00H ;软件计数器清零 ACALL C_TIME ;调用闹铃时间比较子程序 ACALL GET_TEMPER ;调用DS18B20获取温度子程序(1秒获取一次数据) INC _S ;秒加一 MOV A, _S CJNE A, #60, N_3 ;判断秒是否加到60 MOV _S, #00H ;到60则恢复0 INC _M ;分加一 MOV A, _M CJNE A, #60, N_3 ;判断分是否加到60 MOV _M, #00H ;到60则恢复0 INC _H ;时加一 MOV A, _H CJNE A, #24, N_3 ;判断时是否加到24 MOV _H, #00H ;到24则恢复0 AJMP N_3 N_2: MOV A, SCT CJNE A, #00H, NN ;调校状态时不走时 INC R3 ;软件计数器值加一 NN: INC CNT ;调校闪烁速度控制值加一 ;=========================以下控制调校闪烁============================ N_3: MOV A, CNT ;读取调校闪烁速度控制变量 CJNE A, #04H, N_4 ;判断调校闪烁速度控制值是否加到4,否则跳到退出 MOV CNT, #00H ;调校闪烁速度控制变量值恢复0 JB A_SHOW_FLAG, A_N ;判断闹铃显示标志,时钟则顺序执行,闹铃则跳转 ;----------------------------时间调校闪烁----------------------------- MOV A, SCT ;获取当前调校状态 CJNE A, #01H, N_5 ;判定“时”是否闪烁 CPL FLG_H ;“时”标志取反(闪烁) CLR FLG_M ;”分“标志清零(不闪) CLR FLG_S ;”秒“标志清零(不闪) AJMP N_4 ;跳转到退出 N_5: CJNE A, #02H, N_6 ;判定“分”是否闪烁 CLR FLG_H ;“时”标志清零(不闪) CPL FLG_M ;“分”标志取反(闪烁) CLR FLG_S ;“秒”标志清零(不闪) AJMP N_4 ;跳转到退出 N_6: CJNE A, #03H, N_7 ;判定“秒”是否闪烁 CLR FLG_H ;“时”标志清零(不闪) CLR FLG_M ;“分”标志清零(不闪) CPL FLG_S ;“秒”标志取反(闪烁) AJMP N_4 ;跳转到退出 N_7: CLR FLG_H ;“时”标志清零(不闪) CLR FLG_M ;“分”标志清零(不闪) CLR FLG_S ;“秒”标志清零(不闪) AJMP N_4 ;跳转到退出 ;----------------------------闹铃调校闪烁----------------------------- A_N: MOV A, A_SCT ;获取当前闹铃调校状态 CJNE A, #01H, AN_5 ;判定闹铃“时”是否闪烁 CPL AFLG_H ;闹铃“时”标志取反(闪烁) CLR AFLG_M ;闹铃”分“标志清零(不闪) CLR AFLG_S ;闹铃”秒“标志清零(不闪) AJMP N_4 ;跳转到退出 AN_5: CJNE A, #02H, AN_6 ;判定闹铃“分”是否闪烁 CLR AFLG_H ;闹铃”时“标志清零(不闪) CPL AFLG_M ;闹铃“分”标志取反(闪烁) CLR AFLG_S ;闹铃”秒“标志清零(不闪) SJMP N_4 ;跳转到退出 AN_6: CJNE A, #03H, AN_7 ;判定闹铃“秒”是否闪烁 CLR AFLG_H ;闹铃”时“标志清零(不闪) CLR AFLG_M ;闹铃”分“标志清零(不闪) CPL AFLG_S ;闹铃“秒”标志取反(闪烁) AJMP N_4 ;跳转到退出 AN_7: CLR AFLG_H ;闹铃”时“标志清零(不闪) CLR AFLG_M ;闹铃”分“标志清零(不闪) CLR AFLG_S ;闹铃”秒“标志清零(不闪) N_4: POP PSW ;弹出程序状态字 POP ACC ;弹出累加器 RETI ;中断返回 ;*****************************温度获取******************************** ;========================DS18B20初始化子程序========================== INIT_18B20: SETB P2.2 ;拉高数据线 NOP ;空指令 CLR P2.2 ;拉低数据线(需要延时至少ms) ;--------------------------以下延时537微秒---------------------------- MOV R1, #3 TSR1: MOV R0, #107 DJNZ R0, $ DJNZ R1, TSR1 ;------------------------------延时结束------------------------------- SETB P2.2 ;拉高数据线 NOP ;空指令 NOP ;空指令 NOP ;空指令 MOV R0, #25H ;重复检测次数 TSR2: JNB P2.2, TSR3 ;等待DS18B20回应 DJNZ R0, TSR2 ;重复检测25次 AJMP TSR4 ;未检测到DB18B20,跳转 TSR3: SETB DS18B20 ;DS1820存在,置标志位 CLR P1.7 ;点亮P1.7LED AJMP TSR5 ;跳转到延时 TSR4: CLR DS18B20 ;DS1820不存在,清标志位 CLR P1.0 ;点亮P1.0LED AJMP TSR6 ;跳转到返回 TSR5: MOV R0, #117 ;延时初始值 DJNZ R0, $ ;时序要求延时一段时间 TSR6: SETB P2.2 ;拉高数据线 RET ;子程序返回 ;=======================获取转换温度值================================= ;此段程序在T0中经过1秒调用一次,巧妙利用了秒定时来实现温度转换所需的延时 GET_TEMPER: SETB RS0 ;RS0置1,使用第1组通用寄存器(R0~R7) JB TMP, DO ;判断温度延时标志是否为1,为1说明已延时了1秒,可以获取温度数据了 SETB TMP ;置温度延时标志 SETB P2.2 ;拉高数据线 ACALL INIT_18B20 ;调用DS18B20初始化子程序 JB DS18B20, TSS2 ;若DS18B20不存在则返回 CLR P1.1 ;DS18B20不存在点亮P1.1LED CLR TMP ;清温度延时标志 RET ;子程序返回 TSS2: CLR P1.6 ;DS18B20存在点亮P1.6LED MOV A, #0CCH ;跳过ROM匹配 ACALL WRITE_18B20 ;调用写DS18B20子程序 MOV A, #44H ;发出温度转换命令 ACALL WRITE_18B20 ;调用写DS18B20子程序 RET ;子程序返回 ;--下面的程序是上面程序经过延时1秒之后才执行,等待温度转换结束需要约750ms DO: ACALL INIT_18B20 ;准备读温度前先调用初始化 MOV A, #0CCH ;跳过ROM匹配 LCALL WRITE_18B20 ;调用写DS18B20子程序 MOV A, #0BEH ;发出读温度命令 ACALL WRITE_18B20 ;调用写DS18B20子程序 ACALL READ_18B20 ;调用获取DS18B20温度数据子程序 ACALL CONVERT ;调用数据转换子程序 CPL P1.5 ;温度读取完毕P1.5LED取反 CLR TMP ;清温度延时标志 CLR RS0 ;RS0清0,恢复使用第0组通用寄存器(R0~R7) RET ;子程序返回 ;--------------------------写DS18B20子程序--------------------------------- WRITE_18B20: PUSH ACC ;累加器压栈 PUSH PSW ;程序状态字压栈 MOV R2, #8 ;一共写8位数据 CLR C ;清进位位 WR1: CLR P2.2 ;拉低数据线 MOV R3, #5 DJNZ R3, $ ;延时 RRC A ;带进位位右移 MOV P2.2, C ;进位位送数据线 MOV R3, #21 DJNZ R3, $ ;延时 SETB P2.2 ;拉高数据线 NOP ;空指令 DJNZ R2, WR1 ;判断是否写完8个位 SETB P2.2 ;拉高数据线 POP PSW ;弹出程序状态字 POP ACC ;弹出累加器 RET ;子程序返回 ;-----------------------获取DS18B20温度数据子程序--------------------------- READ_18B20: PUSH ACC ;累加器压栈 PUSH PSW ;程序状态字压栈 MOV R4, #2 ;温度数据将分两次写入两个地址空间 MOV R1, #T_L ;高位存入22H(T_H),低位存入23H(T_L) RE0: MOV R2, #8 ;一共读8位数据 RE1: CLR C ;清进位位 SETB P2.2 ;拉高数据线 NOP ;空指令 NOP ;空指令 CLR P2.2 ;拉低数据线 NOP ;空指令 NOP ;空指令 NOP ;空指令 SETB P2.2 ;拉高数据线 MOV R3, #8 DJNZ R3, $ ;延时 MOV C, P2.2 ;读数据线 MOV R3, #21 DJNZ R3, $ ;延时 RRC A ;带进位位右移 DJNZ R2, RE1 ;判断是否读完8个位 MOV @R1, A ;数据写入R1所存地址的空间 DEC R1 ;写入地址减一 DJNZ R4, RE0 ;判断是否写完两个地址空间 MOV R1, #T_L ;恢复初始值 MOV R4, #2 ;恢复初始值 POP PSW ;弹出程序状态字 POP ACC ;弹出累加器 RET ;子程序返回 ;------------------------温度数据转换子程序---------------------------- CONVERT: PUSH ACC ;累加器压栈 PUSH PSW ;程序状态字压栈 MOV A, T_L ;温度低位送入累加器 MOV C, 10H ;将T_H中的第0位移入C RRC A ;带进位位右移 MOV C, 11H ;将T_H中的第1位移入C RRC A ;带进位位右移 MOV C, 12H ;将T_H中的第2位移入C RRC A ;带进位位右移 MOV C, 13H ;将T_H中的第3位移入C RRC A ;带进位位右移 MOV B, #10 ;加载被除数10 DIV AB ;温度除以10 MOV T_S, A ;温度十位送T_S MOV T_G, B ;温度个位送T_G POP PSW ;弹出程序状态字 POP ACC ;弹出累加器 RET ;子程序返回 ;*****************************闹铃比较******************************** C_TIME: PUSH ACC ;累加器压栈 PUSH PSW ;程序状态字压栈 JNB A_SET, C_N1 ;判断闹铃开关是否打开,未打开则跳转 MOV 7CH, #18 ;显示“-”加“.” ,表示闹铃打开 MOV A, _H CJNE A, A_H, C_N1 ;比较“时”是否相等 MOV A, _M CJNE A, A_M, C_N1 ;比较“分”是否相等 CPL P2.3 ;闹铃取反 AJMP C_OUT C_N1: SETB P2.3 ;关闭闹铃 C_OUT: POP PSW ;弹出程序状态字 POP ACC ;弹出累加器 RET ;*****************************字形码表******************************** TABLE: DB 3FH,06H,5BH,4FH,66H,6DH,7DH,07H ;0~7字形 DB 7FH,6FH,77H,7CH,39H,5EH,79H,71H ;8~F字形 DB 40H,00H,0C0H ;“-”、黑屏字形、“-”加“.” 字形 END