• 正文
  • 相关推荐
申请入驻 产业图谱

传感器 | STM32驱动DS18B20温度传感器代码(HAL库 + 标准库)

04/22 10:14
328
加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论

一、说明

程序有HAL库和标准库版本,上拉电阻4.7K到10K都能正常读取数据,PA4引脚需要remap。

二、标准库函数

(1)DS18B20.c
#include "ds18b20.h"
#include "stm32f10x.h"

 /**************************************************************************************
 * 描  述 : 配置DS18B20用到的I/O口
 * 入  参 : 无
 * 返回值 : 无
 **************************************************************************************/
static void DS18B20_GPIO_Config(void)
{		
	GPIO_InitTypeDef GPIO_InitStructure;

	RCC_APB2PeriphClockCmd(DS18B20_CLK|RCC_APB2Periph_AFIO, ENABLE); 
	GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);														   
  GPIO_InitStructure.GPIO_Pin = DS18B20_PIN;	
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;  //推挽输出  
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 
  GPIO_Init(DS18B20_PORT, &GPIO_InitStructure);
	
	GPIO_SetBits(DS18B20_PORT, DS18B20_PIN);	 //DS18B20数据引脚初始化配置为高电平输出
}

 /**************************************************************************************
 * 描  述 : 配置使DS18B20-DATA引脚变为输入模式
 * 入  参 : 无
 * 返回值 : 无
 **************************************************************************************/
static void DS18B20_Mode_IPU(void)
{
 	  GPIO_InitTypeDef GPIO_InitStructure;
	
	  GPIO_InitStructure.GPIO_Pin = DS18B20_PIN; 
	  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;	  //上拉输入
	  GPIO_Init(DS18B20_PORT, &GPIO_InitStructure);
}

 /**************************************************************************************
 * 描  述 : 配置使DS18B20-DATA引脚变为输出模式
 * 入  参 : 无
 * 返回值 : 无
 **************************************************************************************/
static void DS18B20_Mode_Out_PP(void)
{
 	GPIO_InitTypeDef GPIO_InitStructure;
															   
  GPIO_InitStructure.GPIO_Pin = DS18B20_PIN;	

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;   //推挽输出   
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(DS18B20_PORT, &GPIO_InitStructure);
}

 /**************************************************************************************
 * 描  述 : 主机给从机发送复位脉冲
 * 入  参 : 无
 * 返回值 : 无
 **************************************************************************************/
static void DS18B20_Rst(void)
{
	DS18B20_Mode_Out_PP();     //主机设置为推挽输出 
	
	DS18B20_DATA_OUT(LOW);     //主机至少产生480us的低电平复位信号
	delay_us(750);
	DS18B20_DATA_OUT(HIGH);   //主机在产生复位信号后,需将总线拉高
	delay_us(15);   //从机接收到主机的复位信号后,会在15~60us后给主机发一个存在脉冲
}

 /**************************************************************************************
 * 描  述 : 检测从机给主机返回的存在脉冲
 * 入  参 : 无
 * 返回值 : 0:成功   1:失败  
 **************************************************************************************/
static u8 DS18B20_Presence(void)
{
	u8 pulse_time = 0;
	
	DS18B20_Mode_IPU();    //主机设置为上拉输入
	
	/* 等待存在脉冲的到来,存在脉冲为一个60~240us的低电平信号 
	 * 如果存在脉冲没有来则做超时处理,从机接收到主机的复位信号后,会在15~60us后给主机发一个存在脉冲
	 */
	while( DS18B20_DATA_IN() && pulse_time<100 )
	{
		pulse_time++;
		delay_us(1);
	}	

	if( pulse_time >=100 )  //经过100us后,存在脉冲都还没有到来
		return 1;             //读取失败
	else                 //经过100us后,存在脉冲到来
		pulse_time = 0;    //清零计时变量
	
	while( !DS18B20_DATA_IN() && pulse_time<240 )  // 存在脉冲到来,且存在的时间不能超过240us
	{
		pulse_time++;
		delay_us(1);
	}	
	if( pulse_time >=240 ) // 存在脉冲到来,且存在的时间超过了240us
		return 1;        //读取失败
	else
		return 0;
}

 /**************************************************************************************
 * 描  述 : 从DS18B20读取一个bit
 * 入  参 : 无
 * 返回值 : u8 
 **************************************************************************************/
static u8 DS18B20_Read_Bit(void)
{
	u8 dat;
	
	/* 读0和读1的时间至少要大于60us */	
	DS18B20_Mode_Out_PP();
	/* 读时间的起始:必须由主机产生 >1us <15us 的低电平信号 */
	DS18B20_DATA_OUT(LOW);
	delay_us(10);
	
	/* 设置成输入,释放总线,由外部上拉电阻将总线拉高 */
	DS18B20_Mode_IPU();
	
	if( DS18B20_DATA_IN() == SET )
		dat = 1;
	else
		dat = 0;
	
	/* 这个延时参数请参考时序图 */
	delay_us(45);
	
	return dat;
}

 /**************************************************************************************
 * 描  述 : 从DS18B20读一个字节,低位先行
 * 入  参 : 无
 * 返回值 : u8  
 **************************************************************************************/
u8 DS18B20_Read_Byte(void)
{
	u8 i, j, dat = 0;	
	
	for(i=0; i<8; i++) 
	{
		j = DS18B20_Read_Bit();		//从DS18B20读取一个bit
		dat = (dat) | (j<<i);
	}
	
	return dat;																																																																																
}

 /**************************************************************************************
 * 描  述 : 写一个字节到DS18B20,低位先行
 * 入  参 : u8
 * 返回值 : 无  
 **************************************************************************************/
void DS18B20_Write_Byte(u8 dat)
{
	u8 i, testb;
	DS18B20_Mode_Out_PP();
	
	for( i=0; i<8; i++ )
	{
		testb = dat&0x01;
		dat = dat>>1;		
		/* 写0和写1的时间至少要大于60us */
		if (testb)
		{			
			DS18B20_DATA_OUT(LOW);
			delay_us(8);   //1us < 这个延时 < 15us
			
			DS18B20_DATA_OUT(HIGH);
			delay_us(58);    //58us+8us>60us
		}		
		else
		{			
			DS18B20_DATA_OUT(LOW);  
			/* 60us < Tx 0 < 120us */
			delay_us(70);
			
			DS18B20_DATA_OUT(HIGH);			
			/* 1us < Trec(恢复时间) < 无穷大*/
			delay_us(2);
		}
	}
}

 /**************************************************************************************
 * 描  述 : 起始DS18B20
 * 入  参 : 无
 * 返回值 : 无  
 **************************************************************************************/
void DS18B20_Start(void)
{
	DS18B20_Rst();	           //主机给从机发送复位脉冲
	DS18B20_Presence();	       //检测从机给主机返回的存在脉冲
	DS18B20_Write_Byte(0XCC);		 // 跳过 ROM 
	DS18B20_Write_Byte(0X44);		 // 开始转换 
}

 /**************************************************************************************
 * 描  述 : DS18B20初始化函数
 * 入  参 : 无
 * 返回值 : u8
 **************************************************************************************/
u8 DS18B20_Init(void)
{
	DS18B20_GPIO_Config();   
	DS18B20_Rst();
	
	return DS18B20_Presence();
}

 /**************************************************************************************
 * 描  述 : 从DS18B20读取温度值
 * 入  参 : 无  
 * 返回值 : float 
 **************************************************************************************/
float DS18B20_Get_Temp(void)
{
	u8 tpmsb, tplsb;
	short s_tem;
	float f_tem;
	
	DS18B20_Rst();	   
	DS18B20_Presence();	 
	DS18B20_Write_Byte(0XCC);				/* 跳过 ROM */
	DS18B20_Write_Byte(0X44);				/* 开始转换 */
	
	DS18B20_Rst();
  DS18B20_Presence();
	DS18B20_Write_Byte(0XCC);				/* 跳过 ROM */
  DS18B20_Write_Byte(0XBE);				/* 读温度值 */
	
	tplsb = DS18B20_Read_Byte();		 
	tpmsb = DS18B20_Read_Byte(); 
	
	s_tem = tpmsb<<8;
	s_tem = s_tem | tplsb;
	
	if( s_tem < 0 )		/* 负温度 */
		f_tem = (~s_tem+1) * 0.0625;	
	else
		f_tem = (s_tem * 0.625);
	  
																	//这样做的目的将小数点后第一位也转换为可显示数字
																	//同时进行一个四舍五入操作。
	  
	return f_tem; 	
}


/*************************************END OF FILE******************************/

(2)DS18B20.h
#ifndef __DS18B20_H
#define	__DS18B20_H

#include "stm32f10x.h"
#include "delay.h"

#define HIGH  1
#define LOW   0

#define DS18B20_CLK     RCC_APB2Periph_GPIOB
#define DS18B20_PIN     GPIO_Pin_4                  
#define DS18B20_PORT		GPIOB 

//带参宏,可以像内联函数一样使用,输出高电平或低电平
#define DS18B20_DATA_OUT(a)	if (a)	
					GPIO_SetBits(GPIOB,GPIO_Pin_4);
					else		
					GPIO_ResetBits(GPIOB,GPIO_Pin_4)
 //读取引脚的电平
#define  DS18B20_DATA_IN()	   GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_4)

typedef struct
{
	u8  humi_int;		//湿度的整数部分
	u8  humi_deci;	 	//湿度的小数部分
	u8  temp_int;	 	//温度的整数部分
	u8  temp_deci;	 	//温度的小数部分
	u8  check_sum;	 	//校验和
		                 
}DS18B20_Data_TypeDef;

u8 DS18B20_Init(void);
float DS18B20_Get_Temp(void);
#endif /* __DS18B20_H */
(3) main.c
 int main(void)
  {	
		
    delay_init();	    	 //延时函数初始化	  
	NVIC_Configuration(); 	 //设置NVIC中断分组2:2位抢占优先级,2位响应优先级 	
	uart_init(115200);
    DS18B20_Init();
	while(1) 
	{
		tempture = DS18B20_Get_Temp()/10;
		delay_ms(1000);
		printf("temp:%d rn",(int)tempture);
	}	  
	
}

二、HAL库函数版本

(1)DS18B20.c

其他型号MCU注意延时即可。

/* ds18b20.c */
#include "ds18b20.h"

// 系统时钟频率(根据实际情况修改)
#define SYS_CLK_FREQ     72000000  // 72MHz
#define DELAY_CALIBRATION 10        // 校准系数(需根据实际测试调整)

// 微秒级延时函数
static void Delay_us(uint32_t us)
{
    us *= (SYS_CLK_FREQ / 1000000) / DELAY_CALIBRATION;
    while(us--) {
        __NOP(); __NOP(); __NOP(); __NOP();
        __NOP(); __NOP(); __NOP(); __NOP();
    }
}

// 设置GPIO为开漏输出模式(带内部上拉)
static void GPIO_OutputMode(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    GPIO_InitStruct.Pin = DS18B20_GPIO_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(DS18B20_GPIO_PORT, &GPIO_InitStruct);
}

// 设置GPIO为上拉输入模式
static void GPIO_InputMode(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    GPIO_InitStruct.Pin = DS18B20_GPIO_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    HAL_GPIO_Init(DS18B20_GPIO_PORT, &GPIO_InitStruct);
}

// 复位脉冲
uint8_t DS18B20_Reset(void)
{
    GPIO_OutputMode();
    
    // 拉低总线480-960us
    HAL_GPIO_WritePin(DS18B20_GPIO_PORT, DS18B20_GPIO_PIN, GPIO_PIN_RESET);
    Delay_us(480);
    
    // 释放总线
    GPIO_InputMode();
    Delay_us(60);  // 等待15-60us
    
    // 检测存在脉冲
    uint8_t status = HAL_GPIO_ReadPin(DS18B20_GPIO_PORT, DS18B20_GPIO_PIN);
    Delay_us(420);  // 等待剩余时间
    
    return (status == GPIO_PIN_RESET);
}

// 写一位数据
static void WriteBit(uint8_t bit)
{
    GPIO_OutputMode();
    HAL_GPIO_WritePin(DS18B20_GPIO_PORT, DS18B20_GPIO_PIN, GPIO_PIN_RESET);
    
    if(bit) {
        Delay_us(5);   // 1-15us
        GPIO_InputMode();
        Delay_us(55);
    } else {
        Delay_us(60);  // 60-120us
        GPIO_InputMode();
        Delay_us(5);
    }
}

// 读一位数据
static uint8_t ReadBit(void)
{
    uint8_t bit = 0;
    GPIO_OutputMode();
    
    // 产生读时隙
    HAL_GPIO_WritePin(DS18B20_GPIO_PORT, DS18B20_GPIO_PIN, GPIO_PIN_RESET);
    Delay_us(2);
    GPIO_InputMode();
    Delay_us(12);  // 等待15us前采样
    
    bit = HAL_GPIO_ReadPin(DS18B20_GPIO_PORT, DS18B20_GPIO_PIN);
    Delay_us(45);  // 保持总时隙时间
    
    return bit;
}

// 写一个字节
void DS18B20_WriteByte(uint8_t dat)
{
    for(uint8_t i=0; i<8; i++) {
        WriteBit(dat & 0x01);
        dat >>= 1;
    }
}

// 读一个字节
uint8_t DS18B20_ReadByte(void)
{
    uint8_t byte = 0;
    for(uint8_t i=0; i<8; i++) {
        byte >>= 1;
        if(ReadBit()) byte |= 0x80;
    }
    return byte;
}

// 初始化
uint8_t DS18B20_Init(void)
{
    __HAL_RCC_GPIOB_CLK_ENABLE();
    GPIO_InputMode();
    return DS18B20_Reset();
}

// 启动温度转换
void DS18B20_StartConversion(void)
{
    DS18B20_Reset();
    DS18B20_WriteByte(0xCC);  // Skip ROM
    DS18B20_WriteByte(0x44);  // Convert T
}

// 读取温度值
float DS18B20_ReadTemperature(void)
{
    DS18B20_Reset();
    DS18B20_WriteByte(0xCC);  // Skip ROM
    DS18B20_WriteByte(0xBE);  // Read Scratchpad
    
    uint8_t temp_l = DS18B20_ReadByte();
    uint8_t temp_h = DS18B20_ReadByte();
    
    int16_t temp = (temp_h << 8) | temp_l;
    return temp * 0.0625f;  // 正确转换系数
}
(2)DS18B20.h
/* ds18b20.h */
#ifndef __DS18B20_H
#define __DS18B20_H

#include "stm32f1xx_hal.h"

// 配置使用的GPIO端口和引脚
#define DS18B20_GPIO_PORT    GPIOB
#define DS18B20_GPIO_PIN     GPIO_PIN_6

// 函数声明
uint8_t DS18B20_Init(void);
void DS18B20_StartConversion(void);
float DS18B20_ReadTemperature(void);

#endif /* __DS18B20_H */
(3)main.c
int main(void)
{

    DS18B20_Init();
    while(1)
    {
	    float temp;
	    DS18B20_StartConversion();
	    HAL_Delay(750);  // 等待转换完成
	    temp = DS18B20_ReadTemperature();
	    printf("Temperature: %.2f Crn", temp);
    }

}

相关推荐