Skip to content

GPIO 控制DS18B20温度传感器

DS18B20温度传感器的基本特性 可通过数据线供电;供电范围为2.5V至5.5V 测量温度范围为-55°C至+125°C ±0.4°C精度范围从-10°C到+70°C

单线接口只需要一个端口引脚即可进行通信 每个设备都有一个唯一的64位串行代码

温度传感器的寄存器 alt text

可以通过这个表,查案不同的位表示的寄存器功能, alt text

1.硬件连接

主要有3个PIN,GND 和VCC 以及一个输出PIN。代码中PIN为PB5 输出PIN 接了一个4.7K的上拉电阻,提供一个向上的驱动能力。

alt text

2.生成代码

2.1 下图是代码的配置部分

  1. 初始化了SWD,外部晶振,串口
  2. GPIO这里配置的是输入模式,可以给后续的代码来读取温度传感器的输入信息。代码中PIN为PB5

alt text

2.2 时钟的部分配置

这里将系统时钟配置成了72M alt text

2.3 工程配置

我这边使用的是keil 的工程,所以选择了 MDK-ARM 的这个选项

这里注意,框出的路径以及工程名称,不要使用中文的字符,会出现错误!!!!!

alt text

3.编写代码

3.1 18B20.c

18B20.c代码
c


#include "18b20.h"

/****************************************************************************
函数名:delay_us
功能:微秒级延时
输入:延时数据
输出:无
返回值:无
备注:
****************************************************************************/
void delay_us(uint32_t time)
{
  time *= 10;
	while(time)
		time--;
}


/****************************************************************************
函数名:DS18B20_IO_IN
功能:使DS18B20_DQ引脚变为输入模式
输入:无
输出:无
返回值:无
备注:DQ引脚为PA5
****************************************************************************/
void DS18B20_IO_IN(void){
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.Pin = GPIO_PIN_5;
	GPIO_InitStructure.Mode = GPIO_MODE_INPUT;
	HAL_GPIO_Init(GPIOB,&GPIO_InitStructure);
}


/****************************************************************************
函数名:DS18B20_IO_OUT
功能:使DS18B20_DQ引脚变为推挽输出模式
输入:无
输出:无
返回值:无
备注:DQ引脚为PA5
****************************************************************************/
void DS18B20_IO_OUT(void){
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.Pin = GPIO_PIN_5;
	GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
	GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;
	HAL_GPIO_Init(GPIOB,&GPIO_InitStructure);
}


/***************************************************************************
函数名:DS18B20_Rst
功  能:发送复位信号
输  入: 无
输  出:无
返回值:无
备  注:
***************************************************************************/
void DS18B20_Rst(void){
	DS18B20_IO_OUT();//引脚输出模式
	
	//拉低总线并延时750us
	DS18B20_DQ_OUT_LOW;
	delay_us(750);     
	
	//释放总线为高电平并延时等待15~60us
	DS18B20_DQ_OUT_HIGH;
	delay_us(15);
}
	

/***************************************************************************
函数名:DS18B20_Check
功  能:检测DS18B20返回的存在脉冲
输  入: 无
输  出:无
返回值:0:成功  1:失败   2:释放总线失败
备  注:
***************************************************************************/
uint8_t DS18B20_Check(void){
	//定义一个脉冲持续时间
	uint8_t retry = 0;
	//引脚设为输入模式
	DS18B20_IO_IN();
	while(DS18B20_DQ_IN && retry < 200){
		retry++;
		delay_us(1);
	}
	
	if(retry >= 200)
		return 1;
	else
		retry = 0;
	
	//判断DS18B20是否释放总线
	while(!DS18B20_DQ_IN && retry < 240){
		retry++;
		delay_us(1);
	}
	
	if(retry >= 240)
		return 2;
	
	return 0;
}


/***************************************************************************
函数名:DS18B20_Write_Byte
功  能:向DS18B20写一个字节
输  入: 要写入的字节
输  出:无
返回值:无
备  注:
***************************************************************************/
void DS18B20_Write_Byte(uint8_t data){
	uint8_t j;
	uint8_t databit;
	DS18B20_IO_OUT();
	for(j=1;j<=8;j++){
		databit=data&0x01;//取数据最低位
		data=data>>1;     //右移一位
		if(databit){      //当前位写1
			DS18B20_DQ_OUT_LOW;
			delay_us(2);
			DS18B20_DQ_OUT_HIGH;
			delay_us(60);
		}else{          //当前位写0
			DS18B20_DQ_OUT_LOW;
			delay_us(60);
			DS18B20_DQ_OUT_HIGH;
			delay_us(2);
		}
	}
}

/***************************************************************************
函数名:DS18B20_Read_Bit
功  能:向DS18B20读一个位
输  入: 无
输  出:无
返回值:读入数据
备  注:
***************************************************************************/
uint8_t DS18B20_Read_Bit(void){
	uint8_t data;
	DS18B20_IO_OUT();
	DS18B20_DQ_OUT_LOW;
	delay_us(2);
	DS18B20_DQ_OUT_HIGH;
	DS18B20_IO_IN();
	delay_us(12);
	
	if(DS18B20_DQ_IN)
		data = 1;
	else
		data = 0;
	
	delay_us(50);
	return data;
}


/***************************************************************************
函数名:DS18B20_Read_Byte
功  能:向DS18B20读一个字节
输  入: 无
输  出:无
返回值:读入数据
备  注:
***************************************************************************/
uint8_t DS18B20_Read_Byte(void){
	uint8_t i,j,data;
	data = 0;
	for(i=1;i<=8;i++){
		j = DS18B20_Read_Bit();
		data = (j<<7)|(data>>1);
		/*j=0或1,j<<7=0x00或0x80,和data右移一位相或,即把1/0写入最高位,下次再往右移位*/

	}
	return data;
}

/***************************************************************************
函数名:DS18B20_Start
功  能:DS18B20开启
输  入: 无
输  出:无
返回值:无
备  注:
***************************************************************************/
void DS18B20_Start(void){
	DS18B20_Rst();
	DS18B20_Check();
	DS18B20_Write_Byte(0xcc);//跳过ROM
	DS18B20_Write_Byte(0x44);//温度变换命令
}


/***************************************************************************
函数名:DS18B20_Init
功  能:DS18B20初始化
输  入: 无
输  出:无
返回值:无
备  注:
***************************************************************************/
uint8_t DS18B20_Init(void){
	
	DS18B20_Rst();
	return DS18B20_Check();
}

/***************************************************************************
函数名:DS18B20_Read_Temperature
功  能:读取一次温度
输  入: 无
输  出:无
返回值:读取到的温度数据
备  注:适用于总线上只有一个DS18B20的情况
***************************************************************************/
short DS18B20_Get_Temperature(uint8_t a){
	uint8_t temp;
	uint8_t TL,TH;
	short temperature;
	
	DS18B20_Start();
	DS18B20_Rst();
	DS18B20_Check();
    DS18B20_Write_Byte(0xcc);//跳过ROM
	DS18B20_Write_Byte(0xbe);//读暂存器
	TL = DS18B20_Read_Byte();//低八位
	TH = DS18B20_Read_Byte();//高八位
	
	//判断温度值是否为负数
	if(TH>0x70){
		TH = ~TH;
		TL = ~TL;
		temp = 0;
	}else
		temp = 1;
	
	temperature = TH;
	temperature <<= 8;
	temperature += TL;
	temperature = (float)temperature*0.625;
	if(temperature)
		return temperature;
	else
		return -temperature;
}

3.2 18B20.h

申明了 相关使用到的函数

18B20.h代码
c

#include "main.h"


#define DQ_GPIO_Port GPIOB
#define DQ_Pin GPIO_PIN_5


#define  DS18B20_DQ_OUT_HIGH       HAL_GPIO_WritePin(DQ_GPIO_Port, DQ_Pin, GPIO_PIN_SET)
#define  DS18B20_DQ_OUT_LOW        HAL_GPIO_WritePin(DQ_GPIO_Port, DQ_Pin, GPIO_PIN_RESET)
#define  DS18B20_DQ_IN             HAL_GPIO_ReadPin(DQ_GPIO_Port, DQ_Pin)



uint8_t DS18B20_Init(void);
short DS18B20_Get_Temperature(uint8_t a);

3.3 main 函数

串口重定向函数,这边使用的串口1,

c
/* USER CODE BEGIN PV */
#include <stdio.h>
 //重定向c库函数printf到串口USARTx,重定向后可使用printf函数
 int fputc(int ch, FILE *f)
 {
     /* 发送一个字节数据到串口USARTx */
     HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF);
     return (ch);
 }

/* USER CODE END PV */

主函数的代码,主要就是初始化了温度传感器 以及读取18B20 的数据。

main函数代码
c

#include "18b20.h"

int main(void)
{
  /* USER CODE BEGIN 1 */
 float temperature = 0;
  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
    while(DS18B20_Init())
    {
        printf("DS18B20 checked failed!!!\r\n");
        HAL_Delay(500);
    }
    printf("DS18B20 checked success!!!\r\n");
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
       temperature = DS18B20_Get_Temperature();
		if(temperature < 0)
            printf("temperature = -%.2f degree\r\n",temperature/10);
		else
            printf("temperature = %.2f degree\r\n",temperature/10);
		HAL_Delay(200);
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

4 后记

温度传感器多种多样,除了芯片以外,还有:

  1. 热敏电阻:会随温度的变化改变电阻的值,方案价格便宜,需要消耗一路ADC来检测电压
  2. 芯片内部自带的温度传感器,现在很多芯片中都有自带的温度传感器。因为芯片本身发热也很少,所以也可以大概看一下温度传感器的值。