FastBond :基于AD7745和MAX6608的环境温湿度监控系统
本视频是得捷电子FastBond活动作品,使用亚德诺AD7745CDC获取湿度,美信MAX6608获取温度。显示界面可实时显示当前温湿度,绘制动态波形并可显示历史最大最小值。温度与湿度界面每30秒自动切换一次,也可通过用户按键强制切换。
标签
AD7745
MAX6608
DengCJ96
更新2021-11-24
1337

本期视频是得捷电子FastBond活动作品,系统使用亚德诺AD7745电容-数字转换器获取湿度数据,使用美信MAX6608获取温度数据,核心采用CH32V103C8T6单片机,整体单节7号干电池Boost升压供电方案。屏幕型号ST7565P,搭配两个按键,两个状态指示灯。监控系统的显示界面可实时显示当前温度湿度,绘制动态波形并可根据波形数据显示历史最大最小值。温度与湿度界面每30秒自动切换一次,也可通过用户按键强制切换。

系统所使用温度传感器为MAX6608高精度模拟温度传感器。传感器提供SC70和SOT23两种封装形式,工作电压范围:+1.8V~+3.6V,工作电流仅8uA;环境温度+20℃~+50℃精度可达±0.6℃;输出电压与温度增量呈线性关系,0℃基础电压为500mV,按照10mV/℃递增。MAX6608输出模拟电压信号,直接使用MCU的ADC采集即可。换算方式相对简单,通过多次采样求取均值可使数据更加稳定。分享编写好的MAX6608.c文件如下:

void MAX6608_Init(void)
{
    ADC_InitTypeDef ADC_InitStructure;
    GPIO_InitTypeDef GPIO_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
    RCC_ADCCLKConfig(RCC_PCLK2_Div8);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    ADC_DeInit(ADC1);
    ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
    ADC_InitStructure.ADC_ScanConvMode = DISABLE;
    ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
    ADC_InitStructure.ADC_NbrOfChannel = 1;
    ADC_Init(ADC1, &ADC_InitStructure);

    ADC_Cmd(ADC1, ENABLE);

    ADC_ResetCalibration(ADC1);
    while (ADC_GetResetCalibrationStatus(ADC1))
        ;
    ADC_StartCalibration(ADC1);
    while (ADC_GetCalibrationStatus(ADC1))
        ;
}

uint16_t MAX6608_GetVal(void)
{
    uint16_t adc_val = 0;

    ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_239Cycles5);
    ADC_SoftwareStartConvCmd(ADC1, ENABLE);

    while (!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC))
        ;
    adc_val = ADC_GetConversionValue(ADC1);

    return adc_val;
}

float MAX6608_GetT(void)
{
    float temp = 0;
    uint16_t adc_val = 0;
    float adc_mean_val = 0;
    for (uint8_t i = 0; i < 10; i++)
        adc_val = adc_val + MAX6608_GetVal();
    adc_val = adc_val / 10;
    adc_mean_val = 3.3 * 1000 / 4096 * adc_val;
    temp = (adc_mean_val - 500) / 10;
    return temp;
}

亚德诺AD7745电容数字转换器可采用I2C两线串行通信,TSSOP16引脚封装,工作温度范围–40℃至+125℃;共模电容量程 17 pF,满量程变化范围:±4 pF,刷新率:10 Hz 至 90 Hz,线性度:0.01%,分辨率:4 aF,精度:4 fF。芯片内置温度传感器,分辨率0.1℃,精度±2℃。

AD7745采用电荷平衡电路测量外部输入电容。对电容器而言,Q=V×C,若保持电荷Q不超过量程,减小激励电压V至原来的1/F,则输入电容可拓展至F倍。AD7745具有两个独立的激励电压源A和B。参考电路原理图,将A与B反相设置,可以得到衰减后的激励电压幅值与原电压的倍数关系。

系统所使用CHS1101电容式湿度传感器,在湿度为55%时,标称电容值为178.4pF。传感器动态变化范围在162.4pF~194.4pF;取最大值为200pF,除以共模量程17pF,则量程至少需要拓展11倍,原理图中,R2为100k,R3为120k即可满足上述要求。

AD7745使用时需通过内部数据对测量结果进行修正,修正参数在芯片出厂前预先固定于芯片内,实际量程可看作标称值与增益之积。由于传感器电容量仍然大于拓展后的共模量程,使用芯片内CAPDAC补偿共模分量,使剩余电容落在量程以内。本系统必须使用CAPDAC+,具体使用方法请参考官方文档,也可参考如下代码。

void AD7746_Config(void)
{
    uint8_t p = 0;
    {
        AD7746_Read(AD7746_REG_STATUS, &p, 1); //读状态寄存器

        AD7746_Read(AD7746_REG_CAP_GAINH, &cap_gain_h, 1); //读校准寄存器高位
        AD7746_Read(AD7746_REG_CAP_GAINL, &cap_gain_l, 1); //读校准寄存器低位
        cap_gain = ((float)((1 << 16) + ((cap_gain_h << 8) | cap_gain_l))) / (1 << 16);
        cap_ref = 4.096 * cap_gain;
        cap_dac = cap_ref * 3.2;
        cap_lsb_dac = cap_dac / 127;
        cap_eff = cap_lsb_dac * 11;
        cap_set = h_std_pf / cap_eff;

        p = 0x80 | cap_set;
        AD7746_Write(AD7746_REG_CAPDACA, &p, 1); //使能CAPDAC+

        p = AD7746_CAPSETUP_CAPEN;
        AD7746_Write(AD7746_REG_CAP_SETUP, &p, 1); //电容转换使能,单端模式

        p = AD7746_VTSETUP_VTEN;
        AD7746_Write(AD7746_REG_VT_SETUP, &p, 1); //温度转换使能

        p = AD7746_EXCSETUP_EXCA | AD7746_EXCSETUP_NEXCB | AD7746_EXCSETUP_EXCLVL(2);
        AD7746_Write(AD7746_REG_EXC_SETUP, &p, 1); //AB通道激励使能

        //CDC采样速率设置、温度传感器采样速率设置
        //16.1Hz、16.1Hz连续采样
        p = AD7746_CONF_VTFS(2) | AD7746_CONF_CAPFS(4) | AD7746_CONF_MODE_CONT_CONV;
        AD7746_Write(AD7746_REG_CFG, &p, 1);

        //50.0Hz、49.8Hz连续采样
        //p = AD7746_CONF_VTFS(0) | AD7746_CONF_CAPFS(2) | AD7746_CONF_MODE_CONT_CONV;
        //AD7746_Write(AD7746_REG_CFG, &p, 1);
    }
}

float AD7746_GetC(void)
{
    uint32_t cap_u32 = 0;
    float cap_f = 0;

    cap_u32 = AD7746_GetCapData();
    cap_f = ((float)(((int32_t)cap_u32) - 0x800000)) * 4.096 * cap_gain / 0x800000 * 11 + h_std_pf;
    return cap_f;
}

显示界面定时推送,主要是缓存帧操作,涉及一些字符串处理,感兴趣可以看下。

//绘制界面,整帧刷新
void Draw_Desktop(void)
{
    float cap_f = 0; //湿度传感器电容值

    float h_f = 0;    //湿度值
    float h_fmax = 0; //湿度最大值
    float h_fmin = 0; //湿度最小值

    float t_f = 0;    //温度值
    float t_fmax = 0; //温度最大值
    float t_fmin = 0; //温度最小值

    char h_str[10] = {0}; //湿度字符串
    char t_str[10] = {0}; //温度字符串

    uint8_t str_length = 0; //字符串长度
    char *piont_p;          //小数点位置指针
    uint8_t wave_mark = 0;  //波形标记

    Delay_Ms(1000);
    display_sw++;

    if (display_sw < 30)
    {
        //获取湿度传感器电容值
        GPIO_WriteBit(GPIOA, GPIO_Pin_3, Bit_SET);
        cap_f = AD7746_GetC();
        GPIO_WriteBit(GPIOA, GPIO_Pin_3, Bit_RESET);
        //获取温度传感器电压值

        //电容值-湿度转换
        h_f = (cap_f - h_std_pf) / 0.32 + 55;
        //更新湿度序列
        for (uint8_t i = 0; i < 99; i++)
        {
            h_sq[99 - i] = h_sq[98 - i];
        }
        h_sq[0] = h_f;
        //绘制湿度
        //绘制桌面元素
        CF_BMP2FrameBuffer(gImage_humidity);
        CF_Display_12x24_A(20, 0, asiic_12x24_R);
        CF_Display_12x24_A(32, 0, asiic_12x24_H);
        CF_Display_12x24_A(116, 0, asiic_12x24_percent);
        //绘制数据
        sprintf(h_str, "%.2lf", h_f); //将湿度换为字符串数组
        str_length = strlen(h_str);   //获取字符串数组的长度
        piont_p = strchr(h_str, '.'); //获取字符串数组中'.'的地址
                                      //清空上次写入显示缓存的数据
        if (str_length == 5)          //当字符串长度为5,即aa.bb时
        {
            CF_Display_12x24_A(50, 0, asiic_12x24[*(piont_p - 2) - '0']);
        }
        if (str_length == 4) //当字符串长度为4,即a.bb时
        {
            CF_Display_12x24_A(50, 0, asiic_12x24_space);
        }
        CF_Display_12x24_A(62, 0, asiic_12x24[*(piont_p - 1) - '0']);
        CF_Display_12x24_A(74, 0, asiic_12x24_point);
        CF_Display_12x24_A(86, 0, asiic_12x24[*(piont_p + 1) - '0']);
        CF_Display_12x24_A(98, 0, asiic_12x24[*(piont_p + 2) - '0']);

        //绘制动态波形
        h_fmax = h_fmin = h_sq[0];
        for (uint8_t i = 0; i < 100; i++)
        {
            h_fmax = h_fmax > h_sq[i] ? h_fmax : h_sq[i];
            h_fmin = h_fmin < h_sq[i] ? h_fmin : h_sq[i];
        }
        sprintf(h_str, "%.2lf", h_fmax); //将最大湿度换为字符串数组
        str_length = strlen(h_str);      //获取字符串数组的长度
        piont_p = strchr(h_str, '.');    //获取字符串数组中'.'的地址
                                         //清空上次写入显示缓存的数据
        if (str_length == 5)             //当字符串长度为5,即aa.bb时
        {
            CF_Display_5X8_A(0, 34, asiic_5x8[*(piont_p - 2) - '0']);
        }
        if (str_length == 4) //当字符串长度为4,即a.bb时
        {
            CF_Display_5X8_A(0, 56, asiic_5x8_space);
        }
        CF_Display_5X8_A(5, 34, asiic_5x8[*(piont_p - 1) - '0']);
        CF_Display_5X8_A(10, 34, asiic_5x8_point);
        CF_Display_5X8_A(15, 34, asiic_5x8[*(piont_p + 1) - '0']);
        CF_Display_5X8_A(20, 34, asiic_5x8[*(piont_p + 2) - '0']);

        CF_Display_5X8_A(0, 26, asiic_5x8_M);
        CF_Display_5X8_A(5, 26, asiic_5x8_A);
        CF_Display_5X8_A(10, 26, asiic_5x8_X);

        sprintf(h_str, "%.2lf", h_fmin); //将最小湿度换为字符串数组
        str_length = strlen(h_str);      //获取字符串数组的长度
        piont_p = strchr(h_str, '.');    //获取字符串数组中'.'的地址
                                         //清空上次写入显示缓存的数据
        if (str_length == 5)             //当字符串长度为5,即aa.bb时
        {
            CF_Display_5X8_A(0, 56, asiic_5x8[*(piont_p - 2) - '0']);
        }
        if (str_length == 4) //当字符串长度为4,即a.bb时
        {
            CF_Display_5X8_A(0, 56, asiic_5x8_space);
        }
        CF_Display_5X8_A(5, 56, asiic_5x8[*(piont_p - 1) - '0']);
        CF_Display_5X8_A(10, 56, asiic_5x8_point);
        CF_Display_5X8_A(15, 56, asiic_5x8[*(piont_p + 1) - '0']);
        CF_Display_5X8_A(20, 56, asiic_5x8[*(piont_p + 2) - '0']);
        CF_Display_5X8_A(0, 48, asiic_5x8_M);
        CF_Display_5X8_A(5, 48, asiic_5x8_I);
        CF_Display_5X8_A(10, 48, asiic_5x8_N);

        for (uint8_t i = 0; i < 100; i++)
        {
            wave_mark = (h_sq[i] - h_fmin) / (h_fmax + 1.2 - h_fmin) * 38;
            for (uint8_t j = 0; j < 38; j++)
            {
                CF_DrawPoint(28 + i, 26 + j, (38 - j) > wave_mark ? 0 : 1);
            }
        }
    }
    if (display_sw >= 30)
    {
        if (display_sw == 60)
        {
            display_sw = 0;
        }
        //获取温度传感器数值
        GPIO_WriteBit(GPIOA, GPIO_Pin_4, Bit_SET);
        t_f = MAX6608_GetT();
        Delay_Ms(10);
        GPIO_WriteBit(GPIOA, GPIO_Pin_4, Bit_RESET);
        //更新温度序列
        for (uint8_t i = 0; i < 99; i++)
        {
            t_sq[99 - i] = t_sq[98 - i];
        }
        t_sq[0] = t_f;
        //绘制湿度
        //绘制桌面元素
        CF_BMP2FrameBuffer(gImage_temperature);
        //绘制数据
        sprintf(t_str, "%.2lf", t_f); //将湿度换为字符串数组
        str_length = strlen(t_str);   //获取字符串数组的长度
        piont_p = strchr(t_str, '.'); //获取字符串数组中'.'的地址
                                      //清空上次写入显示缓存的数据
        if (str_length == 5)          //当字符串长度为5,即aa.bb时
        {
            CF_Display_12x24_A(50, 0, asiic_12x24[*(piont_p - 2) - '0']);
        }
        if (str_length == 4) //当字符串长度为4,即a.bb时
        {
            CF_Display_12x24_A(50, 0, asiic_12x24_space);
        }
        CF_Display_12x24_A(62, 0, asiic_12x24[*(piont_p - 1) - '0']);
        CF_Display_12x24_A(74, 0, asiic_12x24_point);
        CF_Display_12x24_A(86, 0, asiic_12x24[*(piont_p + 1) - '0']);
        CF_Display_12x24_A(98, 0, asiic_12x24[*(piont_p + 2) - '0']);

        //绘制动态波形
        t_fmax = t_fmin = t_sq[0];
        for (uint8_t i = 0; i < 100; i++)
        {
            t_fmax = t_fmax > t_sq[i] ? t_fmax : t_sq[i];
            t_fmin = t_fmin < t_sq[i] ? t_fmin : t_sq[i];
        }
        sprintf(t_str, "%.2lf", t_fmax); //将最大湿度换为字符串数组
        str_length = strlen(t_str);      //获取字符串数组的长度
        piont_p = strchr(t_str, '.');    //获取字符串数组中'.'的地址
                                         //清空上次写入显示缓存的数据
        if (str_length == 5)             //当字符串长度为5,即aa.bb时
        {
            CF_Display_5X8_A(0, 34, asiic_5x8[*(piont_p - 2) - '0']);
        }
        if (str_length == 4) //当字符串长度为4,即a.bb时
        {
            CF_Display_5X8_A(0, 56, asiic_5x8_space);
        }
        CF_Display_5X8_A(5, 34, asiic_5x8[*(piont_p - 1) - '0']);
        CF_Display_5X8_A(10, 34, asiic_5x8_point);
        CF_Display_5X8_A(15, 34, asiic_5x8[*(piont_p + 1) - '0']);
        CF_Display_5X8_A(20, 34, asiic_5x8[*(piont_p + 2) - '0']);

        CF_Display_5X8_A(0, 26, asiic_5x8_M);
        CF_Display_5X8_A(5, 26, asiic_5x8_A);
        CF_Display_5X8_A(10, 26, asiic_5x8_X);

        sprintf(t_str, "%.2lf", t_fmin); //将最小湿度换为字符串数组
        str_length = strlen(t_str);      //获取字符串数组的长度
        piont_p = strchr(t_str, '.');    //获取字符串数组中'.'的地址
                                         //清空上次写入显示缓存的数据
        if (str_length == 5)             //当字符串长度为5,即aa.bb时
        {
            CF_Display_5X8_A(0, 56, asiic_5x8[*(piont_p - 2) - '0']);
        }
        if (str_length == 4) //当字符串长度为4,即a.bb时
        {
            CF_Display_5X8_A(0, 56, asiic_5x8_space);
        }
        CF_Display_5X8_A(5, 56, asiic_5x8[*(piont_p - 1) - '0']);
        CF_Display_5X8_A(10, 56, asiic_5x8_point);
        CF_Display_5X8_A(15, 56, asiic_5x8[*(piont_p + 1) - '0']);
        CF_Display_5X8_A(20, 56, asiic_5x8[*(piont_p + 2) - '0']);
        CF_Display_5X8_A(0, 48, asiic_5x8_M);
        CF_Display_5X8_A(5, 48, asiic_5x8_I);
        CF_Display_5X8_A(10, 48, asiic_5x8_N);

        for (uint8_t i = 0; i < 100; i++)
        {
            wave_mark = (t_sq[i] - t_fmin) / (t_fmax + 0.2 - t_fmin) * 38;
            for (uint8_t j = 0; j < 38; j++)
            {
                CF_DrawPoint(28 + i, 26 + j, (38 - j) > wave_mark ? 0 : 1);
            }
        }
    }
    //将温度信息写入缓存帧
    CF_PushFrame();
}

视频分为三部分,第一部分是系统结构简要说明,包括软硬件总体框架与核心器件介绍;第二部分是关键内容介绍,包括电容数字转换芯片AD7745量程拓展,容型湿度传感器电容值与湿度换算,使用CH32V单片机读取MAX6608模拟温度传感器电压并换算温度;视频末尾是实物展示,活动提交页面可获取源码包,提供ST7565P显示屏的驱动与帧缓存实现。

 

软硬件
电路图
附件下载
FastBond代码包.zip
团队介绍
个人简介: 机械工程,机械电子方向,研究生在读。主攻工业装备关键部件无损检测与状态监测技术。常年潜水于各电子技术论坛。目前拥有自己的创业小团队,面向基于微控制器的软硬件开发,已成功交付产品数款。
评论
0 / 100
查看更多
目录
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2023 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号