【STM32F103】1-WireDS18B20(含ESP8266代码)

1-Wire 单总线

1-Wire是一种串行通信总线协议,由美国芯片制造商Dallas Semiconductor(现为Maxim Integrated)开发。这种协议主要用于连接和通信各种设备,并在多个领域得到了广泛应用,如温度传感器、电池管理、智能卡等。

1-Wire协议基于单数据线进行串行通信,允许多个设备通过共享这一数据线与控制设备进行通信。这种通信方式极大地简化了硬件布线和设备连接的复杂性。每个1-Wire设备都具有一个唯一的64位地址,这使得系统可以轻松地识别和区分不同的设备。数据传输使用脉冲编码调制(Pulse Code Modulation, PCM)技术,通过发送不同脉冲的组合来表示不同的数据。

1-Wire技术具有节省IO资源、结构简单、成本低廉、便于总线扩展维护等优点。同时,它支持在总线上挂接多个从器件,数量基本上不受到任何限制。此外,每个1-Wire技术的从器件都具备独一无二的64位识别码,这既提高了安全性,也避免了地址冲突的问题。1-Wire技术还具备可达8kV HBM的ESD保护等级,以保证系统的稳定性。

总的来说,1-Wire技术作为一种串行通信总线协议,具有简单可靠、线路长度灵活、低功耗设计等特点,被广泛应用于各种设备和系统的通信中,为连接和通信各种设备提供了重要工具。

以上介绍来自文心一言。

我们需要知道的是1-Wire只需要一根通信线就可以进行通信,但仅适用于单主机的系统中,我们今天的主角DS18B20用的就是这个通信协议。

DS18B20

DS18B20是由DALLAS半导体公司推出的一种数字温度传感器,它采用了“一线总线”接口。这种温度传感器相较于传统的热敏电阻等测温元件,具有诸多优势,如体积小、适用电压宽、与微处理器接口简单等。

DS18B20的工作原理主要基于温度对半导体材料电阻值的影响。其内部包含一个精确的温度传感器,该传感器由一对金属电极和一个细丝电阻器组成。当温度升高时,电阻值会相应增加,反之亦然。通过测量电阻值的变化,DS18B20能够准确地确定环境温度。

在数据传输方面,DS18B20通过单线串行总线与主设备通信,仅需一根数据线即可实现数据的传输。这种通信方式不仅简化了硬件连接,还降低了成本。在通信过程中,主设备会发送指令给DS18B20,然后DS18B20将温度数据以数字形式传输回主设备。

DS18B20的温度测量范围为-55℃至+125℃,精度可达±0.5℃。它可以直接读出被测温度,并且可以通过简单的编程实现9~12位的数字值读数方式。此外,DS18B20还具备高抗干扰性,其现场温度直接以“一线总线”的数字方式传输,这大大提高了系统的稳定性。

在供电和工作模式方面,DS18B20既可以通过总线线路提供供电,也可以通过外部电源供电。其工作电压范围广泛,为3~5.5V,这使得它可以灵活地应用于各种嵌入式系统中。

DS18B20的应用领域十分广泛,包括温度监控、室内温度采集、冷链物流温度监控、工业生产温度监测等。其高精度和便捷的特点使得在各种场景下都能发挥重要作用。同时,DS18B20还具有多种封装形式,如管道式、螺纹式、磁铁吸附式等,这使得它可以根据实际应用场合的需求进行灵活选择。

总的来说,DS18B20数字温度传感器是一种功能强大、应用广泛的测温设备,其高精度、高可靠性和易用性使其在多个领域中都得到了广泛应用。

以上介绍来自文心一言。

可以看得出来DS18B20的厂商和1-Wire的开发公司是同一家,因此DS18B20自然是使用1-Wire进行通信。

上面一大段话没啥用,我们只要知道它是用来测温度的就行。

时序

初始化时序

以上为初始化时序,我们首先先拉低总线(1-Wire默认为上拉状态)480us,接着释放总线。

当DS18B20接收到来自主机的探测信号之后,等待15~60us后会发出一段60~240us的低电平。

以上流程顺利的话,就算是初始化完成了。

写时序

以上为写时序,写每个bit的时序时长最短为60us,最长为120us。两个时序之间需要至少1us的恢复时间。

我们先拉低总线15us,接着发送一个bit的数据保持总线上的电平至少60us。DS18B20会在时序开始的15us~60us这个窗口进行采样。

我们重复上面的时序8次就是发送一个字节,1-Wire上发送数据是从低位到高位的。

读时序

读时序和写时序一样,都必须是最少60us,并且两个时序之间需要至少1us的恢复时间。

我们先拉低总线至少1us接着释放,这标志着读时序的开始。接着我们在15us内采样(读取总线上的电平),然后等待45us(保证一个时序至少是60us)。

重复上述8个时序即可读取一个字节。

命令

我们只需要记住三个命令。
第一个是0x44,温度转换指令,发送一次,DS18B20就会转换一次温度,我们也就可以读取了。

第二个是0xCC,忽略ROM,因为1-Wire可以挂载多个从机,因此ROM是用来确定具体是哪个从机的,但是我们一般情况下不会挂载多个,因此先发送这个指令,下一个指令就不需要ROM了,这样会比较快。

最后一个是0xBE,发送完我们就可以读取寄存器里的值了,一共是九个字节。

我们再了解一下DS18B20的寄存器。

我们需要的数据在前两个字节,因此在读完两个字节之后我们就可以停止读取了。

那么了解了上述内容之后我们就可以开始敲代码了。

完整代码(STM32)

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"


#define DS18B20_DQ GPIO_Pin_0

void Z_DS18B20_Output(void){
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    
    GPIO_InitTypeDef itd;
    itd.GPIO_Mode=GPIO_Mode_Out_PP;    //推挽输出
    itd.GPIO_Pin=DS18B20_DQ; 
    itd.GPIO_Speed=GPIO_Speed_50MHz;                   
    GPIO_Init(GPIOA,&itd);
}

void Z_DS18B20_Input(void){
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    
    GPIO_InitTypeDef itd;
    itd.GPIO_Mode=GPIO_Mode_IPU;        //上拉输入    
    itd.GPIO_Pin=DS18B20_DQ; 
    itd.GPIO_Speed=GPIO_Speed_50MHz;                   
    GPIO_Init(GPIOA,&itd);
}

void Z_DS18B20_SetDQ(BitAction val){
    GPIO_WriteBit(GPIOA,DS18B20_DQ,val);
}

uint8_t Z_DS18B20_GetDQ(void){
    return GPIO_ReadInputDataBit(GPIOA,DS18B20_DQ);
}

void Z_DS18B20_WriteByte(uint8_t data){
    Z_DS18B20_Output();
    for(uint8_t i=0;i<8;++i){
        Z_DS18B20_SetDQ(0);     //拉低总线15us
        Delay_us(15);
        
        Z_DS18B20_SetDQ(data&0x01); //将数据从低位开始放到总线上60us
        Delay_us(60);
        
        Z_DS18B20_SetDQ(1);     //释放总线后延时1us
        Delay_us(1);
        data>>=1;
    }
}


uint8_t Z_DS18B20_ReadBit(void){
    uint8_t res=0;
    Z_DS18B20_Output();
    Z_DS18B20_SetDQ(0);     //拉低总线1us后释放表示开始读取字节
    Delay_us(1);
    Z_DS18B20_SetDQ(1);
    
    Z_DS18B20_Input();
    Delay_us(10);           //等待10us(在15us之内)后读取总线
    res=Z_DS18B20_GetDQ();
    
    Delay_us(50);           //延时50us以保证每个时序至少有60us.
    return res;
}

uint8_t DS18B20_Read_Byte(void){
  uint8_t res=0x00;
  for(uint8_t i=0;i<8;++i){
    if(Z_DS18B20_ReadBit()==1) res|=(0x01<<i);
  }
  return res;
}

uint8_t Z_DS18B20_Init(void){
    Z_DS18B20_Output();
    Z_DS18B20_SetDQ(0);     //复位
    Delay_us(480);
    Z_DS18B20_SetDQ(1);
    Delay_us(15);
    
    uint8_t waitTime=0;
    Z_DS18B20_Input();
    while(Z_DS18B20_GetDQ() && waitTime<=45){   //等待从机拉低总线
        waitTime++;
        Delay_us(1);
    }
    if(waitTime>45) return 1;
    
    waitTime=0;
    while(!Z_DS18B20_GetDQ() && waitTime<=240){ //等待从机松开总线
        waitTime++;
        Delay_us(1);
    }
    if(waitTime>240||waitTime<60) return 1;
    return 0;
}

float Z_DS18B20_GetTemperture(void){
	uint16_t temp;
	uint8_t Hdata,Ldata;
    
    Z_DS18B20_Init();
    Z_DS18B20_WriteByte(0xCC);
    Z_DS18B20_WriteByte(0x44);  //温度转换指令
    Z_DS18B20_Init();
	Z_DS18B20_WriteByte(0xCC);   
	Z_DS18B20_WriteByte(0xBE);  //读取寄存器指令  
	Ldata=DS18B20_Read_Byte();     
	Hdata=DS18B20_Read_Byte();    
	temp=Hdata;
	temp=(temp<<8)|Ldata;
	return temp*0.0625;    
}

int main(void){
    OLED_Init();
    while(1){
        OLED_ShowNum(1,1,Z_DS18B20_GetTemperture(),3);
        OLED_ShowNum(1,5,(int)(Z_DS18B20_GetTemperture()*100)%100,2);
        Delay_ms(300);
    }
}

完整代码(ESP8266)

ESP8266的代码在一些细节上与上面STM32的略有不同,因为ESP8266是我最早借鉴的别人的代码修改的。

而STM32的代码是我查阅了手册之后自己根据时序图写出的。

但是两个版本都是可以正常驱动DS18B20的。

#define DS18B20_DQ_GPIO D2

void DS18B20_Input_Init(void){
  pinMode(DS18B20_DQ_GPIO, INPUT_PULLUP);
}

void DS18B20_Output_Init(void){
  pinMode(DS18B20_DQ_GPIO, OUTPUT);
}

void DS18B20_Reset(void)	   
{                 
  DS18B20_Output_Init();
	digitalWrite(DS18B20_DQ_GPIO,LOW);
	delayMicroseconds(750);
	digitalWrite(DS18B20_DQ_GPIO, HIGH);
	delayMicroseconds(15);
}

uint8_t DS18B20_Check(void){
  uint8_t waitTime=0;
  DS18B20_Input_Init();
  while(digitalRead(DS18B20_DQ_GPIO) && waitTime<200){
    waitTime++;
    delayMicroseconds(1);
  }
  if(waitTime>=200) return 1;
  else waitTime=0;

  while((0==digitalRead(DS18B20_DQ_GPIO)) && waitTime<240){
    waitTime++;
    delayMicroseconds(1);
  }
  if(waitTime>=240) return 1;
  return 0;
}


uint8_t DS18B20_Read_Bit(void){
  uint8_t res=0;
  DS18B20_Output_Init();
  digitalWrite(DS18B20_DQ_GPIO, LOW);
  delayMicroseconds(2);
  digitalWrite(DS18B20_DQ_GPIO, HIGH);
  DS18B20_Input_Init();
  delayMicroseconds(12);
  res=digitalRead(DS18B20_DQ_GPIO);
  delayMicroseconds(50);
  return res;
}

uint8_t DS18B20_Read_Byte(void){
  uint8_t res=0x00;
  for(uint8_t i=0;i<8;++i){
    if(DS18B20_Read_Bit()==1) res|=(0x01<<i);
  }
  return res;
}

void DS18B20_Write_Byte(uint8_t data){
  DS18B20_Output_Init();
  for(uint8_t i=0;i<8;++i){
    if(data&0x01==1){
      digitalWrite(DS18B20_DQ_GPIO,LOW);
      delayMicroseconds(2);
      digitalWrite(DS18B20_DQ_GPIO, HIGH);
      delayMicroseconds(60);
    }else{
      digitalWrite(DS18B20_DQ_GPIO,LOW);
      delayMicroseconds(60);
      digitalWrite(DS18B20_DQ_GPIO, HIGH);
      delayMicroseconds(2);
    }
    data>>=1;
  }
}
 
void DS18B20_Start(void){
  DS18B20_Reset();
  DS18B20_Check();
  DS18B20_Write_Byte(0xCC);
  DS18B20_Write_Byte(0x44);
}
 	 
uint8_t DS18B20_Init(void){
  DS18B20_Output_Init();
 	DS18B20_Reset();
	return DS18B20_Check();
}  
 

float DS18B20_GetTemperture(void){
	uint16_t temp;
	uint8_t a,b;
	float value;
	
	DS18B20_Start();                  
	DS18B20_Reset();
	DS18B20_Check();	 
	DS18B20_Write_Byte(0xCC);// skip rom
	DS18B20_Write_Byte(0xBE);// convert	    
	a=DS18B20_Read_Byte(); // LSB   
	b=DS18B20_Read_Byte(); // MSB   
	temp=b;
	temp=(temp<<8)+a;
	if((temp&0xF800)==0xF800){
		temp=(~temp)+1;
		value=temp*(-0.0625);
	}else{
		value=temp*0.0625;	
	}
	return value;    
}


void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  Serial.println("Hello, STM32!");
  pinMode(D1, OUTPUT);
  digitalWrite(D1, HIGH);
  DS18B20_Init();  
}
int count=0;
void loop() {
  // put your main code here, to run repeatedly:
  digitalWrite(D1, !digitalRead(D1));
  delay(1000); // this speeds up the simulation
  Serial.println(DS18B20_GetTemperture());
}

感兴趣的小伙伴也可以关注我的公众号“折途想要敲代码”回复关键词“DS18B20”,即可免费下载DS18B20相关的资料手册。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

测试用例设计方法-场景法详解

01 定义 场景法是通过运用场景来对系统的功能点或业务流程的描述&#xff0c;从而提高测试效果的一种方法。 场景法一般包含基本流和备用流&#xff0c;从一个流程开始&#xff0c;通过描述经过的路径来确定的过程&#xff0c;经过遍历所有的基本流和备用流来完成整个场景。 …

NO12 蓝桥杯单片机之DS1302的使用

1 DS1302是什么 DS1302由两块存储器组成&#xff0c;一个是日历时钟寄存器还有一个是31位的静态RAM存储器。 而在蓝桥杯中常考的就是日历时钟寄存器&#xff0c;故这里只介绍日历时钟寄存器。简单来说&#xff0c;其就是一个“电子表”&#xff0c;他会自动的实时记录时间&am…

简易挛生分拣系统设计

1 工效组合展示 2 方案规划设计 3 数字挛生建模 基础建模、动画设计、模型导出 4 软件体系架构 5 Web交互设计 5.1 页面架构 5.2 初始构造 5.3 模型运用 5.4 WS通信 5.5 运行展现 6 服务支撑编码 6.1 整体调度 6.2 WS服务 6.3 C/S通信 7 系统级调试完善

了解一下npm i的流程与原理

流程 执行npm install&#xff0c;先判断有无lock文件。 1、没有lock文件。会先根据依赖构建出扁平的依赖关系决定下哪些包。新版本的依赖关系是扁平化的&#xff0c;老版本是树结构&#xff0c;可能会出现依赖重复安装的问题&#xff0c;老版本示意图如下&#xff1a; 作为前…

【探索Linux】—— 强大的命令行工具 P.31(守护进程)

阅读导航 引言一、守护进程简介1. 概念2. 特点 二、用C创建守护进程⭕代码✅主要步骤 温馨提示 引言 当谈到计算机系统中运行的特殊进程时&#xff0c;守护进程&#xff08;daemon&#xff09;无疑是一个备受关注的话题。作为在后台默默运行并提供各种服务的进程&#xff0c;守…

【机器人】UIUC、北大、亚马逊提出基于动作的场景图,让机器人理解和操控未知环境

论文的主要内容是通过机器人操作的交互式探索&#xff0c;构建一个基于动作的场景图&#xff08;Action-Conditioned Scene Graph&#xff0c;简称ACSG&#xff09;来帮助机器人更好地理解和操作未知环境。 全文核心&#xff1a;在未知环境中如何让机器人自主探索并完成复杂任务…

乐维更改IP地址

1.1 系统IP调整 vim /etc/sysconfig/network-scripts/ifcfg-ens1921.2 Web相关服务IP变更 1.2.1 编辑/itops/nginx/html/lwjkapp/.env文件,更改ZABBIXSERVER、ZABBIXRPCURL、DB_HOST中的IP 1.2.2 进入/itops/nginx/html/lwjk_app/目录下,执行php bin/manager process-conso…

记录C++中,vector的迭代器在push_back以后扩容导致迭代器失效的问题

前言 vector是我们用到最多的数据结构&#xff0c;其底层数据结构是单端动态数组&#xff0c;由于数组的特点&#xff0c;vector也具有以下特性&#xff1a; ①O(1)时间的快速访问&#xff1b; ②顺序存储&#xff0c;所以插入到非尾结点位置所需时间复杂度为O(n)&#xff0c;删…

JDK21|史诗级的更新,虚拟线程

作者:鱼仔 博客首页: https://codeease.top 公众号:Java鱼仔 前言 要想看官方对于JDK21的更新说明&#xff0c;可以直接跳转到下面这个官方网站中 官网地址为&#xff1a;https://openjdk.org/projects/jdk/21/ JDK21是最新的LTS版本&#xff0c;里面添加了不少新的特性&…

中小型集群部署,Docker Swarm(集群)使用及部署应用介绍

1、Docker Swarm简介 说到集群&#xff0c;第一个想到的就是k8s&#xff0c;但docker官方也提供了集群和编排解决方案&#xff0c;它允许你将多个 Docker 主机连接在一起&#xff0c;形成一个“群集”&#xff08;Swarm&#xff09;&#xff0c;并可以在这个 Swarm 上运行和管…

【Web APIs】DOM节点

目录 1.节点操作 1.1DOM节点 1.2查找节点 1.2.1父节点查找 1.2.2子节点查找 1.2.3兄弟节点查找 1.3增加节点 1.4克隆节点 1.5删除节点 2.时间对象 2.1实例化 2.2时间对象方法 2.3时间戳 3.重绘和回流 1.节点操作 1.1DOM节点 DOM节点&#xff1a;DOM树中的每一个…

BaseDao封装增删改查

文章目录 什么是BaseDao操作代码增删改查询单个数据查询多个数据 总结 什么是BaseDao BaseDao是&#xff1a; 数据库里负责增加&#xff0c;删除&#xff0c;修改&#xff0c;查询 具体来说是一种接口代码,公共方法的接口类。 在dao层新建basedao,其他dao层接口继承basedao 相…

《VulnHub》Lampião:1

title: 《VulnHub》Lampio&#xff1a;1 date: 2024-03-28 21:37:49 updated: 2024-03-28 21:37:50 categories: WriteUp&#xff1a;Cyber-Range excerpt: 关键技术&#xff1a;主机发现&#xff0c;端口扫描、服务探测、操作系统探测&#xff0c;对开放的端口探测漏洞&#x…

正弦实时数据库(SinRTDB)的使用(5)-历史数据查询

前文已经将正弦实时数据库的使用进行了介绍&#xff0c;需要了解的可以先看下面的博客&#xff1a; 正弦实时数据库(SinRTDB)的安装 正弦实时数据库(SinRTDB)的使用(1)-使用数据发生器写入数据 正弦实时数据库(SinRTDB)的使用(2)-接入OPC DA的数据 正弦实时数据库(SinRTDB)…

民航电子数据库:查询cae服务存在哪些数据库以及删除数据库

目录 一、场景二、查询数据库列表三、删除数据库 一、场景 1、对接民航电子数据库 2、在CAEManage是没有直观展示已存在的数据库的&#xff0c;只能通过SQL查询 3、在CAEManage没有操作按钮可以删除数据库&#xff0c;只能通过SQL进行删除 二、查询数据库列表 1、登录SYSTE…

我是如何在学术界占有一席之地的——专注于我的写作

罗伯特纽贝克 “作为一个移民&#xff0c;你是怎么发表这么多文章的&#xff1f;”意识到我不是以英语为母语的人&#xff0c;当我去年面试教职时&#xff0c;人们无数次问过这个问题。我知道披露我的挣扎不太可能让我找到工作&#xff0c;所以我会笑着说&#xff1a;“我喜欢…

Xinstall广告效果监测,为您的App推广保驾护航

在当前的移动互联网时代&#xff0c;App已经成为企业与用户连接的重要桥梁。然而&#xff0c;App推广过程中&#xff0c;如何准确衡量广告效果、洞悉推广效果以及优化用户体验&#xff0c;一直是广告主和开发者面临的挑战。这时&#xff0c;一款强大而专业的App全渠道统计服务商…

蓝桥杯刷题第四天

思路&#xff1a; 这道题很容易即可发现就是简单的暴力即可完成题目&#xff0c;我们只需满足所有数的和为偶数即可保证有满足条件的分法&#xff0c;同时也不需要存下每个输入的数据&#xff0c;只需要知道他是偶数还是奇数即可&#xff0c;因为我们只需要偶数个奇数搭配在一块…

Manjaro 安装全新 Linux 版微信,从此告别 Wine

目前已经基本上使用 Manjaro 来工作&#xff0c;而工作离不开微信作为日常的工作沟通工具。因为微信官方一直没有 Linux 版本的&#xff0c;所以之前都只能够使用 Wine 版本&#xff0c;然后踩了不少坑&#xff0c;但还算能勉强使用。 最近听说微信终于要发布 Linux 版本的&am…

day22.二叉树part08

day22.二叉树part08 235.二叉搜索树的最近公共祖先 原题链接 代码随想录链接 思路&#xff1a;因为本题是二叉搜索树&#xff0c;利用它的特性可以从上往下进行递归遍历树&#xff0c;这里需要理解一点就是如果遍历到的一个节点发现该节点的值正好位于节点p和节点q的值中间…