STM32 HAL库 DS18B20读取温度值

STM32 HAL库 DS18B20读取温度值


DS18B20是一个单总线的温度传感器,驱动单总线器件时序上是很简单的,按照datasheet编写IO的高低电平即可,关键点就在微秒延时函数的准确性上,下面我提供一下驱动代码,根据自己的平台做移植适配即可。

我的测试MCU是STM32F070F6P6,主频48M。


DS18B20驱动

#ifndef DS18B20_H__
#define DS18B20_H__

#include <stdint.h>

uint8_t DS18B20_Init(void);			//初始化DS18B20
short DS18B20_Get_Temp(void);		//获取温度
void DS18B20_Start(void);			//开始温度转换
void DS18B20_Write_Byte(uint8_t dat);//写入一个字节
uint8_t DS18B20_Read_Byte(void);	//读出一个字节
uint8_t DS18B20_Read_Bit(void);		//读出一个位
uint8_t DS18B20_Check(void);		//检测是否存在DS18B20
void DS18B20_Rst(void);				//复位DS18B20

#endif

#include "ds18b20.h"
#include "tim.h"
#include "main.h"


/
///
///  移植修改区
///
///



#define CPU_FREQUENCY_MHZ 48				/* CPU主频,根据实际进行修改 */

/**
 * 此延时函数代码适用于HAL库
 */
static void delay_us(uint32_t delay)
{
    int last, curr, val;
    int temp;

    while (delay != 0)
    {
        temp = delay > 900 ? 900 : delay;
        last = SysTick->VAL;
        curr = last - CPU_FREQUENCY_MHZ * temp;
        if (curr >= 0)
        {
            do
            {
                val = SysTick->VAL;
            }
            while ((val < last) && (val >= curr));
        }
        else
        {
            curr += CPU_FREQUENCY_MHZ * 1000;
            do
            {
                val = SysTick->VAL;
            }
            while ((val <= last) || (val > curr));
        }
        delay -= temp;
    }
}

static void DS18B20_IO_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
	
	__HAL_RCC_GPIOB_CLK_ENABLE();
	
	/* 总线空闲为高电平 */
	HAL_GPIO_WritePin(DS18B20_GPIO_Port, DS18B20_Pin, GPIO_PIN_SET);

    GPIO_InitStruct.Pin = DS18B20_Pin;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(DS18B20_GPIO_Port, &GPIO_InitStruct);
}

static void DS18B20_IO_OUT(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    GPIO_InitStruct.Pin = DS18B20_Pin;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(DS18B20_GPIO_Port, &GPIO_InitStruct);
}

static void DS18B20_IO_IN(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    GPIO_InitStruct.Pin = DS18B20_Pin;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(DS18B20_GPIO_Port, &GPIO_InitStruct);
}

static void DS18B20_DQ_OUT(int state)
{
    HAL_GPIO_WritePin(DS18B20_GPIO_Port, DS18B20_Pin, state ? GPIO_PIN_SET : GPIO_PIN_RESET);
}

static int DS18B20_DQ_IN(void)
{
    return HAL_GPIO_ReadPin(DS18B20_GPIO_Port, DS18B20_Pin) == GPIO_PIN_SET ? 1 : 0;
}

/
///
///  DS18B20驱动
///
///

//复位DS18B20
void DS18B20_Rst(void)
{
    DS18B20_IO_OUT(); //SET PA0 OUTPUT
    DS18B20_DQ_OUT(0); //拉低DQ
    delay_us(750);    //拉低750us
    DS18B20_DQ_OUT(1); //DQ=1
    delay_us(15);     //15US
}

//等待DS18B20的回应
//返回1:未检测到DS18B20的存在
//返回0:存在
uint8_t DS18B20_Check(void)
{
    uint8_t retry=0;
    DS18B20_IO_IN();//SET PA0 INPUT
    while (DS18B20_DQ_IN()&&retry<200)
    {
        retry++;
        delay_us(1);
    };
    if(retry>=200)return 1;
    else retry=0;
    while (!DS18B20_DQ_IN()&&retry<240)
    {
        retry++;
        delay_us(1);
    };
    if(retry>=240)return 1;
    return 0;
}
//从DS18B20读取一个位
//返回值:1/0
uint8_t DS18B20_Read_Bit(void) 			 // read one bit
{
    uint8_t data;
    DS18B20_IO_OUT();//SET PA0 OUTPUT
    DS18B20_DQ_OUT(0);
    delay_us(2);
    DS18B20_DQ_OUT(1);
    DS18B20_IO_IN();//SET PA0 INPUT
    delay_us(12);
    if(DS18B20_DQ_IN())data=1;
    else data=0;
    delay_us(50);
    return data;
}
//从DS18B20读取一个字节
//返回值:读到的数据
uint8_t DS18B20_Read_Byte(void)    // read one byte
{
    uint8_t i,j,dat;
    dat=0;
    for (i=1; i<=8; i++)
    {
        j=DS18B20_Read_Bit();
        dat=(j<<7)|(dat>>1);
    }
    return dat;
}
//写一个字节到DS18B20
//dat:要写入的字节
void DS18B20_Write_Byte(uint8_t dat)
{
    uint8_t j;
    uint8_t testb;
    DS18B20_IO_OUT();//SET PA0 OUTPUT;
    for (j=1; j<=8; j++)
    {
        testb=dat&0x01;
        dat=dat>>1;
        if (testb)
        {
            DS18B20_DQ_OUT(0);// Write 1
            delay_us(2);
            DS18B20_DQ_OUT(1);
            delay_us(60);
        }
        else
        {
            DS18B20_DQ_OUT(0);// Write 0
            delay_us(60);
            DS18B20_DQ_OUT(1);
            delay_us(2);
        }
    }
}
//开始温度转换
void DS18B20_Start(void)// ds1820 start convert
{
    DS18B20_Rst();
    DS18B20_Check();
    DS18B20_Write_Byte(0xcc);// skip rom
    DS18B20_Write_Byte(0x44);// convert
}

//初始化DS18B20的IO口 DQ 同时检测DS的存在
//返回1:不存在
//返回0:存在
uint8_t DS18B20_Init(void)
{
	DS18B20_IO_Init();
    DS18B20_Rst();
    return DS18B20_Check();
}

//从ds18b20得到温度值
//精度:0.1C
//返回值:温度值 (-550~1250)
short DS18B20_Get_Temp(void)
{
    uint8_t temp;
    uint8_t TL,TH;
    short tem;

    __disable_irq();    /* 中断可能会单总线的时序从而导致读出来的温度值不正确,所以读取之前屏蔽中断 */

    DS18B20_Start ();                    // ds1820 start convert
    DS18B20_Rst();
    DS18B20_Check();
    DS18B20_Write_Byte(0xcc);// skip rom
    DS18B20_Write_Byte(0xbe);// convert
    TL=DS18B20_Read_Byte(); // LSB
    TH=DS18B20_Read_Byte(); // MSB
    if(TH>7)
    {
        TH=~TH;
        TL=~TL;
        temp=0;//温度为负
    }
    else temp=1; //温度为正
    tem=TH; //获得高八位
    tem<<=8;
    tem+=TL;//获得底八位

    __enable_irq();    /* 再将全局中断打开 */

    tem=(float)tem*0.625;//转换
    if(temp)return tem; //返回温度值
    else return -tem;
}

/*

代码使用示例:

int main()
{
	short temp;

	while(DS18B20_Init())
	{
		printf(" ds18b20 init failed ! \r\n");
		HAL_Delay(1000);
	}

	while(1)
	{
		temp = DS18B20_Get_Temp();
		printf("当前温度:%0.2f \r\n", (float)temp / 10);
		HAL_Delay(1000);
	}
}

*/

HK18B20驱动

#include "ds18b20.h"
#include "main.h"


/
///
///  移植修改区
///
///

#define CPU_FREQUENCY_MHZ 48				/* STM32的时钟CPU主频,根据实际进行修改 */

/**
 * 此延时函数代码适用于HAL库
 */
void delay_us(uint32_t delay)
{
    int last, curr, val;
    int temp;
    while(delay != 0)
    {
        temp = delay > 900 ? 900 : delay;
        last = SysTick->VAL;
        curr = last - CPU_FREQUENCY_MHZ * temp;
        if(curr >= 0)
        {
            do
            {
                val = SysTick->VAL;
            }
            while((val < last) && (val >= curr));
        }
        else
        {
            curr += CPU_FREQUENCY_MHZ * 1000;
            do
            {
                val = SysTick->VAL;
            }
            while((val <= last) || (val > curr));
        }
        delay -= temp;
    }
}

static void hk18b20_io_init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    __HAL_RCC_GPIOA_CLK_ENABLE();

    /* 总线空闲为高电平 */
    HAL_GPIO_WritePin(DS18B20_GPIO_Port, DS18B20_Pin, GPIO_PIN_SET);

    GPIO_InitStruct.Pin = DS18B20_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);
}

static void hk18b20_set_io_output(void)
{
//    GPIO_InitTypeDef GPIO_InitStruct = {0};
//    GPIO_InitStruct.Pin = DS18B20_Pin;
//    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
//    GPIO_InitStruct.Pull = GPIO_PULLUP;
//    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
//    HAL_GPIO_Init(DS18B20_GPIO_Port, &GPIO_InitStruct);
}

static void hk18b20_set_io_input(void)
{
//    GPIO_InitTypeDef GPIO_InitStruct = {0};
//    GPIO_InitStruct.Pin = DS18B20_Pin;
//    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
//    GPIO_InitStruct.Pull = GPIO_PULLUP;
//    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
//    HAL_GPIO_Init(DS18B20_GPIO_Port, &GPIO_InitStruct);
}

static int hk18b20_io_read(void)
{
    return HAL_GPIO_ReadPin(DS18B20_GPIO_Port, DS18B20_Pin) == GPIO_PIN_SET ? 1 : 0;
}

static void hk18b20_io_write(int mode)
{
    HAL_GPIO_WritePin(DS18B20_GPIO_Port, DS18B20_Pin, mode ? GPIO_PIN_SET : GPIO_PIN_RESET);
}


/
///
///  驱动代码区
///
///

static void hk18b20_send_byte(uint8_t dat)
{
    uint8_t i;
    hk18b20_set_io_output();   //设置为输出模式
    for(i = 0; i < 8; i++)
    {
        if(dat & 0X01)  //写1
        {
            hk18b20_io_write(0);
            delay_us(5);
            hk18b20_io_write(1);
            delay_us(60);
        }
        else            //写0
        {
            hk18b20_io_write(0);
            delay_us(60);
            hk18b20_io_write(1);
            delay_us(5);
        }
        dat >>= 1;
    }
}

static uint8_t hk18b20_recv_bit(void)
{
    uint8_t bit = 0;
    hk18b20_set_io_output();   //设置为输出模式
    hk18b20_io_write(0);
    delay_us(2);
    hk18b20_io_write(1);
    hk18b20_set_io_input();    //设置为输入模式
    delay_us(10);
    if(hk18b20_io_read())
        bit = 1;
    delay_us(50);
    return bit;
}

static uint8_t hk18b20_recv_byte(void)
{
    uint8_t i = 0;
    uint8_t dat = 0;
    for(i = 0; i < 8; i++)
    {
        dat >>= 1;
        if(hk18b20_recv_bit())
            dat |= 0X80;
    }
    return dat;
}

// <0:未响应  =0:成功
static int hk18b20_check(void)
{
    int retry = 300;
    hk18b20_set_io_input();                  //设置为输入模式
    while(hk18b20_io_read() && retry != 0)   //等待HK18B20拉低总线60~240us
    {
        retry--;
        delay_us(1);
    }
    if(retry == 0)
        return -1;
    retry = 300;
    while(!hk18b20_io_read() && retry != 0)  //等待上拉电阻拉高总线60~240us
    {
        retry--;
        delay_us(1);
    }
    if(retry == 0)
        return -2;
    return 0;
}

// =1:成功  =0:未响应
static int hk18b20_rst(void)
{
    hk18b20_set_io_output();   //设置为输出模式
    hk18b20_io_write(0);       //拉低至少480us
    delay_us(500);
    hk18b20_io_write(1);       //拉高
    delay_us(20);
    return hk18b20_check();
}

// 启动温度转换
static int hk18b20_start(void)
{
    if(hk18b20_rst() < 0)
        return -1;
    hk18b20_send_byte(0xCC);
    hk18b20_send_byte(0x44);
    return 0;
}

//
// 获取温度
// temp:温度值(-550~1250)
// 返回值:=0:成功   <0:失败
//
int hk18b20_get_temp(short* temp)
{
	int ret = 0;
    short t;
    uint8_t buf[2];
	__disable_irq();                         /* 屏蔽所有中断,防止时序被中断打断导致读温度失败 */
    if(hk18b20_start() < 0)
	{
		ret = -1;
		goto __exit;
	}
    if(hk18b20_rst() < 0)
	{
		ret = -2;
		goto __exit;
	}
    hk18b20_send_byte(0xCC);
    hk18b20_send_byte(0xBE);
    buf[0] = hk18b20_recv_byte();
    buf[1] = hk18b20_recv_byte();
    t = (buf[1] << 8) | buf[0];
    t = (float)t * 0.625;
    if(temp) *temp = t;
__exit:
	__enable_irq();
    return ret;
}

// =0:失败  =1:成功
int hk18b20_init(void)
{
    hk18b20_io_init();
    return hk18b20_rst();
}

/*

代码使用示例:

int main()
{
	short temp;

	while(hk18b20_init() == 0)
	{
		printf(" ds18b20 init failed ! \r\n");
		HAL_Delay(1000);
	}

	while(1)
	{
		hk18b20_get_temp(&temp);
		printf("当前温度:%0.2f \r\n", (float)temp / 10);
		HAL_Delay(1000);
	}
}

*/



  • 23
    点赞
  • 114
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 13
    评论
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

觉皇嵌入式

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

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

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

打赏作者

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

抵扣说明:

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

余额充值