stm32实用篇6:HAL库 DS18B20 驱动

DS18B20是很常用的温度传感器,精度很高,测试结果如下:

整个驱动程序基本是根据时序写的。要注意的地方有两个:

1 读数据的时间 < 15us,这个值要实际测试,跟自己实现的延时函数效率有关,我使用的是10us,这个值如果设置的不合理,会直接导致整个数据读取出错;

2 建议使用DS18B20_GetTemp_SkipRom函数,不推荐使用设备号相关的那个读取函数,不太稳定;

 

HAL库驱动程序源码:

bsp_ds18b20.c

/**
  ******************************************************************************
  * @file            bsp_ds18b20.c
  * @author		
  * @date			
  * @version         v1.0
  * @note            DHT11 driver
  ******************************************************************************
  */

#include "bsp_ds18b20.h"

/**
  * @brief DS18B20 输出模式
  */
static void DS18B20_Mode_OUT_PP(void)
{
	GPIO_InitTypeDef GPIO_InitStruct;
	
	GPIO_InitStruct.Pin = BSP_DS18B20_PIN;
	GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
	
	HAL_GPIO_Init(BSP_DS18B20_PORT, &GPIO_InitStruct);
}

/**
  * @brief DS18B20 输入模式
  */
static void DS18B20_Mode_IN_NP(void)
{
	GPIO_InitTypeDef GPIO_InitStruct;
	
	GPIO_InitStruct.Pin = BSP_DS18B20_PIN;
	GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
	GPIO_InitStruct.Pull = GPIO_NOPULL;

	HAL_GPIO_Init(BSP_DS18B20_PORT, &GPIO_InitStruct);
}

/**
  * @brief 主机给从机发送复位脉冲
  */
static void DS18B20_Reset(void)
{
	DS18B20_Mode_OUT_PP();		// 主机输出
	
	DS18B20_OUT_0;						// 主机至少产生 480us 的低电平复位信号 
	bsp_delay_us(750);
	
	DS18B20_OUT_1;						// 主机在产生复位信号后,需将总线拉高 
	
	// 从机接收到主机的复位信号后,会在 15 ~ 60 us 后给主机发一个存在脉冲
	bsp_delay_us(15);					
}

/**
  * @brief  检测从机给主机返回的存在脉冲
  * @return 0:成功		1:失败
	*/
static uint8_t DS18B20_Presence(void)
{
	uint8_t pulse_time = 0;
	
	DS18B20_Mode_IN_NP();				// 主机设为输入 
	
	// 等待存在脉冲的到来,存在脉冲为一个 60 ~ 240 us 的低电平信号 
	// 如果存在脉冲没有来则做超时处理,从机接收到主机的复位信号后,会在 15 ~ 60 us 后给主机发一个存在脉冲

	while (DS18B20_IN && (pulse_time < 100))		// 等待低电平响应脉冲
	{
		pulse_time++;
		bsp_delay_us(1);
	}	
	// 经过 100 us 后,存在脉冲都还没有到来
	if (pulse_time >= 100)
	{
		return 1;
	}
	else
	{
		pulse_time = 0;		
	}
		
	// 响应脉冲(低电平)到来,且存在的时间不能超过 240 us 
	while(!(DS18B20_IN) && pulse_time < 240)
	{
		pulse_time++;
		bsp_delay_us(1);
	}	
	if(pulse_time >= 240)
	{
		return 1;
	}
	else
	{
		return 0;
	}
}

 /**
   * @brief  DS18B20 初始化函数
   * @reurn  0:成功		1:失败
   */
uint8_t DS18B20_Init(void)
{
	DS18B20_Mode_OUT_PP();
	DS18B20_OUT_1;
	
	DS18B20_Reset();
	return DS18B20_Presence();
}

/**
  * @brief 从DS18B20读取一个bit
  */
static uint8_t DS18B20_ReadBit(void)
{
	uint8_t dat;
	
	DS18B20_Mode_OUT_PP();	// 读 0 和读 1 的时间至少要大于 60 us 
	
	DS18B20_OUT_0;					// 读时间的起始:必须由主机产生 > 1us < 15us 的低电平信号 
	
	// 这个时间非常重要,设置为 < 15,需要多次尝试;如果设置不合理,数据会直接出错
	// 参数建议设为 10 11 12,具体值要根据延时函数的执行效率测试
	bsp_delay_us(10);		
	
	DS18B20_Mode_IN_NP();		// 设置成输入,释放总线,由外部上拉电阻将总线拉高 
	
	if (DS18B20_IN == 1)
	{
		dat = 1;
	}
	else
	{
		dat = 0;
	}
		
	bsp_delay_us(45);				// 这个延时参数参考时序图 
	
	return dat;
}

/**
  * @brief 从 DS18B20 读一个字节,低位先行
  */
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,低位先行
  */
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)			// 当前位写 1
		{			
			DS18B20_OUT_0;
			
			bsp_delay_us(5);		// 拉低发送写时段信号
			
			DS18B20_OUT_1;			// 读取电平时间保持高电平
			bsp_delay_us(65);		
		}		
		else						// 当前位写 0			
		{			
			DS18B20_OUT_0;			// 拉低发送写时段信号
			bsp_delay_us(70);		// 读取电平时间保持低电平
			
			DS18B20_OUT_1;				
			bsp_delay_us(2);		// 恢复时间
		}
	}
}

/**
  * @brief  跳过匹配 DS18B20 ROM
  */
static void DS18B20_SkipRom(void)
{
	DS18B20_Reset();	   
	
	DS18B20_Presence();	 
	
	DS18B20_WriteByte(0XCC);		/* 跳过 ROM */
}

/**
  * @brief  执行匹配 DS18B20 ROM
  */
static void DS18B20_MatchRom(void)
{
	DS18B20_Reset();	   
	
	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  无
  * @retval 温度值
  */
float DS18B20_GetTemp_SkipRom(void)
{
	uint8_t tpmsb, tplsb;
	int16_t 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.0625f;	
	}
	else
	{
		f_tem = s_tem * 0.0625f;
	}
		
	return f_tem; 	
}

/**
  * @brief  在匹配 ROM 情况下获取 DS18B20 温度值 
  * @param  ds18b20_id:用于存放 DS18B20 序列号的数组的首地址
  */
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;
	int16_t 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.0625f;	
	}
	else
	{
		f_tem = s_tem * 0.0625f;
	}
		
	return f_tem; 		
}

// 测试程序

#if 0

uint8_t uc, ucDs18b20Id[8];
	
while (DS18B20_Init())
{
	printf("\r\n no ds18b20 exit \r\n");
}

printf("\r\n ds18b20 exit \r\n");

DS18B20_ReadId(ucDs18b20Id);           	// 读取 DS18B20 的序列号
printf("\r\nDS18B20的序列号是: 0x");

for (uc = 0; uc < 8; uc++)          		// 打印 DS18B20 的序列号
{
	printf("%.2x", ucDs18b20Id[uc]);
}

while (1)
{
	printf("\r\n温度: %.1f\r\n", DS18B20_GetTemp_SkipRom());	

	HAL_Delay(1000);		/* 1s 读取一次温度值 */
}

#endif

bsp_ds18b20.h

/**
  ******************************************************************************
  * @file			bsp_ds18b20.h
  * @author		
  * @date			
  * @version	    v1.0
  * @note			DS18B20 driver
  ******************************************************************************
  */

#ifndef __BSP_DS18B20_H
#define __BSP_DS18B20_H

#include "bsp_conf.h"

#define BSP_DS18B20_PORT             TEMP_SENSOR_GPIO_Port
#define BSP_DS18B20_PIN                TEMP_SENSOR_Pin

#define DS18B20_OUT_1                HAL_GPIO_WritePin(BSP_DS18B20_PORT, BSP_DS18B20_PIN, GPIO_PIN_SET)
#define DS18B20_OUT_0                HAL_GPIO_WritePin(BSP_DS18B20_PORT, BSP_DS18B20_PIN, GPIO_PIN_RESET)

#define DS18B20_IN			        HAL_GPIO_ReadPin(BSP_DS18B20_PORT, BSP_DS18B20_PIN)

uint8_t DS18B20_Init(void);
void DS18B20_ReadId(uint8_t *ds18b20_id);
float DS18B20_GetTemp_SkipRom(void);
float DS18B20_GetTemp_MatchRom(uint8_t * ds18b20_id);

#endif	/* __BSP_DS18B20_H */

 

  • 11
    点赞
  • 54
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
下面是使用HAL库读取DS18B20温度传感器的示例代码,需要注意的是,需要先初始化GPIO口,才能正确读取数据。 ```c #include "stm32f1xx_hal.h" #define DS18B20_GPIO_PORT GPIOA #define DS18B20_GPIO_PIN GPIO_PIN_0 #define DS18B20_DELAY(x) HAL_Delay(x) GPIO_InitTypeDef GPIO_InitStruct; void DS18B20_GPIO_Init(void) { GPIO_InitStruct.Pin = DS18B20_GPIO_PIN; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(DS18B20_GPIO_PORT, &GPIO_InitStruct); } void DS18B20_GPIO_Write(uint8_t value) { if (value == 0) { HAL_GPIO_WritePin(DS18B20_GPIO_PORT, DS18B20_GPIO_PIN, GPIO_PIN_RESET); } else { HAL_GPIO_WritePin(DS18B20_GPIO_PORT, DS18B20_GPIO_PIN, GPIO_PIN_SET); } } uint8_t DS18B20_GPIO_Read(void) { return HAL_GPIO_ReadPin(DS18B20_GPIO_PORT, DS18B20_GPIO_PIN); } void DS18B20_Start(void) { DS18B20_GPIO_Write(0); DS18B20_DELAY(480); DS18B20_GPIO_Write(1); DS18B20_DELAY(60); DS18B20_GPIO_Write(0); DS18B20_DELAY(480); } uint8_t DS18B20_ReadBit(void) { uint8_t bit = 0; DS18B20_GPIO_Write(0); DS18B20_DELAY(2); DS18B20_GPIO_Write(1); DS18B20_DELAY(12); bit = DS18B20_GPIO_Read(); DS18B20_DELAY(50); return bit; } uint8_t DS18B20_ReadByte(void) { uint8_t i = 0; uint8_t byte = 0; for (i = 0; i < 8; i++) { byte |= (DS18B20_ReadBit() << i); } return byte; } void DS18B20_WriteByte(uint8_t byte) { uint8_t i = 0; for (i = 0; i < 8; i++) { DS18B20_GPIO_Write(0); DS18B20_DELAY(2); if (byte & (1 << i)) { DS18B20_GPIO_Write(1); } else { DS18B20_GPIO_Write(0); } DS18B20_DELAY(60); DS18B20_GPIO_Write(1); } } float DS18B20_ReadTemperature(void) { uint8_t temperature_data[9]; uint8_t i = 0; float temperature = 0; DS18B20_Start(); DS18B20_WriteByte(0xCC); DS18B20_WriteByte(0x44); HAL_Delay(800); DS18B20_Start(); DS18B20_WriteByte(0xCC); DS18B20_WriteByte(0xBE); for (i = 0; i < 9; i++) { temperature_data[i] = DS18B20_ReadByte(); } temperature = ((float)(temperature_data[1] << 8 | temperature_data[0])) / 16; return temperature; } int main(void) { HAL_Init(); DS18B20_GPIO_Init(); float temperature = DS18B20_ReadTemperature(); while (1) { temperature = DS18B20_ReadTemperature(); // 处理温度数据 } } ``` 在使用该代码前,需要先在 CubeMX 中配置好相应的 GPIO 口和 HAL 库的引脚映射关系。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值