$NOMOD51
$INCLUDE (8051.MCU)
; 硬件定义
DAT BIT P2.0 ; DS18B20数据通信口
BUZZER BIT P3.2 ; 蜂鸣器控制引脚
DIG1 BIT P1.0 ; 数码管1位选
DIG2 BIT P1.1 ; 数码管2位选
; 定时器常量
swpH EQU 0d2H ; 定时器高位初值
swpL EQU 0ffH ; 定时器低位初值
; 变量定义
WDLSB DATA 30H ; 读出的温度低字节
WDMSB DATA 31H ; 读出的温度高字节
TEMP DATA 40H ; 温度整数值存储
ALARM_FLAG BIT 20H.0 ; 报警标志位
ALARM_COUNT_L DATA 50H ; 报警计时计数器低字节
ALARM_COUNT_H DATA 51H ; 报警计时计数器高字节
; 常量定义
ALARM_DUR_L EQU 0B2H ; 434的低字节 (5秒报警)
ALARM_DUR_H EQU 01H ; 434的高字节 (5秒报警)
DIG_SELECT BIT 21H ; 数码管选择标志位
; 程序入口
;***************************************************************
ORG 0000H
LJMP MAIN
ORG 000BH
LJMP TMR0_ISR ; 定时器0中断入口
;********************************************************
; 定时器T0中断服务程序 - 数码管显示和报警计时
TMR0_ISR:
; 重装定时器初值
MOV TH0, #swpH
MOV TL0, #swpL
; 关闭所有数码管
SETB DIG1
SETB DIG2
; 数码管选择显示
JB DIG_SELECT, DISPLAY_UNIT
; 显示十位
MOV P0, 42H
CLR DIG1 ; 选中第一个数码管
SJMP DISPLAY_DONE
DISPLAY_UNIT:
; 显示个位
MOV P0, 43H
CLR DIG2 ; 选中第二个数码管
DISPLAY_DONE:
CPL DIG_SELECT ; 切换数码管选择
; 报警计时处理
JNB ALARM_FLAG, NO_ALARM_TIMING ; 不在报警状态则跳过
; 16位计数器递增
INC ALARM_COUNT_L
MOV A, ALARM_COUNT_L
JNZ NO_HIGH_INC ; 低字节未溢出则跳过
INC ALARM_COUNT_H ; 低字节溢出时增加高字节
NO_HIGH_INC:
; 检查是否达到5秒报警时长
MOV A, ALARM_COUNT_L
CJNE A, #ALARM_DUR_L, NO_ALARM_TIMING
MOV A, ALARM_COUNT_H
CJNE A, #ALARM_DUR_H, NO_ALARM_TIMING
; 达到5秒,关闭报警
CLR ALARM_FLAG
SETB BUZZER ; 关闭蜂鸣器
MOV ALARM_COUNT_L, #0 ; 重置计数器
MOV ALARM_COUNT_H, #0
NO_ALARM_TIMING:
RETI
;********************************************************
; 主程序
MAIN:
; 初始化系统
CLR EA ; 关中断
MOV TMOD, #01H ; 定时器0模式1
MOV TH0, #swpH ; 定时器初值
MOV TL0, #swpL
SETB EA ; 开中断
SETB ET0 ; 允许定时器0中断
SETB TR0 ; 启动定时器0
; 初始化变量
MOV R2, #2
MOV R0, #42H
INIT_LOOP:
MOV @R0, #00H ; 清零显示缓冲区
INC R0
DJNZ R2, INIT_LOOP
; 初始化蜂鸣器(关闭)
SETB BUZZER
; 初始化报警标志和计数器
CLR ALARM_FLAG
MOV ALARM_COUNT_L, #0
MOV ALARM_COUNT_H, #0
CLR DIG_SELECT ; 初始选择十位数码管
; 主循环
MAIN_LOOP:
LCALL READ_TEMP ; 读取温度
; 检查是否需要报警
JNB ALARM_FLAG, CHECK_ALARM ; 当前未报警则检查
SJMP LOOP_CONTINUE ; 已在报警中,跳过检测
CHECK_ALARM:
; 检查温度是否≥37℃
MOV A, TEMP
CJNE A, #37, CHECK_TEMP ; 比较温度
CHECK_TEMP:
JC LOOP_CONTINUE ; 温度<37℃,继续循环
; 温度≥37℃,触发报警
SETB ALARM_FLAG ; 设置报警标志
CLR BUZZER ; 开启蜂鸣器
MOV ALARM_COUNT_L, #0 ; 重置计数器
MOV ALARM_COUNT_H, #0
LOOP_CONTINUE:
LCALL DELAY10 ; 适当延时
SJMP MAIN_LOOP ; 继续主循环
;**********************************************************
; 读取温度值
READ_TEMP:
LCALL DS18B20_RESET ; 复位DS18B20
JNB F0, READ_END ; 复位失败则退出
; 发送跳过ROM命令
MOV R0, #0CCH
LCALL SEND_BYTE
; 发送温度转换命令
MOV R0, #44H
LCALL SEND_BYTE
; 等待温度转换完成
SETB EA
MOV 48H, #1 ; 约1秒延时
WAIT_CONVERSION:
MOV 49H, #255
WAIT_LOOP1:
MOV 4AH, #255
WAIT_LOOP0:
DJNZ 4AH, WAIT_LOOP0
DJNZ 49H, WAIT_LOOP1
DJNZ 48H, WAIT_CONVERSION
CLR EA
; 再次复位DS18B20
LCALL DS18B20_RESET
JNB F0, READ_END
; 发送跳过ROM命令
MOV R0, #0CCH
LCALL SEND_BYTE
; 发送读取温度命令
MOV R0, #0BEH
LCALL SEND_BYTE
; 读取温度值
LCALL READ_BYTE
MOV WDLSB, A ; 温度低字节
LCALL READ_BYTE
MOV WDMSB, A ; 温度高字节
; 转换温度值
LCALL CONVERT_TEMP
READ_END:
SETB EA
RET
;**********************************************************
; 温度转换程序(取整数部分)
CONVERT_TEMP:
; 提取温度整数部分
MOV A, WDLSB
ANL A, #0F0H
MOV R1, A
MOV A, WDMSB
ANL A, #0FH
ORL A, R1
SWAP A
; 保存温度值用于报警判断
MOV TEMP, A
; 转换为十进制
MOV B, #10
DIV AB
MOV 42H, A ; 十位数
MOV 43H, B ; 个位数
; 转换为七段码
MOV DPTR, #SEG_TABLE
MOV A, 42H
MOVC A, @A+DPTR
MOV 42H, A
MOV A, 43H
MOVC A, @A+DPTR
MOV 43H, A
RET
; 七段数码管编码表 (共阳极)
SEG_TABLE:
DB 0C0H ; 0
DB 0F9H ; 1
DB 0A4H ; 2
DB 0B0H ; 3
DB 099H ; 4
DB 092H ; 5
DB 082H ; 6
DB 0F8H ; 7
DB 080H ; 8
DB 090H ; 9
;*************************************************
; DS18B20复位程序
DS18B20_RESET:
SETB DAT
NOP
NOP
CLR DAT
MOV R6, #250
DJNZ R6, $
MOV R6, #50
DJNZ R6, $
SETB DAT
MOV R6, #15
DJNZ R6, $
CALL CHECK_PRESENCE
MOV R6, #60
DJNZ R6, $
SETB DAT
RET
; 检查DS18B20存在脉冲
CHECK_PRESENCE:
MOV C, DAT
JC NO_DS18B20
SETB F0 ; 存在DS18B20
SJMP PRESENCE_END
NO_DS18B20:
CLR F0 ; 未检测到DS18B20
PRESENCE_END:
RET
;*************************************************
; 发送一个字节程序
SEND_BYTE:
MOV A, R0
MOV R5, #8
SEND_BIT:
CLR C
RRC A
JC SEND_1
LCALL WRITE_0 ; 发送0
SJMP NEXT_BIT
SEND_1:
LCALL WRITE_1 ; 发送1
NEXT_BIT:
DJNZ R5, SEND_BIT
RET
;*************************************************
; 读一个字节程序
READ_BYTE:
MOV R5, #8
MOV A, #0
READ_BIT:
LCALL READ_DS18B20
RRC A
DJNZ R5, READ_BIT
MOV R0, A
RET
;*************************************************
; 写0时序
WRITE_0:
CLR DAT
MOV R6, #30
DJNZ R6, $
SETB DAT
RET
;*************************************************
; 写1时序
WRITE_1:
CLR DAT
NOP
NOP
NOP
NOP
NOP
SETB DAT
MOV R6, #30
DJNZ R6, $
RET
;*************************************************
; 读一位数据程序
READ_DS18B20:
SETB DAT ; 释放总线
NOP
NOP
CLR DAT ; 启动读时序
NOP
NOP
SETB DAT ; 准备采样
NOP
NOP
NOP
NOP
NOP
NOP
NOP
MOV C, DAT ; 读取数据位
MOV R6, #23
DJNZ R6, $
RET
;*************************************************
; 10ms延时子程序
DELAY10:
MOV R4, #20
DELAY_LOOP2:
MOV R5, #250
DELAY_LOOP1:
DJNZ R5, DELAY_LOOP1
DJNZ R4, DELAY_LOOP2
RET
END帮我新添加lcd显示功能并且上电后能正确运行程序
最新发布