这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 企业专区 » TI » 课程3/任务2实现温度报警器

共2条 1/1 1 跳转至

课程3/任务2实现温度报警器

助工
2024-05-02 19:00:35     打赏

【任务目标】

1、驱动数码管,可以显示000.0-999.9的数值。

2、驱动DS_18B20数字温度计

3、驱动有源蜂鸣器,在采集到温度值达到规定高度时,这现蜂鸣器报警,低于规定值时关闭报警。

【实现的思路】

1、在任务2时我已经实现的驱动数码管,这里继续沿用程序,不过要加入小数点的支持。如果要显示小数点,由于我们使用的是共阳,那么就需要对第二个位的第8位进行清零即与上0x7f。

2、DS_18B20为单总线驱动,他有着严格的时序,这里我选取PA0为总线驱动IO。在这个GPIO上需要实现对温度传感器写数据时,配置为输出模式,在读数据时配置为输入模式。其代码我用宏定义进行封装:

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

在往总线进行写高低电平时,宏定义了输出高低电平的函数如下:

#define DS18B20_DQ_OUT(x)  ((x)?(DL_GPIO_setPins(HC595_PORT, HC595_DS18B20_PIN)) : (DL_GPIO_clearPins(HC595_PORT, HC595_DS18B20_PIN)))

在读取总线时的宏定义如下:

#define DS18B20_DQ_IN  DL_GPIO_readPins(HC595_PORT,HC595_DS18B20_PIN)

由于总线延时需要用到微秒级的延时,而且在读、阶段是不能被打断的,所以采用的系统的延时函数delay_cycles()进行延时,由于我们的总线是32M,所以延时一微秒需要乘以32也就是delay_cycles(32*us)。

由以上的基础,再结合ds_18B20的初始化时序图:

image.png

读写时序图:

image.png

结合以上的资料,我这里封了ds_18B20的函数库,其源码如下:

/*
 * ds_18b20.h
 *
 *  Created on: 2024年4月24日
 *      Author: liujianhua
 */

#ifndef DS_18B20_H_
#define DS_18B20_H_

#include "ti_msp_dl_config.h"



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

#define DS18B20_DQ_IN  DL_GPIO_readPins(HC595_PORT,HC595_DS18B20_PIN)
#define DS18B20_DQ_OUT(x)  ((x)?(DL_GPIO_setPins(HC595_PORT, HC595_DS18B20_PIN)) : (DL_GPIO_clearPins(HC595_PORT, HC595_DS18B20_PIN)))

uint8_t ds18b20_init(void);         /* 初始化DS18B20 */
uint8_t ds18b20_check(void);        /* 检测是否存在DS18B20 */
short ds18b20_get_temperature(void);/* 获取温度 */



#endif /* DS_18B20_H_ */



/*
 * ds_18b20.c
 *
 *  Created on: 2024年4月24日
 *      Author: liujianhua
 */

#include "ds_18b20.h"


/**
 * @brief       复位DS18B20
 * @param       data: 要写入的数据
 * @retval      无
 */
static void ds18b20_reset(void)
{
    DS18B20_OutPut_Mode();
    DS18B20_DQ_OUT(0);  /* 拉低DQ,复位 */
    delay_cycles(32*750);      /* 拉低750us */
    DS18B20_DQ_OUT(1);  /* DQ=1, 释放复位 */
    delay_cycles(32*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_cycles(32*1);
    }

    if (retry >= 200)
    {
        rval = 1;
    }
    else
    {
        retry = 0;

        while (!(DS18B20_DQ_IN>0) && (retry < 240))   /* 等待DQ变高, 等待240us */
        {
            retry++;
            delay_cycles(32*1);
        }

        if (retry >= 240) rval = 1;
    }

    return rval;
}

/**
 * @brief       从DS18B20读取一个位
 * @param       无
 * @retval      读取到的位值: 0 / 1
 */
static uint8_t ds18b20_read_bit(void)
{
    uint8_t data = 0;
    DS18B20_DQ_OUT(0);
    delay_cycles(32*2);
    DS18B20_DQ_OUT(1);
    delay_cycles(32*12);
    DS18B20_InPut_Mode();
    if (DS18B20_DQ_IN>0)
    {
        data = 1;
    }

    delay_cycles(32*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_cycles(32*2);
            DS18B20_DQ_OUT(1);
            delay_cycles(32*50);
        }
        else
        {
            DS18B20_DQ_OUT(0);  /*  Write 0 */
            delay_cycles(32*50);
            DS18B20_DQ_OUT(1);
            delay_cycles(32*2);
        }

        data >>= 1;             /* 右移,获取高一位数据 */
    }
}

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

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

/**
 * @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;
}

3、报警功能,报警给出的题目是使用有源蜂鸣器来实现。实现蜂鸣器的驱动,我这里采用了PWM来实现,因为数码官+DS18B20都是阻塞式的驱动,如果再增加其他的任务,那么写的状态机就非常复杂。我这里设计生成1个1.56Hz的PWM信号,占空比设计为50%,那么就可以实现0.8秒鸣响与0.8秒停止的报警声,这样听起来就不刺耳,而且还可以通过改变不同的占空比,可以实现不同的报警提示。为此我配置syscfg如下:

image.pngimage.png

生成代码以后,我通过DL_TimerG_setCaptureCompareValue(PWM_0_INST, 0, DL_TIMER_CC_0_INDEX);来设置他的占空比为100%,实现持继输出高电平来关闭蜂鸣器器。

如果到达了温度报警值时使用DL_TimerG_setCaptureCompareValue(PWM_0_INST, 2500, DL_TIMER_CC_0_INDEX);来设置占空比为50%实现报警功能。

综以上面的设计思路,主函数的代码如下:

/*
 * Copyright (c) 2021, Texas Instruments Incorporated
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * *  Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * *  Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * *  Neither the name of Texas Instruments Incorporated nor the names of
 *    its contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "ti_msp_dl_config.h"
#include "ds_18b20.h"
#include "stdio.h"
// 16进制数字显示信史段码(0-9,A-F),段码位=1时,数码管的对应的笔段不会被点亮
uint8_t Disp_DX[] = { 0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80, 0x90, 0x77, 0x83, 0xC6, 0xA1, 0x86, 0x8E, 0xFF, 0xBF };
// 数码管模块的显示位置,自左向右
uint8_t Disp_PX[] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
// 发送数据给数码管模块用的串行时钟,时钟上升沿有效
#define HC595_DAT(x)  ((x)?(DL_GPIO_setPins(HC595_PORT, HC595_DIO_PIN)) : (DL_GPIO_clearPins(HC595_PORT, HC595_DIO_PIN)))
#define HC595_CLK(x)  ((x)?(DL_GPIO_setPins(HC595_PORT, HC595_SCLK_PIN)) : (DL_GPIO_clearPins(HC595_PORT, HC595_SCLK_PIN)))
#define HC595_RCK(x)  ((x)?(DL_GPIO_setPins(HC595_PORT, HC595_RCLK_PIN)) : (DL_GPIO_clearPins(HC595_PORT, HC595_RCLK_PIN)))
#define SCLK_1 DL_GPIO_setPins(HC595_PORT, HC595_SCLK_PIN)

uint8_t TimerCnt;
uint32_t TmpVal;


void Display_Out()
{
    HC595_RCK(0);

    HC595_RCK(1);
}
void HC595_WriteData(uint8_t data)
{
    uint8_t i;
    for(i = 0; i < 8; i++)
    {
        if((data & 0x80)>0){
            HC595_DAT(1);

        }
        else {
            HC595_DAT(0);
        }
        data <<= 1;
        HC595_CLK(0);

        HC595_CLK(1);

    }
}

void HC595_SEND_DATA(uint8_t disp_num, uint8_t disp_bit)
{
    HC595_WriteData(disp_num);
    HC595_WriteData(1<<disp_bit);
    Display_Out();
}

void Disp_Data(uint16_t dataH, uint16_t dataL)
{
    uint16_t tempH,tempL;
    uint8_t num_q, num_b,num_s,num_g;
    tempL = dataL;
    num_q = tempL/1000;
    num_b = tempL/100%10;
    num_s = tempL/10%10;
    num_g = tempL%10;
    HC595_SEND_DATA(Disp_DX[num_q],3);

    HC595_SEND_DATA(Disp_DX[num_b],2);

    HC595_SEND_DATA(Disp_DX[num_s],1);

    HC595_SEND_DATA(Disp_DX[num_g],0);

    tempH = dataH;
    num_q = tempH/1000;
    num_b = tempH/100%10;
    num_s = tempH/10%10 ;
    num_g = tempH%10;
    HC595_SEND_DATA(Disp_DX[num_q],7);
    HC595_SEND_DATA(Disp_DX[num_b],6);
    HC595_SEND_DATA(Disp_DX[num_s] ,5);
    HC595_SEND_DATA(Disp_DX[num_g],4);

}

void Disp_Temp(uint16_t dataL)
{
    uint16_t tempH,tempL;
    uint8_t num_q, num_b,num_s,num_g;
    tempL = dataL;
    num_q = tempL/1000;
    num_b = tempL/100%10;
    num_s = tempL/10%10;
    num_g = tempL%10;
    HC595_SEND_DATA(Disp_DX[num_q],3);

    HC595_SEND_DATA(Disp_DX[num_b],2);

    HC595_SEND_DATA(Disp_DX[num_s] & 0x7F,1);  //显示小数点

    HC595_SEND_DATA(Disp_DX[num_g],0);


}
int main(void)
{
    short temperature;
    TmpVal = 400;

    SYSCFG_DL_init();
    //NVIC_EnableIRQ(TIMER_0_INST_INT_IRQN);
    //DL_TimerG_enableClock(PWM_0_INST);
    //DL_TimerG_disableClock(PWM_0_INST);

    while (1) {
        TmpVal++;
        if(TmpVal >= 80000)
        {
            temperature = ds18b20_get_temperature();
            TmpVal = 0;
            if(temperature>230){
                DL_TimerG_setCaptureCompareValue(PWM_0_INST, 2500, DL_TIMER_CC_0_INDEX);
            }
            else{
                DL_TimerG_setCaptureCompareValue(PWM_0_INST, 0, DL_TIMER_CC_0_INDEX);
            }
        }
        Disp_Temp(temperature);
    }
}


void TIMER_0_INST_IRQHandler(void)
{
    switch(DL_Timer_getPendingInterrupt(TIMER_0_INST)){
        case DL_TIMER_IIDX_ZERO:
        {
            TmpVal --;
            if(TmpVal == 0)
            {
                TmpVal = 4;
            }

        }
        break;
        default:
            break;
    }
}

【实现的功能】

开机后数码管显示实际温度值,超过23度,他就会报警,低于23度,关闭报警。




关键词: MSPM0     18B20     温度报警     pwm    

助工
2024-05-03 00:16:32     打赏
2楼


共2条 1/1 1 跳转至

回复

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