ds18b20温度传感器stm32

ds18b20温度传感器stm32
代码编译无误,检测不到传感器的存在

编译无误只是没有语法错误而已,不代表功能就正常。
可能是硬件连接有问题,也可能是程序逻辑有问题,要结合二者具体分析才行

提供下代码看下!
板卡是用的开发板上的DS18b20还是自己连接的!如果是自己连接,还提供下电路图!

不知道你这个问题是否已经解决, 如果还没有解决的话:
  • 关于该问题,我找了一篇非常好的博客,你可以看看是否有帮助,链接:stm32 驱动DS18B20温度传感器
  • 除此之外, 这篇博客: 怎样用stm32驱动ds18b20温度芯片中的 二、驱动代码介绍 部分也许能够解决你的问题, 你可以仔细阅读以下内容或者直接跳转源博客中阅读:

    1、初始化配置

    初始化包含两步:


    1、`DQ`对应的引脚的GPIO配置
    2、通过`DQ``ds18b20`芯片的初始化
    

    对应驱动代码的这部分:


    /**
      * @brief  配置DQ并复位DS18B20
      * @param   无
      * @retval  无
      */
    void DS18B20_Init(void)
    {
    	/* 初始化GPIO */
    	DS18B20_DQGPIOConfig();
    	/* 复位 */
    	DS18B20_Rst();
    }
    

    DS18B20_DQGPIOConfig()使能APB2总线时钟和GPIO时钟,配置DQ对应的引脚为推挽输出模式即可:


    /**
      * @brief  配置DQ对应的GPIO引脚
      * @param   无
      * @retval  无
      */
    void DS18B20_DQGPIOConfig(void)
    {
    		/*定义一个GPIO_InitTypeDef类型的结构体*/
    		GPIO_InitTypeDef GPIO_InitStructure;
    
    		/*开启LED相关的GPIO外设时钟*/
    		RCC_APB2PeriphClockCmd(DQ_GPIO_CLK, ENABLE);
    		/*选择要控制的GPIO引脚*/
    		GPIO_InitStructure.GPIO_Pin = PINDQ;	
    
    		/*设置引脚模式为通用推挽输出*/
    		GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;   
    
    		/*设置引脚速率为50MHz */   
    		GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 
    
    		/*调用库函数,初始化GPIO*/
    		GPIO_Init(GPIODQ, &GPIO_InitStructure);	
    }
    

    上面的代码中包含一些宏定义:


    /* DQ引脚相关宏定义 */
    #define GPIODQ GPIOB
    #define PINDQ GPIO_Pin_8
    /* GPIO端口时钟 */
    #define DQ_GPIO_CLK 	    RCC_APB2Periph_GPIOB		
    

    :为了不至于看花眼,不会一次性将所有的宏和函数实现贴出来,说到哪儿就贴到那儿。同时也不用担心不好拼凑成完整的驱动程序,因为文末会放出驱动源代码链接。


    重点看DS18B20_Rst()的实现:


    /**
      * @brief  复位DS18B20
      */
    void DS18B20_Rst(void)
    {	
    	DS18B20_SetDQMode_OUT();
    	/* 先将数据线置高电平“1” */
    	DQ_H;
    	/* 延时(该时间要求的不是很严格,但是尽可能的短一点) */
    	Delay_us(1);
    	/* 数据线拉到低电平“0”。 */
    	DQ_L;
    	/* 延时750微秒(该时间的时间范围可以从480到960微秒) */
    	Delay_us(750);
    	/* 数据线拉到高电平“1” */
    	DQ_H;
    	/* 延时等待(如果初始化成功则在15到60微秒时间之内产生一个由
    	DS18B20所返回的低电平“0”。据该状态可以来确定它的存在,
    	但是应注意不能无限的进行等待,不然会使程序进入死循环,
    	所以要进行超时控制)。 */
    	/* 超时时间不要设置得太短(500us是足够的),
    		否则初始化失败,将获取不到环境温度 */
    	Delay_us(500);
    	uint8_t dqStatus = GPIO_ReadInputDataBit(GPIODQ,PINDQ);
    	/*  将数据线再次拉高到高电平“1”后结束。 */
    	DQ_H;
    }
    

    注意看每一步的注释,交代了初始化过程中DQ的电平变化。

    其中最后一个延时函数:


    Delay_us(500);
    

    尤为关键,如果这里的等待时间不足,将导致初始化失败,出现温度值不变的怪病。


    DS18B20_SetDQMode_OUT()是把DQ对应的引脚设置为推挽输出模式:


    /**
      * @brief  设置DQ对应的引脚位推挽输出模式
      * @param   无 
      * @retval  无
      */
    static void DS18B20_SetDQMode_OUT()
    {
    	/*定义一个GPIO_InitTypeDef类型的结构体*/
    	GPIO_InitTypeDef GPIO_InitStructure;
    	/*选择要控制的GPIO引脚*/
    	GPIO_InitStructure.GPIO_Pin = PINDQ;	
    	/*设置引脚模式为通用推挽输出*/
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;   
    	/*设置引脚速率为50MHz */   
    	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 
    	/*调用库函数,初始化GPIO*/
    	GPIO_Init(GPIODQ, &GPIO_InitStructure);	
    }
    

    DQ_H()DQ_L()分别是将DQ对应的引脚设置为高电平和低电平:


    #define DQ_H GPIO_SetBits(GPIODQ,PINDQ)
    #define DQ_L GPIO_ResetBits(GPIODQ,PINDQ)
    

    Delay_us()的实现如下:


    /**
      * @brief 延时函数
      * @param us_cnt 设定的延时微秒数
      * @retval 无
      */
    void Delay_us(uint32_t us_cnt)
    {
        TIM3->CNT = us_cnt-1;
        TIM3->CR1 |= TIM_CR1_CEN;
        while((TIM3->SR & TIM_FLAG_Update)!=SET);
        TIM3->SR = (uint16_t)~TIM_FLAG_Update;
        TIM3->CR1 &= ~TIM_CR1_CEN;
    }
    
    

    这个函数需要配置定时器以支持计时:


    /**
      * @brief 配置延时定时器
      * @param us_cnt 设定的延时微秒数
      * @retval 无
    */
    void Delay_Timer_Init(void)
    {
        TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
    
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
    
        TIM_TimeBaseStructInit(&TIM_TimeBaseInitStruct);
        TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
        TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Down;
        TIM_TimeBaseInitStruct.TIM_Period = 100-1;
        TIM_TimeBaseInitStruct.TIM_Prescaler = (84-1);
        TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStruct);
    
        while((TIM3->SR & TIM_FLAG_Update)!=SET);
        TIM3->SR = (uint16_t)~TIM_FLAG_Update;
    }
    

    2、通过DQ读取一个字节


    /**
      * @brief  通过DQ从DS18B20读取一个字节(Byte)
      * @param   无
      * @retval  读取到的数据(uint8_t类型)
      */
    uint8_t DS18B20_ReadByte(void)
    {
    	uint8_t data = 0x00;
    	for(int i=0;i<8;i++)
    	{
    		DS18B20_SetDQMode_OUT();
    		/* 将数据线拉高“1” */
    		DQ_H;
    		/* 延时2微秒 */
    		Delay_us(2);
    		/* 将数据线拉低“0” */
    		DQ_L;
    		/* 延时3微秒 */
    		Delay_us(3); 
    		data>>=1;
    		/* 将数据线拉高“1” */
    		DQ_H;
    		DS18B20_SetDQMode_IPU();
    		/* 延时5微秒 */
    		Delay_us(5);
    		/* 读数据线的状态得到1个状态位,并进行数据处理 */
    		if(GPIO_ReadInputDataBit(GPIODQ,PINDQ))
    			data|=0x80;
    		/* 延时60微秒 */
    		Delay_us(60);
    	}
    	return data;
    }
    

    同样的,注意阅读注释中的描述。

    DS18B20_SetDQMode_IPU()把DQ对应的引脚设置为输入模式:


    /**
      * @brief  设置DQ对应的引脚为输入模式
      * @param   无  
      * @retval  无
      */
    static void DS18B20_SetDQMode_IPU()
    {
    		/*定义一个GPIO_InitTypeDef类型的结构体*/
    		GPIO_InitTypeDef GPIO_InitStructure;
    
    		/*选择要控制的GPIO引脚*/
    		GPIO_InitStructure.GPIO_Pin = PINDQ;	
    
    		/*设置引脚模式为通用推挽输出*/
    		GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;   
    
    		/*调用库函数,初始化GPIO*/
    		GPIO_Init(GPIODQ, &GPIO_InitStructure);	
    }
    

    3、通过DQ发送一个字节


    /**
    * @brief  通过DQ向DS18B20发送一个字节(Byte)
    * @param   
    	@arg data 待发送的1字节数据
    * @retval  无
      */
    void DS18B20_WriteByte(uint8_t data)
    {
    	for(int i=0;i<8;i++){
    		/* 数据线先置低电平“0” */
    		DQ_L;
    		/* 延时确定的时间为15微秒 */
    		Delay_us(15);
    		/* 按从低位到高位的顺序发送字节(一次只发送一位) */
    		if(data&0x01){
    			GPIO_WriteBit(GPIODQ,PINDQ,Bit_SET);		
    		}else{
    			GPIO_WriteBit(GPIODQ,PINDQ,Bit_RESET);
    		}
    		/* 延时时间为45微秒 */
    		Delay_us(45);
    		/* 将数据线拉到高电平 */
    		DQ_H;
    		data>>=1;
    	}
    }
    

    4、读取温度


    /**
      * @brief  获取温度寄存器的值并转换为温度值返回
      * @param   无
      * @retval  无
      */
    float DS18B20_GetTemp(void)
    {
    	DS18B20_Rst();
    	DS18B20_WriteByte(SKIPROMCOMMAND);
    	DS18B20_WriteByte(CONVERTT);
    	DS18B20_Rst();
    	DS18B20_WriteByte(SKIPROMCOMMAND);
    	DS18B20_WriteByte(READSCRATCHPAD);
    	uint8_t tempL = DS18B20_ReadByte();
    	uint8_t tempH = DS18B20_ReadByte();
    	/* 反码 */
    	if(tempH>0x7f)
    	{
    		tempL = ~tempL;
    		tempH = ~tempH+1;
    	}
    	/* 计算温度值 */
    	float temp = ((tempH<<4)|(tempL>>4))+
    	(float)(tempL&0x0f)*0.0625; 
    
    	return temp;
    }
    
    

    其中的SKIPROMCOMMANDCONVERTTREADSCRATCHPAD都是 ds18b20 的控制指令:


    在这里插入图片描述
    在这里插入图片描述


    温度计算的部分需要注意一下:


    /* 计算温度值 */
    float temp = ((tempH<<4)|(tempL>>4))+
    (float)(tempL&0x0f)*0.0625; 
    

    数据手册的表述如下:


    在这里插入图片描述


    1、黑色-划掉的是多余的符号位
    2、红色-对应着整数位
    3、蓝色-下划线部分对应小数
    

    首先,(高8位左移4位)或上(低八位右移4位),得到8位的整数部分:


    ((tempH<<4)|(tempL>>4))
    

    然后,低8位去掉左边4位:


    (tempL&0x0f)
    

    乘2^(-4)化成小数:


    (float)(tempL&0x0f)*0.0625
    

    整数部分和小数部分加起来得到温度值:


    float temp = ((tempH<<4)|(tempL>>4))+
    (float)(tempL&0x0f)*0.0625; 
    

    好啦,ds18b20的驱动就介绍完了,源代码的链接放在下面:


    基于stm32F1标准库开发的DS18B20驱动

    timer.x提供时序控制支持
    ds18b20.x是驱动内容,供以读取温度数据


  • 您还可以看一下 朱有鹏老师的STM32的定时器和DS18B20调试-第3季第8部分视频课程课程中的 3.8.1.STM32的5种定时器简介小节, 巩固相关知识点

如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^