普中STM32-PZ6806L开发板(HAL库函数实现-访问多个温度传感器DS18B20)

news2025/5/24 10:32:22

简介

我们知道多个DS18B20的DQ线是可以被挂在一起的, 也就是一根线上可以访问不同的DS18B20而不会造成数据错乱, 怎么做到的,其实数据手册都有说到, 就是靠64-bit ROM code 进行识别, 也可以理解成Serial Number进行识别, 因为主要差异还是在Serial Number上面;

电路图

两个DS18B20连接到一起
在这里插入图片描述

实现步骤

创建项目

基于 上一篇 普中STM32-PZ6806L开发板(HAL库函数实现-温度传感器DS18B20)

添加用户代码

获取DS18B20的Serial Number信息, 然后记录下来, 用于向指定DS18B20获取温度值

typedef struct 
{
	uint8_t familyCode;
	uint8_t sns[6];
	uint8_t crc;
} SENSOR_DS18B20_SerialNumberInfo;


SENSOR_DS18B20_SerialNumberInfo SENSOR_DS18B20_GetSN(void)
{
	SENSOR_DS18B20_SerialNumberInfo info;
	uint8_t recvs[8] = { 0 };
	
	SENSOR_DS18B20_Reset ();
	HAL_Delay (1);
	SENSOR_DS18B20_Write (0x33);  // read rom
	HAL_Delay (1);
	
	// 1 byte -> family code
	// 2 ~ 7 byte -> serial number
 //  8 byte -> CRC8	
	recvs[0] = SENSOR_DS18B20_Read(); // family code
	info.familyCode = recvs[0];
	
	for (int i = 0; i < 6; ++i) // serial number
	{ 
		recvs[i+1] = SENSOR_DS18B20_Read();
		info.sns[i] = recvs[i+1];
	}
	recvs[7] = SENSOR_DS18B20_Read(); // CRC8
	info.crc = recvs[7];
	if (SENSOR_DS18B20_CRC8(recvs, 7) != recvs[7]) // CRC8 检查
	{
		info.familyCode = 0;
		memset(info.sns, 0, sizeof(info.sns)/sizeof(uint8_t));
		info.crc = 0; 
		return info; // CRC校验不一致
	}
	return info;
}

实现流程参考pdf
在这里插入图片描述
实现代码

/* 两个DS18B20设备 */
#include <stdio.h>
#include <string.h>

/* DS18B20, 提前读取出来的SN&familyCode&CRC码 */
SENSOR_DS18B20_SerialNumberInfo  ds18b20_infos[] = 
{
	{ 0x28, { 0x2E, 0x7C, 0x04, 0x05, 0x00, 0x00 }, 0xCC },
	{ 0x28, { 0x2F, 0x7D, 0x10, 0x02, 0x01, 0x00 }, 0xBE }
};

/* 引脚重新设置为输入 */
static void SENSOR_DS18B20_SetPinInput(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
{
	GPIO_InitTypeDef GPIO_InitStruct;
	
	GPIO_InitStruct.Pin = GPIO_Pin;
	GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	HAL_GPIO_Init(GPIOx, &GPIO_InitStruct);
}
/* 引脚重新设置为输出 */
static void SENSOR_DS18B20_SetPinOutput(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
{
	GPIO_InitTypeDef  GPIO_InitStruct;
	
	GPIO_InitStruct.Pin = GPIO_Pin;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
	GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
	HAL_GPIO_Init(GPIOx, &GPIO_InitStruct);
}

/*
	SENSOR_DS18B20_Reset :
	初始化,也是复位, 每次发送指令前的动作
		0 : 初始化失败
		1 : 初始化成功
*/
static uint8_t SENSOR_DS18B20_Reset(void)
{
	uint8_t res = 0;
	SENSOR_DS18B20_SetPinOutput(DS18B20_PORT, DS18B20_PIN);   // 引脚输出模式
	HAL_GPIO_WritePin (DS18B20_PORT, DS18B20_PIN, 0);  // 拉低引脚
	delay_us (480);   // 参考初始化时序图, 延时480us

	SENSOR_DS18B20_SetPinInput(DS18B20_PORT, DS18B20_PIN);    // set the pin as input
	delay_us (60);    // 15~60us等待DS18B20回复信息, 多等20us避免检测不到

	if ( !HAL_GPIO_ReadPin(DS18B20_PORT, DS18B20_PIN) )
		res = 1;  // 检测到低电平,  DS18B20有响应
	else 
		res = 0;

	delay_us (420); // 等待DS18B20结束响应

	return res;
}

/* 写流程 */
void SENSOR_DS18B20_Write(uint8_t data)
{
	/*
		按位写, 根据时序图, 按照写的 高电平的时序 和 低电平的时序进行延时
	*/
	for (int i = 0; i < 8; ++i)
	{

		if ((data & (1<<i))!=0) // 写1
		{
			SENSOR_DS18B20_SetPinOutput(DS18B20_PORT, DS18B20_PIN);  
			HAL_GPIO_WritePin(DS18B20_PORT, DS18B20_PIN, 0);  // 拉低
			delay_us (2);  // 低电平保持时间

			SENSOR_DS18B20_SetPinInput(DS18B20_PORT, DS18B20_PIN);  // 输入
			delay_us (60);  // 等待
		}
		else // 写0
		{
			SENSOR_DS18B20_SetPinOutput(DS18B20_PORT, DS18B20_PIN);
			HAL_GPIO_WritePin (DS18B20_PORT, DS18B20_PIN, 0);  // 拉低
			delay_us (60);  // 等待60us

			SENSOR_DS18B20_SetPinInput(DS18B20_PORT, DS18B20_PIN); // 输入
		}
	}
}
/* 读流程 */
uint8_t SENSOR_DS18B20_Read (void)
{
	uint8_t value = 0;
	SENSOR_DS18B20_SetPinOutput(DS18B20_PORT, DS18B20_PIN);
	for (int i=0;i<8;i++)
	{
		SENSOR_DS18B20_SetPinOutput(DS18B20_PORT, DS18B20_PIN);

		HAL_GPIO_WritePin(DS18B20_PORT, DS18B20_PIN, 0);  // 拉低
		delay_us(2);  // 拉低电平等待时间

		SENSOR_DS18B20_SetPinInput(DS18B20_PORT, DS18B20_PIN);
		if (HAL_GPIO_ReadPin (DS18B20_PORT, DS18B20_PIN))  
		{
			value |= 1<<i;  
		}
		delay_us (60);  // DS18B20数据响应时间
	}
	return value;
}

/* 计算CRC码 */
uint8_t SENSOR_DS18B20_CRC8(uint8_t *dats, uint8_t len) 
{
    uint8_t i, dat, crc, fb, st_byt;
    st_byt = 0;
    crc = 0;
    do {
      dat = dats[st_byt];
      for (i = 0; i < 8; i++) 
			{  
					fb = crc ^ dat;
					fb &= 1;
					crc >>= 1;
					dat >>= 1;
					if (fb == 1) 
						crc ^= 0x8c; 
       }
      st_byt++;
    } while (st_byt < len); 
    return crc;
}

/* 获取Serial Number&CRC&family Code */
SENSOR_DS18B20_SerialNumberInfo SENSOR_DS18B20_GetSN(void)
{
	SENSOR_DS18B20_SerialNumberInfo info;
	uint8_t recvs[8] = { 0 };
	
	SENSOR_DS18B20_Reset ();
	HAL_Delay (1);
	SENSOR_DS18B20_Write (0x33);  // read rom
	HAL_Delay (1);
	
	// 1 byte -> family code
	// 2 ~ 7 byte -> serial number
 //  8 byte -> CRC8	
	recvs[0] = SENSOR_DS18B20_Read(); // family code
	info.familyCode = recvs[0];
	
	for (int i = 0; i < 6; ++i) // serial number
	{ 
		recvs[i+1] = SENSOR_DS18B20_Read();
		info.sns[i] = recvs[i+1];
	}
	recvs[7] = SENSOR_DS18B20_Read(); // CRC8
	info.crc = recvs[7];
	if (SENSOR_DS18B20_CRC8(recvs, 7) != recvs[7]) // CRC8 检查
	{
		info.familyCode = 0;
		memset(info.sns, 0, sizeof(info.sns)/sizeof(uint8_t));
		info.crc = 0; 
		return info; // CRC校验不一致
	}
	return info;
}

/* 写Serial Number&CRC&family Code */
void SENSOR_DS18B20_WriteID(uint8_t index) 
{
	uint8_t id_data[8];
	id_data[0] = ds18b20_infos[index].familyCode;
	id_data[7] = ds18b20_infos[index].crc;
	for ( int i = 1; i < 7; ++i )
	{
		id_data[i] = ds18b20_infos[index].sns[i-1];
	}
	
	SENSOR_DS18B20_Reset (); 
	SENSOR_DS18B20_Write (0x55);  // skip ROM; //Match ROM [55h]
	for ( int i = 0; i < 8; i++ )
	{
		SENSOR_DS18B20_Write(id_data[i]);
	}
}

/* 等待电平被拉高 */
void SENSOR_DS18B20_WaitForHigh(uint32_t time) 
{
	SENSOR_DS18B20_SetPinInput(DS18B20_PORT, DS18B20_PIN);
	delay_us(time);
	while(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_9) == 0);
	SENSOR_DS18B20_SetPinOutput(DS18B20_PORT, DS18B20_PIN);
}

/* 将读取值转化成温度值 */
float SENSOR_DS18B20_ValueToTemperature(uint8_t lsb, uint8_t msb)
{
	uint16_t temp = 0;
	temp = (msb << 8) + lsb;
	
	if((temp&0xf800)==0xf800) // 符号位判定是否负数
	{
		temp=(~temp)+1; // 补码转原码
		return temp*(-0.0625); //12bit 增量值
	}
	else
	{
		return temp*0.0625;	//12bit 增量值
	}
}


/* 通过serial number数据获取温度 */
float SENSOR_DS18B20_GetTemperatureByID(uint8_t ds18b20_index)
{
	uint8_t recv_data[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; // 9 Bytes
	uint8_t ds18b20_num = sizeof(ds18b20_infos) / sizeof(SENSOR_DS18B20_SerialNumberInfo);
	uint16_t temp = 0;
	if ( ds18b20_index >= ds18b20_num )
		return 0; // 不存在此设备
	
	SENSOR_DS18B20_Reset ();
	HAL_Delay (1);
	SENSOR_DS18B20_WriteID(ds18b20_index);
	SENSOR_DS18B20_Write(0x44);//Convert Temperature [44h]
	
	SENSOR_DS18B20_WaitForHigh(20);
	SENSOR_DS18B20_Reset ();
	SENSOR_DS18B20_WriteID(ds18b20_index);
	SENSOR_DS18B20_Write(0xBE);//Read Scratchpad [BEh]
	
	
	for (uint8_t i = 0; i < 9; i++)
	{
		recv_data[i] = SENSOR_DS18B20_Read();
	}
	
	return SENSOR_DS18B20_ValueToTemperature(recv_data[0], recv_data[1]);
}

代码

无需下载, 代码上面基本都提供了

Note:
支持你的DS18B20, 你需要修改, 改成你的DS18B20的信息
SENSOR_DS18B20_SerialNumberInfo ds18b20_infos[] =
{
{ 0x28, { 0x2E, 0x7C, 0x04, 0x05, 0x00, 0x00 }, 0xCC },
{ 0x28, { 0x2F, 0x7D, 0x10, 0x02, 0x01, 0x00 }, 0xBE }
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1356000.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

成为一名合格的软件测试工程师,得掌握什么技能?

在这个信息时代&#xff0c;软件行业的需求空前增长&#xff0c;而软件测试工程师作为软件开发过程中的重要角色&#xff0c;也越来越受企业的重视。那么&#xff0c;成为一名合格的软件测试工程师需要掌握什么技能呢&#xff1f;我结合多年的教学经验为大家总结出以下几点。 …

Fast and flexible X-ray tomography using the ASTRA toolbox

使用ASTRA工具箱进行快速灵活的X射线断层扫描 论文链接&#xff1a;http://dX.doi.org/10.1364/OE.24.025129 项目链接&#xff1a;https://astra-toolboX.com/indeX.html Abstract 从一系列投影图像中重建物体&#xff0c;如在计算机断层扫描(CT)中&#xff0c;是许多不同应…

nuxt3 env文件、全局变量处理

有两种方向 通过配置nuxt.config.ts Nuxt提供的钩子函数&#xff0c;实现全局变量的获取 runtimeconfig env文件往runtimeconfig放入内容 useAppConfig 通过env文件配置来获取服务端全局变量&#xff0c;客户端通过vite.define实现 nuxt.config.ts Nuxt钩子 1. runtim…

Unity ab包如何加密

「ab包」全称为 AssetBundle &#xff0c;是Unity提供的一种资源存储压缩包。其中储存了游戏的资源&#xff0c;如图片、模型、纹理、音视频、代码等文件。 由于ab包具有灵活储存、支持热更、包体较小且便于管理等优势&#xff0c;已经成为了市面上主流的游戏资源压缩方式。 …

李沐机器学习系列4---全连接层到卷积

1 从全连接到卷积 1.1 平移不变性 从概率分布的角度来看卷积的定义, f ( τ ) f(\tau) f(τ)是概率密度&#xff0c; g ( t − τ ) g(t-\tau) g(t−τ)是在这个分布下的均值 ( f ∗ g ) ( t ) ∫ − ∞ ∞ f ( τ ) g ( t − τ ) d τ (f*g)(t)\int_{-\infin}^{\infin}f(\t…

2024/01/02 每日AI必读资讯

减少LLM幻觉的方法 这篇论文总结了减少LLM幻觉的32种方法&#xff0c;包括RAG、微调模型&#xff0c;提示词工程等。 论文&#xff1a;https://arxiv.org/abs/2401.01313E5-mistral-7b-instruct&#xff1a;使用合成数据训练的Embedding模型 亮点是仅使用LLM生成的数据即可实现…

指令流水线的计算

我们需要知道以下公式&#xff1a; 设指令的条数为 n&#xff0c;指令执行需要 m 个阶段&#xff0c;时钟周期为 t 不采用流水线执行的时间&#xff1a;T1 n x m x t&#xff1b; 采用流水线执行的时间&#xff1a;T2 m x t (n - 1) x t&#xff1b; 加速比 S T1 / T2&…

PTA——逆序的三位数

程序每次读入一个正3位数&#xff0c;然后输出按位逆序的数字。注意&#xff1a;当输入的数字含有结尾的0时&#xff0c;输出不应带有前导的0。比如输入700&#xff0c;输出应该是7。 输入格式&#xff1a; 每个测试是一个3位的正整数。 输出格式&#xff1a; 输出按位逆序…

MacOS M1/M2 Go Debug 配置

前言 换电脑&#xff0c;Go 环境带来一些麻烦&#xff0c;耽误很多时间&#xff0c;稍作记录。 原始电脑是 Mac 旧款&#xff0c;CPU x86 构型&#xff0c;新电脑 M2&#xff0c;因为旧电脑里本地文件很多&#xff0c;为了简化搬迁&#xff0c;还是用了 Mac 自带的迁移&#x…

LeetCoed刷题:21. 合并两个有序链表

题目&#xff1a; 是否独立解出&#xff1a;否 解题时的思路与想法&#xff1a;解题时有几个问题&#xff1a; 1.怎么遍历两个数组&#xff0c;嵌套两个while循环不能实现&#xff08;后面通过看题解知道list1&#xff01;null&&list2&#xff01;null&#xff09; …

旋转图像(LeetCode 48)

文章目录 1.问题描述2.难度等级3.热门指数4.解题思路参考文献 1.问题描述 给定一个 n n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。 你必须在「原地」旋转图像&#xff0c;这意味着你需要直接修改输入的二维矩阵。请不要使用另一个矩阵来旋转图像。 示…

知虾分析——深入了解Shopee平台的知虾分析工具

Shopee是一家知名的电商平台&#xff0c;为了帮助卖家提高业务表现&#xff0c;他们提供了一款强大的数据分析工具——知虾分析。这个工具可以帮助卖家监控店铺的运营状况&#xff0c;优化销售策略&#xff0c;并提高整体的业务表现。本文将深入解析知虾分析的关键功能和用途&a…

LINUX加固之命令审计

一、前言 在LINUX安全范畴中&#xff0c;安全溯源也是很重要的一个环节。对主机上所有曾操作过的命令详细信息需要有一份记录保存&#xff0c;当系统遭受破坏或者入侵&#xff0c;拿出这份记录&#xff0c;可以帮助定位一些可疑动作。 很多系统通常都会配置安全堡垒机&#xff…

亚马逊站内广告位置在哪设置?怎么设置广告位置?-站斧浏览器

亚马逊站内广告位置在哪设置&#xff1f; 亚马逊提供了多种广告类型&#xff0c;包括&#xff1a; Sponsored Products&#xff08;赞助产品&#xff09;&#xff1a;在搜索结果和商品详情页中展示。 Sponsored Brands&#xff08;赞助品牌&#xff09;&#xff1a;在搜索结…

git提交操作(不包含初始化仓库)

1.进入到本地的git仓库 查看状态 git status 如果你之前有没有成功的提交&#xff0c;直接看第5步。 2.追踪文件 git add . 不要提交大于100M的文件&#xff0c;如果有&#xff0c;看第5步 3.提交评论 git commit -m "你想添加的评论" 4.push (push之前可以再…

weblogic中间件安装

1.下载jdk Java Archive Downloads - Java SE 6 下载jdk-6u45-linux-x64.bin 2.配置防火墙和SELINUX Redhat7操作系统配置防火墙&#xff0c;开放应用端口&#xff0c;例如7001&#xff1b; # firewall-cmd --permanent --add-port7001/tcp # firewall-cmd --reload 关闭selinu…

jmeter使用心得(一)

jmeter作为接口测试的常用工具之一&#xff0c;在我们的测试中经常会用到&#xff0c;往期的文章中&#xff0c;我们也分享过jmeter的各种功能和用法&#xff0c;基本覆盖了方方面面&#xff0c;可以满足各种接口测试的需求。但实际测试中我们也会发现&#xff0c;jmeter这么强…

设计模式——装饰模式(Decorator Pattern)

概述 装饰模式可以在不改变一个对象本身功能的基础上给对象增加额外的新行为&#xff0c;装饰模式是一种用于替代继承的技术&#xff0c;它通过一种无须定义子类的方式来给对象动态增加职责&#xff0c;使用对象之间的关联关系取代类之间的继承关系。在装饰模式中引入了装饰类&…

npm run start启动时提示 A decorated export must export a class declaration报错

问题描述&#xff1a; 基于react开发的项目在启动过程中&#xff0c;提示 A decorated export must export a class declaration报错&#xff0c;如下图所示: 解决办法&#xff1a; 上面是一个react hoc高阶组件&#xff0c;es6装饰器的语法是要包裹class组件的&#xff0c;所…

组合数学复习

2章-Pigeonhole Principle鸽子洞原理 A Theorem of Ramsey 考虑一个有趣的事实&#xff1a;任意6个人&#xff0c;其中至少有3个人互相不认识&#xff0c;或者互相认识可以将它用图论的语言进行描述&#xff1a;给一个K6&#xff08;6个节点的完全图&#xff09;的边涂上红色…