STM32F4 HAL库开发 -- 温度传感器(DS18B20)

Posted 聚优致成

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了STM32F4 HAL库开发 -- 温度传感器(DS18B20)相关的知识,希望对你有一定的参考价值。

参看:《嵌入式-STM32开发指南》第三部分 外设篇 - 第2章 温度传感器DS18B20
这篇文章讲的非常详细了。

一、简介

1、概述

DS18B20 是 DALLAS 最新单线数字温度传感器,新的"一线器件"体积更小、适用电压更宽、更经济。Dallas 半导体公司的数字化温度传感器 DS1820 是世界上第一片支持 "一线总线"接口的温度传感器。

DS18B20采用的单总线协议,也就是只需占用主机一个I/O口,无需其他外围电路,直接将环境温度转换为数字信号,使用户可轻松地组建传感器网络,为测量系统的构建引入全新概念。另外,以"一线总线"的数字方式传输,大大提高了系统的抗干扰性。适合于恶劣环境的现场温度测量,如:环境控制、设备或过程控制、测温类消费电子产品等。

2、特性

(1) 具有独特的单总线接口,与主机主需要一个线即可实现双向通信;
(2) 测温范围为-55+125℃,在-10+85℃时,精度为±0.5℃;
(3) 可编程的分辨率为 9~12 位,对应的可分辨温度分别为 0.5℃、0.25℃、0.125℃和 0.0625℃;
(4) 在9 位分辨率时,最多在93.75ms 内把温度值转换为数字,在12 位分辨率时,最多在 750ms 内把温度值转换为数字;
(5) 负压特性,电源极性接反时,温度计不会因发热而烧毁,但不能正常工作。
(6) 工作电压范围宽,电压范围为3.0~5.5V,还可用数据线供电;
(7) 支持多点组网,多个DS18B20可以并联实现多点组网测温。值得注意的是,如果数量过多,需要解决供电问题,否则电压过低会导致信号传输不稳定;
(8) 测量结果采用数字信号输出,同时具有CRC校验,具较强的抗干扰和纠错能力。

3、外形结构

DS18B20 内部结构主要由四部分组成:64 位光刻 ROM、温度传感器、非挥发的温度报警触发器 TH 和 TL、配置寄存器。DS18B20 的管脚排列如下图所示。

其中与操作有关的有:64位光刻ROM、9个字节的RAM存储器、温度传感器、EERPOM(温度报警寄存器TH和TL、配置寄存器)

二、HAL库完整代码

/* Includes*********************************************************************/
#include "stm32f103_DS18B20.h"

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
static void DS18B20_Mode_IPU(void);
static void DS18B20_Mode_Out_PP(void);
static void DS18B20_Rst(void);
static uint8_t DS18B20_Presence(void);
static uint8_t DS18B20_ReadBit(void);
static uint8_t DS18B20_ReadByte(void);
static void DS18B20_WriteByte(uint8_t dat);
static void DS18B20_SkipRom(void);
static void DS18B20_MatchRom(void);

#define CPU_FREQUENCY_MHZ    72		// STM32时钟主频
void delay_us(__IO uint32_t delay)

    int last, curr, val;
    int temp;

    while (delay != 0)
    
        temp = delay > 900 ? 900 : delay;
        last = SysTick->VAL;
        curr = last - CPU_FREQUENCY_MHZ * temp;
        if (curr >= 0)
        
            do
            
                val = SysTick->VAL;
            
            while ((val < last) && (val >= curr));
        
        else
        
            curr += CPU_FREQUENCY_MHZ * 1000;
            do
            
                val = SysTick->VAL;
            
            while ((val <= last) || (val > curr));
        
        delay -= temp;
    


static void delay_us_bak(uint16_t time)

	uint8_t i;

  while(time)
      
	  for (i = 0; i < 10; i++)
    
      
    
    time--;
  


/**
  * @brief  DS18B20 初始化函数
  * @param  None
  * @retval None
  */
uint8_t DS18B20_Init(void)

  DS18B20_Dout_GPIO_CLK_ENABLE();
  
  DS18B20_Mode_Out_PP();
	
	DS18B20_Dout_HIGH();
	
	DS18B20_Rst();
  
  return DS18B20_Presence ();


/**
  * @brief  使DS18B20-DATA引脚变为上拉输入模式
  * @param  None
  * @retval None
  */
static void DS18B20_Mode_IPU(void)

  GPIO_InitTypeDef GPIO_InitStruct;
  
  /* 串口外设功能GPIO配置 */
  GPIO_InitStruct.Pin   = DS18B20_Dout_PIN;
  GPIO_InitStruct.Mode  = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull  = GPIO_PULLUP;
  HAL_GPIO_Init(DS18B20_Dout_PORT, &GPIO_InitStruct);


/**
  * @brief  使DS18B20-DATA引脚变为推挽输出模式
  * @param  None
  * @retval None
  */
static void DS18B20_Mode_Out_PP(void)

  GPIO_InitTypeDef GPIO_InitStruct;
  
  /* 串口外设功能GPIO配置 */
  GPIO_InitStruct.Pin = DS18B20_Dout_PIN;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  HAL_GPIO_Init(DS18B20_Dout_PORT, &GPIO_InitStruct); 	 


/**
  * @brief  主机给从机发送复位脉冲
  * @param  None
  * @retval None
  */
static void DS18B20_Rst(void)

	/* 主机设置为推挽输出 */
	DS18B20_Mode_Out_PP();
	
	DS18B20_Dout_LOW();
  
	/* 主机至少产生480us的低电平复位信号 */
	delay_us(750);
	
	/* 主机在产生复位信号后,需将总线拉高 */
	DS18B20_Dout_HIGH();
	
	/*从机接收到主机的复位信号后,会在15~60us后给主机发一个存在脉冲*/
	delay_us(15);


/**
  * @brief  检测从机给主机返回的存在脉冲
  * @param  None
  * @retval 0:成功,1:失败
  */
static uint8_t DS18B20_Presence(void)

	uint8_t pulse_time = 0;
	
	/* 主机设置为上拉输入 */
	DS18B20_Mode_IPU();
	
	/* 等待存在脉冲的到来,存在脉冲为一个60~240us的低电平信号 
	 * 如果存在脉冲没有来则做超时处理,从机接收到主机的复位信号后,会在15~60us后给主机发一个存在脉冲
	 */
	while( DS18B20_Data_IN() && pulse_time<100 )
	
		pulse_time++;
		delay_us(1);
		
	/* 经过100us后,存在脉冲都还没有到来*/
	if( pulse_time >=100 )
		return 1;
	else
		pulse_time = 0;
	
	/* 存在脉冲到来,且存在的时间不能超过240us */
	while( !DS18B20_Data_IN() && pulse_time<240 )
	
		pulse_time++;
		delay_us(1);
		
	if( pulse_time >=240 )
		return 1;
	else
		return 0;


/**
  * @brief  从DS18B20读取一个bit
  * @param  None
  * @retval 读取到的数据
  */
static uint8_t DS18B20_ReadBit(void)

	uint8_t dat;
	
	/* 读0和读1的时间至少要大于60us */	
	DS18B20_Mode_Out_PP();
	/* 读时间的起始:必须由主机产生 >1us <15us 的低电平信号 */
	DS18B20_Dout_LOW();
	delay_us(10);
	
	/* 设置成输入,释放总线,由外部上拉电阻将总线拉高 */
	DS18B20_Mode_IPU();
	//Delay_us(2);
	
	if( DS18B20_Data_IN() == SET )
		dat = 1;
	else
		dat = 0;
	
	/* 这个延时参数请参考时序图 */
	delay_us(45);
	
	return dat;


/**
  * @brief  从DS18B20读一个字节,低位先行
  * @param  None
  * @retval 读取到的数据
  */
static uint8_t DS18B20_ReadByte(void)

	uint8_t i, j, dat = 0;	
	
	for(i=0; i<8; i++) 
	
		j = DS18B20_ReadBit();		
		dat = (dat) | (j<<i);
	
	
	return dat;


/**
  * @brief  写一个字节到DS18B20,低位先行
  * @param  dat:待写入数据
  * @retval None
  */
static void DS18B20_WriteByte(uint8_t dat)

	uint8_t i, testb;
	DS18B20_Mode_Out_PP();
	
	for( i=0; i<8; i++ )
	
		testb = dat&0x01;
		dat = dat>>1;		
		/* 写0和写1的时间至少要大于60us */
		if (testb)
					
			DS18B20_Dout_LOW();
			/* 1us < 这个延时 < 15us */
			delay_us(8);
			
			DS18B20_Dout_HIGH();
			delay_us(58);
				
		else
					
			DS18B20_Dout_LOW();
			/* 60us < Tx 0 < 120us */
			delay_us(70);
			
			DS18B20_Dout_HIGH();		
			/* 1us < Trec(恢复时间) < 无穷大*/
			delay_us(2);
		
	


/**
  * @brief  跳过匹配 DS18B20 ROM
  * @param  None
  * @retval None
  */
static void DS18B20_SkipRom ( void )

	DS18B20_Rst();	   	
	DS18B20_Presence();	 	
	DS18B20_WriteByte(0XCC);		/* 跳过 ROM */	



/**
  * @brief  执行匹配 DS18B20 ROM
  * @param  None
  * @retval None
  */
static void DS18B20_MatchRom ( void )

	DS18B20_Rst();	   	
	DS18B20_Presence();	 	
	DS18B20_WriteByte(0X55);		/* 匹配 ROM */	


/*
 * 存储的温度是16 位的带符号扩展的二进制补码形式
 * 当工作在12位分辨率时,其中5个符号位,7个整数位,4个小数位
 *
 *         |---------整数----------|-----小数 分辨率 1/(2^4)=0.0625----|
 * 低字节  | 2^3 | 2^2 | 2^1 | 2^0 | 2^(-1) | 2^(-2) | 2^(-3) | 2^(-4) |
 *
 *
 *         |-----符号位:0->正  1->负-------|-----------整数-----------|
 * 高字节  |  s  |  s  |  s  |  s  |    s   |   2^6  |   2^5  |   2^4  |
 *
 * 
 * 温度 = 符号位 + 整数 + 小数*0.0625
 */
/**
  * @brief  在跳过匹配 ROM 情况下获取 DS18B20 温度值 
  * @param  None
  * @retval 温度值
  */
float DS18B20_GetTemp_SkipRom ( void )

	uint8_t tpmsb, tplsb;
	short s_tem;
	float f_tem;
	
	DS18B20_SkipRom ();
	DS18B20_WriteByte(0X44);				/* 开始转换 */
	
	DS18B20_SkipRom ();
  DS18B20_WriteByte(0XBE);				/* 读温度值 */
	
	tplsb = DS18B20_ReadByte();		 
	tpmsb = DS18B20_ReadByte(); 
	
	
	s_tem = tpmsb<<8;
	s_tem = s_tem | tplsb;
	
	if( s_tem < 0 )		/* 负温度 */
		f_tem = (~s_tem+1) * 0.0625;	
	else
		f_tem = s_tem * 0.0625;
	
	return f_tem; 	



/**
  * @brief  在匹配 ROM 情况下获取 DS18B20 温度值 
  * @param  ds18b20_id:用于存放 DS18B20 序列号的数组的首地址
  * @retval None
  */
void DS18B20_ReadId ( uint8_t * ds18b20_id )

	uint8_t uc;
		
	DS18B20_WriteByte(0x33);       //读取序列号
	
	for ( uc = 0; uc < 8; uc ++ )
	  ds18b20_id [ uc ] = DS18B20_ReadByte();	


/**
  * @brief  在匹配 ROM 情况下获取 DS18B20 温度值 
  * @param  ds18b20_id:存放 DS18B20 序列号的数组的首地址
  * @retval 温度值
  */
float DS18B20_GetTemp_MatchRom ( uint8_t * ds18b20_id )

	uint8_t tpmsb, tplsb, i;
	short s_tem;
	float f_tem;
	
	
	DS18B20_MatchRom ();            //匹配ROM
	
  for(i=0;i<8;i++)
		DS18B20_WriteByte ( ds18b20_id [ i ] );	
	
	DS18B20_WriteByte(0X44);				/* 开始转换 */

	
	DS18B20_MatchRom ();            //匹配ROM
	
	for(i=0;i<8;i++)
		DS18B20_WriteByte ( ds18b20_id [ i ] );	
	
	DS18B20_WriteByte(0XBE);				/* 读温度值 */
	
	tplsb = DS18B20_ReadByte();		 
	tpmsb = DS18B20_ReadByte(); 
	
	
	s_tem = tpmsb<<8;
	s_tem = s_tem | tplsb;
	
	if( s_tem < 0 )		/* 负温度 */
		f_tem = (~s_tem+1) * 0.0625;	
	else
		f_tem = s_tem * 0.0625;
	
	return f_tem; 		

以上是关于STM32F4 HAL库开发 -- 温度传感器(DS18B20)的主要内容,如果未能解决你的问题,请参考以下文章

STM32F4 HAL库开发 -- 温度传感器(DS18B20)

STM32F4 HAL库开发 -- 温度传感器(DS18B20)

STM32F4 HAL库开发 -- 温度传感器(DS18B20)

[STM32F4裸机]STM32F4HAL库开发

STM32F4 HAL库开发 -- 再识

STM32F4 HAL库开发 -- DMA