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

共3条 1/1 1 跳转至

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

菜鸟
2024-05-06 21:29:45     打赏

一、功能需求

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

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

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

二、分析

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

    从网上找到一个ds18b20的手册,学习下它使用的 1-wire 通讯协议的时序规则。手册中有各个通讯过程的详细时序图,按图来实现规则即可。

三、硬件SysConfig配置

    通讯只需要一根数据线,根据使用的引脚配置它:

image.png

四、1-wire协议的实现

      新建两个文件:DS18B20.c 和 DS18B20.h, 将与它通讯的1-wire 协议封装在模块中,方便后续使用。

     因为 1-wire协议时序严格,通讯过程中的延时要很严格否则通讯失败,所以最好使用阻塞式的delay_cycles()函数,因为主频是32M,微妙与cycle相差32倍,包装一个延迟微秒的函数:

void delay_us(uint32_t us)  //阻塞延迟微秒数
{  
    delay_cycles(us*32);  
}

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

#define DS18B20_DQ_OUT(x)  ((x)?(DL_GPIO_setPins(GPIO_HC595_PORT, GPIO_HC595_DS18B20_DQ_PIN)) : (DL_GPIO_clearPins(GPIO_HC595_PORT, GPIO_HC595_DS18B20_DQ_PIN)))  
#define DS18B20_DQ_IN  	   ( DL_GPIO_readPins(GPIO_HC595_PORT,GPIO_HC595_DS18B20_DQ_PIN) )

    通讯针需要输出和输入状态切换,继续宏定义:

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


    做好以上的准备,开始真正的通讯过程开发。

(1)初始化序列:

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

image.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)读写序列:

    接着是读写一个字节的序列。手册上的时序图:

image.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;             /* 右移,获取高一位数据 */  
    }  
}


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

(1)寄存器分布

image.png

从手册中可见,温度值是存放在两个字节中,一个高字节,一个低字节。只要读取出他们的值,拼接一下就得到我们想要的温度

(2)通讯过程实现

  •     首先通讯前要初始化

  •    然后因为是点对点的网络,可以简化下,只发送 skip rom指令

  •   发送 Convert T 操作指令

两个指令的说明,手册上摘抄如下:

image.png

image.png

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

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


(2)从DS18B20获得高低字节,拼接成温度值

    温度转换指令发送后,采集温度后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;  
}


六、代码完成并演示效果

    从手册看,DS18B20除了测量温度外,还有高低限制报警等功能,具体不再累述。

    74HC595数码管显示,还有蜂鸣器的驱动,沿用第3课的代码,设定报警温度为28.0度,编译下载测试,一切正常。

    b站视频如下:

     https://www.bilibili.com/video/BV1vt421c76c?p=4


专家
2024-05-07 08:04:12     打赏
2楼

谢谢分享


工程师
2024-05-08 09:15:41     打赏
3楼

学习了


共3条 1/1 1 跳转至

回复

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