怎样用stm32驱动ds18b20温度芯片
一、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;
}
其中的SKIPROMCOMMAND
、CONVERTT
、READSCRATCHPAD
都是 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温度芯片相关推荐
- STM32驱动DS18B20温度传感器
简介:STM32F103C8T6驱动DS18B20温度传感器源码介绍. 开发平台:KEIL ARM MCU型号:STM32F103C8T6 传感器型号:DS18B20 特别提示:驱动内可能使用了某些其 ...
- STM32驱动AD7366-5/AD7367-5芯片
目录 芯片介绍 芯片引脚定义 芯片电路图 根据时序写驱动代码 运行环境 时序与代码讲解 完整的代码 在实验室项目上,根据需求最终选用到了这款AD7367-5,在此记录一下这款AD芯片的驱动调试过程.目 ...
- STM32读取DS18B20温度,并在OLED上显示
部分代码来源于网络,侵权删 本文使用硬件:STM32F103C8T6最小系统板.IIC协议0.96寸OLED屏幕显示.DS18B20传感器 实现功能:在OLED上显示出DS18B20采集到的温度,精确 ...
- stm32驱动syn6288语音合成芯片
一.6288电路原理图 二.模块与 USB 转 TTL下载器的连接 根据模块的端口 VCC-RXD-TXD-GND (如图一实物引 脚 ) 对 应 连 接 USB 转 TTL 下 载 器 的 VCC- ...
- STM32入门开发: 编写DS18B20温度传感器驱动(读取环境温度、支持级联)
一.环境介绍 编程软件: keil5 操作系统: win10 MCU型号: STM32F103C8T6 STM32编程方式: 寄存器开发 (方便程序移植到其他单片机) 温度传感器: DS1820 DS ...
- K_A11_002 基于STM32等单片机驱动DS18B20串口与OLED0.96双显示
K_A11_002 基于STM32等单片机驱动DS18B20 串口与OLED0.96双显示 一.资源说明 二.基本参数 1.参数 2.引脚说明 三.驱动说明 时序 对应程序: 四.部分代码说明 1.接 ...
- 基于STM32的DS1302时钟芯片驱动
基于STM32的DS1302时钟芯片驱动 /****************************************************************************** ...
- stm32读取目标芯片_使用stm32驱动RC522读IC卡(代码留言邮箱)
RC522与PN532简介 关于STM32驱动方式 接线说明 程序烧录 查看卡号 总结 RC522与PN532简介 在写这篇文章之前有写过一篇有关于PN532的文章,RC522与PN532在使用上都可 ...
- 【常用芯片】ULN2003工作原理及中文资料(实例:STM32驱动28BYJ48步进电机)
ULN2003的基本介绍 ULN2003的概述 ULN2003是高耐压.大电流复合晶体管阵列,由七个硅NPN 复合晶体管组成.一般采用DIP-16 或SOP-16 塑料封装. ULN2003的主要特点 ...
- 51单片机驱动DS18B20温度传感器测量温度
51单片机驱动DS18B20温度传感器测量温度 1.DS18B20温度传感器介绍: 2.51单片机驱动DS18B20测量温度 1.DS18B20温度传感器介绍: ①引脚定义 引脚 符号 说明 1 GN ...
最新文章
- Java性能优化最易操作的10大技巧!
- windows如何卸载Oracle
- 王者服务器维护宝箱礼包都没领,王者荣耀:S19战令最后一天,还没领取奖励的玩家要注意了...
- 解决ajax 发送post 请求时csrf_token 问题
- PID算法搞不懂?看这篇文章就够了。
- 在Java 8之前的项目中使用JUnit 5
- C++轻量级微服务_微服务技术栈:API网关中心,落地实现方案
- Atom飞行手册翻译: 4.5 ~ 4.8
- leetcode Valid Palindrome
- Android9王者荣耀卡顿,王者荣耀卡顿掉帧?教你如何让王者荣耀流畅爆表
- 调用大漠插件5.1423
- android媒体--stagefright概述
- 私域流量客服社群运营员工工作绩效表格方案计划手册指南宝典
- Ubuntu 20.04 Micosoft edg 浏览器安装教程
- HTML5文件夹隐藏了怎么打开,win10怎么打开隐藏文件夹
- ES7210四通道ADC芯片电路PCB-LAYOUT注意
- 1.background、color、渐变
- TCP/IP协议分层
- 看图学习VMWare以及常见问题答疑(转)
- u盘写入映像时提示:主引导记录(mbr)写入失败!!