|
//******************************************************************************
// 用于河北北方学院宣化教学部2015级单片机课程实验的
// 单线数字温度传感器DS18B20的C51驱动代码
//
// 代码沿革
// 创建: 2015年4月1日
// 修改: 2015年4月4日,代码优化
// 2015年4月9日,注释
// 版权声明
// 1.版权拥有者是河北北方学院宣化教学部2005级单片机课程全体学生及该课程任课
// 教师.
// 2.任何团体或个人均可无条件使用本代码, 但版权拥有者不对由此引起的任何直接
// 或间接后果负担任何法律责任
// 3.一旦部分或全部使用本代码,则必须在源程序文档中无条件包含本版权声明
//******************************************************************************
#include "DS18b20.h"
#include "reg52.h"
//******************************************************************************
// DS18B20复位和初始化函数: DS18B20_Reset(void)
// 功能: 8051发出时间长度>=480us的低电平到数据线,然后拉高数据线维持15~60us
// 输入: 无
// 输出: DS18B20被复位
// 返回: 无
//******************************************************************************
void DS18B20_Reset(void)
{
uchar i;
DQ = 0; //拉低数据线DQ
i = 80; //使用12MHz晶体时用80,根据晶体频率按比例增减i的值
while(i--); //软件延时,"while(i--);"的反汇编代码单次循环消耗6us,80*6us=480us
DQ = 1;
i = 5; //使用12MHz晶体时用5,根据晶体频率按比例增减
while(i--); //软件延时,"while(i--);"的反汇编代码单次循环消耗6us,5*6us=30us
}
//******************************************************************************
// 读取一位数据函数: bit bitread(void)
// 功能: 51发长3us的低电平到数据线, 然后拉高数据线7us,再读回数据线,最后由软件延
// 时消耗掉60us位时间的剩余部分.
// 输入: 无
// 输出: 无
// 返回: 位值
//******************************************************************************
bit bitread(void)
{
uchar i;
bit dat;
DQ = 0; //拉低数据线DQ
i++; //模拟1~15us的延时,反汇编显示实际延时3us
DQ = 1; //拉高数据线DQ
i++; i++; //适当延时,反汇编显示实际延时7us
dat = DQ; //至此,DS18B20会在DQ上给出位值,读回此位值
i = 8; //从DQ拉低至此,反汇编显示已耗时13us, 60us-13us=47us约=48us
while(i--); //软件延时,"while(i--);"的反汇编代码单次循环消耗6us,8*6us=48us
return(dat); //返回位值
}
//******************************************************************************
// 读取一个字节数据函数: uchar byteread(void)
// 功能: 通过8次调用读取一位函数, 从DS18B20读回一个字节值,注意先读的是最低位
// 输入: 无
// 输出: 无
// 返回: 字节值
//******************************************************************************
uchar byteread(void)
{
uchar i, j, dat;
dat = 0;
for(i=1; i<=8; i++)
{
j = bitread(); //顺序读8个位
dat >>= 1;
dat |= (j<<7); //组装成一个字节
}
return(dat); //返回字节值
}
//******************************************************************************
// 写一个字节数据或命令函数: bytewrite(uchar dat)
// 功能: 写一个字节数据或命令到DS18B20中
// 输入: dat是准备写入DS18B20的一个命令字节或数据字节
// 输出: 命令字节或数据字节被写入DS18B20中
// 返回: 无
// 按位写入: 位值1写法:在DQ上发 1~ 15us低电平后跟高电平,应使位时间>=60us
// 位值0写法:在DQ上发60~120us低电平后跟高电平,应使位时间>=60us
// 注意:延时时间的统计计算需要浏览反汇编代码
//******************************************************************************
void bytewrite(uchar dat)
{
uchar i, j;
for(j=0; j<8; j++)
{
if(dat&0x01) //如果当前位的值为1,发1~15us低电平后跟高电平到数据线DQ
{
DQ = 0; //拉低数据线DQ
DQ = 0; //延时1us
DQ = 0; //到此共延时2us, 1us<2us<15us
DQ = 1; //拉高数据线DQ
i = 7; //自DQ拉低后到此语句执行完毕共耗时4us
while(i--); //每次循环耗时8us,7*8us=56us, 56us+4us=60us
}
else //如果当前位的值为0,发60~120us低电平后跟高电平到数据线DQ
{
DQ = 0; //拉低数据线DQ
i = 8; while(i--); //延时约65us, 60us<65us<120us
DQ =1; //拉高数据线DQ
DQ =1; //延时1us
DQ =1; //延时2us
}
dat = dat>>1; //右移,准备下一个位
}
}
//******************************************************************************
// 温度转换启动函数: uchar DS18B20_Start(void)
// 功能: 复位DS18B20并检测其是否在位,若在位则启动温度转换
// 输入: 无
// 输出: 若DS18B20在位,启动温度转换过程
// 返回: 0启动失败,1启动成功
//******************************************************************************
uchar DS18B20_Start(void)
{
uchar i = 10;
DS18B20_Reset(); //复位DS18B20,返回时DQ已拉高,DS18B20最多60us后发在位脉冲
while((DQ==1) && //等待DS18B20在数据线DQ上发低电平在位脉冲
(i--)); //最多等待80us(80us>60us)
if(i!=0) //在i递减到0之前检测到DQ被拉低,说明DS18B20在位
{
while(DQ==0); //等待DS18B20把她的在位脉冲发完(持续60~120us)
bytewrite(0xcc); //写"跳过ROM检测命令"到DS18B20
bytewrite(0x44); //写"开始温度转换命令"到DS18B20
return 1;
}
return 0;
}
//******************************************************************************
// 读取温度值函数: DS18B20_Tempread(void)
// 输入: 无
// 输出: 无
// 返回: 补码表示的摄氏温度值,有符号整型数,若DS18B20异常则返回0x7fff
//******************************************************************************
int DS18B20_Tempread(void)
{
uchar a, b, i = 10;
DS18B20_Reset(); //复位DS18B20,返回时DQ已拉高,DS18B20最多60us后发在位脉冲
while((DQ==1) && //等待DS18B20在数据线DQ上发低电平在位脉冲
(i--)); //最多等待80us(80us>60us)
if(i!=0) //在i递减到0之前检测到DQ被拉低,说明DS18B20在位
{
while(DQ==0); //等待DS18B20把她的在位脉冲发完(持续60~120us)
bytewrite(0xcc); //写"跳过ROM检测命令"到DS18B20
bytewrite(0xbe); //写"连续读9个寄存器命令"到DS18B20
a = byteread(); //读第一个寄存器(温度值低字节)
b = byteread(); //读第二个寄存器(温度值高字节)
; //其余7个寄存器不读
return (a + (b*256)); //温度值组装成一个16位字
}
return 0x7fff; //最高五位正常情况下是值相同的符号位,现为01111,表明DS18B20异常
}
//******************************************************************************
// 配置函数: void DS18B20_Set(uchar v_reg2, v_reg3, v_reg4)
// 配置DS18B20的高温阀值寄存器,低温阀值寄存器,分辨率设置寄存器
// 输入: v_reg2 高温阀值寄存器的值
// v_reg3 低温阀值寄存器的值
// v_reg4 分辨率设置寄存器的值
// 输出: 若DS18B20在位,指定的三个寄存器被配置好
// 返回: 无
//******************************************************************************
void DS18B20_Set(uchar v_reg2, v_reg3, v_reg4)
{
uchar i = 10;
DS18B20_Reset(); //复位DS18B20,返回时DQ已拉高,DS18B20最多60us后发在位脉冲
while((DQ==1) && //等待DS18B20在数据线DQ上发低电平在位脉冲
(i--)); //最多等待80us(80us>60us)
if(i!=0) //在i递减到0之前检测到DQ被拉低,说明DS18B20在位
{
while(DQ==0); //等待DS18B20把她的在位脉冲发完(持续60~120us)
v_reg4 |= 0x80; //保证最高位TM=1
bytewrite(0xcc); //写"跳过ROM检测命令"到DS18B20
bytewrite(0x4e); //写"连续写9个寄存器命令"到DS18B20
bytewrite(0x00); //写第一个寄存器(温度值低字节,写无意义,给0)
bytewrite(0x00); //写第二个寄存器(温度值高字节,写无意义,给0)
bytewrite(v_reg2); //写第三个寄存器(高温阀值)
bytewrite(v_reg3); //写第四个寄存器(低温阀值)
bytewrite(v_reg4); //写第五个寄存器(分辨率)
; //其余4个寄存器不写
}
}
//******************************************************************************
//读取64位ROM
//******************************************************************************
uchar sn[8];
void DS18B20_Readrom(void)
{
uchar i = 10;
DS18B20_Reset(); //复位DS18B20,返回时DQ已拉高,DS18B20最多60us后发在位脉冲
while((DQ==1) && //等待DS18B20在数据线DQ上发低电平在位脉冲
(i--)); //最多等待80us(80us>60us)
if(i!=0) //在i递减到0之前检测到DQ被拉低,说明DS18B20在位
{
while(DQ==0); //等待DS18B20把她的在位脉冲发完(持续60~120us)
bytewrite(0x33);
for(i=0; i<8; i++)
sn[ i] = byteread();
}
}
|
|