写的不知道好不好,有什么不对的地方还请指出,谢了。
1、本节基于DS18B20 1总线通讯。
2、驱动DS18B20,代码3个:初始化DS18B20、写1字节、读1字节。
3、运用DS18B20,接口有7个:读取ROM编码、配置高温报警低温报警及精度、温度转换、拷贝寄存器值到EEPROM、召回EEPROM值到寄存器里、读取DS18B20的状态(好像没有什么用)、读取DS18B20的温度(float类型,精度自行选择)。
4、温度读取出来后用数码管来显示小数,目前数码管显示小数有点小问题。这个问题以后在解决。
5、DS18B20对时序有要求,故代码里有加入延迟处理。
#ifndef __DS18B20_H__
#define __DS18B20_H__
#include <reg52.h>
sbit wire = P2^2;//GPIO P2.2
extern unsigned char ROM[8];
//bit DS18B20_RST(void); //1、复位初始化DS18B20,如果返回0则初始化失败
//void write_1_byte_DS18B20(unsigned char); //2、向DS18B20写1字节
//unsigned char read_1_byte_DS18B20(void); //3、读DS18B20 1字节 之前的读取多移动了一位,哎 sb了
void view_DS18B20(void);//4、读取DS18B20 ROM编码 //0x33表示读取64位ROM编码0x55表示匹配ROM对应的器件0xf0表示搜索ROM
void acc_DS18B20(char TH, char TL, unsigned char z);//5、配置一个器件的TH高温报警温度和TL低温报警温度和温度精度z
void convert_DS18B20(unsigned char); //6、转换温度,x为选择使用的精度9位 10位 11位 12位,默认12位
void copy_acc_EEPROM_DS18B20(void); //7、拷贝配置好的寄存器的值到EEPROM里
void recall_EEPROM_DS18B20(void);//8、召回EEPROM里的3个字节数据到寄存器对应里面(高温、低温、精度)
bit wire_status_DS18B20(void); //9、读取DS18B20反馈状态 1bit 这个好像没什么用处
float read_temp_DS18B20(unsigned char);//10、读取DS18B20的温度,输入选择的精度9位 10位 11位 12位 9 10 11 12,默认12位
#endif
#include "delay.h"
#include <intrins.h>
#include "led.h"
#include "ds18b20.h"
//与DS18B20通讯传输数据的时候均是先传送低位最后传送高位
unsigned char ROM[8];
//1、复位初始化DS18B20
bit DS18B20_RST(void)
{
wire = 0;
delay_us(75); //拉低480us复位DS18B20
wire = 1; //释放数据线
delay_us(8); //延迟60us开始判断是否有应答信号
if(wire) //没有应答的话
{
delay_us(26);//延迟180us二次判断DS18B20回复存在信号,即应答ACK信号
if (wire)//还没有应答的话
{
return 0;//当函数返回0表示DS18B20初始化失败
}
else//有应答信号了
{
delay_us(26);//延迟180us判断是否器件释放总线
if (wire)//释放总线的话
{
delay_us(26);//再次延长180us
return 1;//当函数返回1表示DS18B20初始化成功
}
else
{
return 0;//当函数返回0表示DS18B20初始化失败
}
}
}
else//有应答信号了
{
delay_us(38);//延长240us
if (wire == 1)//如果器件释放总线的话
{
delay_us(38);//再次延长240us
return 1;//当函数返回1表示DS18B20初始化成功
}
else
{
return 0;//当函数返回0表示DS18B20初始化失败
}
}
}
//2、向DS18B20写1字节
void write_1_byte_DS18B20(unsigned char x)
{
unsigned char i=0;
for (i;i < 8;i++)
{
wire = 0;
_nop_(); //延迟大于1us
wire = x & 0x01;
delay_us(8);//延迟60us让DS18B20好采样
wire = 1;//释放总线
x = x >> 1;
}
}
//3、读DS18B20 1字节。。。。马来币之前dat返回数据没有取反,总线没有释放就直接读取数据了
unsigned char read_1_byte_DS18B20(void)
{
unsigned char i;
unsigned char dat=0;
for ( i=0 ; i < 8; i ++)
{
dat = dat >> 1;//放在for循环后面有问题,会向右多移动一位,怪不得之前的数据读取出来有问题
wire = 0;
_nop_();
wire = 1;//释放总线,等待DS18B20发送数据到总线上
_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();//延迟个6us时间在采集数据
if(wire)//这个if里面的数不建议写成if(wire);推荐写成if(wire==1);
{
dat += 0x80;
}
wire = 1;//释放总线
delay_us(8);//延迟60us
}
return dat;
}
//4、读取DS18B20 ROM编码 ,需要读取DS18B20 ROM编码
void view_DS18B20(void) //0x33表示读取64位ROM编码0x55表示匹配ROM对应的器件0xf0表示搜索ROM
{
unsigned char i;
DS18B20_RST();
write_1_byte_DS18B20(0x33);
for (i = 0; i < 8; i++)
{
ROM[i] = read_1_byte_DS18B20();
}
}
//5、配置一个器件的TH高温报警温度和TL低温报警温度和温度精度z
void acc_DS18B20(char TH,char TL,unsigned char z)
{
unsigned char i;//用来存储精度对应的指令
switch (z)
{
case 9:i = 0x1f;break;
case 10:i = 0x3f;break;
case 11:i = 0x5f;break;
case 12:i = 0x7f;break;
default:i = 0x7f;//默认12位精度
break;
}
DS18B20_RST();//复位初始化成功
write_1_byte_DS18B20(0xcc); //跳过64位ROM码检测
write_1_byte_DS18B20(0x4e);//配置寄存器指令。马来币这个语句忘记写了 不写那么配置数据坑定写不进去啊
write_1_byte_DS18B20(TH); //配置高温报警温度 最高位为1则表示负温度,为0则表示正温度,±1℃
write_1_byte_DS18B20(TL); //配置低温报警温度
write_1_byte_DS18B20(i); //i=0001 1111 0x1f 9位精度,转换时间93.75ms
//i=0011 1111 0x3f 10位精度,转换时间187.5ms
//i=0101 1111 0x5f 11位精度,转换时间375ms
//i=0111 1111 0x7f 12位精度,转换时间750ms
}
//6、转换温度,x为选择使用的精度9位 10位 11位 12位,默认12位
void convert_DS18B20(unsigned char x)
{
DS18B20_RST(); //初始化函数
write_1_byte_DS18B20(0xcc); //跳过64位ROM码检测
write_1_byte_DS18B20(0x44); //温度转换指令-功能命令
//x=0001 1111 0x1f 9位精度,转换时间93.75ms
//x=0011 1111 0x3f 10位精度,转换时间187.5ms
//x=0101 1111 0x5f 11位精度,转换时间375ms
//x=0111 1111 0x7f 12位精度,转换时间750ms
switch (x)
{
case 9: delay_ms(95); break;
case 10:delay_ms(190); break;
case 11:delay_ms(380); break;
case 12:delay_ms(750); break;
default:delay_ms(900); break;//默认按照12位精度转换时间
}
}
//7、拷贝配置好的寄存器的值到EEPROM里
void copy_acc_EEPROM_DS18B20(void)
{
DS18B20_RST();//初始化函数
write_1_byte_DS18B20(0xcc); //跳过64位ROM码检测
write_1_byte_DS18B20(0x48);//将配置好的寄存器的值拷贝到EEPROM里
}
//8、召回EEPROM里的3个字节数据到寄存器对应里面(高温、低温、精度)
void recall_EEPROM_DS18B20(void) //召回EEPROM里的3个字节数据到寄存器对应里面(高温、低温、精度)
{
DS18B20_RST(); //初始化DS18B20函数
write_1_byte_DS18B20(0xcc); //跳过64位ROM码检测
write_1_byte_DS18B20(0xb8); //操作指令将EEPROM里的数据拷贝到寄存器里
}
//9、读取DS18B20反馈状态 1bit 这个好像没什么用处
bit wire_status_DS18B20(void)
{
if(!wire)
{
delay_ms(1000);//延长1s时间
if (!wire)
{
return 1;//转换时长太长了,转换失败
}
else
{
LED_shan_suo(2);//led灯闪烁2次
return 0;//转换完成
}
}
LED_shan_suo(2);//led灯闪烁2次
return 0;//转换完成
}
//10、读取DS18B20的温度,输入选择的精度9位 10位 11位 12位 9 10 11 12,默认12位
float read_temp_DS18B20(unsigned char x)
{
bit a;//临时变量负责判断温度是正数还是负数,正数为0,负数为1
unsigned char TL = 0;
unsigned int TH = 0;
float result;
DS18B20_RST();//复位器件
write_1_byte_DS18B20(0xcc);//跳过ROM检测指令
write_1_byte_DS18B20(0xbe);//读取暂存寄存器使用的指令
TL = read_1_byte_DS18B20();//将读取的低温8位存起来
TH = read_1_byte_DS18B20();//将读取的高温8位存起来
DS18B20_RST();//强制复位,后面的数据不在读取了
//开始使用算法计算温度
if (TH < 8)
{
a = 0;//为正数
}
else
{
a = 1;//为负数
}
TH <<= 8;
TH += TL;//TH = TH | TL;
if (a)//判断TH是不是负温度
{
TH = ~TH + 1;//先转换为正数,主要是要处理数据
}
switch (x)
{
case 9: TH>>=3;result = TH * 0.5; break;//右移表示精度不需要太高需要匹配9位精度
case 10: TH>>=2;result = TH * 0.25; break;//右移表示精度不需要太高需要匹配10位精度
case 11: TH>>=1;result = TH * 0.125; break;//右移表示精度不需要太高需要匹配11位精度
case 12: TH>>=0;result = TH * 0.0625; break;
default:result = TH * 0.0625; break;
}
if (!a)
{
return result;//返回正小数
}
else
{
return -result;//返回负小数
}
}
//11、搜索是否温度有报警0xec指令 只有温度超过设定值后才会响应