这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 企业专区 » TI » 【MSP焕新大作战】课程3+任务1DS18B20测温.数码管显示.高温报警

共2条 1/1 1 跳转至

【MSP焕新大作战】课程3+任务1DS18B20测温.数码管显示.高温报警

菜鸟
2024-05-30 22:52:41     打赏

一、功能需求

  • 用DS18B20实现环境温度的采样

  • 用数码管显示:  显示一位小数, 例如 23.6

  • 实现高温蜂鸣器报警:  超过28.0蜂鸣器响

二、分析

  数码管显示, 蜂鸣器报警, 这些功能在视频教程里都已经讲过。此次作业,关键在于与DS18B20通讯,采集实时的环境温度到mcu。

三、原理分析

(1)图形化配置

配置:

选择PA17作为通信口

1717075082702026.png

蜂鸣器配置,选择PA3驱动蜂鸣器,因为该蜂鸣器为低电平驱动,所以配置时拉高该io口

1717075195649326.png

DS1B20的通信协议为单总线,也就是只靠一根线来进行通信。那么这个IO口就要不断改变输出输入模式,查找资料后,写成宏定义的方式

#define DS18B20_OutPut_Mode() {DL_GPIO_initDigitalOutput(GPIO_DS18B20_DQ_IOMUX);}    
#define DS18B20_InPut_Mode()  {DL_GPIO_initDigitalInput(GPIO_DS18B20_DQ_IOMUX);}

为了简化通讯引脚的状态读取,以及置高低电平,使用宏定义:

#define DS18B20_DQ_OUT(x)  ((x)?(DL_GPIO_setPins(GPIO_DS18B20_PORT, GPIO_DS18B20_DQ_PIN)) : (DL_GPIO_clearPins(GPIO_DS18B20_PORT, GPIO_DS18B20_DQ_PIN)))    
#define DS18B20_DQ_IN       ( DL_GPIO_readPins(GPIO_DS18B20_PORT,GPIO_DS18B20_DQ_PIN) )

(2)1-wire协议的实现

1)初始化序列:

  1-wire单总线协议通讯总是以初始化序列开始,包含一个复位脉冲和一个存在脉冲

1717080115991974.png

按手册上序列图实现代码如下:

/**  
 * @brief       复位DS18B20  
 * @param       无 
 * @retval      无  
 */    
static void ds18b20_reset(void)    
{    
    DS18B20_OutPut_Mode();    
    DS18B20_DQ_OUT(0);  /* 拉低DQ,复位 */    
    delay_us(750);      /* 拉低750us */    
    DS18B20_DQ_OUT(1);  /* DQ=1, 释放复位 */    
    delay_us(15);       /* 延迟15US */    
}

  接着是等待存在脉冲,即回应信号。实现代码如下:

/**  
 * @brief       等待DS18B20的回应  
 * @param       无  
 * @retval       0, DS18B20正常  
 *           1, DS18B20异常/不存在  
 */    
uint8_t ds18b20_check(void)    
{    
    uint8_t retry = 0;    
    uint8_t rval = 0;    
    
    while ((DS18B20_DQ_IN>0) && (retry < 200))    /* 等待DQ变低, 等待200us */    
    {    
        retry++;    
        delay_us(1);    
    }    
    
    if (retry >= 200)    
    {    
        rval = 1;    
    }    
    else    
    {    
        retry = 0;    
    
        while (!(DS18B20_DQ_IN>0) && (retry < 240))   /* 等待DQ变高, 等待240us */    
        {    
            retry++;    
            delay_us(1);    
        }    
    
        if (retry >= 240) rval = 1;    
    }    
    
    return rval;    
}

组合一下,就是初始化序列的完整代码:

/**  
 * @brief       初始化DS18B20的IO口 DQ 同时检测DS18B20的存在  
 * @param       无  
 * @retval      0, 正常  
 *              1, 不存在/不正常  
 */    
uint8_t ds18b20_init(void)    
{    
    ds18b20_reset();    
    return ds18b20_check();    
}

2)读写序列:

1717080254980100.png

先实现读取一个bit的时序 ,循环8次就可实现读取一个字节。注意,协议总是最低位先行

/**  
 * @brief       从DS18B20读取一个位  
 * @param       无  
 * @retval      读取到的位值: 0 / 1  
 */    
static uint8_t ds18b20_read_bit(void)    
{    
    uint8_t data = 0;    
    DS18B20_DQ_OUT(0);    
    delay_us(2);    
    DS18B20_DQ_OUT(1);    
    delay_us(12);    
    DS18B20_InPut_Mode();    
    if (DS18B20_DQ_IN>0)    
    {    
        data = 1;    
    }    
    
    delay_us(50);    
    return data;    
}   
  
/**  
 * @brief       从DS18B20读取一个字节  
 * @param       无  
 * @retval       读到的数据  
 */    
static uint8_t ds18b20_read_byte(void)    
{    
    uint8_t i, b, data = 0;    
    
    for (i = 0; i < 8; i++)    
    {    
        b = ds18b20_read_bit(); /* DS18B20先输出低位数据 ,高位数据后输出 */    
    
        data |= b << i;         /* 填充data的每一位 */    
    }    
    
    return data;    
}

接下来是写出一个字节的时序,代码如下:

/**  
 * @brief       写一个字节到DS18B20  
 * @param       data: 要写入的字节  
 * @retval      无  
 */    
static void ds18b20_write_byte(uint8_t data)    
{    
    uint8_t j;    
    
    for (j = 1; j <= 8; j++)    
    {    
        if (data & 0x01)    
        {    
            DS18B20_DQ_OUT(0);  /*  Write 1 */    
            delay_us(2);    
            DS18B20_DQ_OUT(1);    
            delay_us(50);    
        }    
        else    
        {    
            DS18B20_DQ_OUT(0);  /*  Write 0 */    
            delay_us(50);    
            DS18B20_DQ_OUT(1);    
            delay_us(2);    
        }    
    
        data >>= 1;             /* 右移,获取高一位数据 */    
    }    
}

3)与DS18B20使用1-wire协议通讯,读取温度值

1717080472289881.png

1717080425563891.png

按照说明书,实现温度转换的功能如下:

/**  
 * @brief       开始温度转换  
 * @param       无  
 * @retval      无  
 */    
static void ds18b20_start(void)    
{    
    ds18b20_reset();    
    ds18b20_check();    
    ds18b20_write_byte(0xcc);   /*  skip rom */    
    ds18b20_write_byte(0x44);   /*  convert */    
}

温度转换指令发送后,采集温度后DS18B20就会返回温度值的高低字节,mcu转入接收模式,获取这两个字节。完整的获取一次温度值的过程,包装成一个完整的函数:

/**  
 * @brief       从ds18b20得到温度值(精度:0.1C)  
 * @param       无  
 * @retval      温度值 (-550~1250)  
 *   @note      返回的温度值放大了10倍.  
 *              实际使用的时候,要除以10才是实际温度.  
 */    
short ds18b20_get_temperature(void)    
{    
    uint8_t flag = 1;           /* 默认温度为正数 */    
    uint8_t TL, TH;    
    short temp;    
    
    ds18b20_start();            /*  ds1820 start convert */    
    ds18b20_reset();    
    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)    
    {/* 温度为负,查看DS18B20的温度表示法与计算机存储正负数据的原理一致:  
        正数补码为寄存器存储的数据自身,负数补码为寄存器存储值按位取反后+1  
        所以我们直接取它实际的负数部分,但负数的补码为取反后加一,但考虑到低位可能+1后有进位和代码冗余,  
        我们这里先暂时没有作+1的处理,这里需要留意 */    
        TH = ~TH;    
        TL = ~TL;    
        flag = 0;   /* 温度为负 */    
    }    
    
    temp = TH;      /* 获得高八位 */    
    temp <<= 8;    
    temp += TL;     /* 获得底八位 */    
    
    /* 转换成实际温度 */    
    if (flag == 0)    
    {   /* 将温度转换成负温度,这里的+1参考前面的说明 */    
        temp = (double)(temp+1) * 0.625;    
        temp = -temp;    
    }    
    else    
    {    
        temp = (double)temp * 0.625;    
    }    
    
    return temp;    
}

主函数中

#include "ti_msp_dl_config.h"
#include "HC595.h"
#include "Delay.h"
#include "DS18B20.h"

int8_t num=10;
short value;
int main(void)
{
    SYSCFG_DL_init();
		ds18b20_init();
		NVIC_EnableIRQ(TIMER_0_INST_INT_IRQN);
		DL_TimerG_startCounter(TIMER_0_INST);
    while (1)
		{
			LED8_Display ();
    }
}

//定时实现10到0递减
void TIMER_0_INST_IRQHandler(void)
{
		value=ds18b20_get_temperature();
		LED[2]=(uint8_t)(value*1.0/100)%10;
		LED[1]=(uint8_t)(value*1.0/10)%10;
		LED[0]=(uint8_t)(value*1.0/1)%10;
		if(value>=290)
			DL_GPIO_clearPins(GPIO_Beep_PORT,GPIO_Beep_Beep_PIN );  
		else
			DL_GPIO_setPins(GPIO_Beep_PORT,GPIO_Beep_Beep_PIN);
		DL_GPIO_togglePins(GPIO_LED_PORT,GPIO_LED_LED1_PIN);
}


、下载验证

设定报警温度为29.0度,编译下载测试,一切正常。

b站视频如下:

https://www.bilibili.com/video/BV1Bt421N7Ls/?share_source=copy_web&vd_source=3969f4161d002b07aea10c26424c9e9c




关键词: DS18B20     报警     高温    

高工
2024-05-31 11:55:53     打赏
2楼

谢谢分享


共2条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]