本文是关于ATMEL公司AT89S52单片机的应用实例的说明文档,Cute51单片机实验板由中国信息技术资源网提供。
您可以无偿使用附件源代码,但出于对原作者劳动的尊重,请保留版权声明区之内容。
Keil μVision3是由Keil公司开发的51内核单片机软件集成开发环境。本案例程序在Keil μVision3中调试通过。并通过ISP下载软件加载到Cute51单片机实验板。
源代码已经给出了较为详细的注释,所以我们不准备详细介绍源代码。只是提出几个需要注意的地方:
;************************* 版 权 声 明 ********************* ;程序名称:电子表仿真程序。 ;版权申明:(S) Scripted By FairyFar. ChuZhou•China. ;作者网站:http://www.200yi.com ;开源程序,但出于对原作者劳动的尊重,请保留版权声明区之内容。 ;************************* 版 权 声 明 ******************** ;********************************************************** ;实用环境:使用于Cute51单片机实验板(AT89S52)。 ;开发时间:2006.12—2007.01 ;功能说明: ;①、日期与时间显示与设定; ;②、可指定开始及持续时间的闹铃功能; ;③、闹铃时,可被随时终止; ;④、可设定的整点响铃功能(7:00—23:00)。 ;********************************************************** ;变量定义区 ;R0,确定延时长度。 ;R3、R4,控制数码管闪烁时间系数。 ;R5,数码管点灭标志,R5=0则当前灭(用于控制闪烁功能)。 ;R6,存放功能选择码。 MySecond EQU 30H ;秒 MyMinute EQU 31H ;分 MyHour EQU 32H ;小时 MyDay EQU 33H ;天 MyWeek EQU 34H ;周(预留) EnBeep EQU 35H ;允许整点响铃标志位 CLK_fun EQU 36H ;正在设置闹钟功能选择码(为0,则表示当前不是在进行闹铃设置。) HowMinute EQU 37H ;闹铃持续分钟数 CLKMinute EQU 38H ;闹铃开始分 CLKHour EQU 39H ;闹铃开始小时 CLKDay EQU 3AH ;闹铃开始天 CLKWeek EQU 3BH ;闹铃开始周(预留) EndSecond EQU 3CH ;(预留) EndMinute EQU 3DH ;闹铃截止分 EndHour EQU 3EH ;闹铃截止小时 EndDay EQU 3FH ;闹铃截止天 EndWeek EQU 40H ;闹铃截止周(预留) Bell_Flag EQU 41H ;通知外部,1表示现在闹铃正在响铃。 Bell_int EQU 42H ;0表示闹铃被临时关闭 Loop_R9 EQU 43H ;响铃时,用于延时内循环。 Loop_R10 EQU 44H ;响铃时,用于延时外循环。 ;********************************************************** ;********************************************************** ORG 0000H AJMP MAIN ORG 0003H LJMP PLUSVAL ;转到INT0(KEY2,设置数值键)中断服务程序 ORG 0013H LJMP SETING ;转到INT1(按键1,功能选择键)中断服务程序 ORG 001BH LJMP SERVE ;转到T1中断服务程序,2。 ;主程序 MAIN: MOV IP,#00001000B ;T1具有高优先级 MOV TMOD,#10H ;设置T0工作于模式1,T1模式1。 MOV 20H,#20D ;中断次数 CLR A MOV MySecond,A ;秒、分、小时、天初始化。 MOV MyMinute,A MOV MyHour,#08D MOV MyDay,#01H MOV EnBeep,#01H ;允许整点响铃! MOV CLK_fun,A ;正在设置闹钟功能选择码 MOV HowMinute,#05D ;闹铃持续分钟数 MOV CLKMinute,#30D ;分 MOV CLKHour,#07D ;小时 MOV CLKDay,A ;天 MOV EndMinute,#35D ;闹铃截止时间初始化 MOV EndHour,#07D MOV EndDay,A MOV Bell_int,#01H ;0表示闹铃被临时关闭 MOV Bell_Flag,#00H;1则通知外部,现在闹铃正在响铃。 SETB ET1 ;允许T1中断 SETB EX0 ;允许INT0中断 SETB EX1 ;允许INT1中断 SETB EA ;允许CPU中断 MOV TH1,#3CH MOV TL1,#0B0H SETB TR1 ;启动定时器T1 MOV R6,#00H ;功能选择码初始值 MOV R5,#00H ;灭灯 ;********************************************************** ;显示程序 DISP: MOV A,R6 JNZ TABLEJ30 MOV A,CLK_fun JNZ TABLEJ30 ;当前正在设置时间或闹铃,则不进行闹铃判断。 MOV A,EndMinute CLR CY SUBB A,CLKMinute JZ TABLEJ31 ;CLKMinute=EndMinute,则不闹铃。 MOV A,CLKDay JZ Judge_Hour ;CLKDay=0时,每天都判断是否闹铃。 MOV A,EndDay CLR CY SUBB A,CLKDay JNZ J_MeC_Day ;EndDay<>CLKDay,则转到MyDay与CLKDay比较。 MOV A,MyDay CLR CY SUBB A,CLKDay JZ Judge_Hour ;CLKDay=MyDay,把判断依据扔给小时。 LJMP NotBell ;********************************************************** ;跳转表(解决长转移问题,下同。) TABLEJ30: LJMP B_DISP ;********************************************************** J_MeC_Day: MOV A,MyDay CLR CY SUBB A,CLKDay JNZ JJ0001 ;MyDay<>CLKDay,则转到EndDay与MyDay比较。 MOV A,MyHour CLR CY SUBB A,CLKHour JZ JJ0002 ;MyDay=CLKDay,且MyHour=CLKHour,则比较MyMinute与CLKMinute。 LJMP NotBell JJ0002: MOV A,MyMinute CLR CY SUBB A,CLKMinute JC TABLEJ31 LJMP BellStart JJ0001: MOV A,MyDay CLR CY SUBB A,EndDay JNZ TABLEJ31 ;MyDay<>CLKDay,且MyDay<>EndDay,则不响铃。 MOV A,MyHour CLR CY SUBB A,EndHour JZ JJ0003 ;MyHour=EndHour,则比较MyMinte和EndMinute。 LJMP NotBell JJ0003: MOV A,MyMinute SUBB A,EndMinute JC BellStart LJMP NotBell ;********************************************************** ;小时算法 Judge_Hour: MOV A,EndHour ;算法同“天” CLR CY SUBB A,CLKHour JNZ J_MeC_Hour ;EndHour<>CLKHour,则转到MyHour与CLKHour比较。 MOV A,MyHour CLR CY SUBB A,CLKHour JZ Judge_Minute ;把判断依据扔给分 LJMP NotBell J_MeC_Hour: MOV A,MyHour CLR CY SUBB A,CLKHour JNZ JJ0004 ;MyHour<>CLKHour,则转到MyHour与EndHour比较。 MOV A,MyMinute ;MyHour=CLKHour,则进行MyMinute与CLKMinute比较。 CLR CY SUBB A,CLKMinute JC NotBell LJMP BellStart ;********************************************************** ;跳转表 TABLEJ0: LJMP Disp_Clock TABLEJ31: LJMP NotBell TABLEJ33: LJMP DISP ;********************************************************** JJ0004: MOV A,EndHour CLR CY SUBB A,MyHour JNZ NotBell ;MyHour<>EndHour,则不响铃。 MOV A,MyMinute ;MyHour=EndHour,则进行MyMinute与EndMinute比较。 SUBB A,EndMinute JC BellStart LJMP NotBell ;********************************************************** ;分算法 Judge_Minute: MOV A,MyMinute CLR CY SUBB A,CLKMinute JC NotBell MOV A,EndMinute CLR CY SUBB A,MyMinute JC NotBell JZ NotBell BellStart: MOV A,Bell_int JZ B_DISP MOV Bell_Flag,#01H CLR P3.4 ;开 MOV R0,#100D CALL DELYxM SETB P3.4 ;关 MOV R0,#100D CALL DELYxM CLR P3.4 ;开 MOV R0,#100D CALL DELYxM SETB P3.4 ;关 JMP B_DISP NotBell: MOV Bell_int,#01H MOV Bell_Flag,#00H ;********************************************************** ;闹铃之后的显示程序 B_DISP: MOV A,Bell_Flag ;判断闹铃是否正在响 JZ Loop_R11 MOV A,Bell_int JZ Loop_R11 MOV A,R6 JNZ Loop_R11 MOV Loop_R10,#15D ;闹铃时延时的外循环 Loop_R12: MOV Loop_R9,#250D ;闹铃时延时的内循环 Loop_R11: MOV A,CLK_fun JNZ TABLEJ0 ;不为零表示当前正在进行闹铃设置,则转移到显示闹铃时间程序。 MOV A,CLK_fun JNZ TABLEJ33 ;再次判断(重要!),只要CLK_fun<>0程序就不向下走。 CJNE R6,#05H,Temp_1 ;如果R6<>05H,则程序继续推进。 LJMP SetEnBeep ;如果R6=05H,则正在进行整点响铃设置,转移到显示BEEP On/OFF。 Temp_1: MOV A,R6 JZ FlashSe ;如果R6=00H,则不闪烁。 MOV R3,#8D LOOPR4: MOV R4,#250D ;闪烁时间系数 FlashLED: CJNE R6,#01H,FlashSe ;不是设置秒,则秒管不闪! CJNE R5,#00H,FlashMi ;当前数码管是灭还是亮? FlashSe: MOV A,MySecond ;显示秒 MOV B,#10D DIV AB ;累加器A中内容除以B中内容,商放到A中,余数送到B中。 MOV DPTR,#TABLE MOVC A,@A+DPTR MOV P0,A CLR P2.1 NOP NOP SETB P2.1 MOV A,B MOVC A,@A+DPTR MOV P0,A CLR P2.0 NOP NOP SETB P2.0 CJNE R6,#02H,FlashMi ;不是设置分,则分管不闪! CJNE R5,#00H,FlashHo FlashMi: MOV A,MyMinute ;显示分 MOV B,#10D DIV AB MOV DPTR,#TABLE MOVC A,@A+DPTR MOV P0,A CLR P2.3 NOP NOP SETB P2.3 MOV A,B MOVC A,@A+DPTR MOV P0,A CLR P2.2 NOP NOP SETB P2.2 CJNE R6,#03H,FlashHo ;不是设置小时,则小时管不闪! CJNE R5,#00H,FlashDa FlashHo: MOV A,MyHour ;显示小时 MOV B,#10D DIV AB MOV DPTR,#TABLE MOVC A,@A+DPTR MOV P0,A CLR P2.5 NOP NOP SETB P2.5 MOV A,B MOVC A,@A+DPTR MOV P0,A CLR P2.4 NOP NOP SETB P2.4 CJNE R6,#04H,FlashDa ;不是设置天,则天管不闪! CJNE R5,#00H,FlashEnd FlashDa: MOV A,MyDay ;显示天 MOV B,#10D DIV AB MOV DPTR,#TABLE MOVC A,@A+DPTR MOV P0,A CLR P2.7 NOP NOP SETB P2.7 MOV A,B MOVC A,@A+DPTR MOV P0,A CLR P2.6 NOP NOP SETB P2.6 FlashEnd: MOV A,Bell_Flag ;判断闹铃是否正在响 JZ BeepDudge MOV A,Bell_int JZ BeepDudge MOV A,R6 JNZ BeepDudge DJNZ Loop_R9,TABLEJ41 DJNZ Loop_R10,TABLEJ42 ;整点响铃程序(闪烁结束) BeepDudge: MOV A,MyHour ;07~23点允许响铃 CLR CY SUBB A,#07D JC UnBell MOV A,MyMinute ;每逢整点响铃 CJNE A,#00D,UnBell ;秒和分同时为0,才响铃。 MOV A,MySecond CJNE A,#00D,UnBell MOV A,EnBeep ;允许响铃吗? JZ UnBell CLR P3.4 ;启动蜂鸣器 MOV R0,#250D ;延时250ms CALL DELYxM SETB P3.4 ;关闭蜂鸣器 UnBell: MOV A,R6 JZ TABLEJ1 ;如果R6=00H,则不闪烁。到跳转表去。 CJNE R6,#05H,Temp_2 LJMP SetEnBeep ;(重要)如果R6=05H,则正在进行整点响铃设置,转移到显示BEEP On/OFF。 Temp_2: DJNZ R4,TABLEJ2 ;到跳转表去 DJNZ R3,TABLEJ3 ;到跳转表去 CJNE R5,#00H,SetR5 ;对灭灯进行设置 MOV R5,#01H LJMP DISP SetR5: MOV R5,#00H LJMP DISP ;********************************************************** ;跳转表 TABLEJ1: LJMP DISP TABLEJ2: LJMP FlashLED TABLEJ3: LJMP LOOPR4 TABLEJ41: LJMP Loop_R11 TABLEJ42: LJMP Loop_R12 ;********************************************************** ;是否正在进行整点响铃设置 SetEnBeep: MOV A,EnBeep JNZ DISPon MOV P0,#10001110B ;F。显示OFF CLR P2.1 SETB P2.1 MOV P0,#10001110B ;F CLR P2.0 SETB P2.0 MOV P0,#11000000B ;O CLR P2.2 SETB P2.2 JMP DISPbeep DISPon: MOV P0,#11000000B ;O。显示On CLR P2.1 SETB P2.1 MOV P0,#11001000B ;n CLR P2.0 SETB P2.0 DISPbeep: MOV P0,#10001100B ;BEEP CLR P2.4 SETB P2.4 MOV P0,#10000110B CLR P2.5 SETB P2.5 MOV P0,#10000110B CLR P2.6 SETB P2.6 MOV P0,#10000000B CLR P2.7 SETB P2.7 LJMP DISP ;********************************************************** Disp_Clock: MOV R3,#8D CLKLOOPR4: MOV R4,#250D ;闪烁时间系数 CLKFlashLED:MOV A,CLK_fun CJNE A,#01H,CLKFlashEn ;不是设置闹铃持续时间,则秒管不闪! CJNE R5,#00H,CLKFlashMi ;当前数码管是灭还是亮? CLKFlashEn: MOV A,HowMinute ;显示闹铃持续分钟数 MOV B,#10D DIV AB ;累加器A中内容除以B中内容,商放到A中,余数送到B中。 MOV DPTR,#TABLE MOVC A,@A+DPTR MOV P0,A CLR P2.1 NOP NOP SETB P2.1 MOV A,B MOV DPTR,#TABLED MOVC A,@A+DPTR MOV P0,A CLR P2.0 NOP NOP SETB P2.0 MOV A,CLK_fun ;显示闹铃分 CJNE A,#02H,CLKFlashMi ;不是设置闹铃分,则分管不闪! CJNE R5,#00H,CLKFlashHo CLKFlashMi: MOV A,CLKMinute ;显示闹铃分 MOV B,#10D DIV AB MOV DPTR,#TABLE MOVC A,@A+DPTR MOV P0,A CLR P2.3 NOP NOP SETB P2.3 MOV A,B MOV DPTR,#TABLED MOVC A,@A+DPTR MOV P0,A CLR P2.2 NOP NOP SETB P2.2 MOV A,CLK_fun ;显示闹铃小时 CJNE A,#03H,CLKFlashHo ;不是设置闹铃小时,则小时管不闪! CJNE R5,#00H,CLKFlashDa CLKFlashHo: MOV A,CLKHour ;显示闹铃小时 MOV B,#10D DIV AB MOV DPTR,#TABLE MOVC A,@A+DPTR MOV P0,A CLR P2.5 NOP NOP SETB P2.5 MOV A,B MOV DPTR,#TABLED MOVC A,@A+DPTR MOV P0,A CLR P2.4 NOP NOP SETB P2.4 MOV A,CLK_fun ;显示闹铃天 CJNE A,#04H,CLKFlashDa ;不是设置闹铃天,则天管不闪! CJNE R5,#00H,CLKFlashEnd CLKFlashDa: MOV A,CLKDay ;显示天 MOV B,#10D DIV AB MOV DPTR,#TABLE MOVC A,@A+DPTR MOV P0,A CLR P2.7 NOP NOP SETB P2.7 MOV A,B MOV DPTR,#TABLED MOVC A,@A+DPTR MOV P0,A CLR P2.6 NOP NOP SETB P2.6 CLKFlashEnd: DJNZ R4,TABLEJ10 ;到跳转表去 DJNZ R3,TABLEJ11 ;到跳转表去 MOV R3,#8D MOV R4,#250D ;重设闪烁时间系数(冗余代码,但很有效!) CJNE R5,#00H,CLKSetR5 ;对灭灯进行设置 MOV R5,#01H LJMP DISP CLKSetR5: MOV R5,#00H LJMP DISP ;********************************************************** ;跳转表 TABLEJ10: LJMP CLKFlashLED TABLEJ11: LJMP CLKLOOPR4 ;********************************************************** ;T1中断服务程序区 SERVE: PUSH PSW ;2个周期指令,下同。 PUSH ACC ;2 MOV TH1,#3CH ;重新赋初值。1 MOV TL1,#(0B0H+10D) ;(主要时间补偿)加了时间补偿。1。 DJNZ 20H,RETUNT ;2 MOV 20H,#20D ;2 INC MySecond ;秒加1 MOV A,MySecond CJNE A,#60D,RETUNT MOV MySecond,#00H INC MyMinute ;分加1 MOV A,MyMinute CJNE A,#60D,RETUNT MOV MyMinute,#00H CLR ET1 ;禁止T1中断 MOV R0,#200D ;(次要时间补偿)每小时扣除200ms,这是一个计算与实验综合得到的数值。 CALL DELYxM SETB ET1 ;允许T1中断 INC MyHour ;小时加1 MOV A,MyHour CJNE A,#24D,RETUNT MOV MyHour,#00H INC MyDay ;天加1 MOV A,MyDay CJNE A,#32D,RETUNT MOV MyDay,#01H RETUNT: POP ACC ;2 POP PSW ;2 RETI ;2 ;********************************************************** ;加1键中断服务(INT0,KEY2)(也作为闹钟设置选择键) PLUSVAL: PUSH PSW PUSH ACC CLR EX0 ;关中断 MOV R0,#200D ;延时200ms CALL DELYxM ;重要程序区************************************************ MOV A,Bell_Flag ;只有当前闹铃正在响铃时才允许中断之! JZ Temp_01 MOV A,Bell_int ;当前是闹铃时间,且闹铃被用户临时关闭,则允许功能键。 JZ Temp_01 MOV Bell_int,#00H ;临时关闭闹铃 LJMP RETUNP ;重要程序区************************************************ Temp_01: MOV A,R6 JZ CLKfunSet ;R6=00H时才允许准备设置闹铃功能 CJNE R6,#01H,SetMi ;秒 INC MySecond MOV A,MySecond CJNE A,#60D,TABLEJ20 MOV MySecond,00H SetMi: CJNE R6,#02H,SetHo ;分 INC MyMinute MOV A,MyMinute CJNE A,#60D,TABLEJ20 MOV MyMinute,00H SetHo: CJNE R6,#03H,SetDa ;小时 INC MyHour MOV A,MyHour CJNE A,#24D,RETUNP MOV MyHour,00H SetDa: CJNE R6,#04H,SetEBe ;天 INC MyDay MOV A,MyDay CJNE A,#32D,RETUNP MOV MyDay,#01H SetEBe: CJNE R6,#05H,RETUNP ;设置是否整点响铃 MOV A,EnBeep JZ SETBeep MOV EnBeep,#00H ;禁止响铃 JMP RETUNP SETBeep: MOV EnBeep,#01H ;允许响铃 JMP RETUNP ;设置闹铃功能选择码 CLKfunSet: INC CLK_fun MOV A,CLK_fun ;设置闹钟功能选择码加1 CJNE A,#05H,CalEndTime MOV CLK_fun,00H JMP CalEndTime ;********************************************************** ;跳转表 TABLEJ20: LJMP RETUNP ;********************************************************** ;由闹铃开始时间计算→闹铃截止时间 CalEndTime: MOV Bell_int,#01H MOV A,HowMinute ;计算闹铃截止分 ADD A,CLKMinute MOV EndMinute,A MOV A,#59D CLR CY SUBB A,EndMinute JNC CalEndHo ;分未溢出,则直接转移到设置小时。CY=0 MOV A,EndMinute CLR CY SUBB A,#60D MOV EndMinute,A SETB CY ;分溢出标志。CY=1 CalEndHo: MOV A,CLKHour ;计算闹铃截止小时 ADDC A,#00H MOV EndHour,A MOV A,#23D CLR CY SUBB A,EndHour JNC CalEndDa ;小时未溢出,则直接转移到设置天。CY=0 MOV EndHour,#00H SETB CY ;小时溢出标志。CY=1 CalEndDa: MOV A,CLKDay MOV EndDay,A JZ RETUNP ;天为0则直接退出 ADDC A,#00H MOV EndDay,A MOV A,#31D CLR CY SUBB A,EndDay JNC RETUNP ;天未溢出,则直接退出。 MOV EndDay,#01H RETUNP: SETB EX0 POP ACC POP PSW RETI ;********************************************************** ;功能选择键中断服务(INT1,KEY1)(也用于设置闹铃时间) SETING: PUSH PSW PUSH ACC CLR EX1 ;关中断 MOV R0,#200D ;延时200ms CALL DELYxM MOV A,CLK_fun ;CLK_fun<>0表示当前正在进行闹铃设置,转移。 JNZ CLK_Seting INC R6 ;功能码加1 CJNE R6,#06H,RETUNS MOV R6,00H MOV Bell_int,#01H ;设置时间后自动将闹铃临时关闭取消(人性化设计) JMP RETUNS CLK_Seting: MOV A,CLK_fun CJNE A,#01H,SetCLKMi ;允许闹铃标志位(占用秒位) INC HowMinute ;HowMinute为零则禁止闹铃,否则其存放的是闹铃持续分钟数。 MOV A,HowMinute CJNE A,#60D,RETUNS MOV HowMinute,00H SetCLKMi: MOV A,CLK_fun CJNE A,#02H,SetCLKHo ;闹铃分钟加1 INC CLKMinute MOV A,CLKMinute CJNE A,#60D,RETUNS MOV CLKMinute,00H SetCLKHo: MOV A,CLK_fun CJNE A,#03H,SetCLKDa ;闹铃小时加1 INC CLKHour MOV A,CLKHour CJNE A,#24D,RETUNS MOV CLKHour,00H SetCLKDa: MOV A,CLK_fun CJNE A,#04H,RETUNS ;闹铃天加1(天如果为0,则表示闹铃每天有效,否则只1天有效。) INC CLKDay MOV A,CLKDay CJNE A,#32D,RETUNS MOV CLKDay,00H RETUNS: SETB EX1 POP ACC POP PSW RETI ;********************************************************** ;延时x ms通用程序(x由R0传入) DELYxM: MOV R1,#250 LOOP: NOP NOP DJNZ R1,LOOP DJNZ R0,DELYxM RET ;********************************************************** ;定义8段码 TABLED: DB 40H, 79H, 24H, 30H,19H,12H,02H, 78H,00H,10H TABLE: DB 0c0H,0f9H,0a4H,0b0H,99H,92H,82H,0f8H,80H,90H ; '0' '1' '2' '3' '4' '5' '6' '7' '8' '9' END