一,原理
DS18B20为单总线数字温度传感器,先来读手册来知道它的原理和结构
1.DS18B20的基本知识
1:测温范围为-55℃到+125℃,在-10℃到+85℃范围内误差为±0.4°。
2:返回16位二进制温度数值
3:主机和从机通信使用单总线,即使用单线进行数据的发送和接收
4:在使用中不需要任何外围元件,独立芯片即可完成工作。
5:掉电保护功能 DS18B20 内部含有 EEPROM ,通过配置寄存器可以设定数字转换精度和报警温度,在系统掉电以后,它仍可保存分辨率及报警温度的设定值。
6:每个DS18B20都有独立唯一的64位-ID,此特性决定了它可以将任意多的DS18b20挂载到一根总线上,通过ROM搜索读取相应DS18B20的温度值
7:宽电压供电,电压2.5V~5.5V
2.内部寄存器
读手册可以知道,DS18B20内部有ROM单元和9字节的高速暂存器
第0字节:温度数据的低8位。
第1字节:温度数据的高8位。
第3字节:TH用户字节,设置报警温度最高值。
第4字节:TL用户字节,设置报警温度最低值。
第5字节:配置寄存器,设置转换精度,默认12位。
第6字节和第7字节:保留,不用管。
第8字节:CRC码。
DS18B20以16位带符号位扩展的二进制补码形式读出BIT0-BIT3存储小数部分,
BIT4-BIT10为整数部分,BIT11-BIT15则为符号位
1.官方会提供onewire的相关代码文件,但是在第15届蓝桥杯中,只给了.C文件没有给.h文件,应该是官方故意挖的坑,所以我们得自己配置.h文件。
2.官方提供的延时函数中提供的频率为12MHZ,而单片机上面的却是1MHZ的,所以我们应该改延时函数的时间扩大10~12倍,否则无法驱动
二.代码实现思路
DS18B20单线通信功能是分时完成的,它有严格的时隙概念,如果出现序列混乱,器件将不响应主机,因此读写时序很重要。
而单总线访问DS18B20的协议如下
步骤1: 复位初始化
步骤2: ROM操作指令
步骤3: DS18B20功能指令
DS18B20的高速暂存存储器由9个字节组成,当温度转换命令发布后,经转换所得的温度值以二字节补码形式存放在高速暂存存储器的第0和第1个字节。在上电状态下,DS18B20默认的精度为12位。启动后它保持低功耗等待状态。当需要执行温度测量和AD转换时,总线控制器必须发出温度转换命令。在那之后,产生的温度数据以两个字节的形式被存储到高速暂存器的温度寄存器中,DS18B20继续保持等待状态。单片机可通过单线接口可以读到该数据,读取时低位在前,高位在后。
读手册可以知道 三个DS18B20指令的位置
1.这个是skip ROM寄存器,位置是0XCC
作用是:跳过ROM指令,忽略64位ROM地址,直接向DS18B20发起各种温度转换指令。
2.这个是温度转化指令 地址是0X44
作用是:温度转换指令,启动DS18B20进行温度转换,转换时间最长为500ms(典型值为200ms),结果保存在高速RAM中。
3,这个是读暂存器指令,地址是0xBE作用是:读暂存器指令,读取高速暂存存储器9个字节的内容。
所以我们得现在头文件定义好着三个指令的位置
读取一次DS18B20温度基本操作:
我们分两步走,先转化,在读取
转化部分:
1.主机对DS18B20进行复位初始化
2.主机向DS18B20写0xCC命令,跳过ROM
3. 主机向DS18B20写0x44命令,开始进行温度转换,并等待温度转化完成
bit init_ds18b20(void)
{
bit initflag = 0;
DQ = 1;
Delay_OneWire(12);
DQ = 0;
Delay_OneWire(80);
DQ = 1;
Delay_OneWire(10);
initflag = DQ;
Delay_OneWire(5);
return initflag;
}
void DS18B20_Start(void)
{
init_ds18b20();
Write_DS18B20(OW_SKP_ROM);
Write_DS18B20(DS18B20_CONVERT);
}
读取部分:
1.主机对DS18B20进行复位初始化。
2.主机向DS18B20写0xCC命令,跳过ROM。
3.主机向DS18B20写0xBE命令
4.读取发出的第0个数据和第1个数据
5.通过算法整合出数据
int DS18B20_Get(void)
{
unsigned char low=0,high=0;
int temp =0;
init_ds18b20();
Write_DS18B20(OW_SKP_ROM);
Write_DS18B20(DS18B20_READ);
low= Read_DS18B20();
high =Read_DS18B20();
init_ds18b20();
temp=0x00;
temp=high;
temp=(temp<<8)|low;
if(temp&0xf800==0x0000)
{
temp>>=4;
temp=temp*10;
temp=temp+(low&0x0f)*0.625;
}
// temp=(high<<4);
// temp|=(low>>4);
return temp;
}
三,代码演示
主函数
#include "Timer0.h"
#include "uart.h"
#include "onewire.h"
//unsigned char dat=0;
//unsigned int flag=0;
//unsigned long t=0;
int T=0;
void main(void)
{
ALL_Init();
// INT0_Init();
//Timer0Init();
UartInit();
DS18B20_Start();
T=DS18B20_Get();
while(1)
{
DS18B20_Start();
T=DS18B20_Get();
//keyscans16();
display1(T/1000%10,T/100%10);
display2(T/10%10,T%10);
}
}
DS18B20模块函数
/* # 单总线代码片段说明
1. 本文件夹中提供的驱动代码供参赛选手完成程序设计参考。
2. 参赛选手可以自行编写相关代码或以该代码为基础,根据所选单片机类型、运行速度和试题
中对单片机时钟频率的要求,进行代码调试和修改。
*/
//
#include "onewire.h"
void Delay_OneWire(unsigned int t)
{
unsigned char i;
while(t--){
for(i=0;i<12;i++);
}
}
//
void Write_DS18B20(unsigned char dat)
{
unsigned char i;
for(i=0;i<8;i++)
{
DQ = 0;
DQ = dat&0x01;
Delay_OneWire(5);
DQ = 1;
dat >>= 1;
}
Delay_OneWire(5);
}
//
unsigned char Read_DS18B20(void)
{
unsigned char i;
unsigned char dat;
for(i=0;i<8;i++)
{
DQ = 0;
dat >>= 1;
DQ = 1;
if(DQ)
{
dat |= 0x80;
}
Delay_OneWire(5);
}
return dat;
}
//
bit init_ds18b20(void)
{
bit initflag = 0;
DQ = 1;
Delay_OneWire(12);
DQ = 0;
Delay_OneWire(80);
DQ = 1;
Delay_OneWire(10);
initflag = DQ;
Delay_OneWire(5);
return initflag;
}
void DS18B20_Start(void)
{
init_ds18b20();
Write_DS18B20(OW_SKP_ROM);
Write_DS18B20(DS18B20_CONVERT);
}
int DS18B20_Get(void)
{
unsigned char low=0,high=0;
int temp =0;
init_ds18b20();
Write_DS18B20(OW_SKP_ROM);
Write_DS18B20(DS18B20_READ);
low= Read_DS18B20();
high =Read_DS18B20();
init_ds18b20();
temp=0x00;
temp=high;
temp=(temp<<8)|low;
if(temp&0xf800==0x0000)
{
temp>>=4;
temp=temp*10;
temp=temp+(low&0x0f)*0.625;
}
// temp=(high<<4);
// temp|=(low>>4);
return temp;
}
四,最终效果
可以看出,现在室温是25度,往年蓝桥杯比赛只要求显示整数部分即可