网上摘录的DS18B20程序,里面有点小问题,修改后再加详细备注。
#include<reg51.h>
#include<intrins.h>
#include <math.H> //要用到取绝对值函数abs()
#define uchar unsigned char
#define uint unsigned int
//通过DS18B20测试当前环境温度, 并通过数码管显示当前温度值, 目前显示范围: -55~ +125度
sbit wela = P2^7; //数码管位选
sbit dula = P2^6; //数码管段选
sbit ds = P2^2; //ds18b20总线端口
int tempValue; //整型温度值
uchar const timeCount = 4; //动态扫描的时间间隔
//0-F数码管的编码(共阴极)
uchar code table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
//0-9数码管的编码(共阴极), 带小数点
uchar code tableWithDot[]={0xbf,0x86,0xdb,0xcf,0xe6,0xed,0xfd,0x87,0xff,0xef};
//延时1ms函数。 对于12MHz时钟, 例i=10,则大概延时10ms.
void delay(uchar i)
{
uint j;
while(i--)
{
for(j = 0; j < 122; j++);
}
}
//初始化DS18B20
//让DS18B20一段相对长时间低电平, 然后一段相对非常短时间高电平, 即可启动
void dsInit()
{
//12MHz时钟, unsigned int型的i, 作一个i++操作的时间为3us,i--为4us
uint i;
ds = 0;
i = 100; //拉低约800us, 符合协议要求的480us以上(400-960)
while(i>0)
i--;
ds = 1; //产生一个上升沿,释放总线, 进入等待应答状态 ( 15-60 )
i = 4;
while(i>0)
i--;
}
void dsWait()
{
uint i;
while(ds);
while(~ds); //等待应答脉冲 (DS18B20发出60-240us存在低脉冲)
i=4;
while(i>0)
i--;
}
//向DS18B20读取一位数据
//读一位, 让DS18B20一小周期低电平, 然后两小周期高电平,
//之后DS18B20则会输出持续一段时间的一位数据
bit readBit()
{
uint i;
bit b;
ds=0;
i++; //延时约8us, 符合协议要求至少保持1us
ds=1;
i++;
i++; //延时约16us, 符合协议要求的至少延时15us以上
b=ds;
i=8;
while(i>0)
i--; //延时约64us, 符合读时隙不低于60us要求
return b;
}
//读取一字节数据, 通过调用readBit()来实现
uchar readByte()
{
uint i;
uchar j, dat;
dat = 0;
for(i=0;i<8;i++)
{
j = readBit();
//最先读出的是最低位数据
dat=(j<<7)|(dat>>1);
}
return dat;
}
//向DS18B20写入一字节数据
void writeByte(uchar dat)
{
uint i;
uchar j;
bit b;
for(j = 0; j < 8; j++)
{
b = dat & 0x01;
dat >>= 1;
//写"1", 将DQ拉低15us后, 在15us~60us内将DQ拉高, 即完成写1
if(b)
{
ds = 0;
i++;
i++; //拉低约16us, 符号要求15~60us内
ds = 1;
i = 8;
while(i>0)
i--; //延时约64us, 符合写时隙不低于60us要求
}
else //写"0", 将DQ拉低60us~120us
ds = 0;
i = 8;
while(i>0)
i--; //拉低约64us, 符号要求
ds = 1;
i++;
i++; //整个写0时隙过程已经超过60us, 这里就不用像写1那样, 再延时64us了
}
}
//向DS18B20发送温度转换命令
void sendChangeCmd()
{
dsInit(); //初始化DS18B20, 无论什么命令, 首先都要发起初始化
dsWait(); //等待DS18B20应答
delay(1); //延时1ms, 因为DS18B20会拉低DQ 60~240us作为应答信号
writeByte(0xcc); //写入跳过序列号命令字 Skip Rom
writeByte(0x44); //写入温度转换命令字 Convert T
}
//向DS18B20发送读取数据命令
void sendReadCmd()
{
dsInit();
dsWait();
delay(1);
writeByte(0xcc); //写入跳过序列号命令字 Skip Rom
writeByte(0xbe); //写入读取数据令字 Read Scratchpad
}
//获取当前温度值
int getTmpValue()
{
uint tmpvalue;
int value; //存放温度数值
float t;
uchar low, high;
sendReadCmd();
//连续读取两个字节数据
low = readByte();
high = readByte();
//将高低两个字节合成一个整形变量
//计算机中对于负数是利用补码来表示的
//若是负值, 读取出来的数值是用补码表示的, 可直接赋值给int型的value
tmpvalue = high;
tmpvalue <<= 8;
tmpvalue |= low;
value=tmpvalue;
//使用DS18B20的默认分辨率12位, 精确度为0.0625度, 即读回数据的最低位代表0.0625度
t=value*0.0625;
//将它放大100倍, 使显示时可显示小数点后两位, 并对小数点后第三进行4舍5入
//如t=11.0625, 进行计数后, 得到value = 1106, 即11.06 度
//如t=-11.0625, 进行计数后, 得到value = -1106, 即-11.06 度
value=t*100+(value>0?0.5:-0.5); //大于0加0.5, 小于0减0.5
return value;
}
//显示当前温度值, 精确到小数点后一位
//若先位选再段选, 由于IO口默认输出高电平, 所以当先位选会使数码管出现乱码
void display(int v)
{
uchar count;
uchar datas[] = {0, 0, 0, 0, 0};
uint tmp = abs(v); //abs取绝对值函数,包含在math中
datas[0] = tmp / 10000;
datas[1] = tmp % 10000 / 1000;
datas[2] = tmp % 1000 / 100;
datas[3] = tmp % 100 / 10;
datas[4] = tmp % 10;
//显示“-”号
if(v<0)
{
P0 = 0xff; //关位选, 去除对上一位的影响
wela = 1; //打开锁存, 给它一个下降沿量
wela = 0;
//段选
P0 = 0x40; //显示"-"号
dula = 1; //打开锁存, 给它一个下降沿量
dula = 0;
//位选
P0 = 0xfe;
wela = 1; //打开锁存, 给它一个下降沿量
wela = 0;
delay(timeCount);
}
//显示数值
for(count=0;count !=5;count++)
{
//关位选, 去除对上一位的影响
P0 = 0xff;
wela = 1; //打开锁存, 给它一个下降沿量
wela = 0;
//段选
if(count != 2) //显示数字(除了带小数点那位)
{
P0 = table[datas[count]]; //显示数字
}
else // 显示带小数点那位数字
{
P0 = tableWithDot[datas[count]]; //显示带小数点数字
}
dula = 1; //打开锁存, 给它一个下降沿量
dula = 0;
//位选
P0 = _crol_(0xfd, count); //选择第(count + 1) 个数码管 (_crol_循环左移命令,包含在intrins中)
wela = 1; //打开锁存, 给它一个下降沿量
wela = 0;
delay(timeCount);
}
}
void main()
{
uchar i;
while(1)
{
//启动温度转换
sendChangeCmd();
//显示5次
for(i = 0; i < 5; i++)
{
display(tempValue);
}
tempValue=getTmpValue();
}
}
点击此处下载
ourdev_721004GC64H1.rar(文件大小:27K) (原文件名:51.rar)
要是实现单总线,还得加个读取DS18B20序列号的程序呢!
一周热门 更多>