⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 01-15.asm

📁 基于51的多功能电子钟,多闹钟,温度测试
💻 ASM
📖 第 1 页 / 共 4 页
字号:
;==============================
;地址分配
;=============================
BYTECNT   DATA 30H       ;I2C字节计数器地址
BITCNT    DATA 31H       ;I2C位计数器地址
RTCADR    DATA 32H       ;PCF8563在I2C上从器件地址
RTCREGADR DATA 33H       ;PCF8563内部寄存器地址
RECDATBUF DATA 40H       ;接收数据缓冲区 (40H-45H)
SENDATBUF DATA 50H       ;发送数据缓冲区
FINISH    BIT  00H       ;发送及接收成功标志;0成功,1表示失败
ACK       BIT  20H       ;接收数据非应答标志位
TIMEDATA  DATA 70H       ;时间设置与闹钟设定的时间临时缓冲区

KEYNAME   DATA 34H       ;b4~b0位记录按键值
                         ;b7-作为按键有效标志,b7为0时,表示b4-b0位中的键值无效。
                         ;b7为1时,表示b4-b0位记录的按键值有效,且未尚未处理,不能
                         ;接受新按键。
                         ;外部程序执行了按键功能后,将按键有效标志清0,允许接收新按键
		         ;b6-保留。
KEYSTU    DATA 35H       ;键盘按键状态寄存器,其中b2、b1、b0分别记录最近
                         ;三次定时中断的按键状态。
PORTDR    DATA 36H       ;U105(八上升沿D型触发器74HC273)芯片在内存中的影射地址
                         ;设置影射地址的目的是为了在执行键盘扫描过程中不影响
                         ;该输出口高3位(b7~b5)位内容
TIMEBELL  DATA 37H       ;蜂鸣器鸣响时间
BTIME     DATA 38H       ;50ms计数单元
DISPB     BIT  01H       ;50ms定时时间到标志

PORTA     EQU 9000H      ;8255A口地址
PORTB     EQU 9100H      ;8255B口地址
PORTC     EQU 9200H      ;8255C口地址
PORTS     EQU 9300H      ;8255控制/状态口地址
PORTD     EQU 8800H      ;U105(八上升沿D型触发器74HC273)地址


MOUSE     DATA 3AH       ;光标地址单元

CLONUM    DATA 39H       ;闹钟数量计数单元
CLONUM1   DATA 3DH       ;闹钟序数
CLOADR1   DATA 3BH       ;闹钟存储单元的首地址低四位
CLOADR2   DATA 3CH       ;闹钟存储单元的首地址高四位

ALMTIME   DATA 0000H     ;将外部RAM的0000H~0DFH共256个单元作为定时时间
                         ;保存区。8个单元(1个序号+6个具体时间) X 32个闹钟时间 = 224个单元


CONTROL1 EQU  50H        ;定义控制寄存器1
CONTROL2 EQU  51H        ;定义控制寄存器2
SEC      EQU  52H        ;定义秒初值存储地址
MIN      EQU  53H        ;定义分初值存储地址
HOUR     EQU  54H        ;定义时初值存储地址
DATE     EQU  55H        ;定义天初值存储地址
WEEK     EQU  56H        ;定义周初值存储地址
MONTH    EQU  57H        ;定义月初值存储地址
YEAR     EQU  58H        ;定义年初值存储地址
MINAL    DATA 59H        ;定义分定时初值存储地址
HOURAL   DATA 5AH        ;定义时定时初值存储地址
DATEAL   DATA 5BH        ;定义日定时初值存储地址
WEAKAL   DATA 5CH        ;定义星期定时初值存储地址
MONTHAL  DATA 5DH        ;定义月定时初值存储地址
YEARAL   DATA 5EH        ;定义年定时初值存储地址
ALMODE   DATA 5FH        ;闹钟模式地址(有1.2.3种模式 )

ALMODE1  BIT  10H        ;闹钟辅助标志位(1:表示闹钟还有效;0表示无效)

TEMPER_L EQU 4BH		;用于保存读出温度的低8位
TEMPER_H EQU 4AH		;用于保存读出温度的高8位
FLAG1 EQU 4CH			;是否检测到DS18B20标志位
TEM1 EQU 4DH			;数码管个位数存放内存位置
TEM2 EQU 4EH 			;数码管十位数存放内存位置

;===========================
;端口位定义
;===========================
SCL BIT P1.0             ;定义 P1.0为I2C总线串行时钟输入端
SDA BIT P1.1             ;定义P1.1为I2C总线串行数据双向输入输出端
RS  BIT P1.4             ;定义P3.3为LCM寄存器选择控制端
R_W BIT P1.5             ;定义P3.4为LCM 读写控制端
E   BIT P1.6             ;定义P3.5为LCM使能控制端
DB0_DB7 EQU P2           ;定义P0端口为LCD数据端口
IO  BIT P1.7

;========================
;程序开始
;========================
ORG 0000H
LJMP MAIN
;ORG 0003H               ;开INT0外中断
;LJMP INT0
;ORG 002BH               ;定时器T2中断服务入口地址
;LJMP CTC2
ORG 0050H
PROC MAIN
MAIN:
      MOV SP,#07FH       ;重新设定SP起始位置
      MOV DPTR,#8000H    ;关闭峰鸣器
      MOV A,#0FFH
      MOVX @DPTR,A
      MOV R0,#08H        ;将080H-0FFH内部RAM清零
LOOP: MOV @R0,#0
      INC R0
      CJNE R0,#0,LOOP

;----------------------------------------------------------
;初始化U107(8255)可编程并行I/O接口芯片的工作方式
;----------------------------------------------------------
     MOV DPTR, #PORTS     ;8255控制/状态口地址
     MOV A, #10011011B    ;A口工作在方式0,输入;B口工作在方式0,输入;
                          ;C口高、低半部暂时定义为输入
     MOVX @DPTR, A        ;送控制字寄存器
                          ;将PD4~PD0置为高电平,使U105(74HC273)输出级截止,降低功耗。
     MOV DPTR, #PORTD     ;U105口地址送DPTR
     MOV A, PORTDR        ;读U105口在内存中的映象地址
     ORL A, #1FH
     MOVX @DPTR, A        ;数据送U105输出口


     SETB P1.3
;-----------------------------------------------------
;赋时间初值
;-------------------------------------------------
      LCALL INITIAL             ;初始化LCM
      MOV 76H,#00H
      MOV 75H,#01H
      MOV 74H,#00H
      MOV 73H,#01H
      MOV 72H,#00H
      MOV 71H,#01H
      MOV 70H,#00H

      ;LCALL READTIME            ;若时间不为零(即时间有效)则不用再赋初值
      ;MOV A,46H
      ;CJNE A,#00H,LOOP1

      LCALL SENDTIME             ;否则赋初值

      MOV DPTR,#0000H            ;清外部RAM
LOOP2:
      MOV A,#00H
      MOVX @DPTR,A
      INC DPTR
      MOVX A,@DPTR
      CJNE A,#00H,LOOP2


      MOV CLOADR1,#00H           ;赋指针初值
      MOV CLOADR2,#00H

      CLR ALMODE1                ;清空闹钟模式标志位
      LCALL INITIAL              ;调用LCM初始化子程序
LOOP1:

      LCALL READTIME             ;调用时间读取子程序
      MOV A,42H
      CJNE A,#023H,NEXT1
      CLR C
      MOV A,41H
      SUBB A,#059H
      JNC NEXT2
      CLR C
NEXT1:
      LCALL DISP                 ;调用LCM显示子程序

      LCALL TEMPER
      LCALL DEL10MS              ;调用50ms延时子程序
      LCALL KEY                  ;调用键盘扫描程序
      LCALL ALMCHECK             ;调用闹钟与实时时间比较子程序
      AJMP LOOP1                 ;返回继续循环
NEXT2:

      CLR ALMODE1
      LCALL DISP
      LCALL TEMPER
      LCALL DEL10MS
      AJMP LOOP1
END

;-------------------------------------------
;温度显示子程序
;----------------------------------------------
PROC TEMPER
TEMPER:
       LCALL INIT_1820
       LCALL RE_CONFIG

       LCALL 	GET_TEMPER	;调用读温度子程序

                                ;进行温度显示
                                ;显示范围00到99度,显示精度为1度
                                ;因为12位转化时每一位的精度为0.0625度,我们不要求显示小数所以可以抛弃29H的低4位
                                ;将28H中的低4位移入29H中的高4位,这样获得一个新字节,这个字节就是实际测量获得的温度
       MOV A,#0F0H
       ANL A,4BH ; 舍去温度低位中小数点
       SWAP A
       MOV 4BH,A
       MOV A,4BH
       JNB ACC.3,TEMPER_COV1 ; 四舍五入去温度值
       INC 4BH
TEMPER_COV1:
       MOV A,4AH
       ANL A,#07H
       SWAP A
       ADD  A,4BH
       MOV 4BH,A ; 保存变换后的温度数据
   

       LCALL DISPLAY		;调用显示子程序
       LJMP EXIT


				;DS18B20复位初始化子程序
INIT_1820:
	SETB 	IO
	NOP
        CLR 	IO
				;主机发出延时537微秒的复位低脉冲
        MOV 	R0,#0FAH
TSR1:	
	DJNZ 	R0,TSR1
	SETB 	IO		;然后拉高数据线
	NOP
	NOP
	NOP
	MOV 	R0,#17H
TSR2:
	JNB 	IO,TSR3         ;等待DS18B20回应
	DJNZ 	R0,TSR2
	LJMP 	TSR4 		;延时
TSR3:
	SETB 	FLAG1 		;置标志位,表示DS1820存在
	LJMP	TSR5
TSR4:
	CLR 	FLAG1 		;清标志位,表示DS1820不存在
        LJMP  TSR7

TSR5:
	MOV 	R0,#0FCH
TSR6:
	DJNZ 	R0,TSR6         ;时序要求延时一段时间
TSR7:
	SETB 	IO
	RET

RE_CONFIG:JB FLAG1,RE_CONFIG1 ; 若DS18B20存在,转RE_CONFIG1
      RET
RE_CONFIG1:
      MOV A,#0CCH ; 发SKIP ROM命令
      LCALL WRITE_1820
      MOV A,#4EH ; 发写暂存存储器命令
      LCALL WRITE_1820
      MOV A,#00H ; TH(报警上限)中写入00H
      LCALL WRITE_1820
      MOV A,#00H ; TL(报警下限)中写入00H
      LCALL WRITE_1820
      MOV A,#1FH ; 选择9位温度分辨率
      LCALL WRITE_1820
      RET
				; 读出转换后的温度值
GET_TEMPER:
	SETB IO
	LCALL 	INIT_1820	;先复位DS18B20
	JB 	FLAG1,TSS2
        RET 			;判断DS1820是否存在?若DS18B20不存在则返回
TSS2:
                  		;DS18B20已经被检测到!!!!!!!!!!!!!!!!!!
	MOV A,#0CCH 		;跳过ROM匹配
	LCALL WRITE_1820
        MOV A,#44H 		;发出温度转换命令
	LCALL WRITE_1820
        MOV R5,#0DH
NEXT7:
        LCALL DEL10MS
        DJNZ R5,NEXT7
	;这里通过调用显示子程序实现延时一段时间,等待AD转换结束,12位的话750微秒

	LCALL 	INIT_1820		;准备读温度前先复位

	MOV 	A,#0CCH 		; 跳过ROM匹配
	LCALL 	WRITE_1820

	MOV 	A,#0BEH 		; 发出读温度命令
	LCALL 	WRITE_1820

	LCALL 	READ_18200	; 将读出的温度数据保存到35H/36H
	RET

;**************************************写DS18B20的子程序(有具体的时序要求)
WRITE_1820:
	MOV 	R2,#8		;一共8位数据
	CLR 	C
WR1:
	CLR 	IO
	MOV 	R3,#7
	DJNZ 	R3,$
	RRC 	A
	MOV 	IO,C
	MOV 	R3,#25
	DJNZ 	R3,$
	SETB 	IO
	NOP
	DJNZ 	R2,WR1
	SETB IO
	RET

;***************************************读DS18B20的程序,从DS18B20中读出两个字节的温度数据
READ_18200:
	MOV 	R4,#2 		;将温度高位和低位从DS18B20中读出
	MOV 	R1,#4BH 	;低位存入29H(TEMPER_L),高位存入28H(TEMPER_H)
RE00:
	MOV 	R2,#8		;数据一共有8位
RE01:
	CLR 	C
	SETB 	IO
	NOP
	NOP
	CLR 	IO
	NOP
	NOP
	NOP
	SETB 	IO
        MOV R3,#7
        DJNZ R3,$
	MOV 	C,IO
	MOV 	R3,#23
RE20:
	DJNZ 	R3,RE20
	RRC 	A
	DJNZ 	R2,RE01
	MOV 	@R1,A
	DEC 	R1
	DJNZ 	R4,RE00

	RET

;**********************************************************显示子程序
display:
	MOV 	A,4BH		;将29H中的十六进制数转换成10进制
	MOV  	B,#10 		;10进制/10=10进制
	DIV 	AB
	MOV  TEM1,A 		;十位在a
        MOV  TEM2,B		;个位在b
        MOV A,#0CDH
        LCALL WRITE_COM
        CLR C
        MOV A,#30H
        ADD A,TEM1
        LCALL WRITE_DATA

        MOV A,#30H
        CLR C
        ADD A,TEM2
        LCALL WRITE_DATA
        MOV A,#0DFH
        LCALL WRITE_DATA
EXIT:
        RET
END


;-----------------------------------------
;闹钟与实时时间比较子程序
;------------------------------------------

PROC ALMCHECK
ALMCHECK:

      LCALL READTIME             ;读入此时时间
      MOV R4,#8
LOOP1:
      LCALL CLOLOCATE            ;载入闹钟值子程序
      MOV A,MINAL
      CJNE A,41H,LOOP3           ;将第一个闹钟的时间从年到分逐一与实时时间的年到分比较若相等则报警
      MOV A,HOURAL
      CJNE A,42H,LOOP3
                                 ;比较闹钟模式选择,进行相应处理
      MOV A,ALMODE
      CJNE A,#02H,NEXT1          ;进入模式2,闹钟为一次性的
      SJMP NEXT3
NEXT1:
      CJNE A,#03H,NEXT2          ;进入模式3,闹钟为每日都有效
      SJMP NEXT5
NEXT2:
      CJNE A,#01H,NEXT3          ;进入模式1,闹钟为每周同一时间有效
      SJMP NEXT4
NEXT3:
      MOV A,DATEAL
      CJNE A,43H,LOOP3
NEXT4:
      MOV A,WEAKAL
      CJNE A,44H,LOOP3
      ;MOV A,MONTHAL
      ;CJNE A,45H,LOOP3
      ;MOV A,YEARAL
      ;CJNE A,46H,LOOP3
NEXT5:
      MOV C,ALMODE1
      JC EXIT2
      LCALL INITIAL
      MOV A,#084H
      LCALL WRITE_COM
      MOV DPTR,#LINE7
      LCALL DISP2
      MOV A,#0C0H
      LCALL WRITE_COM
      MOV DPTR,#LINE8
      LCALL DISP2
      MOV A,ALMODE
      CLR C
      SUBB A,#01H
      JC NEXT6
      CLR C
      SETB ALMODE1
NEXT6:
      LCALL DEL5S
      MOV A,KEYNAME
      CJNE A,#00H,EXIT           ;若有键盘输入则退出报警子程序
      LCALL DEL2S                ;停两秒后再报警
      CJNE A,#00H,EXIT
      LCALL DEL5S

EXIT:
      LCALL INITIAL
      ;MOV DPL,CLOADR1
      ;MOV DPH,CLOADR2
      MOV C,ALMODE1
      JC EXIT2

      MOV R2,#8
      MOV DPTR,#0000H
      MOV A,#0
LOOP2:
      MOVX @DPTR,A
      INC DPTR
      DJNZ R2,LOOP2
      ;MOV CLOADR1,DPL
      ;MOV CLOADR2,DPH
NEXT10:
      MOV A,#00H                  ;将键名清空
      MOV KEYNAME,A
      SJMP EXIT2
LOOP3:
      ;MOV  A,#08H
      ;ADD A,CLOADR1
      ;MOV CLOADR1,A
      ;DJNZ R4,LOOP1
      ;MOV CLOADR1,#00H
EXIT2:
      RET
END




;----------------------------------------------------
; 载入闹钟值子程序
;---------------------------------------------------
PROC CLOLOCATE
CLOLOCATE:

      MOV DPL,CLOADR1
      MOV DPH,CLOADR2
      MOV DPTR,#0000H

NEXT1:MOV R5,#8
      MOV R0,#059H            ;提取的闹钟时间值放入以#059H为首的缓冲区内
LOOP: MOVX A,@DPTR
      MOV @R0,A
      INC DPTR
      INC R0
      DJNZ R5,LOOP
EXIT:
      RET
END






;-----------------------------------------------------
;键盘响应子程序
;----------------------------------------------------
PROC KEYDO
KEYDO:
LOOP1:
    LCALL INITIAL           ;初始化LCM
    MOV A,#080H             ;显示功能选择菜单1
    LCALL WRITE_COM
    MOV DPTR,#LINE1
    LCALL DISP2             ;调用字符串显示子程序
    MOV A,#0C0H
    LCALL WRITE_COM
    MOV DPTR,#LINE2
    LCALL DISP2

FUN1:
    LCALL KEYWAIT
    MOV A,KEYNAME
    CJNE A,#00H,LOOP2
    SJMP FUN1
LOOP2:
    CJNE A,#011H,NEXT1      ;当按下"ESC"时退出 ,否则向下运行
    LCALL INITIAL
    LJMP EXIT2
NEXT1:

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -