目录
一、DS18B20温度传感器原理
1.1 内部结构
1.2 电路图
二、DS18B20温度传感器 操作步骤
通过单线总线端口访问DS18B20的协议如下:
- 初始化
- ROM 操作指令
- DS18B20 功能指令
- 每一次 DS18B20 的操作都必须满足以上步骤,若是缺少步骤或是顺序混乱,器件将不会返回值
2.1 初始化
- 和 DS18B20 间的任何通讯都需要以初始化开始,初始化序列如上图。
- 一个复位脉冲跟着一个存在脉冲表明 DS18B20 已经准备好发送和接收数据。
在初始化序列期间,拉低总线并保持480us 以发出(TX)一个复位脉冲,然后释放总线,进入接收状态(RX)。单总线是由5k上拉电阻拉到高电平的。当 DS18B20 检测到I/O引脚上的上升沿后,等待15-60us,然后发出一个由60-240us低电平信号构成的存在脉冲。
2.2 ROM操作指令
2.3 功能指令
2.4 写时序
有两种写时序,一种写1时序,一种写0时序。
所有写时序必须最少持续60us。包括两个写周期之间至少1us的恢复时间。
当总线从逻辑高电平拉到低电平时,写时序开始。
- 要写一个时序时,必须把数据线拉到低电平,然后释放,在写时序后的15us释放总线。当总线被释放时,5k的上拉电阻将拉高总线(这是写1)。总控制器要生成一个写0时序,必须把数据先拉到低电平并持续保持至少60us。
总结:当总线控制器初始化写时序后,DS18B20 在一个 15us 到 60us 的窗口内对I/O线采样。如果线上是高电平,就是写1。如果线上是低电平,就是写0。
2.5 读时序
总线控制器在发出“读指令”后必须立刻开始读时序。
所有的读时序必须最少60us,包括两个读周期间至少1u的恢复时间。
当总线从逻辑高电平拉到低电平时(至少保持1us),读时序开始。然后总线被释放。
DS1B20通过拉高或拉低总线来传输1或0。当传输逻辑0结束后,总线将被释放,通过上拉电阻回到上升沿状态。
三、代码
3.1 mian.c
#include "bsp_init.h"
#include "timer.h"
#include "bsp_seg.h"
#include "bsp_key.h"
#include "stdio.h"
#include "bsp_led.h"
#include "bsp_ds1302.h"
#include "bsp_onewire.h"
/******函数声明******/
void Key_Proc();
void Seg_Proc();
void Led_Proc();
/******数码管显示专用******/
unsigned char seg_buf[8];
unsigned char seg_string[10];
unsigned char pos = 0;
/******按键专用******/
unsigned char Key_value;
unsigned char Key_Down,Key_Old;
/******按键和显示函数减速专用******/
unsigned int Key_Slow_Down;
unsigned int Seg_Slow_Down;
/******ds1302专用******/
unsigned char ucRtc[3] = {11,22,33};//时分秒
unsigned int ms_count;//记录毫秒
unsigned char s_count;//记录秒
unsigned char ucled;
unsigned char state; //运行状态,按下按键后状态state变化
void main()
{
Cls_Peripheral(); //关闭外设
Timer1Init(); //定时器1初始化
EA = 1;
Set_Rtc(ucRtc); //初始化时间
while(1)
{
Key_Proc();
Seg_Proc();
Led_Proc();
}
}
void tm1_isr() interrupt 3
{
if(++Key_Slow_Down == 10)Key_Slow_Down = 0;
if(++Seg_Slow_Down == 10)Seg_Slow_Down = 0;
Led_Disp(ucled);
if(++ms_count == 1000) //记录运行时间
{
ms_count = 0;
s_count++;
}
Seg_Disp(seg_buf,pos);
if(++pos == 8) pos = 0;
}
void Key_Proc() //按键处理
{
if(Key_Slow_Down)return;
Key_Slow_Down = 1;
Key_value = Key_Read(); //读取按键按下的键码
//下降沿检测
Key_Down = Key_value & (Key_Old ^ Key_value);
Key_Old = Key_value;
if(Key_Down)
{
if(++state == 3)state = 0;
}
}
void Seg_Proc() //显示处理
{
if(Seg_Slow_Down)return;
Seg_Slow_Down = 1;
switch(state)
{
case 0:
sprintf(seg_string,"----%04.2f",read_temperature()/16.0); //将温度显示到数码管上
break;
case 1:
Read_Rtc(ucRtc);//读取ds1302中的时间,并将其放到数组中
sprintf(seg_string,"%02d-%02d-%02d",(unsigned int)ucRtc[0],(unsigned int)ucRtc[1],(unsigned int)ucRtc[2]);
break;
case 2:
sprintf(seg_string,"-----%3d",(unsigned int)s_count);
}
/****永远不变****/
Seg_Tran(seg_string,seg_buf);
}
void Led_Proc() //Led处理
{
switch(state)
{
case 0:
ucled = 0x03;break;
case 1:
ucled = 0x0C;break;
case 2:
ucled = 30;
}
}
3.2 bsp_onewire.c
#include "bsp_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()
{
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()
{
bit initflag = 0;
DQ =1;
Delay_OneWire(12);
DQ = 0;
Delay_OneWire(80); //延时大于480us
DQ = 1;
Delay_OneWire(10);
initflag = DQ;
Delay_OneWire(5);
return initflag;
}
/**
* @brief 温度读取函数
* @param 吴
* @retval 高、低温度的两个字节
* @functon 温度转换,并将其返回
*/
unsigned int read_temperature()
{
unsigned char low,high; //返回的高、低温度(8位)
init_ds18b20(); //初始化
Write_DS18B20(0xCC); //跳过ROM
Write_DS18B20(0x44); //进行温度转化
init_ds18b20(); //初始化
Write_DS18B20(0xCC); //跳过ROM
Write_DS18B20(0xBE); //进行温度转化
low = Read_DS18B20(); //温度低位
high = Read_DS18B20(); //温度高位
return (high << 8) | low;
}
3.3 bsp_onewire.h
#include <STC15F2K60S2.H>
sbit DQ = P1^4;
void Delay_OneWire(unsigned int t);
void Delay_OneWire(unsigned int t);
unsigned char Read_DS18B20();
unsigned int read_temperature();
四、板子实现
用手捂住温度传感器后显示的温度