找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1756|回复: 3
收起左侧

单片机程序中的计算分贝值的算法看不太懂,大神帮帮忙讲解一下

[复制链接]
天狼星666 发表于 2019-6-3 17:19 | 显示全部楼层 |阅读模式
***************************************************************/
#include<reg52.h>                //头文件
#include<LCD1602.h>
#include<ADC0832.h>
#include<AT24C02.h>

/************************引脚定义************************/
sbit ledr     =P1^3; //红色LED灯
sbit ledg     =P1^5; //绿色LED灯
sbit key_she  =P1^0; //设置键
sbit key_jia  =P1^1; //加值键
sbit key_jian =P1^2; //减值键

/************************变量定义************************/
uchar db_up;                 //分贝限值
bit set_f=0;                 //设置变量,=0正常测量,=1处于设置分贝限值

uint ad=0;                          //存储AD转换值
double VCC=500;             //存储系统电源电压,放大100倍
double V;                 //存储当前所测电压
double low_V;                 //存储上一次所测电压

uchar db;                 //存储当前所测分贝
/********************************************************
函数名称:void delayms(uint ms)
函数作用:毫秒延时函数
参数说明:ms为延时的毫秒数
********************************************************/
void delayms(uint ms)
{
        uchar i=100,j;
        for(;ms;ms--)
        {
                while(--i)
                {
                        j=10;
                        while(--j);
                }
        }
}

/*********************************************************
函数名称:void display()
函数作用:正常显示函数
参数说明:
*********************************************************/
void display()
{
        lcd1602_write_character(0,1,"  Decibel:    ");

        LCD_disp_char(10,1,ASCII[db/100]);        //显示分贝值
        LCD_disp_char(11,1,ASCII[db%100/10]);
        LCD_disp_char(12,1,ASCII[db%10]);
        lcd1602_write_character(13,1,"db");        //显示【db】
        lcd1602_write_character(2,2,"TC:");          // ()SSN        UN IN
        //lcd1602_write_character(8,2," FC:LFN");        // IFN HFN
        if(db>db_up)  //实测值大于设置值
        {
                ledr=0;          //红色指示灯亮
                ledg=1;
        }
        else                  //否则处于正常
        {
                ledr=1;
                ledg=0;          //绿色指示灯亮
        }                                    
}
/*********************************************************
函数名称:void display2()
函数作用:显示设置分贝提示限值函数
参数说明:
*********************************************************/
void display2()
{
        lcd1602_write_character(0,1,"Set decibe limit");

        LCD_disp_char(5,2,ASCII[db_up/100]);
        LCD_disp_char(6,2,ASCII[db_up%100/10]);
        LCD_disp_char(7,2,ASCII[db_up%10]);
        lcd1602_write_character(8,2,"db");                                    
}
/*********************************************************
函数名称:void scan()
函数作用:按键检测处理
参数说明:
*********************************************************/
void scan()
{
        //设置键
        if(key_she==0)                                        //按键按下
        {
                delayms(7);                                        //延时消抖
                if(key_she==0)                                //再次判断按键是否按下
                {
                        set_f=~set_f;                        //切换设置和正常测量
                        if(set_f==0)                        //如果设置完成
                                AT24C02_write_date(0,db_up);//存储【分贝】限值
                        LCD_write_command(0x01);//清除屏幕显示
                        delay_n40us(100);            //等待清除完成
                }
                while(!key_she);                        //等待按键松开
        }
        //加键
        if(key_jia==0&&set_f!=0)
        {
                delayms(7);
                if(key_jia==0)
                {
                        if(db_up<100)
                                db_up++;
                }                                
        }
        //减键
        if(key_jian==0&&set_f!=0)
        {
                delayms(7);
                if(key_jian==0)
                {
                        if(db_up>1)
                                db_up--;
                }
        }
}
/*********************************************************
函数名称:db_count()
函数作用:计算分贝值
参数说明:
*********************************************************/

void db_count()
{
        ad=ad/100;                         //采集100次ad值后计算平均值,均值滤波
        
        V=VCC*ad/255.0;                 //计算所测电压, V/ad=VCC/255

        low_V=(low_V+V)/2;         //与上一次测量电压值求平均值

        low_V=V;                         //记录分贝电压值
        db=35+V/4.0;                 //根据电压对应计算分贝值
}
/*********************************************************
函数名称:void main()
函数作用:主函数
参数说明:
*********************************************************/
void main()
{
        uint i=0;       //存储采集次数
        if(key_jian==0)
        {
                delayms(100);
                if(key_jian==0)
                        AT24C02_write_date(0,60);//存储【分贝】限值
        }
        db_up=AT24C02_read_date(0);//先读取存储的【分贝限值】
        LCD_init();                //初始化液晶
        while(1)                //死循环
        {        
                scan();                                //按键检测与处理
                if(set_f==0)                //正常显示
                {
                        i++;            //循环次数+1
                        ad+=ADC0832_read(0);//读取AD值,并累加记录到ad上
                        
                        if(i>=100)                //每采集100次计算一次分贝值
                        {
                                i=0;                //重置计数变量

                                db_count(); //计算分贝
                                display();  //显示分贝        

                                ad=0;            //重置ad值
                        }
                        delay_n40us(80);
                }
                else                                //否则,处于设置模式
                        display2();                //显示设置界面
        }
}

回复

使用道具 举报

cjm82 发表于 2019-6-4 00:33 | 显示全部楼层

DB的定义是个以10为底的对数,比如1000换成DB就是 20*lg1000=60.
所以说正常计算的话,怎么样都要包含MATH.H
而程序里 db=35+V/4.0
这个应该是输入模拟量的器件(比如传感器)为了使用方便,已经做了线性处理的,电压值跟DB值是线性关系.一般这种公式在该器件的说明书里能找到.
回复

使用道具 举报

幻剑心 发表于 2019-6-4 02:44 | 显示全部楼层

     if(set_f==0)                //正常显示
    {
          i++;            //循环次数+1
          ad+=ADC0832_read(0);//读取AD值,并累加记录到ad上                        
          if(i>=100)                //每采集100次计算一次分贝值
          {
               i=0;                //重置计数变量
              db_count(); //计算分贝
              display();  //显示分贝        
              ad=0;            //重置ad值
         }
set_f=0,即正常测量的时候 adwhile每次循环采集一次实时分贝值(通过ADC0832转换获得)。等采集累积到100个值的时候调用db_count()计算分贝值(主要是滤波,取100个值的平均值),计算好平均分贝值后,调用display()进行显示。然后ad清零,i清零重新采集实时分贝值。ADC0832_read(0)是在另一个.c文件中的函数,应该是进行模拟量的分贝值采集然后进行模数转换,将分贝值转换成数字量。
回复

使用道具 举报

太阳黑子1 发表于 2019-6-4 13:06 | 显示全部楼层
注释的挺详细的啊!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表