历史上的今天
返回首页

历史上的今天

今天是:2025年07月26日(星期六)

正在发生

2021年07月26日 | STM32CubeMX | 33-使用GPIO读取温度传感器数据(DS18B20)

2021-07-26 来源:eefocus

本篇详细的记录了如何使用STM32CubeMX配置 STM32103RET6 的硬件GPIO外设读取温度传感器DS18B20的数据。


1. 准备工作

硬件准备

  • 开发板
    首先需要准备一个开发板,这里我准备的是一个工业DTU,主控芯片为STM32103RBT6。

  • DS18B20
    DTU开发板板载一颗DS18B20温度传感器。

3. 使用STM32CubeMX生成工程


选择芯片型号

打开STM32CubeMX,打开MCU选择器:

搜索并选中芯片STM32F103RET6:


配置时钟源

  • 如果选择使用外部高速时钟(HSE),则需要在System Core中配置RCC;

  • 如果使用默认内部时钟(HSI),这一步可以略过;

这里我都使用外部时钟:

配置调试选项

STM32CubMX配置默认没有开启调试选项,需要手动开启:

配置串口

开发板板载了一个CH340换串口,连接到USART1,可用于日志打印:

接下来开始配置USART1:

配置DS18B20通信GPIO

查看开发板原理图,找到与DS18B20通信的GPIO:

配置PA1引脚:

配置时钟树

STM32F103RET6的最高主频到72M,使HCLK = 72Mhz即可:

生成工程设置

代码生成设置

最后设置生成独立的初始化文件:

生成代码

点击GENERATE CODE即可生成MDK-V5工程:

3. 重定向printf到串口1

在usart.c文件末尾添加重定向代码:


/* USER CODE BEGIN 1 */

#if 1

#include


int fputc(int ch, FILE *stream)

{

    /* 堵塞判断串口是否发送完成 */

    while((USART1->SR & 0X40) == 0);


    /* 串口发送完成,将该字符发送 */

    USART1->DR = (uint8_t) ch;


    return ch;

}

#endif

/* USER CODE END 1 */


详细说明请参考文章:STM32CubeMX_09 | 重定向printf函数到串口输出的多种方法。


4. 编写DS18B20驱动代码

4.1. STM32微妙级延时函数

DS18B20是单总线驱动,所以需要精确的us级延时函数,参考文章:


一种Cortex-M内核中的精确延时方法

4.2. DS18B20底层操作函数封装

主要包括:


GPIO输出模式配置

GPIO输出高电平

GPIO输出低电平

GPIO输入模式配置

GPIO读取输入

us级延时函数

在ds18b20.h中编写代码,使用宏来封装,便于驱动移植:


#include "stm32f1xx.h"

#include "core_delay/core_delay.h"


/* DS18B20控制引脚 */

#define DS18B20_GPIO_PORT     GPIOA

#define DS18B20_GPIO_PIN      GPIO_PIN_1


/* DS18B20控制IO模式配置 */

#define DS18B20_OutPut_Mode() {DS18B20_GPIO_PORT->CRL &= 0x0FFFFFFF;DS18B20_GPIO_PORT->CRL |= 0x30000000;}

#define DS18B20_InPut_Mode()  {DS18B20_GPIO_PORT->CRL &= 0x0FFFFFFF;DS18B20_GPIO_PORT->CRL |= 0x80000000;}


/* DS18B20控制IO操作函数 */

#define DS18B20_Out(n)        (n?HAL_GPIO_WritePin(DS18B20_GPIO_PORT,DS18B20_GPIO_PIN,GPIO_PIN_SET):HAL_GPIO_WritePin(DS18B20_GPIO_PORT,DS18B20_GPIO_PIN,GPIO_PIN_RESET))

#define DS18B20_In()           HAL_GPIO_ReadPin(DS18B20_GPIO_PORT,DS18B20_GPIO_PIN)


/* DS18B20 us 级延时函数 */

#define DS18B20_Delay_us(n)   CPU_TS_Tmr_Delay_US(n)


4.3. DS18B20操作时序实现

DS18B20主要有几个操作时序,在ds18b20.c中实现:


① 复位信号:



实现代码如下:


/**

  * @brief    发送复位信号

  * @param    none

  * @retval   none

*/

static void DS18B20_Send_Reset_Single(void)

{

DS18B20_OutPut_Mode();

    

    /* 拉低总线 480 - 960 us*/

DS18B20_Out(0);

DS18B20_Delay_us(750);

    

    /* 释放总线 15 - 60 us */

DS18B20_Out(1);

DS18B20_Delay_us(15);

}


/**

  * @brief    检测DS18B20存在脉冲

  * @param    none

  * @retval   0 DS18B20设备正常

  * @retval   1  DS18B20设备响应复位信号失败

  * @retval   2  DS18B20设备释放总线失败

*/

static uint8_t DS18B20_Check_Ready_Single(void)

{

uint8_t cnt = 0;

    

/* 1.检测存在脉冲 */

DS18B20_InPut_Mode();

    

    //等待DS18B20 拉低总线 (60~240 us 响应复位信号)

while (DS18B20_In() && cnt < 240) {

DS18B20_Delay_us(1);

cnt++;

}

    

if (cnt > 240) {

        return 1;

    }

    

/* 2.检测DS18B20是否释放总线 */

cnt = 0;

DS18B20_InPut_Mode();

    

    //判断DS18B20是否释放总线(60~240 us 响应复位信号之后会释放总线)

while ((!DS18B20_In()) && cnt<240) {

DS18B20_Delay_us(1);

cnt++;

}

    

if (cnt > 240) {

        return 2;

    } else {

        return 0;

    }

}


/**

  * @brief    检测DS18B20设备是否正常

  * @param    none

  * @retval   0 DS18B20设备正常

  * @retval   1  DS18B20设备响应复位信号失败

  * @retval   2  DS18B20设备释放总线失败

*/

static uint8_t DS18B20_Check_Device(void)

{

    /*1.主机发送复位信号*/

DS18B20_Send_Reset_Single();

    

    /*2.检测存在脉冲*/

return DS18B20_Check_Ready_Single();

}


/**

  * @brief    DS18B20初始化

  * @param    none

  * @retval   none

*/

void DS18B20_Init(void)

{

/* 1.DS18B20控制引脚初始化 */

    //在main函数中已经初始化,不需要再次重复。


/*2.检测DS18B20设备是否正常*/

switch (DS18B20_Check_Device()) {

case 0:

            printf("DS18B20_Init OK!n");

            break;

case 1:

            printf("DS18B20设备响应复位信号失败!n");

            break;

case 2:

            printf("DS18B20设备释放总线失败!n");

            break;

}

}


② 向DS18B20写一个字节时序:

实现代码如下:


/**

  * @brief    向DS18B20写一个字节

  * @param    cmd 要写入的字节

  * @retval   none

*/

static uint8_t DS18B20_Write_Byte(uint8_t cmd)

{

uint8_t i = 0;

    

    /* 1. 设置总线为输出模式 */

DS18B20_OutPut_Mode();

    

    /* 2. 发送数据,低位在前 */

for (i = 0; i < 8; i++) {

DS18B20_Out(0);

DS18B20_Delay_us(2);  

DS18B20_Out(cmd & 0x01);

DS18B20_Delay_us(60);

DS18B20_Out(1);

cmd >>= 1;

DS18B20_Delay_us(2);

}

    

return 0;

}


③ 从DS18B20读取一个字节数据时序:


实现代码如下:


/**

  * @brief    从DS18B20读一个字节

  * @param    none

  * @retval   读取到的一个字节数据

*/

uint8_t DS18B20_Read_Byte(void)

{

uint8_t i = 0;

    uint8_t data = 0;

    

    /* 读取数据 */

for (i  =0; i < 8; i++) {

DS18B20_OutPut_Mode();

DS18B20_Out(0);  

DS18B20_Delay_us(2);

DS18B20_Out(1);

        

DS18B20_InPut_Mode();

DS18B20_Delay_us(10);

data >>= 1 ;

if (DS18B20_In()) {

            data |= 0x80;

        }

        

DS18B20_Delay_us(60);

DS18B20_Out(1);

}

    

return data;

}


4.4. DS18B20读取温度函数实现

DS18B20读取温度需要发送一些命令,


温度转换指令:0x44(启动Ds18b20启动转换温度)

读暂存器指令:0xBE(读取暂存器中的九字节数据)

实现代码如下:


/**

  * @brief    从DS18B20读取一次数据

  * @param    none

  * @retval   读取到的温度数据

  * @note     适用于总线上只有一个DS18B20的情况

*/

uint16_t DS18B20_Read_Temperature(void)

{

    uint16_t temp = 0;

    uint8_t  temp_H, temp_L;


    DS18B20_Check_Device();

    

    DS18B20_Write_Byte(0xCC);

    DS18B20_Write_Byte(0x44);

    

    while (DS18B20_Read_Byte() != 0xFF);

    

    DS18B20_Check_Device();   //必须,不能省略

    

    DS18B20_Write_Byte(0xCC);

    DS18B20_Write_Byte(0xBE); 

    

    temp_L = DS18B20_Read_Byte(); 

    temp_H = DS18B20_Read_Byte(); 

    temp   = temp_L | (temp_H << 8);

    

    return temp;

}


至此,驱动编写完成,将两个供用户调用的函数在头文件中声明:


void DS18B20_Init(void);

uint16_t DS18B20_Read_Temperature(void);


4.5. 测试DS18B20温度值读取

在main.c中包含驱动头文件:


/* Private includes ----------------------------------------------------------*/

/* USER CODE BEGIN Includes */

#include

#include "ds18b20.h"

/* USER CODE END Includes */


在main函数中定义存放温度数据的变量:


/* USER CODE BEGIN 1 */

uint16_t temp;

int      intT, decT;

/* USER CODE END 1 */


在main函数中调用DS18B20初始化函数:


/* USER CODE BEGIN 2 */

printf("DS18B20 Test By Mculover666rn");

DS18B20_Init();

/* USER CODE END 2 */


接着每隔1s读取一次数据,并打印:


/* Infinite loop */

/* USER CODE BEGIN WHILE */

while (1)

{

/* USER CODE END WHILE */

/* USER CODE BEGIN 3 */

temp = DS18B20_Read_Temperature();

intT   = temp >> 4 ;          /*合成实际温度整数部分****精度相对上面的更高*/ 

decT   = temp & 0xF ;         /*合成实际温度小数部分*/

printf("Temp:%d.%drn", intT, decT);

  

HAL_Delay(1000);

}


编译,下载,在串口助手中查看结果,如下:

推荐阅读

史海拾趣

安路科技(Anlogic)公司的发展小趣事

随着技术的不断积累和市场的逐步开拓,安路科技在XXXX年成功推出了其首款高性能FPGA产品。这款产品以其优异的性能、稳定的品质和良好的性价比,迅速赢得了市场的青睐。此后,安路科技的产品线不断丰富,逐渐覆盖了更多应用领域,公司的市场份额也逐年攀升。

FILTRAN公司的发展小趣事

在发展过程中,安路科技积极寻求与产业链上下游企业的战略合作,通过技术合作、市场共享等方式,共同推动FPGA产业的发展。同时,公司也吸引了多家知名投资机构的关注,成功获得了多轮融资。这些资本的注入为安路科技的技术研发和市场拓展提供了强有力的支持。

博众电气(BOZHONG ELECTRIC)公司的发展小趣事

博众电气始终坚信,品质是企业生存和发展的根本。因此,公司始终将品质管理放在首位,并严格执行ISO9001等国际质量管理体系标准。

为了进一步提升产品品质和管理水平,博众电气还积极申请并通过了多项国际认证。这些认证不仅证明了博众电气的产品品质和管理水平达到了国际先进水平,还为公司的国际化发展提供了有力保障。

酷宅(Coolkit)公司的发展小趣事

酷宅科技始终将技术创新作为公司发展的核心驱动力。公司不断投入研发资源,推动物联网、云计算、大数据等前沿技术的研发和应用。通过技术创新,酷宅科技不仅提高了产品的智能化水平,还降低了生产成本,提高了生产效率。同时,公司还积极与高校、科研机构等合作,共同开展技术攻关和人才培养工作,为公司的长期发展提供坚实的技术支持。

达方(DARFON)公司的发展小趣事

面对日益严峻的环境问题,达方电子积极响应国家号召,将绿色发展理念融入公司战略。公司加大了对环保技术的研发力度,推出了多款绿色、节能的产品。同时,达方电子还积极参与公益事业,为社会做出了积极贡献。这一阶段的努力,不仅提升了公司的社会形象,也为公司的可持续发展奠定了坚实基础。

Fortiming Corporation公司的发展小趣事

背景:在电子行业,成本控制和供应链管理是企业竞争力的重要体现。

发展:Fortiming不断优化供应链管理流程,与上游供应商建立长期稳定的合作关系,确保原材料的稳定供应和质量可靠。同时,公司还通过技术创新和工艺改进,降低生产成本,提高产品竞争力。这些措施使得Fortiming在激烈的市场竞争中保持了良好的盈利能力。

问答坊 | AI 解惑

倒计时程序有问题

《无线电》2004年第9期(带光盘)有一个99分钟89C2051倒计时程序,2个数码管显示,我按其作了一个,并将其光盘上的程序拷入,实际运行结果出现这样一个问题:     就是十位和个位到0后并没有停止(停止时显示‘--’2个负号),而是继续显示‘ ...…

查看全部问答>

ARM与嵌入式linux入门的建议

本帖最后由 paulhyde 于 2014-9-15 08:56 编辑 ARM与嵌入式linux入门的建议  …

查看全部问答>

射频电路板设计技巧

成功的RF设计必须仔细注意整个设计过程中每个步骤及每个细节,这意味着必须在设计开始阶段就要进行彻底的、仔细的规划,并对每个设计步骤的进展进行全面持续的评估。而这种细致的设计技巧正是国内大多数电子企业文化所欠缺的。     近几 ...…

查看全部问答>

如何控制LED静电死灯?

replyreload += \',\' + 380148;Timson,如果您要查看本帖隐藏内容请回复…

查看全部问答>

供S5PC100开发板 ARMcortex A8 core

供S5PC100开发板 ARMcortex A8 core iPhone 3GS 采用Samsung S5PC100主控拥有720p高清视频engineering, 在iPhone中Apple特意降低了处理器运行频率为600MHz,以减少功耗。 显然S5PC100的拥有很强大的处理功能,包括3D engineering S5PC100集多 ...…

查看全部问答>

嵌入式软件开发工程师

汉王科技股份有限公司 嵌入式软件开发工程师-OCR软件部 电子邮箱:          yinsg@hanwang.com.cn 发布日期:         2007-03-21         工作地 ...…

查看全部问答>

iar442不能设置断点是怎么回事啊?

                                 rt…

查看全部问答>

有什么好办法解决STM32RTC不起振么

                                 最近焊了一批板子,那个RTC的晶振死活不起振,十个里面只有一个能起来,其他的怎么弄都起不来。原来在别的板子上好 ...…

查看全部问答>

PR788应用于LED路灯设计

简介:德州仪器电源管理产品经理Pietro Scalia为您简述一款LED路灯板。通过分析PR788参考设计电路图使你更清楚的了解到这个设计是如何实现更节能的目的的   $(\'swf_cT7\').innerHTML=AC_FL_RunContent(\'width\', \'550\', \'height\', \'4 ...…

查看全部问答>

三极管电路分析

请大虾们帮忙分析下,怎么理解?…

查看全部问答>