STM32F407霸天虎HAL库CubeMX学习笔记——DS18B20

发布于:2022-12-17 ⋅ 阅读:(285) ⋅ 点赞:(0)

一、软件准备

软件准备

二、硬件准备

STM32F407霸天虎
DAP高速下载器
USB转串口线
DS18B20温度传感器

工作原理
DS18B20的读写时序和测温原理与DS1820相同,只是得到的温度值的位数因分辨率不同而不同,且温度转换时的延时时间由2s减为750ms低温度系数晶振的振荡频率受温度影响很小,用于产生固定频率的脉冲信号发送给计数器1。高温度系数晶振随温度变化其振荡频率明显改变,所产生的信号作为计数器2的脉冲输入。计数器1和温度寄存器被预置在-55℃所对应的一个基数值。计数器1对低温度系数晶振产生的脉冲信号进行减法计数,当计数器1的预置值减到0时,温度寄存器的值将加1,计数器1的预置将重新被装入,计数器1重新开始对低温度系数晶振产生的脉冲信号进行计数,如此循环直到计数器2计数到0时,停止温度寄存器值的累加,此时温度寄存器中的数值即为所测温度。斜率累加器用于补偿和修正测温过程中的非线性,其输出用于修正计数器1的预置值。

三、CubeMX配置

STM32F407霸天虎用的是STM32F407ZGT6
在这里插入图片描述
选择外部高速时钟
在这里插入图片描述
在这里插入图片描述
我们这里选择LED_B,又因为霸道开发板上的LED是默认低电平点亮的,所以这里我们GPIO选择默认输出高电平
在这里插入图片描述
根据STM32F407霸道开发板原理图可以知道DS18B20的数据引脚是在PE3上
在这里插入图片描述
这里配置PE3为输出模式,其他具体配置如下:
在这里插入图片描述

USART1选择异步通信,其他配置默认
在这里插入图片描述
时钟树选择168MHz,具体配置方法见上篇的时钟树配置
在这里插入图片描述
因为DS18B20是单总线通讯,所以我们这里需要使用到us微秒级别的延时,选择普通定时器TIM6,具体配置如下:
在这里插入图片描述
PSC填写168-1,这是在STM32芯片定义好了的公式,实际上用到的还是168

而后根据自己的喜好编辑工程的名称,存放位置,IDE选择ARM-MDKV5
在这里插入图片描述

最后点击
在这里插入图片描述
到此CubeMX的配置就完成了。

四、Keil

由于我们的Debug用的是DAP,如图下选择Debug和下载配置
在这里插入图片描述

printf重写

首先勾选Use MicroLIB调用MDK的微库,MicroLIB是对C标准库高度优化之后的库,比标准库代码更少,使用效率更高。
在这里插入图片描述

添加至usart.c文件的用户自定义代码块1中
这里直接操作寄存器来发送,效率更高

#if 1
#include <stdio.h>
int fputc(int ch,FILE *stream)
{
	//阻塞判断串口是否发送完成
	while((USART1->SR & 0x40)==0);
	//串口发送完成,将发送该字符
	USART1->DR = (uint8_t)ch;
	return ch;
}
#endif

tim.c

在该文件的最末尾加上us函数

void delay_us(uint16_t us)
{
	uint16_t differ=0xffff-us-5;   //设定定时器计数器起始值 

	
	HAL_TIM_Base_Start(&htim6);           //启动定时器
	__HAL_TIM_SetCounter(&htim6,differ); 
	while(differ < 0xffff-5)                     //补偿,判断            
	{ 
		differ = __HAL_TIM_GetCounter(&htim6);   //查询计数器的计数值 
	} 
	HAL_TIM_Base_Stop(&htim6);

}

DS18B20.h

先在DS18B20.h中宏定义封装以下函数:

  1. GPIO输出模式配置
  2. GPIO输入模式配置
  3. GPIO输出高电平
  4. GPIO输出低电平
  5. GPIO读取输入
    相关引脚定义已在mian.h文件中
#ifndef		__DS18B20_H
#define 	__DS18B20_H

#include "main.h"
#include "tim.h"
#include "usart.h"
#include <stdio.h>

//IO方向设置
#define DS18B20_IO_IN()  {DS18B20_GPIO_Port->MODER&=~(3<<(3*2));DS18B20_GPIO_Port->MODER|=0<<3*2;}	//PE3输入模式
#define DS18B20_IO_OUT() {DS18B20_GPIO_Port->MODER&=~(3<<(3*2));DS18B20_GPIO_Port->MODER|=1<<3*2;} 	//PE3输出模式


/* DS18B20控制IO操作函数 */
#define DS18B20_Out(n)        (n? HAL_GPIO_WritePin(DS18B20_GPIO_Port,DS18B20_Pin,GPIO_PIN_SET):HAL_GPIO_WritePin(DS18B20_GPIO_Port,DS18B20_Pin,GPIO_PIN_RESET))
#define DS18B20_In()           HAL_GPIO_ReadPin(DS18B20_GPIO_Port,DS18B20_Pin)

void DS18B20_Init(void);
uint16_t DS18B20_Read_Temperature(void);


#endif

DS18B20.c

DS18B20操作时序实现

1、 复位信号:

在这里插入图片描述

此部分在DS18B20.c中实现

/**
  * @brief    发送复位信号
  * @param    none
  * @retval   none
*/
static void DS18B20_Reset(void)
{
	//设置DS18B20为输出模式
	DS18B20_IO_OUT();
	//拉低总线480-960us
	DS18B20_Out(0);
	delay_us(660);
	
	//释放总线15-60us
	DS18B20_Out(1);
	delay_us(30);
}
/**
  * @brief    检测DS18B20存在脉冲
  * @param    none
  * @retval   0 DS18B20设备正常
  * @retval   1  DS18B20设备响应复位信号失败
  * @retval   2  DS18B20设备释放总线失败
*/
static uint8_t DS18B20_Check_Pulse(void)
{
	uint8_t cnt = 0;
	//检测是否存在脉冲
	DS18B20_IO_IN();
	//等待DS18B20 拉低总线 (60~240 us 响应复位信号)
	while (DS18B20_In() && cnt < 240) {
		delay_us(1);
		cnt++;
	}
    
	if (cnt > 240) {
        return 1;
    }
    
	/* 2.检测DS18B20是否释放总线 */	
	cnt = 0;
	DS18B20_IO_IN();
//判断DS18B20是否释放总线(60~240 us 响应复位信号之后会释放总线)
	while ((!DS18B20_In()) && cnt<240) {
		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(void)
{
	//发送复位信号
	DS18B20_Reset();
	//检测是否存在脉冲
	return DS18B20_Check_Pulse();
}

/**
  * @brief    DS18B20初始化
  * @param    none
  * @retval   none
*/
void DS18B20_Init(void)
{
	if(DS18B20_Check() == 0)
	{
		printf("DS18B20设备初始化成功!\r\n");
	}
	else if(DS18B20_Check() == 1)
	{
		printf("DS18B20设备响应复位信号失败!\r\n");
	}
	else
	{
		printf("DS18B20设备释放总线失败!\r\n");
	}
}

2、向DS18B20写一个字节时序

在这里插入图片描述

代码如下:

/**
  * @brief    向DS18B20写一个字节
  * @param    cmd 要写入的字节
  * @retval   none
*/
static uint8_t DS18B20_Write_Byte(uint8_t cmd)
{
	uint8_t i = 0;
    
    /* 1. 设置总线为输出模式 */
		DS18B20_IO_OUT();
    
    /* 2. 发送数据,低位在前 */
	for (i = 0; i < 8; i++) 
	{
		DS18B20_Out(0);
		delay_us(2);  
		DS18B20_Out(cmd & 0x01);
		delay_us(60);
		DS18B20_Out(1);
		cmd >>= 1;
		delay_us(2);
	}
    
	return 0;
}

3、从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_IO_OUT();
		DS18B20_Out(0);  
		delay_us(2);
		DS18B20_Out(1);
        
		DS18B20_IO_IN();
		delay_us(10);
		data >>= 1 ;
		if (DS18B20_In()) 
			{
            data |= 0x80;
        }
		delay_us(60);
		DS18B20_Out(1);
	}
    
	return data;
}

4、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();
    
    DS18B20_Write_Byte(0xCC);
    DS18B20_Write_Byte(0x44);
    
    while (DS18B20_Read_Byte() != 0xFF);
    
    DS18B20_Check();   //必须,不能省略
    
    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;
}


Main.c

在头文件包含处添加代码:

/* USER CODE BEGIN Includes */
#include <stdio.h>
#include "ds18b20.h"
/* USER CODE END Includes */

添加变量:

/* USER CODE BEGIN PV */
uint16_t temp;
int      intT, decT;
/* USER CODE END PV */

在main函数里添加

  /* USER CODE BEGIN 2 */
	printf("\r\nhi! 物联网小白Jayce!\r\n");
	printf("DS18B20 Test!\r\n");
	DS18B20_Init();
  /* USER CODE END 2 */

在while循环里添加

		temp = DS18B20_Read_Temperature();
		intT   = temp >> 4 ;          /*合成实际温度整数部分****精度相对上面的更高*/ 
		decT   = temp & 0xF ;         /*合成实际温度小数部分*/
		HAL_GPIO_TogglePin(LED_B_GPIO_Port,LED_B_Pin);
		printf("当前温度为:%d.%d℃\r\n", intT, decT);	
		HAL_Delay(1000);
	 	HAL_GPIO_TogglePin(LED_B_GPIO_Port,LED_B_Pin);

五、实验效果

开发板上蓝灯每闪一次就打印一次温度信息

在这里插入图片描述


网站公告

今日签到

点亮在社区的每一天
去签到