一、DS18B20简介

DS18B20是一一款常用的数字温度传感器,使用单个引脚完成主从机的双向通信是这款芯片的特点。

物理连接简单,那自然有特殊的时序需要满足,这也是使用这款芯片时麻烦的一点。

由于DS18B20不支持我们熟悉的IIC和SPI协议,那也就没有现成的库函数来支持我们的读写操作,也就是需要我们自行编写驱动。

但本文并不打算从解读数据手册中的时序图开始说太多废话,只给把代码给出,介绍一下驱动编写时可能遇到的一些问题,结合代码给出解决方案。


根据数据手册,这款芯片通常有三种封装:



三者都是通过DQ这个引脚来进行与主机的通信。所以问题简化为:


控制与DQ连接的引脚的电平变化


实际上,ds18b20支持六个操作指令:



只需要按照一定电平协议把这些命令发出去,就能够从DQ读取到想要的数据。而这些指令都刚好只有8位(bit),也就是一个字节。于是乎,ds18b20驱动的编写进一步简化为四个小任务:


1、初始化配置
2、通过DQ读取一个字节
3、通过DQ发送一个字节
4、读取温度

二、驱动代码介绍


1、初始化配置

初始化包含两步:


1、`DQ`对应的引脚的GPIO配置
2、通过`DQ`对`ds18b20`芯片的初始化

对应驱动代码的这部分:


/*** @brief  配置DQ并复位DS18B20* @param   无* @retval  无*/
void DS18B20_Init(void)
{/* 初始化GPIO */DS18B20_DQGPIOConfig();/* 复位 */DS18B20_Rst();
}

DS18B20_DQGPIOConfig()使能APB2总线时钟和GPIO时钟,配置DQ对应的引脚为推挽输出模式即可:


/*** @brief  配置DQ对应的GPIO引脚* @param   无* @retval  无*/
void DS18B20_DQGPIOConfig(void)
{/*定义一个GPIO_InitTypeDef类型的结构体*/GPIO_InitTypeDef GPIO_InitStructure;/*开启LED相关的GPIO外设时钟*/RCC_APB2PeriphClockCmd(DQ_GPIO_CLK, ENABLE);/*选择要控制的GPIO引脚*/GPIO_InitStructure.GPIO_Pin = PINDQ;    /*设置引脚模式为通用推挽输出*/GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;   /*设置引脚速率为50MHz */   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; /*调用库函数,初始化GPIO*/GPIO_Init(GPIODQ, &GPIO_InitStructure);
}

上面的代码中包含一些宏定义:


/* DQ引脚相关宏定义 */
#define GPIODQ GPIOB
#define PINDQ GPIO_Pin_8
/* GPIO端口时钟 */
#define DQ_GPIO_CLK         RCC_APB2Periph_GPIOB

:为了不至于看花眼,不会一次性将所有的宏和函数实现贴出来,说到哪儿就贴到那儿。同时也不用担心不好拼凑成完整的驱动程序,因为文末会放出驱动源代码链接。


重点看DS18B20_Rst()的实现:


/*** @brief  复位DS18B20*/
void DS18B20_Rst(void)
{   DS18B20_SetDQMode_OUT();/* 先将数据线置高电平“1” */DQ_H;/* 延时(该时间要求的不是很严格,但是尽可能的短一点) */Delay_us(1);/* 数据线拉到低电平“0”。 */DQ_L;/* 延时750微秒(该时间的时间范围可以从480到960微秒) */Delay_us(750);/* 数据线拉到高电平“1” */DQ_H;/* 延时等待(如果初始化成功则在15到60微秒时间之内产生一个由DS18B20所返回的低电平“0”。据该状态可以来确定它的存在,但是应注意不能无限的进行等待,不然会使程序进入死循环,所以要进行超时控制)。 *//* 超时时间不要设置得太短(500us是足够的),否则初始化失败,将获取不到环境温度 */Delay_us(500);uint8_t dqStatus = GPIO_ReadInputDataBit(GPIODQ,PINDQ);/*  将数据线再次拉高到高电平“1”后结束。 */DQ_H;
}

注意看每一步的注释,交代了初始化过程中DQ的电平变化。

其中最后一个延时函数:


Delay_us(500);

尤为关键,如果这里的等待时间不足,将导致初始化失败,出现温度值不变的怪病。


DS18B20_SetDQMode_OUT()是把DQ对应的引脚设置为推挽输出模式:


/*** @brief  设置DQ对应的引脚位推挽输出模式* @param   无 * @retval  无*/
static void DS18B20_SetDQMode_OUT()
{/*定义一个GPIO_InitTypeDef类型的结构体*/GPIO_InitTypeDef GPIO_InitStructure;/*选择要控制的GPIO引脚*/GPIO_InitStructure.GPIO_Pin = PINDQ;    /*设置引脚模式为通用推挽输出*/GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;   /*设置引脚速率为50MHz */   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; /*调用库函数,初始化GPIO*/GPIO_Init(GPIODQ, &GPIO_InitStructure);
}

DQ_H()DQ_L()分别是将DQ对应的引脚设置为高电平和低电平:


#define DQ_H GPIO_SetBits(GPIODQ,PINDQ)
#define DQ_L GPIO_ResetBits(GPIODQ,PINDQ)

Delay_us()的实现如下:


/*** @brief 延时函数* @param us_cnt 设定的延时微秒数* @retval 无*/
void Delay_us(uint32_t us_cnt)
{TIM3->CNT = us_cnt-1;TIM3->CR1 |= TIM_CR1_CEN;while((TIM3->SR & TIM_FLAG_Update)!=SET);TIM3->SR = (uint16_t)~TIM_FLAG_Update;TIM3->CR1 &= ~TIM_CR1_CEN;
}

这个函数需要配置定时器以支持计时:


/*** @brief 配置延时定时器* @param us_cnt 设定的延时微秒数* @retval 无
*/
void Delay_Timer_Init(void)
{TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);TIM_TimeBaseStructInit(&TIM_TimeBaseInitStruct);TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Down;TIM_TimeBaseInitStruct.TIM_Period = 100-1;TIM_TimeBaseInitStruct.TIM_Prescaler = (84-1);TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStruct);while((TIM3->SR & TIM_FLAG_Update)!=SET);TIM3->SR = (uint16_t)~TIM_FLAG_Update;
}

2、通过DQ读取一个字节


/*** @brief  通过DQ从DS18B20读取一个字节(Byte)* @param   无* @retval  读取到的数据(uint8_t类型)*/
uint8_t DS18B20_ReadByte(void)
{uint8_t data = 0x00;for(int i=0;i<8;i++){DS18B20_SetDQMode_OUT();/* 将数据线拉高“1” */DQ_H;/* 延时2微秒 */Delay_us(2);/* 将数据线拉低“0” */DQ_L;/* 延时3微秒 */Delay_us(3); data>>=1;/* 将数据线拉高“1” */DQ_H;DS18B20_SetDQMode_IPU();/* 延时5微秒 */Delay_us(5);/* 读数据线的状态得到1个状态位,并进行数据处理 */if(GPIO_ReadInputDataBit(GPIODQ,PINDQ))data|=0x80;/* 延时60微秒 */Delay_us(60);}return data;
}

同样的,注意阅读注释中的描述。

DS18B20_SetDQMode_IPU()把DQ对应的引脚设置为输入模式:


/*** @brief  设置DQ对应的引脚为输入模式* @param   无  * @retval  无*/
static void DS18B20_SetDQMode_IPU()
{/*定义一个GPIO_InitTypeDef类型的结构体*/GPIO_InitTypeDef GPIO_InitStructure;/*选择要控制的GPIO引脚*/GPIO_InitStructure.GPIO_Pin = PINDQ;    /*设置引脚模式为通用推挽输出*/GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;   /*调用库函数,初始化GPIO*/GPIO_Init(GPIODQ, &GPIO_InitStructure);
}

3、通过DQ发送一个字节


/**
* @brief  通过DQ向DS18B20发送一个字节(Byte)
* @param   @arg data 待发送的1字节数据
* @retval  无*/
void DS18B20_WriteByte(uint8_t data)
{for(int i=0;i<8;i++){/* 数据线先置低电平“0” */DQ_L;/* 延时确定的时间为15微秒 */Delay_us(15);/* 按从低位到高位的顺序发送字节(一次只发送一位) */if(data&0x01){GPIO_WriteBit(GPIODQ,PINDQ,Bit_SET);      }else{GPIO_WriteBit(GPIODQ,PINDQ,Bit_RESET);}/* 延时时间为45微秒 */Delay_us(45);/* 将数据线拉到高电平 */DQ_H;data>>=1;}
}

4、读取温度


/*** @brief  获取温度寄存器的值并转换为温度值返回* @param   无* @retval  无*/
float DS18B20_GetTemp(void)
{DS18B20_Rst();DS18B20_WriteByte(SKIPROMCOMMAND);DS18B20_WriteByte(CONVERTT);DS18B20_Rst();DS18B20_WriteByte(SKIPROMCOMMAND);DS18B20_WriteByte(READSCRATCHPAD);uint8_t tempL = DS18B20_ReadByte();uint8_t tempH = DS18B20_ReadByte();/* 反码 */if(tempH>0x7f){tempL = ~tempL;tempH = ~tempH+1;}/* 计算温度值 */float temp = ((tempH<<4)|(tempL>>4))+(float)(tempL&0x0f)*0.0625; return temp;
}

其中的SKIPROMCOMMANDCONVERTTREADSCRATCHPAD都是 ds18b20 的控制指令:




温度计算的部分需要注意一下:


/* 计算温度值 */
float temp = ((tempH<<4)|(tempL>>4))+
(float)(tempL&0x0f)*0.0625;

数据手册的表述如下:



1、黑色-划掉的是多余的符号位
2、红色-对应着整数位
3、蓝色-下划线部分对应小数

首先,(高8位左移4位)或上(低八位右移4位),得到8位的整数部分:


((tempH<<4)|(tempL>>4))

然后,低8位去掉左边4位:


(tempL&0x0f)

乘2^(-4)化成小数:


(float)(tempL&0x0f)*0.0625

整数部分和小数部分加起来得到温度值:


float temp = ((tempH<<4)|(tempL>>4))+
(float)(tempL&0x0f)*0.0625;

好啦,ds18b20的驱动就介绍完了,源代码的链接放在下面:


基于stm32F1标准库开发的DS18B20驱动

timer.x提供时序控制支持
ds18b20.x是驱动内容,供以读取温度数据


怎样用stm32驱动ds18b20温度芯片相关推荐

  1. STM32驱动DS18B20温度传感器

    简介:STM32F103C8T6驱动DS18B20温度传感器源码介绍. 开发平台:KEIL ARM MCU型号:STM32F103C8T6 传感器型号:DS18B20 特别提示:驱动内可能使用了某些其 ...

  2. STM32驱动AD7366-5/AD7367-5芯片

    目录 芯片介绍 芯片引脚定义 芯片电路图 根据时序写驱动代码 运行环境 时序与代码讲解 完整的代码 在实验室项目上,根据需求最终选用到了这款AD7367-5,在此记录一下这款AD芯片的驱动调试过程.目 ...

  3. STM32读取DS18B20温度,并在OLED上显示

    部分代码来源于网络,侵权删 本文使用硬件:STM32F103C8T6最小系统板.IIC协议0.96寸OLED屏幕显示.DS18B20传感器 实现功能:在OLED上显示出DS18B20采集到的温度,精确 ...

  4. stm32驱动syn6288语音合成芯片

    一.6288电路原理图 二.模块与 USB 转 TTL下载器的连接 根据模块的端口 VCC-RXD-TXD-GND (如图一实物引 脚 ) 对 应 连 接 USB 转 TTL 下 载 器 的 VCC- ...

  5. STM32入门开发: 编写DS18B20温度传感器驱动(读取环境温度、支持级联)

    一.环境介绍 编程软件: keil5 操作系统: win10 MCU型号: STM32F103C8T6 STM32编程方式: 寄存器开发 (方便程序移植到其他单片机) 温度传感器: DS1820 DS ...

  6. K_A11_002 基于STM32等单片机驱动DS18B20串口与OLED0.96双显示

    K_A11_002 基于STM32等单片机驱动DS18B20 串口与OLED0.96双显示 一.资源说明 二.基本参数 1.参数 2.引脚说明 三.驱动说明 时序 对应程序: 四.部分代码说明 1.接 ...

  7. 基于STM32的DS1302时钟芯片驱动

    基于STM32的DS1302时钟芯片驱动 /****************************************************************************** ...

  8. stm32读取目标芯片_使用stm32驱动RC522读IC卡(代码留言邮箱)

    RC522与PN532简介 关于STM32驱动方式 接线说明 程序烧录 查看卡号 总结 RC522与PN532简介 在写这篇文章之前有写过一篇有关于PN532的文章,RC522与PN532在使用上都可 ...

  9. 【常用芯片】ULN2003工作原理及中文资料(实例:STM32驱动28BYJ48步进电机)

    ULN2003的基本介绍 ULN2003的概述 ULN2003是高耐压.大电流复合晶体管阵列,由七个硅NPN 复合晶体管组成.一般采用DIP-16 或SOP-16 塑料封装. ULN2003的主要特点 ...

  10. 51单片机驱动DS18B20温度传感器测量温度

    51单片机驱动DS18B20温度传感器测量温度 1.DS18B20温度传感器介绍: 2.51单片机驱动DS18B20测量温度 1.DS18B20温度传感器介绍: ①引脚定义 引脚 符号 说明 1 GN ...

最新文章

  1. Java性能优化最易操作的10大技巧!
  2. windows如何卸载Oracle
  3. 王者服务器维护宝箱礼包都没领,王者荣耀:S19战令最后一天,还没领取奖励的玩家要注意了...
  4. 解决ajax 发送post 请求时csrf_token 问题
  5. PID算法搞不懂?看这篇文章就够了。
  6. 在Java 8之前的项目中使用JUnit 5
  7. C++轻量级微服务_微服务技术栈:API网关中心,落地实现方案
  8. Atom飞行手册翻译: 4.5 ~ 4.8
  9. leetcode Valid Palindrome
  10. Android9王者荣耀卡顿,王者荣耀卡顿掉帧?教你如何让王者荣耀流畅爆表
  11. 调用大漠插件5.1423
  12. android媒体--stagefright概述
  13. 私域流量客服社群运营员工工作绩效表格方案计划手册指南宝典
  14. Ubuntu 20.04 Micosoft edg 浏览器安装教程
  15. HTML5文件夹隐藏了怎么打开,win10怎么打开隐藏文件夹
  16. ES7210四通道ADC芯片电路PCB-LAYOUT注意
  17. 1.background、color、渐变
  18. TCP/IP协议分层
  19. 看图学习VMWare以及常见问题答疑(转)
  20. u盘写入映像时提示:主引导记录(mbr)写入失败!!

热门文章

  1. spark的安装详细步骤
  2. shp系列(四)——利用C++进行Shx文件的读(打开)
  3. 字节跳动的面试算法题,实在太变态了
  4. 齿轮转速比和啮合频率
  5. Mall谷粒商城(基础篇的开发)
  6. 数字隔离器件在功率计量芯片中的应用
  7. 原生JavaScript + Canvas实现图片局部放大器
  8. 数字电路基础知识—— IO外设之GPIO介绍
  9. NRF52840 BLE OTA
  10. linux下游戏手柄测试程序