单片机 | 温度传感器(DS18B20)

一、参数

|------|-----------------------------------------------|
| 参数 | 数值 |
| 检测范围 | -55℃~125℃ |
| 精度 | ±0.5v |
| 工作电压 | 3v~5.5v |
| 分辨率 | 9位:0.5℃ 10位:0.25℃ 11位:0.0125℃ 12位(默认): 0.0625 |

二、操作ROM指令

读 ROM(0x33)

搜索ROM(0xF0)

匹配ROM(0x55)

跳过ROM(0xCC)

报警搜索(0xEC)

接上拉电阻的目的;

51单片机拉高,DS18B20拉高,引脚保持高电平

三、温度采集流程

复位:发送复位脉冲,拉低总线,然后释放,等待传感器响应脉冲

发送0xCC,跳过ROM:单总线指令,跳过ROM寻址,直接操作芯片

发送0x44,开启温度转换

延时1s:保证温度转换完成

复位:重新初始化总线,为读取数据做准备

发送0xCC,跳过ROM:再次跳过ROM,准备读取数据

发送0xBE,读取温度

读取两个字节温度:先读低字节,在读高字节,组合成最终温度值

四、DS18B20时序

复位:

主机先将总线拉低至少480us,再释放总线(至少15us),代表主机发送了一个复位脉冲

主机如果在60~240us检测到总线出现低电平,代表DS18B20恢复了一个"存在脉冲"

DS18B20最终释放总线,总线为高电平

写时序:

写0时序:

主机总线拉低大于60us

DS18B20在60us内进行采样,如果采到低电平,代表主机发送了一个'0'

主机释放总线,将引脚拉高

写1时序:

主机将总线拉低大于1us

主机释放总线,将引脚拉高

DS18B20在45us内进行采样,如果采到高电平,代表主机发了一个1

读时序:

主机将总线拉低大于1us,释放总线,引脚变为高电平

主机在15u内采样

若采到一个高电平,代表读到1

若采到一个低电平,代表读到0

最终DS18B20释放总线

示例代码:

cpp 复制代码
#include <reg51.h>
#include "bs18b20.h"
#include "delay.h"
#include "uart.h"
#include <intrins.h>
#include <stdio.h>

#define PIN_HIGH		(P3 |= (1 << 7))  //将P37引脚拉高
#define PIN_LOW			(P3 &= ~(1 << 7)) //将P37引脚拉低
#define PIN_CHECK		((P3 & (1 << 7))!= 0) //判断是否为高电平		

//复位
int Bs18b20_Reset(void)
{
	int time = 0;
	//发送一个复位脉冲
	PIN_LOW;
	Delay10us(70);
	PIN_HIGH;
	Delay10us(5);

	//等待低电平到来
	while(PIN_CHECK && time < 30)
	{
		Delay10us(1);
		time++;					
	}
	if(time >= 30)
	{
		UartSendStr("wait ds18b20_low timeout!\r\n");
		return -1;
	}

	//等待高电平到来
	time = 0;
	while(!PIN_CHECK && time < 30)
	{
		Delay10us(1);
		time++;	
	}
	if(time >= 30)
	{
		UartSendStr("wait ds18b20_high timeout!\r\n");
		return -2;
	}

	return 1;
}


//写时序
void Bs18b20_Write(unsigned char dat)
{
	int i = 0;

	for(i = 0; i < 8; i++)
	{	//写1时序
		if(dat & 1)		 //如果主机发了一个高电平
		{
			PIN_LOW;
			_nop_();
			_nop_();
			PIN_HIGH;
			Delay10us(5);
		}
		else		//写0时序
		{
			PIN_LOW;
			Delay10us(6);
			PIN_HIGH;
		}
		dat >>= 1; //每次再右移一位 进循环判断
	}
}

//读时序
unsigned char Bs18b20_Read(void)
{
	int i = 0;
	unsigned char dat = 0;

	for(i = 0; i < 8; i++)
	{	
		//进行采样
		PIN_LOW;
		_nop_();
		_nop_(); 
		PIN_HIGH;
		//进行采样
		_nop_();
		_nop_();
		_nop_();
		
		//若采到高电平,将对应位置成1
		if(PIN_CHECK)
		{
			dat |= (1 << i);
		}
		Delay10us(6);	
	}

	return dat;
}

//获得温度(根据采集温度流程)
float Get_Temp(void)
{
	unsigned char temp_low = 0;
	unsigned char temp_high = 0;
	short temp = 0;

	Bs18b20_Reset();   //复位

	Bs18b20_Write(0xCC);	//跳过 ROM
							
	Bs18b20_Write(0x44);	//开启温度转换

	Delay1ms(1000);		   //延时1s

	Bs18b20_Reset();	   //复位

	Bs18b20_Write(0xCC);	//跳过ROM

	Bs18b20_Write(0xBE);	//读取温度

	temp_low = Bs18b20_Read();	  //读低位
	temp_high = Bs18b20_Read();   //读高位

	temp = temp_high << 8;
	temp |= temp_low; 		  //组合成最终温度值

	return temp * 0.0625;
}

void Delay10us(unsigned int n)	//@11.0592MHz
{
	unsigned char data i;

	_nop_();
	_nop_();
	_nop_();
	i = 2 * n;
	while (--i)
	{			
		_nop_();
		_nop_();
	}
}

void delay(unsigned int n)
{
	while(n--);
}

void Delay1ms(unsigned int n)
{
	while(n--)
	{
		Delay10us(100);	
	}
}

xdata char RecvBuff[32];
int pos = 0;

//串口接收中断
void Uart_handler(void)		interrupt 4
{
	if((SCON & (1 << 0)) == 1)		  //判断是否接收到数据
	{
		if(pos < sizeof(RecvBuff))
		{
			RecvBuff[pos++] = SBUF;
			RecvBuff[pos] = 0;
		}

		SCON &= ~(1 << 0);
	}
}

void UartInit(void)
{
	//配置串口工作模式为8位UART、波特率可变
	SCON &= ~(3 << 6); //M1(bit6)、M0(bit7)清0
	SCON &= ~(1 << 7); //M0清0
	SCON |= (1 << 6);  //M1置1

	//允许串口接收数据
	SCON |= (1 << 4);  //REN(bit4)置1

	//波特率翻倍,PCON寄存器的SMOD0和SMOD1共同指定串口工作方式
	PCON &= ~(3 << 6);
	PCON |= (1 << 7); //SMOD1(bit7)置1 波特率翻倍
	PCON &= ~(1 << 6);  //SMOD0(bit 6)清0 SMOD1共同指定串口工作方式

	//配置定时器1工作模式为8位自动重装载(产生波特率)
	TMOD &= ~(0x0F << 4); //高四位清零
	TMOD &= ~(1 << 4); //M0(bit4)清0
	TMOD |= (1 << 5); //M1(bit5)置1

	//向TH1和TL1中装入定时器初值
	TH1 = 232;
	TL1 = 232;

	//允许定时器1开始计数
	TCON |= (1 << 6); //TR1(bit6)置1

	//开启总中断
	IE |= (1 << 7);

	//允许串口产生中断
	IE |= (1 << 4); //ES(bit4)置1
}

//发送单个字符
void UartSendAscii(unsigned char ch)
{
	SBUF = ch; //发送字符

	while((SCON & (1 << 1)) == 0); 	 //判断是否发完

	SCON &= ~(1 << 1); //将标志位清0
}

//发送字符串
void UartSendStr(const char *pstr)
{
	while(*pstr != '\0')
	{
		UartSendAscii(*pstr++);
	}
}

//发送指定长度的数据
void UartSendBuff(const char *pstr, int len)
{
	while(len--)
	{
		UartSendAscii(*pstr++);	
	}
}

int main(void)
{
	int ret = 0;
	float temp = 0;
	xdata unsigned char buff[32] = {0};

	UartInit();

	while(1)
	{
		temp = Get_Temp();
		sprintf(buff, "temp = %.2f\r\n", temp);
		UartSendStr(buff);		
	}

	return 0;
}
相关推荐
天天爱吃肉82182 小时前
【电机双闭环控制问答:PI 输出为何不同?测功机台架选型有多关键】
功能测试·嵌入式硬件·信息可视化·汽车
学嵌入式的小杨同学2 小时前
STM32 进阶封神之路(二十四):低功耗实战全攻略 —— 电池供电传感器节点(RTC 唤醒 + DHT11 采集 + 功耗优化)
c++·stm32·单片机·嵌入式硬件·mcu·架构·硬件架构
电子工程师成长日记-C512 小时前
51单片机热敏电阻测温
单片机·嵌入式硬件·51单片机
Hello World . .2 小时前
51单片机——UART 串口通信
网络·嵌入式硬件·51单片机
熬夜有啥好2 小时前
51 单片机基础架构与最小系统详解
单片机·嵌入式硬件·51单片机
ACP广源盛139246256732 小时前
ASW3810@ACP#4 路差分 2:1/1:2 双向多路复用 / 解复用器 产品规格与应用总结
大数据·单片机·嵌入式硬件·计算机外设·电脑
学嵌入式的小杨同学2 小时前
STM32 进阶封神之路(二十三):低功耗深度解析 —— 从睡眠模式到停机模式(底层原理 + 寄存器配置)
c++·stm32·单片机·嵌入式硬件·mcu·架构·硬件架构
小飞菜涅3 小时前
FAST-LIVO2相机内参标定
linux·嵌入式硬件·ubuntu·相机
我在人间贩卖青春5 小时前
SysTick 定时器
单片机·嵌入式硬件·滴答定时器·systick