📄 ds18b20_web.asm
字号:
;用DP-51+ 来读DS18B20单总线温度传感器
;进行温度显示,显示范围00到99度,显示精度为1度
;因为12位转化时每一位的精度为0.0625度,我们不要求显示小数所以可以抛弃29H的低4位, 16(FFFFH)x0.00625=1度
;将28H中的低4位移入29H中的高4位,这样获得一个新字节,这个字节就是实际测量获得的温度,非常简洁无需乘于0.0625系数
;DS18B20复位初始化子程序,P0和P2已被系统占用,而P1用来驱动LED和数码管,
;所以用P3口作普通I/O口,P3.2 是输入和输出数据线
;单片机内存分配申明!
TEMPER_L EQU 29H ;用于保存读出温度的低8位,
;29H在内部RAM的20H~2FH里(位寻址区)
TEMPER_H EQU 28H ;用于保存读出温度的高8位
;28H在内部RAM位寻址区
FLAG1 EQU 38H ;是否检测到DS18B20标志位,是可寻址位
a_bit EQU 20h ;数码管个位数存放内存位置
b_bit EQU 21h ;数码管十位数存放内存位置
SDA EQU P1.0
CLK EQU P1.1
//ORG 0000H
ORG 4000H
LJMP MAIN
MAIN:
LCALL GET_TEMPER ;调用读温度子程序
MOV A, 29H ;温度的低8位
MOV C, 40H ;将28H中的最低位移入C, 40H是位寻址(RAM单元28H)
RRC A
MOV C, 41H
RRC A
MOV C, 42H
RRC A
MOV C, 43H
RRC A
MOV 29H, A ;将28H中的低4位移入29H中的高4位,这样获得一个新字节,29H内存所要温度数据
LCALL DISPLAY ;调用数码管显示子程序
;CPL P1.0 ;直接寻址位取反
AJMP MAIN
INIT_1820:
SETB P3.2 ;P3.2 是数据线,
NOP
CLR P3.2
;主机发出延时537微秒的复位低脉冲
MOV R1, #3
TSR1:
MOV R0, #107
DJNZ R0, $
DJNZ R1, TSR1 ;双重循环
SETB P3.2 ;然后拉高数据线,
;释放总线,读口线前先置"1"
;过程其实是"读--改--写"
NOP ;空操作,消耗一个机器周期
NOP
NOP
MOV R0, #25H
TSR2:
JNB P3.2, TSR3 ;等待DS18B20回应, "低"表示DS18B20存在
;读口线并判断,"低"转移
DJNZ R0, TSR2 ;R0不为零,有时间限制的继续查寻P3.2,否则死循环
;25x2us=50us 最大时间限制
LJMP TSR4 ;DS18B20不存在,转移
TSR3:
SETB FLAG1 ;置标志位,表示DS1820存在,
;是位寻址38H, 指令是位操作指令
CLR P1.7 ;检查到DS18B20就蜂鸣BUZZER
;see schematic, Q6 bipolar
LJMP TSR5
TSR4:
CLR FLAG1 ;清标志位,表示DS1820不存在
;CLR P1.1 ;
LJMP TSR7
TSR5:
MOV R0, #117
TSR6:
DJNZ R0, $ ;时序要求延时一段时间
TSR7:
SETB P3.2 ;然后拉高数据线
RET ;结束复位初始化,返回
; 读出转换后的温度值子程序
GET_TEMPER:
SETB P3.2 ;
LCALL INIT_1820 ;先复位DS18B20
JB FLAG1, TSS2 ;判断DS1820是否存在
;CLR P1.2 ;
RET ;DS18B20不存在则返回
TSS2:
;CLR P1.3 ;DS18B20已经被检测到
;
; 发出"温度转换"命令
MOV A, #0CCH ;"跳过ROM匹配"命令
LCALL WRITE_1820 ;发出命令
MOV A, #44H ;"起动转换"命令
LCALL WRITE_1820 ;发出命令
LCALL DISPLAY ;这里通过调用显示子程序实现延时一段时间,
;等待AD转换结束,12位的话750微秒
;时序见 write slot
LCALL INIT_1820 ;准备读温度前先复位, 是否会abort上句的温度转换命令#44H??,
;不会, 每一次读写之前都要对DS18B20进行复位
;发出"读温度"命令
MOV A, #0CCH ;"跳过ROM匹配"命令
LCALL WRITE_1820 ;发出命令
MOV A, #0BEH ;"读温度"命令
LCALL WRITE_1820 ;发出命令
LCALL READ_1820 ;读出温度数据
;CLR P1.4 ;
RET ;结束读出转换后的温度值子程序, 返回
; /写DS18B20的子程序(有具体的时序要求)
WRITE_1820:
MOV R2, #8 ;一共8位数据
CLR C
WR1:
CLR P3.2 ;clear p3.2,
;P3.2口从逻辑高到逻辑低时,写时间隙开始
;DS18B20将在15us~60us窗口内采样P3.2口线
MOV R3, #5
DJNZ R3, $ ;2us, $ 代表PC当前值, 可使程序原地踏步等待中断或程序结束
;total 2x5=10us延时
RRC A ;A中有命令字, 一位一位传递给C
MOV P3.2, C ;一位一位通过P3.2发
MOV R3, #21
DJNZ R3, $ ;2us, total 21x2=42us延时,
;write slot最少持续60us
SETB P3.2 ;拉高数据线, 为"逻辑高到逻辑低"作准备
NOP ;延时 2uS
DJNZ R2, WR1 ;循环, 直至命令字8位发完
SETB P3.2
RET ;结束写子程序, 返回
; 读DS18B20的子程序,从DS18B20中读出两个字节的温度数据
READ_1820:
MOV R4, #2 ;将温度高位和低位从DS18B20中读出
MOV R1, #29H ;低位存入29H(TEMPER_L),高位存入28H(TEMPER_H)
RE00:
MOV R2, #8 ;数据一共有8位
RE01:
CLR C
SETB P3.2 ;拉高数据线, 为"逻辑高到逻辑低"作准备
NOP
NOP
CLR P3.2 ;P3.2口从逻辑高到逻辑低时,读时间隙开始
;从DS18B20输出的数据在读时间隙的下降沿出现后15us内有效
NOP ;1us
NOP ;1us
NOP ;1us
SETB P3.2 ;1us,释放总线,读口线前先置"1, 停止驱动P3.2口低,而置为高电平
;read slot,
MOV R3, #9 ;1us
RE10:
DJNZ R3, RE10 ;2us, total:9x2=18us
MOV C, P3.2 ;1us, P3.2传递给C,
MOV R3, #23
RE20:
DJNZ R3, RE20 ;2us, total 23x2=46us, write slot最少持续60us
RRC A ;C位传递给A
DJNZ R2, RE01 ;循环,直至8位传递完
MOV @R1, A ;A->29H
DEC R1 ;28H
DJNZ R4, RE00 ;开始传递 A->28H 的过程
RET ;结束读子程序, 返回
DISPLAY:
MOV R2,#0BFH ;10111111,P1.6->LED1,P1.5->LED2,P1.4->LED3,P1.3->LED4
;MOV R2,#0EFH ;11101111,P1.4
MOV A,29H
MOV B,#10
DIV AB
MOV b_bit, A ;十位数
MOV a_bit, B ;个位数
MOV A, b_bit ;先显示十位数->LED1,
ACALL TAB
ACALL TXDBYTE
MOV A, R2 ;LED位选, 10111111,P1.6
MOV A, #0BFH
MOV P1, A
ACALL DELAY
MOV P1,#0FFH
MOV A, a_bit ;显示个位数->LED2,
ACALL TAB
ACALL TXDBYTE
MOV A,#0DFH ;LED位选, 11011111,P1.5
MOV P1,A
ACALL DELAY
MOV P1,#0FFH
RET
TXDBYTE:
MOV R3, #08H
TXDUP:
RLC A
MOV SDA, C
CLR CLK
SETB CLK
DJNZ R3,TXDUP
RET
DELAY:
MOV R7,#50H
DELAY0:
MOV R6,#10H
DELAY1:
DJNZ R6, DELAY1
DJNZ R7, DELAY0
TAB:
;INC A
;MOVC A,@A+PC
;或者
MOV DPTR, #numtab
MOVC A,@A+DPTR
RET
numtab:
DB 0C0H,0F9H,0A4H,0B0H,099H,092H,082H,0F8H,80H,090H
END
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -