之前在这篇文章:【STM32学习记录4】1.44寸TFT液晶屏显示字符、汉字和图片
卖了一个关子:
今天把这个给补上。点击下载完整工程
根据手册,DS18B20的硬件接法很简单,分为以下两种:
需要注意的是不管哪一种接法DQ上一定要接个上拉电阻
1.【寄生接法】
DS18B20_GND → \to → STM32F407_GND
DS18B20_VCC → \to → STM32F407_GND
DS18B20_DQ → \to → STM32F407_P**
DQ引脚可接任意IO口
关于寄生方式,需要注意以下几点:
2.【正常供电】
DS18B20_GND → \to → STM32F407_GND
DS18B20_VCC → \to → STM32F407_VCC
DS18B20_DQ → \to → STM32F407_P**
参考文章:https://blog.csdn.net/weixin_40774605/article/details/88557470
关于
DQ上一定要接个上拉电阻
这个问题,我做的时候是没有接上拉电阻的,但是也可以读到温度。emmm,有点玄学了。
执行序列 通过单线总线端口访问 DS18B20 的协议如下:
通过单总线的所有执行操作处理都从一个初始化序列开始。初始化序列包括一个由总线控制器发出的复位脉冲和其后由从机发出的存在脉冲。存在脉冲让总线控 制器知道 DS18B20 在总线上且已准备好操作。
一旦总线控制器探测到一个存在脉冲,它就发出一条 ROM 指令。如果总线上挂有 多只 DS18B20,这些指令将基于器件独有的 64 位 ROM 片序列码使得总线控制器 选出特定要进行操作的器件。这些指令同样也可以使总线控制器识别有多少只, 什么型号的器件挂在总线上,同样,它 们也可以识别哪些器件已经符合报警条件。ROM 指令有 5 条,都是 8 位长度。总线控制器在发起一条 DS18B20 功能指令之前必须先发出一条 ROM 指令。
在总线控制器发给欲连接的DS18B20一条ROM命令后,跟着可以发送一条 DS18B20 功能指令。这些命令允许总线控制器读写 DS18B20 的暂存器,发起温度转换和识别电源模式。
// =============================================
# @Time : 2020-06-08
# @Author : AXYZdong
# @CSDN : https://blog.csdn.net/qq_43328313
# @FileName: DS18B20.h
# @Software: keil5 MDK
// =============================================
#ifndef __DS18B20_H
#define __DS18B20_H
#include "stm32f4xx.h"
/************************** DS18B20 连接引脚定义********************************/
#define RCC_DS18B20 RCC_AHB1Periph_GPIOB
#define DS18B20_DQ_GPIO_PORT GPIOB
#define DS18B20_DQ_GPIO_PIN GPIO_Pin_6
/************************** DS18B20 函数宏定义********************************/
#define DS18B20_DQ_L GPIO_ResetBits ( DS18B20_DQ_GPIO_PORT, DS18B20_DQ_GPIO_PIN )
#define DS18B20_DQ_H GPIO_SetBits ( DS18B20_DQ_GPIO_PORT, DS18B20_DQ_GPIO_PIN )
#define DS18B20_DQ_IN() GPIO_ReadInputDataBit ( DS18B20_DQ_GPIO_PORT, DS18B20_DQ_GPIO_PIN )
/************************** DS18B20 函数声明 ********************************/
void DS18B20_Init(void);
void display(char *tab);
#endif /* __DS18B20_H */
// =============================================
# @Time : 2020-06-08
# @Author : AXYZdong
# @CSDN : https://blog.csdn.net/qq_43328313
# @FileName: DS18B20.c
# @Software: keil5 MDK
// =============================================
#include "stm32f4xx.h"
#include "ds18b20.h"
#include "delay.h"
/*******************************************************************************
* 函数名:DS18B20_GPIO_Config
* 描述 :配置DS18B20用到的I/O口
* 输入 :无
* 输出 :无
*******************************************************************************/
void DS18B20_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_DS18B20, ENABLE); /*开启DS18B20对应的GPIO的外设时钟*/
GPIO_InitStructure.GPIO_Pin = DS18B20_DQ_GPIO_PIN; /*选择要控制的DS18B20引脚*/
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; /*设置引脚模式输出模式*/
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; /*设置引脚的输出类型为推挽输出*/
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; /*设置引脚速率为50MHz */
GPIO_Init(DS18B20_DQ_GPIO_PORT, &GPIO_InitStructure); /*调用库函数,初始化相应GPIO*/
}
/*******************************************************************************
* 函数名:DS18B20_Mode_Out
* 描述 :使DS18B20-DATA引脚变为输出模式
* 输入 :无
* 输出 :无
*******************************************************************************/
static void DS18B20_Mode_Out(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/*选择要控制的DS18B20_DQ_GPIO_PORT引脚*/
GPIO_InitStructure.GPIO_Pin = DS18B20_DQ_GPIO_PIN;
/*设置引脚模式输出模式*/
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
/*设置引脚的输出类型为推挽输出*/
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
/*设置引脚速率为50MHz */
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
/*调用库函数,初始化DS18B20_DQ_GPIO_PORT*/
GPIO_Init(DS18B20_DQ_GPIO_PORT, &GPIO_InitStructure);
}
/*******************************************************************************
* 函数名:DS18B20_Mode_IN
* 描述 :使DS18B20-DATA引脚变为输入模式
* 输入 :无
* 输出 :无
*******************************************************************************/
static void DS18B20_Mode_IN(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/*选择要控制的DS18B20_DQ_GPIO_PORT引脚*/
GPIO_InitStructure.GPIO_Pin = DS18B20_DQ_GPIO_PIN;
/*设置引脚模式为浮空输入模式*/
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
/*调用库函数,初始化DS18B20_DQ_GPIO_PORT*/
GPIO_Init(DS18B20_DQ_GPIO_PORT, &GPIO_InitStructure);
}
void DS18B20_Init()
{
DS18B20_GPIO_Config();
}
/*******************************************************************************
* 函数名:DS18B20_Reset
* 描述 :初始化DS18B20
* 输入 :无
* 输出 :无
* 返回值:初始化成功为0,不成功为1
*******************************************************************************/
int DS18B20_Reset(void)
{
DS18B20_Mode_Out();
int initflag = 0;
DS18B20_DQ_H; //先置高
delay_us(700); //延时700us,使总线稳定
DS18B20_DQ_L; //复位脉冲,低电位
delay_us(750); //保持至少480us,这里500us
DS18B20_DQ_H; //拉高数据线,释放总线
delay_us(40); //等待15-60us,这里33us
DS18B20_Mode_IN();
initflag = GPIO_ReadInputDataBit(DS18B20_DQ_GPIO_PORT,DS18B20_DQ_GPIO_PIN);
delay_us(60);
return initflag;
}
/*******************************************************************************
* 函数名:DS18B20_Wbyte
* 功能:写一个字节
* 输入:uint8_t xbyte
* 输出:无
* 返回值:无
* 备注:无
*******************************************************************************/
void Write_DS18B20(unsigned char xbyte)
{
int8_t i ,x = 0;
DS18B20_Mode_Out();
//8次循环实现逐位写入
for(i = 1; i <= 8; i++)
{
//先取低位
x = xbyte & 0x01;
//写1
if(x)
{
DS18B20_DQ_H;
//拉低总线
DS18B20_DQ_L;
//延时15us
delay_us(15);
//总线写1
DS18B20_DQ_H;
//延时15us
delay_us(15);
//保持高电平
DS18B20_DQ_H;
delay_us(4);
}
//写0
else
{
DS18B20_DQ_H;
//总线拉低
DS18B20_DQ_L;
//延时15us
delay_us(15);
//总线写0
DS18B20_DQ_L;
//延时15us
delay_us(15);
//保持高电平
DS18B20_DQ_H;
delay_us(4);
}
//xbyte右移一位
xbyte = xbyte >> 1;
}
}
/*******************************************************************************
* 函数名:DS18B20_Rbit
* 功能:从DS18B20读一个位
* 输入:无
* 输出:无
* 返回值:读取到的位
* 备注:无
*******************************************************************************/
uint8_t DS18B20_Rbit(void)
{
//rbit是最终位数据,x是取状态变量
uint8_t rbit = 0x00,x = 0;
DS18B20_Mode_Out(); //改变DQ为输出模式
DS18B20_DQ_H;
DS18B20_DQ_L;
delay_us(1);
DS18B20_DQ_H;
//延时大约3us
//delay_us(7);
//获取总线电平状态
x = DS18B20_DQ_IN();
//如果是1,则返回0x80,否则返回0x00
if(x)
rbit = 0x80;
//延时大约60us
delay_us(60);
return rbit;
}
/*******************************************************************************
* 函数名:DS18B20_Rbyte
* 功能:从DS18B20读一个字节
* 输入:无
* 输出:无
* 返回值:读取到的字节
* 备注:无
*******************************************************************************/
uint8_t DS18B20_Rbyte(void)
{
//rbyte:最终得到的字节
//tempbit:中间运算变量
uint8_t rbyte = 0,i = 0, tempbit =0;
for (i = 1; i <= 8; i++)
{
//读取位
tempbit = DS18B20_Rbit();
//右移实现高低位排序
rbyte = rbyte >> 1;
//或运算移入数据
rbyte = rbyte|tempbit;
}
return rbyte;
}
/*******************************************************************************
* 函数名:ReadTemperature
* 功能:读取温度
* 输入:无
* 输出:温度值
* 返回值:无
* 备注:注意温度的转换
*******************************************************************************/
int ReadTemperature(void)
{
int fg; //fg:符号位
int data; //data:温度的整数部分
float f_data; //f_data:温度(浮点型)
DS18B20_Reset(); //DS18B20初始化
Write_DS18B20(0xcc); //跳过读序列号
Write_DS18B20(0x44); //启动温度转换
delay_us(200); //等待温度转换
DS18B20_Reset(); //DS18B20初始化
Write_DS18B20(0xcc); //跳过读序列号
Write_DS18B20(0xbe); //读温度寄存器
uint8_t TempL = DS18B20_Rbyte();
uint8_t TempH = DS18B20_Rbyte();
//符号位为负
if(TempH > 0x70)
{
TempL = ~TempL;
TempH = ~TempH;
fg = 0;
}
else
fg = 1;
//整数部分
data = TempH;
data <<= 8;
data = data | TempL;
f_data = data*0.0625;
data = f_data *10 ;
if(fg)
return data;
else
return -data;
}
/*******************************************************************************
* 函数名:display
* 功能:显示温度
* 输入:*tab
* 输出:温度值
* 返回值:无
* 备注:注意温度的转换
*******************************************************************************/
void display(char *tab)
{
tab[0] = ReadTemperature()/100 + 0x30;
tab[1] = ReadTemperature()%100/10 + 0x30;
tab[3] = ReadTemperature()%10 + 0x30;
tab[2] = '.';
tab[4] = 'C';
}
若果要移植代码,只需修改头文件中
DS18B20 连接引脚定义
本次的分享就到这里