STM32CubeMX系列 | DS18B20温度传感器

2023-03-21  

1. DS18B20简介

DS18B20是由DALLAS半导体公司推出的一种单总线接口的温度传感器,与传统的热敏电阻等测温元件相比,它是一种新型的体积小、实用电压宽、与微处理器接口简单的数字化温度传感器。 DS18B20的内部结构如下图示

ROM中的64位序列号是出厂前就被光刻好的,可以看做是DS18B20的地址序列号。64位光刻ROM的排列是:8位产品类型标号+48位DS18B20序列号+8位循环冗余校验码。光刻ROM 的作用是使每一个DS18B20都各不相同,这样就可以实现一根总线上挂接多个DS18B20

DS18B20的内部存储器(9个字节)包括一个高速暂存器RAM和一个EEPROM,EEPROM里存放高温和低温触发器和配置寄存器,存储器详细组成见下图:

配置寄存器是配置不同的位数来确定温度和数字的转化,其结构下图示:低五位都是1,TM是测试模式位(设置工作模式或测试模式,默认为0即工作模式),R1和R0用来设置精度,可设9~12位精度,对应的温度分辨率为0.5/0.25/0.125/0.0625℃

所有的单总线器件都要求采样严格的信号时序,以保证设局的完整性。DS18B20的时序有:初始化时序、写(0和1)时序、读(0和1)时序。DS18B20发送所有的命令和数据都是字节的低位在前,下面介绍这几个信号的时序:

  • 初始化时序:单总线上的所有通讯都是以初始化序列开始。主机输出低电平,保持低电平时间至少480us(480 ~ 960us之间),以产生复位脉冲;接着主机释放总线,外部的上拉电阻将单总线拉高,延时15 ~ 60us,并进入接收模式;接着DS18B20拉低总线60 ~ 240us,以产生低电平应答脉冲,若为低电平,再延时480us;初始化时序图如下

  • 写时序:写时序包括写0和写1时序。所有写时序至少需要60us,并且在2次独立的写时序之间至少需要1us的恢复时间,两种写时序均起始于主机拉低总线。写1时序,主机输出低电平,延时2us,然后释放总线,延时60us;写0时序,主机输出低电平,延时60us,然后释放总线,延时2us。写时序图如下

  • 读时序:单总线器件仅在主机发出读时序时,才向主机传输数据,所以在主机发出读数据命令后,必须马上产生读时序,以便从机能够传输数据。所有读时序至少需要60us,且在2次独立的读时序之间至少需要1us的恢复时间。每个读时序都由主机发起,至少拉低总线1us,主机在读时序器件必须释放总线,并且在时序起始后的15us之内采样总线状态。典型的读时序过程为,主机输出低电平延时2us,然后主机转入输入模式延时12us,然后读取单总线当前的电平,然后延时50us

DS18B20的典型温度读取过程:复位 --> 发SKIP ROM命令(0XCC) --> 发开始转换命令(0X44) --> 延时 --> 复位 --> 发SKIP ROM命令(0XCC) --> 发读存储器命令(0XBE) --> 连续读出两个字节数据(即温度) --> 结束

2. 硬件设计

D1指示灯用来提示系统运行状态,DS18B20温度传感器用来检测环境温度,串口1用来打印温度值

  • D1指示灯

  • DS18B20

  • USART1

  • TIM7(提供us延时)

3. 软件设计

3.1 STM32CubeMX设置

  • RCC设置外接HSE,时钟设置为72M

  • PC0设置为GPIO推挽输出模式、上拉、高速、默认输出电平为高电平

  • USART1选择为异步通讯方式,波特率设置为115200Bits/s,传输数据长度为8Bit,无奇偶校验,1位停止位

  • PG11设置为GPIO推挽输出模式、上拉、高速

  • 激活TIM7,预分频因子设为72-1,向上计数,自动重载值为65535;因此计数器CNT_CLK = 1MHz,计数器周期为1us

  • 输入工程名,选择工程路径(不要有中文),选择MDK-ARM V5;勾选Generated periphera initialization as a pair of ‘.c/.h’ files per IP ;点击GENERATE CODE,生成工程代码

3.2 MDK-ARM编程

  • 在tim.c文件下实现微秒延时(us)函数

void delay_us(uint16_t us){

    uint16_t differ = 0xffff-us-5;              

    __HAL_TIM_SET_COUNTER(&htim7,differ);   //设定TIM7计数器起始值

    HAL_TIM_Base_Start(&htim7);     //启动定时器 


    while(differ < 0xffff-5){   //判断

        differ = __HAL_TIM_GET_COUNTER(&htim7);     //查询计数器的计数值

    }

    HAL_TIM_Base_Stop(&htim7);

}

创建按键驱动文件ds18b20.c 和相关头文件ds18b20.h

void DS18B20_IO_IN(void){

    GPIO_InitTypeDef GPIO_InitStructure;

    GPIO_InitStructure.Pin = GPIO_PIN_11;

    GPIO_InitStructure.Mode = GPIO_MODE_INPUT;

    HAL_GPIO_Init(GPIOG,&GPIO_InitStructure);

}


void DS18B20_IO_OUT(void){

    GPIO_InitTypeDef GPIO_InitStructure;

    GPIO_InitStructure.Pin = GPIO_PIN_11;

    GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;

    GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;

    HAL_GPIO_Init(GPIOG,&GPIO_InitStructure);

}


void DS18B20_Rst(void){

    DS18B20_IO_OUT();

    DS18B20_DQ_OUT_LOW;

    delay_us(750);

    DS18B20_DQ_OUT_HIGH;

    delay_us(15);

}


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;


    while(!DS18B20_DQ_IN && retry < 240){

        retry++;

        delay_us(1);

    }


    if(retry >= 240)

        return 1;


    return 0;

}


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;

}


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);

    }

    return data;

}


void DS18B20_Write_Byte(uint8_t data){

    uint8_t j;

    uint8_t testb;

    DS18B20_IO_OUT();

    for(j=1;j<=8;j++){

        testb=data&0x01;

        data=data>>1;

        if(testb){

            DS18B20_DQ_OUT_LOW;

            delay_us(2);

            DS18B20_DQ_OUT_HIGH;

            delay_us(60);

        }else{

            DS18B20_DQ_OUT_LOW;

            delay_us(60);

            DS18B20_DQ_OUT_HIGH;

            delay_us(2);

        }

    }

}


void DS18B20_Start(void){

    DS18B20_Rst();

    DS18B20_Check();

    DS18B20_Write_Byte(0xcc);

    DS18B20_Write_Byte(0x44);

}


uint8_t DS18B20_Init(void){

    GPIO_InitTypeDef GPIO_InitStructure;

    GPIO_InitStructure.Pin = GPIO_PIN_11;

    GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;

    GPIO_InitStructure.Pull = GPIO_PULLUP;

    GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;

    HAL_GPIO_Init(GPIOG,&GPIO_InitStructure);


    DS18B20_Rst();

    return DS18B20_Check();

}


short DS18B20_Get_Temperature(void){

    uint8_t temp;

    uint8_t TL,TH;

    short temperature;


    DS18B20_Start();

    DS18B20_Rst();

    DS18B20_Check();

    DS18B20_Write_Byte(0xcc);

    DS18B20_Write_Byte(0xbe);

    TL = DS18B20_Read_Byte();

    TH = DS18B20_Read_Byte();


    if(TH>7){

        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;

}

在main.c文件下编写ds18b20测试代码

int main(void){

  float temperature;

  HAL_Init();

  SystemClock_Config();

  MX_GPIO_Init();

  MX_TIM7_Init();

  MX_USART1_UART_Init();

  /* USER CODE BEGIN 2 */

  while(DS18B20_Init()){

    printf("DS18B20 checked failed!!!rn");

    HAL_Delay(500);

  }

  printf("DS18B20 checked success!!!rn");

  /* USER CODE END 2 */

  while (1){

    temperature = DS18B20_Get_Temperature();

        if(temperature < 0)

            printf("temperature = -%.2f degreern",temperature/10);

        else

            printf("temperature = %.2f degreern",temperature/10);


        HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_0);

        HAL_Delay(200);

  }

}

4. 下载验证

编译无误下载到开发板后,可以看到D1指示灯不断闪烁,串口不断打印出当前温度值


文章来源于:电子工程世界    原文链接
本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。