【STM32】stm32f407 + DS18B20 碰出不一样的火花

Author:AXYZdong 自动化专业 工科男
有一点思考,有一点想法,有一点理性!
定个小小目标,努力成为习惯!在最美的年华遇见更好的自己!
CSDN@AXYZdong,CSDN首发,AXYZdong原创
唯一博客更新的地址为: 👉 AXYZdong的博客 👈

在这里插入图片描述

▲ 碰撞、火花


前言

之前在这篇文章:【STM32学习记录4】1.44寸TFT液晶屏显示字符、汉字和图片
卖了一个关子:
在这里插入图片描述
今天把这个给补上。点击下载完整工程

  • 开发板:stm32f407VET6
  • 开发环境:keil5 MDK

一、硬件基础——DS18B20

1.DS18B20简介

在这里插入图片描述

2.硬件连接

根据手册,DS18B20的硬件接法很简单,分为以下两种:

需要注意的是不管哪一种接法DQ上一定要接个上拉电阻

1.【寄生接法】

DS18B20_GND → \to STM32F407_GND

DS18B20_VCC → \to STM32F407_GND

DS18B20_DQ → \to STM32F407_P**

DQ引脚可接任意IO口

关于寄生方式,需要注意以下几点:

  • DS18B20的寄生方式是在DQ引脚为高电平时“窃取”电源,同时将部分能量存储在内部的电容里。
    所以,上拉电阻!!一定要接上!!

  • 为了使DS18B20准确完成温度转换,当温度转换发生时,IO口必须提供足够大的功率。
    DS18B20的工作电流高达1mA,5K的上拉电阻使得IO口没有足够的驱动能力。
    如果多个DS18B20在同一个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,有点玄学了。

3.单总线协议

在这里插入图片描述

执行序列 通过单线总线端口访问 DS18B20 的协议如下:

  • 步骤1. 初始化
  • 步骤2. ROM 操作指令
  • 步骤3. DS18B20 功能指令

步骤1. 初始化

通过单总线的所有执行操作处理都从一个初始化序列开始。初始化序列包括一个由总线控制器发出的复位脉冲和其后由从机发出的存在脉冲。存在脉冲让总线控 制器知道 DS18B20 在总线上且已准备好操作。

步骤2. ROM 操作指令

一旦总线控制器探测到一个存在脉冲,它就发出一条 ROM 指令。如果总线上挂有 多只 DS18B20,这些指令将基于器件独有的 64 位 ROM 片序列码使得总线控制器 选出特定要进行操作的器件。这些指令同样也可以使总线控制器识别有多少只, 什么型号的器件挂在总线上,同样,它 们也可以识别哪些器件已经符合报警条件。ROM 指令有 5 条,都是 8 位长度。总线控制器在发起一条 DS18B20 功能指令之前必须先发出一条 ROM 指令。

步骤3. DS18B20 功能指令

在总线控制器发给欲连接的DS18B20一条ROM命令后,跟着可以发送一条 DS18B20 功能指令。这些命令允许总线控制器读写 DS18B20 的暂存器,发起温度转换和识别电源模式。

插播一条反爬虫信息,读者可以忽略:


在这里插入图片描述

二、编程思路

在这里插入图片描述

DS18B20.h


// =============================================
# @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 */

DS18B20.c


// =============================================
# @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 连接引脚定义


三、效果

在这里插入图片描述

总结

  • 写驱动的时间不是很长的,也有很多源码,参考修改即可。

  • 最关键的还是后期的调试,以及把读出来的温度显示到 TFT 屏上

  • 单总线的时序也要关注,不同开发板的频率不同,延时也有差异。


「你可能还想看」系列文章:
【STM32】点亮LED
【STM32】GPIO输入—按键检测
【STM32】0.96寸OLED显示屏(7针SPI协议)软件模拟SPI
【STM32】1.44寸TFT液晶屏显示字符、汉字和图片
【STM32】5分钟了解STM32的串口通信
【STM32】串口通信—用代码与芯片对话
【STM32】串口通信出现乱码(使用官方标准库)
【STM32】EXTI—外部中断/事件控制器
【STM32】TIM—基本定时器
【STM32】PWM 输出 (标准库)

【STM32】CubeMX+HAL 点亮LED
【STM32】CubeMX+HAL 输出PWM

【STM32】ST-LINK下载器下载后需复位,程序才运行的问题

其他相关文章:
【信号与系统】笔记合集,你确定不收藏吗?我已经收藏了
我用50行代码居然「让天猫精灵把客厅灯开了」
流程图在线绘制,快速、便捷、高效!


  本次的分享就到这里


11

好书不厌百回读,熟读自知其中意。将学习成为习惯,用知识改变命运,用博客见证成长,用行动证明努力。
如果我的博客对你有帮助、如果你喜欢我的博客内容,请 “点赞” “评论” “收藏” 一键三连哦!
听说 👉 点赞 👈 的人运气不会太差,每一天都会元气满满呦!^ _ ^ ❤️ ❤️ ❤️
码字不易,大家的支持就是我坚持下去的动力。点赞后不要忘了👉关注👈我哦!
更多精彩内容请前往 AXYZdong的博客


如果以上内容有任何错误或者不准确的地方,欢迎在下面👇留个言。或者你有更好的想法,欢迎一起交流学习~~~

STM32F407单片机读写 DS18B20温度传感器 并串口屏显示DEMO软件例程源码,可以做为你的学习设计参考。 int main(void) { uint8_t DS18B20ID[8]; float temperature; /* 复位所有外设,初始化Flash接口和系统滴答定时器 */ HAL_Init(); /* 配置系统时钟 */ SystemClock_Config(); /* 初始化串口并配置串口中断优先级 */ MX_DEBUG_USART_Init(); HMI_USARTx_Init(); while(DS18B20_Init()) { printf("DS18B20温度传感器存在\n"); HAL_Delay(1000); } printf("检测到DS18B20温度传感器,并初始化成功\n"); DS18B20_ReadId(DS18B20ID); /* 无限循环 */ while (1) { temperature=DS18B20_GetTemp_MatchRom(DS18B20ID); /* 打印通过 DS18B20 序列号获取的温度值 */ printf("获取该序列号器件的温度:%.1f\n",temperature); HMI_value_setting("page1.gross.val",temperature*10); HAL_Delay(1000); } } /** * 函数功能: 向串口屏发送数据 * 输入参数: 无 * 返 回 值: 无 * 说 明: 无 */ void HMI_value_setting(const char *val_str,uint32_t value) { uint8_t tmp_str[30]={0}; uint8_t i; sprintf((char *)tmp_str,"%s=%d",val_str,value); for(i=0;iDR=tmp_str[i]; while(__HAL_UART_GET_FLAG(&husartx_HMI, UART_FLAG_TXE) == RESET); } HMI_USARTx->DR=0xFF; while(__HAL_UART_GET_FLAG(&husartx_HMI, UART_FLAG_TXE) == RESET); HMI_USARTx->DR=0xFF; while(__HAL_UART_GET_FLAG(&husartx_HMI, UART_FLAG_TXE) == RESET); HMI_USARTx->DR=0xFF; while(__HAL_UART_GET_FLAG(&husartx_HMI, UART_FLAG_TXE) == RESET); } /** * 函数功能: 向串口屏发送浮点数据 * 输入参数: 无 * 返 回 值: 无 * 说 明: 无 */ void HMI_string_setting(const char *val_str,int32_t value) { uint8_t tmp_str[50]={0}; uint8_t i; float temp=(float)value; sprintf((char *)
### IntelliJ IDEA 中通义灵码 AI 功能介绍 IntelliJ IDEA 提供了一系列强大的工具来增强开发体验,其中包括与通义灵码 AI 相关的功能。这些功能可以帮助开发者更高效地编写代码并提高生产力。 #### 安装通义灵码插件 为了使用通义灵码的相关特性,在 IntelliJ IDEA 中需要先安装对应的插件: 1. 打开 **Settings/Preferences** 对话框 (Ctrl+Alt+S 或 Cmd+, on macOS)。 2. 导航到 `Plugins` 页面[^1]。 3. 在 Marketplace 中搜索 "通义灵码" 并点击安装按钮。 4. 完成安装后重启 IDE 使更改生效。 #### 配置通义灵码服务 成功安装插件之后,还需要配置通义灵码的服务连接信息以便正常使用其提供的各项能力: - 进入设置中的 `Tools | Qwen Coding Assistant` 菜单项[^2]。 - 填写 API Key 和其他必要的认证参数。 - 测试连接以确认配置无误。 #### 使用通义灵码辅助编程 一旦完成上述准备工作,就可以利用通义灵码来进行智能编码支持了。具体操作如下所示: ##### 自动补全代码片段 当输入部分语句时,IDE 将自动提示可能的后续逻辑,并允许一键插入完整的实现方案[^3]。 ```java // 输入 while 循环条件前半部分... while (!list.isEmpty()) { // 激活建议列表选择合适的循环体内容 } ``` ##### 解释现有代码含义 选中某段复杂的表达式或函数调用,右键菜单里会有选项可以请求通义灵码解析这段代码的作用以及优化意见。 ##### 生产测试案例 对于已有的业务逻辑模块,借助于通义灵码能够快速生成单元测试框架及初始断言集,减少手动构建的成本。 ```python def test_addition(): result = add(2, 3) assert result == 5, f"Expected 5 but got {result}" ```
评论 38
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AXYZdong

你的鼓励是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值