;**********************************************************************
;晶振为12MHZ,显示实时时间,温度
;测量温度范围为-55~+99摄氏度
;***********************************************************************
T_RST EQU P1.5 //DS1302复位线引脚
T_CLK EQU P1.6 //DS1302时钟线引脚
T_IO EQU P1.7 //DS1302数据线引脚
TEM_L EQU 40H //存放从DS18B20中读出的高、低位温度值
TEM_H EQU 41H
TEM_NUM EQU 42H //存放温度转换后的整数部分
FLAG0 EQU 45H //FLAG0存放温度的符号
DQ EQU P2.3 //DS18B20数据线
RS BIT P2.0 //LCD控制线定义
RW BIT P2.1
E BIT P2.2
SKIP_B20 EQU 0CCH //DS18B20跳过ROM命令
START_B20 EQU 44H //DS18B20温度变换命令
READDS EQU 0BEH //DS18B20读暂存器命令
ORG 0000H
AJMP MAIN
ORG 0100H
MAIN: MOV SP,#90H
ACALL LCD_INT //进行LCD初始化
MOV A,#8BH //在LCD第一行第12列显示WEEK
LCALL W_COM
MOV A,#57H //字母'W'的字符库为01010111
LCALL W_DAT
MOV A,#45H //字母'E'的字符库为01000101
LCALL W_DAT
MOV A,#45H
LCALL W_DAT
MOV A,#4BH //字母'K’的字符库为01001011
LCALL W_DAT
MOV A,#0C0H //第二行第一列显示TIME
LCALL W_COM
MOV A,#54H //字母'T'的字符库为01010100
LCALL W_DAT
MOV A,#49H //字母'I'的字符库为01001001
LCALL W_DAT
MOV A,#4DH //字母'M'的字符库为01001101
LCALL W_DAT
MOV A,#45H //字母'E'的字符库为01000101
LCALL W_DAT
MOV 60H,#00H //设置秒存储单元
MOV 61H,#00H //设置分存储单元
MOV 62H,#16H //设置时存储单元
MOV 63H,#05H //设置日存储单元
MOV 64H,#01H //设置月存储单元
MOV 65H,#03H //设置星期存储单元
MOV 66H,#18H //设置年存储单元
LCALL SET1302 //向DS1302写入时间
REP: LCALL GET1302 //读出时间
LCALL GET_TEM //读出转换后的温度值
LCALL TEM_COV
;;;;;;;;;;在LCD第一行显示年月日和星期;;;;;;;;;;
MOV A,#80H //显示在LCD第一行第一列
LCALL W_COM //调用LCD写命令子程序
MOV A,#'2'
ACALL W_DAT //调用LCD写数据子程序
MOV A,#'0'
ACALL W_DAT
MOV A,56H //年拆分成十位与个位,转换字符显示
MOV B,#10H
DIV AB
ADD A,#30H //数字的字符库从00110000B即30H开始
ACALL W_DAT
MOV A,B
ADD A,#30H
ACALL W_DAT
MOV A,#'-'
ACALL W_DAT
MOV A,54H //月拆分成十位与个位,转换字符显示
MOV B,#10H
DIV AB
ADD A,#30H
ACALL W_DAT
MOV A,B
ADD A,#30H
ACALL W_DAT
MOV A,#'-'
ACALL W_DAT
MOV A,53H //日拆分成十位与个位,转换字符显示
MOV B,#10H
DIV AB
ADD A,#30H
ACALL W_DAT
MOV A,B
ADD A,#30H
ACALL W_DAT
MOV A,#8FH //设置LCD显示星期的位置为第一行第十六列
LCALL W_COM
MOV A,55H //显示星期
ADD A,#30H
LCALL W_DAT
;;;;;;;;;;在LCD第二行显示时分秒和温度;;;;;;;;;;;;;
MOV A,#0C4H //写入显示缓冲区的起始地址为第二行第五列开始
LCALL W_COM
MOV A,52H //小时拆分成十位与个位,转换字符显示
MOV B,#10H
DIV AB
ADD A,#30H
LCALL W_DAT
MOV A,B
ADD A,#30H
LCALL W_DAT
MOV A, #':'
LCALL W_DAT
MOV A,51H //分拆分成十位与个位,转换字符显示
MOV B,#10H
DIV AB
ADD A,#30H
LCALL W_DAT
MOV A,B
ADD A,#30H
LCALL W_DAT
MOV A, #':'
LCALL W_DAT
MOV A,50H //秒拆分成十位与个位,转换字符显示
MOV B,#10H
DIV AB
ADD A,#30H
LCALL W_DAT
MOV A,B
ADD A,#30H
LCALL W_DAT
MOV A,#0CDH //温度显示在LCD第二行第十四列
LCALL W_COM
MOV A,FLAG0 //显示温度正负号
ACALL W_DAT
MOV A,TEM_NUM //温度整数拆分成十位和个位显示
MOV B,#0AH
DIV AB //商送给A,余数送给B
ADD A,#30H
CJNE A,#30H,REP1 //如果十位为0,则不显示
MOV A,#20H //字符库中00100000B(20H)为空白
REP1: ACALL W_DAT //调用LCD写数据子程序
MOV A,B //将求得的余数送给A
ADD A,#30H
ACALL W_DAT //调用LCD写数据子程序
LJMP REP
/******************时间**************************/
;;;;;;;;累加器A写一字节到DS1302;;;;;;;;;;;;;
WE: MOV 70H,#08H //一个字节八位,移动八次
INB1: MOV A,B //将命令字送给A
RRC A //通过A移入进位标志位C
MOV B,A
MOV T_IO,C //移入到芯片内
SETB T_CLK
CLR T_CLK
DJNZ 70H,INB1
RET
;;;;;;;;读一字节到累加器A中;;;;;;;;;;;;;;;;;
READ: MOV 70H,#08H //一个字节八位,移动八次
OUTB1: MOV C,T_IO //从芯片内移动到进位标志位C
RRC A //通过C再移入累加器A中
SETB T_CLK
CLR T_CLK
DJNZ 70H,OUTB1
RET
;;;;;;;;;向DS1302写入时间子程序;;;;;;;;;;;;;;
SET1302:CLR T_RST //RST引脚为低电平,数据传送终止
CLR T_CLK //清零时钟总线
SETB T_RST //RST引脚为高电平,逻辑控制有效
MOV B,#8EH //控制命令字(10001110-进行存取时间,写操作)
LCALL WE //调用写字节命令
MOV B,#00H //写操作前清写保护位W
LCALL WE
SETB T_CLK
CLR T_RST
MOV R0,#60H //秒 分 时 日 月 星期 年 数据存储在60-66H单元
MOV R7,#07H //共7个字节
MOV R1,#80H //写秒寄存器命令
S1: CLR T_RST
CLR T_CLK
SETB T_RST
MOV B,R1 //写入写秒指令
LCALL WE
MOV A,@R0 //将秒存储单元中的数值送给A
MOV B,A
LCALL WE
INC R0 //R0加一,指向下一个写入的日历、时钟数据
INC R1 //指向下一个时间寄存器
INC R1
SETB T_CLK
CLR T_RST
DJNZ R7,S1
CLR T_RST
CLR T_CLK
SETB T_RST
MOV B,#8EH //控制命令字(10001110-进行存取时间,写操作)
LCALL WE
MOV B,#80H //控制寄存器中WP置1
LCALL WE
SETB T_CLK
CLR T_RST //结束写过程
RET
;;;;;;;;;;;;;;;读时间子程序;;;;;;;;;;;;;;;;;
GET1302:MOV R0,#50H
MOV R7,#7
MOV R1,#81H //读秒寄存器命令
G1: CLR T_RST
CLR T_CLK
SETB T_RST
MOV B,R1 //写入读秒寄存器命令
LCALL WE
LCALL READ
MOV @R0,A //存入读出数据
INC R0 //指向下一个存放日历、时钟的存储单元
INC R1 //指向下一个日历、时钟寄存器
INC R1
SETB T_CLK
CLR T_RST
DJNZ R7,G1 //未读完,继续读下一个
RET
/********************温度************************/
;;;;;;;;;;;;;;DS18B20复位程序;;;;;;;;;;;;;;;;;
B20_INT:SETB DQ //将数据线置高电平“1”
NOP //延时
NOP
CLR DQ //数据线拉到低电平“1”
MOV R7,#0CH //延时60*12=720US
INT_DEL:ACALL DEL60US
DJNZ R7,INT_DEL
SETB DQ //数据线拉到高电平“1”
ACALL DEL60US //延时等待
ACALL DEL60US
MOV C,DQ //将数据线的状态送给C,判断初始化是否成功,是否产生一个低电平
JC ERROR //如果C等于1,则跳出,初始化失败
ACALL DEL60US //初始化成功,CPU读到数据线上的低电平,继续延时
ACALL DEL60US
ACALL DEL60US
ACALL DEL60US
RET
ERROR: CLR DQ //初始化未成功,继续进行初始化
SJMP B20_INT
RET
;;;;;;;;;;;;;;;;;读DS18B20一个字节到累加器A子程序;;;;;;;;;;;;
R_BYTE: MOV R7,#08H //读取8位为一字节
SETB DQ
NOP
NOP
LOOP: CLR DQ //将数据线从高电平拉为低电平时,作为一个读周期的开始
NOP //延时,保证低电平至少为1US
NOP
NOP
SETB DQ
MOV R6,#07H //循环到A的最高位
DJNZ R6,[ DISCUZ_CODE_1 ]nbsp;
MOV C,DQ //将数据线中的值送给进位标志位C
ACALL DEL60US
RRC A //累加器A带进位右移
SETB DQ
DJNZ R7,LOOP //将一字节读到累加器A
ACALL DEL60US
ACALL DEL60US
RET
;;;;;;;;;;;;;累加器A写到DS18B20子程序;;;;;;;;;;
W_BYTE: MOV R7,#08H //将8位连续数据(一字节)写入A
SETB DQ //拉高数据线
NOP
NOP
LOOP1: CLR DQ //将数据线拉到低电平,作为写周期的开始
MOV R6,#07H //循环到累加器A的最高位Acc.7
DJNZ R6,$
RRC A //从累加器A的最高位开始写入
MOV DQ,C //将进位C送给DS18B20(写入时序,0或者1时序)
ACALL DEL60US //保持60US
SETB DQ //在15US内将数据线拉为高电平
DJNZ R7,LOOP1 //将一字节写入A
RET
DEL60US:MOV R6,#1EH //延时(30*2)us
DJNZ R6,$
RET
;;;;;;;;;;;读温度子程序;;;;;;;;;;;;;;;;;;
GET_TEM:ACALL B20_INT //DS18B20复位程序
MOV A,#0CCH //DS18B20跳过ROM命令
ACALL W_BYTE //调用写DS18B20子程序
ACALL DEL60US
ACALL DEL60US
MOV A,#44H //DS18B20温度转换命令,开始装换温度
ACALL W_BYTE //调用写DS18B20子程序
ACALL DEL60US
ACALL B20_INT //写完之后,将DS18B20复位
MOV A,#0CCH //DS18B20跳过ROM命令
ACALL W_BYTE //调用写DS18B20子程序
ACALL DEL60US
MOV A,#0BEH //DS18B20读暂存器命令
ACALL W_BYTE //调用写DS18B20子程序
ACALL DEL60US
ACALL R_BYTE //读温度低字节
MOV TEM_L,A //将读出的温度低字节保存在40H
ACALL R_BYTE //读温度高字节
MOV TEM_H,A // 将读出的温度高字节保存在41H
RET
;;;;;将从DS18B20中读出的温度转换成整数显示;;;;;;;;;;;;
TEM_COV:MOV FLAG0,#'+' //设置当前温度为正,并且存放在45H
MOV A,TEM_H //将读取的温度高字节送给A
SUBB A,#0F8H //判断C的值是否为1,为1则为正,为0则为负
JC TEM0 //看温度值是否为负,不是(C=1),转
MOV FLAG0,#'-' //是,置FLAG0为负
MOV A,TEM_L //将读取的温度低字节送给A
CPL A //求此时负值温度的补码
ADD A,#01H
MOV TEM_L,A //将求得的补码存放在40H
MOV A,TEM_H //将读取的温度高字节送给A
CPL A
ADDC A,#01H
MOV TEM_H,A //在将其补码放在41H
TEM0: MOV A,TEM_L //存放整数部分到TEMPER_NUM
ANL A,#0F0H //取出温度低字节的高四位
SWAP A //将取出的高四位存放在A中低四位位置
MOV TEM_NUM,A //将其存放在42H
MOV A,TEM_H
SWAP A
ORL A,TEM_NUM
MOV TEM_NUM,A
RET
/***************LCD显示*******************/
;;;;;;LCD初始化子程序;;;;;;;;;;;;
LCD_INT:MOV A,#00000001H //清屏
ACALL W_COM //调用读命令子程序
MOV A,#00111000B //传输8位数据,显示两行,使用5*7的字符
LCALL W_COM
MOV A,#00001100B //显示器开,光标关,字符不闪烁
LCALL W_COM
MOV A,#00000110B //字符不动,光标自动右移一格
LCALL W_COM
RET
;;;;;写入命令子程序(RS=0,RW=0);;;;;;
W_COM: ACALL F_BUSY
CLR E
CLR RS
CLR RW
SETB E
MOV P0,A
CLR E
RET
;;;;;写入数据子程序(RS=1,RW=0);;;;;
W_DAT: ACALL F_BUSY
CLR E
SETB RS
CLR RW
SETB E
MOV P0,A
CLR E
RET
;;;;;查忙子程序;;;;;;;;;;;;;
F_BUSY: PUSH ACC
MOV P0,#0FFH
CLR RS //忙标志
SETB RW
WAIT: CLR E //给使能端有效信号(下降沿触发)
SETB E
JB P0.7,WAIT //直接寻址位P0.7是否为1,为1则忙,继续等待
POP ACC
RET
END
|