一、硬件电路:
DS18B20内部电路:
(客观题可能会考,但是编程时由于我们直接输入命令让模块自己工作,所以我们并不需要了解该电路)
![](https://i-blog.csdnimg.cn/blog_migrate/28cf746d5bef617273a6a5c54648b58c.png)
我们需要了解的是三部分:64位ROM、暂存器、EEPROM存储器
(1)64位ROM:存放地址码,其中包括了8位CRC校验码(由CRC发生器产生)+48位序列号(每个产品不同)+8位系列码(DS18B20都为0x28)
(2)暂存器:
![](https://i-blog.csdnimg.cn/blog_migrate/925c8967973cbd86357a0897cbc5b19a.jpeg)
(3)EEPROM存储器:包括TH、TL寄存器和配置寄存器CR
![](https://i-blog.csdnimg.cn/blog_migrate/99acadc61359dcec86592c86f1d193ff.png)
TH,TL:规定最高温度和最低温度
CR:规定了分辨率与最大转换时间
![](https://i-blog.csdnimg.cn/blog_migrate/1112cc7347f85c0e295eab584e8caf90.png)
![](https://i-blog.csdnimg.cn/blog_migrate/f90874fcbfaa0bfa77671a55d89246ad.png)
蓝桥杯板子上的电路
![](https://i-blog.csdnimg.cn/blog_migrate/876323844324745690a1bc148bf8535d.png)
该电路可以分为两部分,一部分为1,3脚的供电部分;一部分为2接上拉电阻以满足漏极开路门输入输出
二、命令:
ROM命令:
(由于板子上只有一个DS18B20,所以只需要记住0xCC跳过ROM操作就行)
![](https://i-blog.csdnimg.cn/blog_migrate/edd630b800ed1d09fa86b07e87344194.jpeg)
2.功能命令:(重要)
![](https://i-blog.csdnimg.cn/blog_migrate/396d01a27f5dbd0ebe93e015fdb69cee.jpeg)
三、具体操作步骤:(每发一个命令都要按照这个步骤,而不能连续发功能命令)
复位——》ROM命令——》功能命令
复位:
(1)首先将总线拉低480us,产生复位脉冲,然后释放总线(拉高电平)。
(2)这时DS8B20检测到请求之后,会将总线拉低60~240us,来表示应答,最后释放总线。
(3)单片机可以选择在第一次释放总线后60~240us去读取总线的电平,如果是低电平,那么表示初始化成功(基本不用这个操作)
![](https://i-blog.csdnimg.cn/blog_migrate/b94334d0a5e69a116ab8504887bc7aec.png)
写操作:(低位先行)
(1)写“0”操作:将总线拉低60到120us,再释放总线
(2)写“1”操作:将总线拉低小于15us,再释放总线
(3)一个写操作总时间必须大于60us,每两个写操作之间必须间隔1us
![](https://i-blog.csdnimg.cn/blog_migrate/0ad218fe91cbacf2bddb5314749cb118.png)
读操作:(低位先行)
(1)首先将总线拉低然后释放,让DS18B20知道我们要开始读数据了,然后DS18B20就会开始传数据
(2)然后我们就要在15us内将总线传输的数据读走
(3)一个读操作总时间大于60us,每两个读操作之间间隔1us
![](https://i-blog.csdnimg.cn/blog_migrate/c1a7169442e92f5c37d49911802d169b.png)
四、DS18B20实验:
![](https://i-blog.csdnimg.cn/blog_migrate/7516d7c13e43d268ab1d595c6f426658.png)
我根据上面手册中的时序写了一份代码,但是实际的时序可能并不相同,我还是建议可以自己写一下收获会更多,但是比赛的时候建议直接用官方给的代码(写的不好仅供参考)
(1)公共函数:
#ifndef _PUBLIC_H
#define _PUBLIC_H
#include "STC15F2K60S2.H"
#define u8 unsigned char
#define u16 unsigned int
void Delay_1ms(u16 num);
void Close_All(void);
void Delay_10us(u16 num);
#endif
#include "Public.h"
// 延时函数(最小约1ms@12MHz)
void Delay_1ms(u16 num)
{
unsigned int i;
while(num--)
for(i=0; i<628; i++);
}
/*
输入变量:无
输出变量:无
功能:关闭蜂鸣器和继电器
*/
void Close_All(void)
{
//关闭蜂鸣器和继电器
P0 = 0x00;
P2 = (P2 & 0x1f) | 0xA0;
P2 &= 0x1f;
//关闭LED灯
P0 = 0xff;
P2 = (P2 & 0x1F) | 0x80;
P2 &= 0x1f;
}
void Delay_10us(u16 num)
{
u16 i;
while(num--)
for(i=0; i<5; i++);
}
(2)主函数:
// 使用程序前,将J13调整为IO模式(2-3脚短接)
#include "Public.h"
#include "stdio.h"
u8 SEG_COT[9];
u8 SEG_Code[8];
u8 SEF_POS = 0;
u16 SEG_delay;
void SEG_TSL(u8 *input,u8 *output);
void SEG_Show(u8 num,u16 PIS);
void Timer_0_Init(u16 time);
void SEG_Proc();
sbit DQ = P1^4;
void DS18B20_Init();
void DS18B20_Write(u8 w_dat);
u8 DS18B20_Read();
// 主函数
void main(void)
{
Close_All();
Timer_0_Init(1000);
while(1)
{
SEG_Proc();
}
}
void SEG_Proc()
{
u8 LSB,MSB;
u16 t_temp;
if(SEG_delay)return;
SEG_delay = 1;
DS18B20_Init();
DS18B20_Write(0xCC);
//转换温度
DS18B20_Write(0x44);
DS18B20_Init();
DS18B20_Write(0xCC);
//读取暂存器
DS18B20_Write(0xBE);
//温度数据低八位
LSB = DS18B20_Read();
//温度数据高八位
MSB = DS18B20_Read();
t_temp = LSB | (MSB<<8);
if((t_temp & 0xf800) == 0)//符号位为0
sprintf(SEG_COT, " %2.2f", t_temp*0.0625);
else if((t_temp | 0x07ff) == 1)//符号位为1
sprintf(SEG_COT, "-%04.2f", ((~t_temp)+1)*0.0625);//负数的补码要进行取反加一操作
SEG_TSL(SEG_COT,SEG_Code);
}
void DS18B20_Init()
{
u8 b_temp=1,time_out=10;
while(b_temp && ((time_out--) != 0))
{
DQ = 0;
Delay_us(48);
DQ = 1;
Delay_us(5);
b_temp = DQ;
}
Delay_us(20);
}
void DS18B20_Write(u8 w_dat)
{
u8 i=0;
for(i=0;i<8;i++)
{
DQ = 0;
Delay_us(1);
DQ = w_dat&0x01;
Delay_us(5);
DQ = 1;
w_dat >>= 1;
}
}
u8 DS18B20_Read()
{
u8 r_dat=0;
u8 i=0;
for(i=0;i<8;i++)
{
DQ = 0;
r_dat >>= 1;
DQ = 1;
Delay_us(1);
if(DQ)
{
r_dat |= 0x80;
}
Delay_us(5);
}
return r_dat;
}
/***************************数码管*****************************/
/*
输入变量:input,输入字符数组;output:输出16进制数数组
输出变量:无
功能:将字符串转化为对应数码管显示的16进制数
注意:记得定义数组——u8 SEG_COT[9];u8 SEG_Code[8];
*/
void SEG_TSL(u8 *input,u8 *output)
{
u8 i=0,temp=0,j=0;
for(i=0;i<8;i++,j++)
{
switch(input[j])
{
case '0': temp = 0xc0; break;
case '1': temp = 0xf9; break;
case '2': temp = 0xa4; break;
case '3': temp = 0xb0; break;
case '4': temp = 0x99; break;
case '5': temp = 0x92; break;
case '6': temp = 0x82; break;
case '7': temp = 0xf8; break;
case '8': temp = 0x80; break;
case '9': temp = 0x90; break;
case 'A': temp = 0x88; break;
case 'B': temp = 0x83; break;
case 'C': temp = 0xc6; break;
case 'D': temp = 0xA1; break;
case 'E': temp = 0x86; break;
case 'F': temp = 0x8E; break;
case 'H': temp = 0x89; break;
case 'L': temp = 0xC7; break;
case 'N': temp = 0xC8; break;
case 'P': temp = 0x8c; break;
case 'U': temp = 0xC1; break;
case '-': temp = 0xbf; break;
case ' ': temp = 0xff; break;
default: temp = 0xff;
}
if(input[j+1] == '.')
{
temp &= 0x7f;
j++;
}
output[i] = temp;
}
}
/*
输入变量:num,要显示数据;PIS,显示位置,从左到右分别为0-7
输出变量:无
功能:操作138译码器,4-7分别对应Y4-Y7,其余都会使译码器不起作用
注意:需要把存放从1-f对应的16进制数数组也移植
*/
void SEG_Show(u8 num,u16 PIS)
{
//消影
P0 = 0xff;
P2 = (P2 & 0x1f) | 0xE0;
P2 &= 0x1f;
//改变显示位置
P0 = 0x01<<PIS;
P2 = (P2 & 0x1f) | 0xC0;
P2 &= 0x1f;
//改变数据
P0 = num;
P2 = (P2 & 0x1f) | 0xE0;
P2 &= 0x1f;
}
/***************************定时器*****************************/
/*
输入变量:定时时长___us
输出变量:无
功能:配置并开启定时器0
*/
void Timer_0_Init(u16 time)
{
//12T模式
AUXR &= 0x7f;
//定时器0 模式0
TMOD &= 0xf0;
//设置初值
TH0 = (65536-time)/256;
TL0 = (65536-time)%256;
//打开中断
ET0 = 1;
EA = 1;
//开始计数
TR0 = 1;
}
void Timer_0_IT(void) interrupt 1
{
if(SEG_delay++ == 500)SEG_delay = 0;//0.5s
SEG_Show(SEG_Code[SEF_POS],SEF_POS);
if(++SEF_POS == 8 )SEF_POS = 0;
}
根据官方写的时序:
(1)官方给的库函数
#ifndef __ONEWIRE_H
#define __ONEWIRE_H
#include "Public.h"
sbit DQ = P1^4;
void Write_DS18B20(unsigned char dat);
unsigned char Read_DS18B20(void);
bit init_ds18b20(void);
#endif
#include "onewire.h"
//单总线内部延时函数
void Delay_OneWire(unsigned int t)
{
unsigned char i;
while(t--){
for(i=0;i<8;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;
}
//DS18B20初始化
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;
}
(2)根据官方给的库函数写的主函数
// 使用程序前,将J13调整为IO模式(2-3脚短接)
#include "Public.h"
#include "stdio.h"
#include "onewire.h"
u8 SEG_COT[9];
u8 SEG_Code[8];
u8 SEF_POS = 0;
u16 SEG_delay;
void SEG_TSL(u8 *input,u8 *output);
void SEG_Show(u8 num,u16 PIS);
void Timer_0_Init(u16 time);
void SEG_Proc();
// 主函数
void main(void)
{
Close_All();
Timer_0_Init(1000);
while(1)
{
SEG_Proc();
}
}
u16 TEMP_Proc();
void SEG_Proc()
{
float temper;
u16 t_temp;
if(SEG_delay)return;
SEG_delay = 1;
t_temp = TEMP_Proc();
if(!(t_temp & 0xf800))//符号位为0
{
temper = t_temp*0.0625;
sprintf(SEG_COT, " %2.2f", temper);
}
else if(t_temp | 0x07ff)//符号位为1
{
temper = ((~t_temp)+1)*0.0625;
sprintf(SEG_COT, "-%04.2f", temper);
}
SEG_TSL(SEG_COT,SEG_Code);
}
u16 TEMP_Proc()
{
u8 LSB,MSB;
init_ds18b20();
Write_DS18B20(0xcc);
Write_DS18B20(0x44);
init_ds18b20();
Write_DS18B20(0xcc);
Write_DS18B20(0xbe);
LSB = Read_DS18B20();
MSB = Read_DS18B20();
init_ds18b20();
return LSB | (MSB<<8);
}
/***************************数码管*****************************/
/*
输入变量:input,输入字符数组;output:输出16进制数数组
输出变量:无
功能:将字符串转化为对应数码管显示的16进制数
注意:记得定义数组——u8 SEG_COT[9];u8 SEG_Code[8];
*/
void SEG_TSL(u8 *input,u8 *output)
{
u8 i=0,temp=0,j=0;
for(i=0;i<8;i++,j++)
{
switch(input[j])
{
case '0': temp = 0xc0; break;
case '1': temp = 0xf9; break;
case '2': temp = 0xa4; break;
case '3': temp = 0xb0; break;
case '4': temp = 0x99; break;
case '5': temp = 0x92; break;
case '6': temp = 0x82; break;
case '7': temp = 0xf8; break;
case '8': temp = 0x80; break;
case '9': temp = 0x90; break;
case 'A': temp = 0x88; break;
case 'B': temp = 0x83; break;
case 'C': temp = 0xc6; break;
case 'D': temp = 0xA1; break;
case 'E': temp = 0x86; break;
case 'F': temp = 0x8E; break;
case 'H': temp = 0x89; break;
case 'L': temp = 0xC7; break;
case 'N': temp = 0xC8; break;
case 'P': temp = 0x8c; break;
case 'U': temp = 0xC1; break;
case '-': temp = 0xbf; break;
case ' ': temp = 0xff; break;
default: temp = 0xff;
}
if(input[j+1] == '.')
{
temp &= 0x7f;
j++;
}
output[i] = temp;
}
}
/*
输入变量:num,要显示数据;PIS,显示位置,从左到右分别为0-7
输出变量:无
功能:操作138译码器,4-7分别对应Y4-Y7,其余都会使译码器不起作用
注意:需要把存放从1-f对应的16进制数数组也移植
*/
void SEG_Show(u8 num,u16 PIS)
{
//消影
P0 = 0xff;
P2 = (P2 & 0x1f) | 0xE0;
P2 &= 0x1f;
//改变显示位置
P0 = 0x01<<PIS;
P2 = (P2 & 0x1f) | 0xC0;
P2 &= 0x1f;
//改变数据
P0 = num;
P2 = (P2 & 0x1f) | 0xE0;
P2 &= 0x1f;
}
/***************************定时器*****************************/
/*
输入变量:定时时长___us
输出变量:无
功能:配置并开启定时器0
*/
void Timer_0_Init(u16 time)
{
//12T模式
AUXR &= 0x7f;
//定时器0 模式0
TMOD &= 0xf0;
//设置初值
TH0 = (65536-time)/256;
TL0 = (65536-time)%256;
//打开中断
ET0 = 1;
EA = 1;
//开始计数
TR0 = 1;
}
void Timer_0_IT(void) interrupt 1
{
if(SEG_delay++ == 500)SEG_delay = 0;//0.5s
SEG_Show(SEG_Code[SEF_POS],SEF_POS);
if(++SEF_POS == 8 )SEF_POS = 0;
}