• 【51单片机】DS18B20(江科大)


    一、DS18B20温度传感器

    1.DS18B20介绍

    · DS18B20是一种常见的数字温度传感器,其控制命令和数据都是以数字信号的方式输入输出,相比较于模拟温度传感器,具有功能强大、硬件简单、易扩展、抗干扰性强等特点
    · 测温范围 :- 55℃到+125℃
    · 通信接口:1-Wire(单总线)
    · 其它特征:可形成总线结构、内置温度报警功能、可寄生供电

    2.引脚及应用电路

    在这里插入图片描述
    本开发板原理图如图:

    本开发板的IO口已经外接了一个电阻了(与AT24C02类似),所以这个就没有再单独接一个电阻
    在这里插入图片描述

    3.内部结构框图

    在这里插入图片描述
    parasite power circuit:是寄生电路部分,也就是说DS18B20可以不用通过VDD来进行供电,通过DQ口接电源也可以进行供电。DQ为高电平时,会对电容CPP进行充电,DQ为低电平时,电容会进行供电。
    64-BIT ROM:作为器件地址,用于总线通信的寻址
    MEMORY CONTROL LOGIC: 存储控制逻辑,用于控制数据的传输
    SCRATCHPAD(暂存器):用于总线的数据交互(RAM)
    TEMPERATURE SENSOR:模拟温度传感器
    ALARM HIGH TRIGGER REGISTER:报警高位触发寄存器,存储温度上限阈值
    ALARM LOW TRIGGER REGISTER: 报警低位触发寄存器,存储温度下限阈值
    CONFIGURATION REGISTER:配置寄存器,用于设置分辨率(精度)
    EEPROM: 用于保存温度触发阈值和配置参数
    8-BIT CRC GENERATOR: 8位CRC生成器(CRC,循环冗余码,一种校验码)

    存储器结构:
    在这里插入图片描述
    Byte0和Byte1分别存储温度的低位和高位,默认为85

    不能直接读写EEPROM,需要先将数据写入存储器,然后通过通信,将数据在写入EEPROM,读出数据同理

    Byte5、Byte6和Byte7为保留字段

    4.单总线介绍

    ·单总线(1-Wire BUS)是由Dallas公司开发的一种通用数据总线
    ·一根通信线:DQ
    ·异步、半双工
    ·单总线只需要一根通信线即可实现数据的双向传输,当采用寄生供电时,还可以省去设备的VDD线路,此时,供电加通信只需要DQ和GND两根线
    在这里插入图片描述

    单总线电路规范
    ·设备的DQ均要配置成开漏输出模式(类似于IIC)

    ·DQ添加一个上拉电阻,阻值一般为4.7KΩ左右(类似于IIC)

    ·若此总线的从机采取寄生供电,则主机还应配一个强上拉输出电路(像读EEPROM等耗电操作仅仅靠弱上拉是不行的)
    在这里插入图片描述

    单总线时序结构
    ·初始化:主机将总线拉低至少480us,然后释放总线,等待15 ~ 60us后,存在的从机会拉低总线60 ~ 240us以响应主机,之后从机将释放总线(实际写程序中,一般取中间值)
    在这里插入图片描述

    ·发送一位:主机将总线拉低60 ~ 120us,然后释放总线,表示发送0;主机将总线拉低1 ~ 15us,然后释放总线,表示发送1。从机将在总
    线拉低30us后(典型值)读取电平,整个时间片应大于60us

    也就是说,在30us这个时间点,读取总线的电平状态,如果是高电平,则表示发送1,如果是低电平,则表示发送0
    在这里插入图片描述
    · 接收一位:主机将总线拉低1~15us,然后释放总线,并在拉低后15us内读取总线电平(尽量贴近15us的末尾),读取为低电平则为接收0,读取为高电平则为接收1,整个时间片应大于60us
    在这里插入图片描述
    在这里插入图片描述

    5.DS18B20操作流程

    ·初始化:从机复位,主机判断从机是否响应

    ·ROM操作:ROM指令+本指令需要的读写操作

    ·功能操作:功能指令+本指令需要的读写操作

    ROM操作就是访问64位ROM,功能操作就是访问暂存器
    在这里插入图片描述
    本实验使用SKIP ROM,因为本开发板从机只有一个DS18B20,不需要ROM来进行寻址

    6.DS18B20数据帧

    · 温度变换:初始化→跳过ROM→开始温度变换
    在这里插入图片描述
    · 温度读取:初始化→跳过ROM→读暂存器→连续的读操作
    在这里插入图片描述
    温度存储格式
    在这里插入图片描述
    其中S是符号位,温度为负,则BIT11-15全为1,温度为正,则BIT11-15全为0

    BITO-10为温度数据(补码),举例如下:
    在这里插入图片描述

    7.DS18B20温度读取

    现象:利用DS18B20读取温度并将温度显示在LCD1602上
    OneWire.c
    引脚定义

    #include 
    
    //引脚定义
    sbit OneWire_DQ=P3^7;
    
    • 1
    • 2
    • 3
    • 4

    初始化(温度传感器插上显示0,拔下显示1)
    因为延时函数将nop删了,删了之后,生成的480us就没有480us了,为了保证延时不少于480us,故延时了500us

    /**
      * @brief  单总线初始化
      * @param  无
      * @retval 从机响应位,0为响应,1为未响应
      */
    unsigned char OneWire_Init(void)
    {
    	unsigned char i;
    	unsigned char AckBit;
    	OneWire_DQ=1;
    	OneWire_DQ=0;
    	i = 247;while (--i);		//Delay 500us
    	OneWire_DQ=1;
    	i = 32;while (--i);			//Delay 70us
    	AckBit=OneWire_DQ;
    	i = 247;while (--i);		//Delay 500us
    	return AckBit;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    发送一位

    /**
      * @brief  单总线发送一位
      * @param  Bit 要发送的位
      * @retval 无
      */
    void OneWire_SendBit(unsigned char Bit)
    {
    	unsigned char i;
    	OneWire_DQ=0;
    	i = 4;while (--i);			//Delay 10us
    	OneWire_DQ=Bit;
    	i = 24;while (--i);			//Delay 50us
    	OneWire_DQ=1;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    接收一位

    /**
      * @brief  单总线接收一位
      * @param  无
      * @retval 读取的位
      */
    unsigned char OneWire_ReceiveBit(void)
    {
    	unsigned char i;
    	unsigned char Bit;
    	OneWire_DQ=0;
    	i = 2;while (--i);			//Delay 5us
    	OneWire_DQ=1;
    	i = 2;while (--i);			//Delay 5us
    	Bit=OneWire_DQ;
    	i = 24;while (--i);			//Delay 50us
    	return Bit;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    发送一个字节

    /**
      * @brief  单总线发送一个字节
      * @param  Byte 要发送的字节
      * @retval 无
      */
    void OneWire_SendByte(unsigned char Byte)
    {
    	unsigned char i;
    	for(i=0;i<8;i++)
    	{
    		OneWire_SendBit(Byte&(0x01<<i));
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    接收一个字节

    /**
      * @brief  单总线接收一个字节
      * @param  无
      * @retval 接收的一个字节
      */
    unsigned char OneWire_ReceiveByte(void)
    {
    	unsigned char i;
    	unsigned char Byte=0x00;
    	for(i=0;i<8;i++)
    	{
    		if(OneWire_ReceiveBit()){Byte|=(0x01<<i);}
    	}
    	return Byte;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    OneWire.h

    #ifndef __ONEWIRE_H__
    #define __ONEWIRE_H__
    
    unsigned char OneWire_Init(void);
    void OneWire_SendBit(unsigned char Bit);
    unsigned char OneWire_ReceiveBit(void);
    void OneWire_SendByte(unsigned char Byte);
    unsigned char OneWire_ReceiveByte(void);
    
    #endif
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    DS18B20.c
    宏定义指令
    0xCC进行设备寻址(只有一个从机时使用)
    0x44温度变换(读取温度前要执行温度变换,将温度值放到暂存器里)
    0xBE温度读取(将暂存器里的温度读出)

    #include 
    #include "OneWire.h"
    
    //DS18B20指令
    #define DS18B20_SKIP_ROM			0xCC
    #define DS18B20_CONVERT_T			0x44
    #define DS18B20_READ_SCRATCHPAD 	0xBE
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    DS18B20开始温度变换

    /**
      * @brief  DS18B20开始温度变换
      * @param  无
      * @retval 无
      */
    void DS18B20_ConvertT(void)
    {
    	OneWire_Init();
    	OneWire_SendByte(DS18B20_SKIP_ROM);
    	OneWire_SendByte(DS18B20_CONVERT_T);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    DS18B20读取温度
    只需读取暂存器的前两个即可(TLSB)(TMSB)
    温度存储格式为4为整数,4为小数。2的4次方是16,且要保持精度,所以除以16.0

    /**
      * @brief  DS18B20读取温度
      * @param  无
      * @retval 温度数值
      */
    float DS18B20_ReadT(void)
    {
    	unsigned char TLSB,TMSB;
    	int Temp;
    	float T;
    	OneWire_Init();
    	OneWire_SendByte(DS18B20_SKIP_ROM);
    	OneWire_SendByte(DS18B20_READ_SCRATCHPAD);
    	TLSB=OneWire_ReceiveByte();
    	TMSB=OneWire_ReceiveByte();
    	Temp=(TMSB<<8)|TLSB;
    	T=Temp/16.0;
    	return T;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    DS18B20.h

    #ifndef __DS18B20_H__
    #define __DS18B20_H__
    
    void DS18B20_ConvertT(void);
    float DS18B20_ReadT(void);
    
    #endif
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    main.c
    (unsigned long)(T*10000)%10000,4):因为小数不能取余再取整unsigned int超过,所以用unsigned long

    #include 
    #include "LCD1602.h"
    #include "DS18B20.h"
    #include "Delay.h"
    
    float T;
    
    void main()
    {
    	DS18B20_ConvertT();		//上电先转换一次温度,防止第一次读数据错误
    	Delay(1000);			//等待转换完成
    	LCD_Init();
    	LCD_ShowString(1,1,"Temperature:");
    	while(1)
    	{
    		DS18B20_ConvertT();	//转换温度
    		T=DS18B20_ReadT();	//读取温度
    		if(T<0)				//如果温度小于0
    		{
    			LCD_ShowChar(2,1,'-');	//显示负号
    			T=-T;			//将温度变为正数
    		}
    		else				//如果温度大于等于0
    		{
    			LCD_ShowChar(2,1,'+');	//显示正号
    		}
    		LCD_ShowNum(2,2,T,3);		//显示温度整数部分
    		LCD_ShowChar(2,5,'.');		//显示小数点
    		LCD_ShowNum(2,6,(unsigned long)(T*10000)%10000,4);//显示温度小数部分
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    8.温度报警器

    main.c

    #include 
    #include "LCD1602.h"
    #include "DS18B20.h"
    #include "Delay.h"
    #include "AT24C02.h"
    #include "Key.h"
    #include "Timer0.h"
    
    float T,TShow;
    char TLow,THigh;
    unsigned char KeyNum;
    
    void main()
    {
    	DS18B20_ConvertT();		//上电先转换一次温度,防止第一次读数据错误
    	Delay(1000);			//等待转换完成
    	THigh=AT24C02_ReadByte(0);	//读取温度阈值数据
    	TLow=AT24C02_ReadByte(1);
    	if(THigh>125 || TLow<-55 || THigh<=TLow)
    	{
    		THigh=20;			//如果阈值非法,则设为默认值
    		TLow=15;
    	}
    	LCD_Init();
    	LCD_ShowString(1,1,"T:");
    	LCD_ShowString(2,1,"TH:");
    	LCD_ShowString(2,9,"TL:");
    	LCD_ShowSignedNum(2,4,THigh,3);
    	LCD_ShowSignedNum(2,12,TLow,3);
    	Timer0_Init();
    	
    	while(1)
    	{
    		KeyNum=Key();
    		
    		/*温度读取及显示*/
    		DS18B20_ConvertT();	//转换温度
    		T=DS18B20_ReadT();	//读取温度
    		if(T<0)				//如果温度小于0
    		{
    			LCD_ShowChar(1,3,'-');	//显示负号
    			TShow=-T;		//将温度变为正数
    		}
    		else				//如果温度大于等于0
    		{
    			LCD_ShowChar(1,3,'+');	//显示正号
    			TShow=T;
    		}
    		LCD_ShowNum(1,4,TShow,3);		//显示温度整数部分
    		LCD_ShowChar(1,7,'.');		//显示小数点
    		LCD_ShowNum(1,8,(unsigned long)(TShow*100)%100,2);//显示温度小数部分
    		
    		/*阈值判断及显示*/
    		if(KeyNum)
    		{
    			if(KeyNum==1)	//K1按键,THigh自增
    			{
    				THigh++;
    				if(THigh>125){THigh=125;}
    			}
    			if(KeyNum==2)	//K2按键,THigh自减
    			{
    				THigh--;
    				if(THigh<=TLow){THigh++;}
    			}
    			if(KeyNum==3)	//K3按键,TLow自增
    			{
    				TLow++;
    				if(TLow>=THigh){TLow--;}
    			}
    			if(KeyNum==4)	//K4按键,TLow自减
    			{
    				TLow--;
    				if(TLow<-55){TLow=-55;}
    			}
    			LCD_ShowSignedNum(2,4,THigh,3);	//显示阈值数据
    			LCD_ShowSignedNum(2,12,TLow,3);
    			AT24C02_WriteByte(0,THigh);		//写入到At24C02中保存
    			Delay(5);
    			AT24C02_WriteByte(1,TLow);
    			Delay(5);
    		}
    		if(T>THigh)			//越界判断
    		{
    			LCD_ShowString(1,13,"OV:H");
    		}
    		else if(T<TLow)
    		{
    			LCD_ShowString(1,13,"OV:L");
    		}
    		else
    		{
    			LCD_ShowString(1,13,"    ");
    		}
    	}
    }
    
    void Timer0_Routine() interrupt 1
    {
    	static unsigned int T0Count;
    	TL0 = 0x18;		//设置定时初值
    	TH0 = 0xFC;		//设置定时初值
    	T0Count++;
    	if(T0Count>=20)
    	{
    		T0Count=0;
    		Key_Loop();	//每20ms调用一次按键驱动函数
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
  • 相关阅读:
    LintCode 3209: Moving fruit 堆典型题
    报名开启!飞桨AI for Science公开课与共创计划邀您来学,探索AI与科学的融合
    新材料制造业工厂MES系统解决方案
    OpenCV画图(画OpenCV的标志)
    Jackson ImmunoResearch 过敏测试
    前端工作总结99-关于第二个git仓库提交代码
    MATLAB中cellstr函数的使用
    栈和队列的应用 —— 顺序队列
    10亿美元,微软收购AT&T旗下广告业务
    脚本合集部分源码
  • 原文地址:https://blog.csdn.net/2302_80796399/article/details/136104430