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. 芯片内部自带的温度传感器,现在很多芯片中都有自带的温度传感器。因为芯片本身发热也很少,所以也可以大概看一下温度传感器的值。