DS18B20单从设备与51的接口程序(最新)
;===========================================================================
;DS18B20与80C51系列单片机的接口程序
;单片机晶振24MHz,机器周期为0.5uS
;
; 温度转换---> ....→读取温度→CRC校验→温度转换→数据处理→其他服务→
; ↑_____________↓________________________________↓
;===========================================================================
;1 wire 总线DQ
DQ bit P1^1
;===========================================================================
NAME DS18B20 ;模块名称
;===========================================================================
;延时子程序
delay_500uS: ;延时大于480uS
mov r5,#2;
d500_1: mov r6,#248;
djnz r6,$;
djnz r5,d500_1;
ret
delay_90uS:
mov r5,#89;
djnz r5,$;
ret
delay_400uS:
mov r5,#2;
d400_1: mov r6,#198;
djnz r6,$;
djnz r5,d400_1;
ret
;===========================================================================
;主机对1 wire 设备初始化子程序
;函数原型:bit reset_ds18b20(void)
;返回值Cy:1=设备存在;0=设备不存在
;===========================================================================
?PR?_reset_ds18b20?DS18B20 SEGMENT CODE
PUBLIC _reset_ds18b20
RSEG ?PR?_reset_ds18b20?DS18B20
_reset_ds18b20:
clr DQ;
call delay_500uS;
setb DQ;
call delay_90uS;
setb c; 设备存在
jnb DQ,i_ret;
clr c; 设备不存在
ajmp j_ret;
i_ret: call delay_400uS;
j_ret: ret
;==============================================================================
;主机向DS18B20写一个字节数据
;入口:欲写的数据在A中
;==============================================================================
write_byte:
push psw;
mov r6,#8;
clr c;
w_loop1:
rrc a; 数据的低位先发,后发高位
jc write1;
clr DQ;
call delay_90uS;
setb DQ;
ajmp w_loop2;
write1: clr DQ;
nop; 恢复时间延时必须大于1uS
nop;
nop;
nop;
setb DQ;
call delay_90uS;
w_loop2:djnz r6,w_loop1;
pop psw;
pop acc;
ret
;==============================================================================
;主机从DS18B20读取一个字节数据
;出口:数据在A中
;
;===============================================================================
read_byte:
push psw;
mov r6,#8;
read_loop: clr DQ;
nop; 拉低总线时间应大于1uS
nop;
nop;
setb DQ;
mov r7,#5; //必须在从拉低总线开始的15uS以内采样总线
djnz r7,$;
mov c,DQ;
rrc a;
mov r7,#49;延时50uS
djnz r7,$;
nop;;恢复时间延时必须大于1uS
nop
nop
djnz r6,read_loop;
pop psw;
ret
;=================================================================================
;单从设备温度转换函数
;函数原型:void temp_conver(void)
;
;=================================================================================
?PR?temp_conver?DS18B20 SEGMENT CODE
PUBLIC temp_conver
RSEG ?PR?temp_conver?DS18B20
temp_conver:
call _reset_ds18b20;
mov A,#0cch; //跳跃ROM命令
call write_byte;
mov A,#044h; //温度转换命令
call write_byte;
ret
;=================================================================================
;主机读取单从设备暂存器函数
;函数原型:void read_scrat(unsigned char data * buf,unsigned char n)
;入口:r7(buf):数据缓冲区首址
; R5(n):欲读取的字节数
;================================================================================
?PR?_read_scrat?DS18B20 SEGMENT CODE
PUBLIC _read_scrat
RSEG ?PR?_read_scrat?DS18B20
_read_scrat:
mov a,r7;
mov r0,a;
call _reset_ds18b20; //
mov A,#0cch; //跳跃ROM命令
call write_byte;
mov A,#0beh; //读暂存器命令
call write_byte;
r_scrat_loop:
call read_byte;
mov @r0,a;
inc r0;
djnz r5,r_scrat_loop;
call _reset_ds18b20;
ret
;================================================================================
;主机写单从设备的3个暂存器函数
;函数原型:void write_scrat(unsigned char data * buf)
;入口:R7(buf)欲写数据的首地址
;================================================================================
?PR?_write_scrat?DS18B20 SEGMENT CODE
PUBLIC _write_scrat
RSEG ?PR?_write_scrat?DS18B20
_write_scrat:
mov r6,#3;
mov a,r7;
mov r0,a;
call _reset_ds18b20; //
mov a,#0cch; //跳跃ROM命令
call write_byte;
mov a,#04eh; //写暂存器命令
call write_byte;
w_scrat_loop:
mov a,@r0;
call write_byte;//写数据
inc r0;
djnz r6,w_scrat_loop;
ret
;=================================================================================
;单从设备将3个暂存器内容复制到E2PROM函数
;函数原型:void copy_scrat(void)
;=================================================================================
?PR?copy_scrat?DS18B20 SEGMENT CODE
PUBLIC copy_scrat
RSEG ?PR?copy_scrat?DS18B20
copy_scrat:
call _reset_ds18b20; //
mov a,#0cch; //跳跃ROM命令
call write_byte;
mov a,#048h; //复制暂存器命令
call write_byte;
ret
;=================================================================================
;单从设备回读E2PROM内容至暂存器函数
;函数原型:void recall_e2p(void)
;=================================================================================
?PR?recall_e2p?DS18B20 SEGMENT CODE
PUBLIC recall_e2p
RSEG ?PR?recall_e2p?DS18B20
recall_e2p:
call _reset_ds18b20; //
mov a,#0cch; //跳跃ROM命令
call write_byte;
mov a,#0b8h; //回读E2prom命令
call write_byte;
ret
;===================================================================================
;===================================================================================
;温度数据(HEX)转换为8位(4字节)BCD码
;函数原型:void hextobcd(unsigned char data * source ,unsigned char data * disten)
;入口:source(R7):需转换数据的首地址指针;disten(R5):转换后数据保存地址指针
;===================================================================================
?PR?_hextobcd?DS18B20 SEGMENT CODE
PUBLIC _hextobcd
RSEG ?PR?_hextobcd?DS18B20
_hextobcd:
mov a,r7;
mov r0,a;
mov a,r5;
mov r1,a;
mov a,@r0;
mov r7,a;//低字节
inc r0;
mov a,@r0;
mov r6,a;//高字节
call neg;//判负求补
call data_apart;整数与小数分离
call hbcd;//转换为BCD码
mov a,r0;//恢复数据指针
mov r7,a;
mov a,r1;
mov r5,a;
ret
;===================================================================================
;===================================================================================
;两字节HEX数据转换为两字节BCD(
;入口:欲转换的数据在R6R7,R6为整数,R7为小数部分;
; R1=转换后BCD数据保存首地址
;出口:转换后的BCD码首地址在R1中,(R1),(R1)+1为整数部分,(R1)的第7位为数据符号位:1=负数;0=正数
; (R1)+2,(R1)+3为小数部分。
;=================================================================================
hbcd:
;整数部分转换
mov a,r1;
push acc;
mov a,r6;
mov c,acc.7;
mov F0,c;//暂存符号位
mov b,#100;
div ab;
mov c,F0;
mov acc.7,c;恢复符号位
mov @r1,a;
mov a,#10;
xch a,b;
div ab;
swap a;
orl a,b;
mov r7,a;
inc r1;
mov @r1,a;
;小数部分BCD码转换
clr a;
mov r2,a;
mov r3,a;
mov a,r7;
jnb acc.7,hbcd_1;
mov r2,#50h;
hbcd_1: jnb acc.6,hbcd_2;
push acc;
mov a,r2;
add a,#25h;
mov r2,a;
pop acc;
hbcd_2: jnb acc.5,hbcd_3;
push acc;
mov a,r2;
add a,#12h;
mov r2,a;
mov r3,#50;
pop acc;
hbcd_3: jnb acc.4,hbcd_4;
mov a,r2;
add a,#06h;
da a;
inc r1;
mov @r1,a;
mov a,r3;
add a,#25h;
inc r1;
mov @r1,a;
hbcd_4: pop acc;//恢复数据指针
mov r1,a;
ret
;===================================================================================
;数据求补运算子程序
;入口:R6,R7;R6为高字节
;出口:数据地址不变
;===================================================================================
neg:
mov a,r6;
jnb acc.7,neg_ret;//判断数据是否是负数,若非负数则直接退出
mov a,r7; //否则求补
cpl a;
clr c;
add a,#1;
mov r7,a;
mov a,r6;
cpl a;
addc a,#0;
setb acc.3;//设置负数标志
mov r7,a;
neg_ret: ret
;==========================================================================================
;整数与小数部分的分离
;入口:数据在R6,R7中,R6为高字节
;出口:分离的整数在R6中,小数在R7中
;=========================================================================================
data_apart:
mov a,r7;
anl a,#0f0h;
swap a;
mov b,a;//
mov a,r6;
anl a,#0fh;
swap a;
orl a,b;
mov r6,a;//存整数部分
mov a,r7;
anl a,#0fh;
swap a;
mov r7,a;//存小数部分
ret
;=============================================================================================
;CRC校验
;入口:数据首址在R0;
;出口:ACC,ACC=0,数据正确;ACC≠0数据不正确,需重新读取数据
;=============================================================================================
tcrc: mov r7,#9; 字节计数单元赋初值
mov r2,#0; 移位寄存器清零
tcrc2: mov a,@r0;
mov r3,a;
mov r6,#8;移位次数单元赋初值
tcrc3: xrl a,r2;
anl a,#01h;
mov r4,a;
mov a,r2;
clr c;
rrc a;
cjne r4,#1,tcrc4;结果为1进行异或操作
xrl a,#8ch;
tcrc4: mov r2,a;
mov a,r3;
rrc a;
mov r3,a;
djnz r6,tcrc3;
inc r0;
djnz r7,tcrc2;
mov a,r2;
ret
;=============================================================================================
;单字节BCD码转换为单字节HEX
;入口:ACC
;出口:ACC
;=============================================================================================
bcdh: mov b,#10;
div ab;
mov r4,b;
mov b,#10;
mul ab;
add a,r4;
ret;
;============================================================================================
end
发表时间:2004年4月30日9:50:51