【STM32CubeMX学习】1WIRE总线读取DS18B20温度

1、1WIRE总线介绍

        1WIRE总线只用一根线就可以完成读写操作,下面以STM32为主机,DS18B20为从机,介绍1WIRE总线的各种时序。

①复位脉冲:主机输出低电平,保持低电平时间至少480us,然后主机释放总线,延时15~60us,并进入接收模式。

②应答脉冲:从机发现总线有上升沿,拉低总线并保持60~240us,表示应答。

③写时序(低位先写):

        写"1":主机输出低电平, 延时2us,然后释放总线,延时60us。

        写"0":主机输出低电平,延时60us,然后释放总线,延时2us。

④读时序:主机输出低电平延时2us,然后主机转入输入模式延时12us,然后读取单总线当前的电平,得到一位数据1/0(低位在前),然后延时50us。

2、DS18B20简介

温度测量范围:-55℃~+125℃。
通信协议:1WIRE总线,数据线接上拉电阻,使总线空闲时处于高电平。
转换精度:9~12位分辨率可调,默认为12位,即分辨率是0.0625。
转换时间:典型值200ms。

DS18B20的内部有64位的ROM单元和9字节的高速暂存器。64位ROM单元包含了DS18B20唯一的序列号,因为这里只使用了一个DS18B20,因此不必关心这个ROM的内容。需要关注的是9字节的高速暂存器:

byte0:温度数据的低8位。
byte1:温度数据的高8位。
byte2:TH用户字节,设置报警温度最高值。
byte3:TL用户字节,设置报警温度最低值。
byte4:保留。
byte5:保留。
byte6、7:配置寄存器,设置转换精度,默认12位。
byte8:CRC码

DS18B20的温度数据格式如下:

BIT0~3:小数部分。
BIT4~10:整数部分。
BIT11~15:00000为正温度,11111为负温度。

若温度问正,则直接将这个值乘0.0625,若温度为负,则将这个值取反加一,再乘0.0625。

3、代码实现读取温度

ds18b20.h

#ifndef __DS18B20_H
#define __DS18B20_H	

#include "main.h"

//IO方向设置
#define DS18B20_GPIO_MODE_Pos    GPIO_CRH_MODE9_Pos                           
#define DS18B20_IO_IN   {ONEWIRE_DQ_GPIO_Port->CRH&=0XFFFFFF0F;GPIOB->CRH|=8<<GPIO_CRH_MODE9_Pos;}
#define DS18B20_IO_OUT {ONEWIRE_DQ_GPIO_Port->CRH&=0XFFFFFF0F;GPIOB->CRH|=3<<GPIO_CRH_MODE9_Pos;}

//IO操作函数											   
#define DS18B20_DQ_LOW      HAL_GPIO_WritePin(ONEWIRE_DQ_GPIO_Port,ONEWIRE_DQ_Pin,GPIO_PIN_RESET)
#define DS18B20_DQ_HIGH     HAL_GPIO_WritePin(ONEWIRE_DQ_GPIO_Port,ONEWIRE_DQ_Pin,GPIO_PIN_SET)

#define DS18B20_DQ_READ     HAL_GPIO_ReadPin(ONEWIRE_DQ_GPIO_Port,ONEWIRE_DQ_Pin)

short DS18B20_Get_Temp(void);

#endif

ds18b20.c

读取步骤:复位 -> 发SKIP ROM命令(0XCC) -> 发开始转换命令(0X44) -> 延时 -> 复位 -> 发送 SKIP ROM 命令(0XCC) -> 发读存储器命令(0XBE) -> 连续读出两个字节温度数据 -> 结束。

#include "ds18b20.h"	

//复位DS18B20
void DS18B20_Rst(void)	   
{                 
	DS18B20_IO_OUT;//设置为输出
	DS18B20_DQ_LOW;//拉低DQ
	Delay_Us(500);//拉低500us
	DS18B20_DQ_HIGH;//拉高DQ
	Delay_Us(20);//20us
}

//等待DS18B20的应答,返回值:0-非应答,1-应答
uint8_t Wait_DS18B20_ACK(void) 	   
{   
	uint8_t retry=0;
	DS18B20_IO_IN;//设置为输入
  while(DS18B20_DQ_READ&&(retry<200))
	{
		retry++;
		Delay_Us(1);
	}	 
	if(retry>=200)return 0;//超过200us未读到低电平,无应答
	else retry=1;//200us内转为低电平
  while ((!DS18B20_DQ_READ)&&(retry<240))
	{
		retry++;
		Delay_Us(1);
	}
	if(retry>=240)return 0;//低电平超过240us,无应答	    
	return 1;//低电平在240以内,有应答
}

//从DS18B20读取一位,返回值:1/0
uint8_t DS18B20_Read_Bit(void) 
{
	uint8_t data;
	DS18B20_IO_OUT;//设置为输出
	DS18B20_DQ_LOW; 
	Delay_Us(2);
	DS18B20_DQ_HIGH; 
	DS18B20_IO_IN;//设置为输入
	Delay_Us(12);
	if(DS18B20_DQ_READ)data=1;
	else data=0;	 
	Delay_Us(50);           
	return data;
}

//从DS18B20读取一个字节,返回值:读到的数据
uint8_t DS18B20_Read_Byte(void)   
{        
	uint8_t i,j,dat;
	dat=0;
	for(i=0;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;//设置为输出
  for (j=0;j<8;j++) 
	{
     testb=dat&0x01;
     dat=dat>>1;
     if(testb)//写1
     {
        DS18B20_DQ_LOW;
        Delay_Us(2);                            
        DS18B20_DQ_HIGH;
        Delay_Us(60);             
     }
     else//写0
     {
        DS18B20_DQ_LOW;
        Delay_Us(60);             
        DS18B20_DQ_HIGH;
        Delay_Us(2);                          
     }
  }
}
 
//开始温度转换
void DS18B20_Start(void)
{   						               
    DS18B20_Rst();	   
    Wait_DS18B20_ACK();	 
    DS18B20_Write_Byte(0xcc);//跳过64位ROM地址
    DS18B20_Write_Byte(0x44);//启动温度转换
}

//从ds18b20得到温度值,精度:0.1℃,返回值:温度值 (-550~1250) 
short DS18B20_Get_Temp(void)
{
    uint8_t TL,TH;
    short temp;
    DS18B20_Start ();//开始转换
    Delay_Ms(200); 
    DS18B20_Rst();
    Wait_DS18B20_ACK();	 
    DS18B20_Write_Byte(0xcc);  //跳过64位ROM地址
    DS18B20_Write_Byte(0xbe);  //读取暂存器数据	    
    TL=DS18B20_Read_Byte();  //LSB   
    TH=DS18B20_Read_Byte();  //MSB 
    
    temp = TH;//获得高八位
    temp<<=8;    
    temp+=TL;//获得底八位

    //分辨率为0.0625,这里比实际值大十倍
    if(TH>7)//温度为负 
        temp = -((~temp+1)*0.625); 
    else//温度为正
      temp = temp*0.625;  
    return temp;    
}

定义全局变量

short temperature;//温度值

在main函数中查询

/* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */

    temperature=DS18B20_Get_Temp();//获取温度值
    printf("temperature=%d.%d\r\n",temperature/10,temperature%10);
    Delay_Ms(1000);


  }
  /* USER CODE END 3 */

运行结果

猜你喜欢

转载自blog.csdn.net/weixin_46183891/article/details/123466677