找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1524|回复: 11
收起左侧

单片机AD采样,算术平均滤波后得到的数据出错

[复制链接]
ID:975927 发表于 2021-11-16 09:45 | 显示全部楼层 |阅读模式
请教各位大佬,我想用51单片机写一个定时器每10ms进行一次AD采样,对16次的采样值进行算术平均滤波,采样函数和滤波函数都应该在哪调用,中断还是主函数?
回复

使用道具 举报

ID:750420 发表于 2021-11-16 10:59 | 显示全部楼层
采样函数和滤波函数均在主函数中调用,使用标记位的方式,在主函数中去检测标记位是否被触发,然后执行相应的函数即可
回复

使用道具 举报

ID:546770 发表于 2021-11-16 11:43 | 显示全部楼层
滤波在主函数最好,ADC转换完成一般也可以有个引脚触发中断,在这个中断读取转换的值就好了,只要中断里面不加延时函数一般都没多大问题的。
回复

使用道具 举报

ID:401564 发表于 2021-11-16 13:05 | 显示全部楼层
在中断中进行ADC数字量的累加和平均,最大值最多加到一个32位整型数据,256次以下的累加用不了多少时间的,平均后的数据存放到一个全局变量中,在主程序中通过这个全局变量来处理就可以
中断中不能有延时,等待,浮点运算
回复

使用道具 举报

ID:975927 发表于 2021-11-16 13:46 | 显示全部楼层
本帖最后由 1027669350 于 2021-11-16 15:57 编辑
Y_G_G 发表于 2021-11-16 13:05
在中断中进行ADC数字量的累加和平均,最大值最多加到一个32位整型数据,256次以下的累加用不了多少时间的,平 ...

不好意思,问一个低级的问题,我这样写数码管是不会显示的,能帮忙修改一下吗
void main()
{
        adcs=0;
        Init();
        while(1)
        {
                display(2*value);
        }
}
//定时器中断函数
void time0() interrupt 1
{
        
        TH0=(65536-9174)/256;      //重新装入初值
  TL0=(65526-9174)%256;
        num++;
        myvalue=getad();
        sum+=myvalue;
     
        if(num==16)
        {
                value=sum/16;
        }
}
回复

使用道具 举报

ID:908826 发表于 2021-11-16 14:37 | 显示全部楼层
主函数里面吧,
回复

使用道具 举报

ID:624769 发表于 2021-11-16 16:42 | 显示全部楼层
我很好奇,你怎么会认为:“每10ms进行一次AD采样,对16次的采样值进行算术平均滤波,” 这个操作对“滤波”是最优解的?
我们撇开Hz率不讲,举个现实中的例子, 要统计地铁的平均客流量, 是每天定时去采样1小时,连续30天(共计30小时)来的准确,还是, 直接去连续统计24小时平均后来的准确?
回复

使用道具 举报

ID:975927 发表于 2021-11-16 16:52 | 显示全部楼层
188610329 发表于 2021-11-16 16:42
我很好奇,你怎么会认为:“每10ms进行一次AD采样,对16次的采样值进行算术平均滤波,” 这个操作对“滤波 ...

那我应该采用什么方法进行采样和滤波呢,刚接触这一方面,知道的太少了
回复

使用道具 举报

ID:885416 发表于 2021-11-16 17:13 来自手机 | 显示全部楼层
耗时时间短的操作在中断里去做,耗时时间长的如计算在主函数做
回复

使用道具 举报

ID:624769 发表于 2021-11-16 17:22 | 显示全部楼层
1027669350 发表于 2021-11-16 16:52
那我应该采用什么方法进行采样和滤波呢,刚接触这一方面,知道的太少了

采样不要用定时器间隔,直接连续采样,计算可以参考地板。
回复

使用道具 举报

ID:401564 发表于 2021-11-16 17:29 | 显示全部楼层
1027669350 发表于 2021-11-16 16:52
那我应该采用什么方法进行采样和滤波呢,刚接触这一方面,知道的太少了

ADC采用中断方式呀
我一开始没有认真看,还以为你是采用ADC中断模式
ADC采用中断模式,128次ADC累加后,取平均值就行,我试过,去不去掉这个最大和最小值,对于结果影响并不大,可以说是没啥效果以下是我STC8G的ADC,你参考一下
/*stc8g系列单片机ADC程序*/

#include "Stc8g.h"
#include "Stc8g_Adc.h"
#define         ADC_P10 0x80
#define         ADC_P11 0x81
#define         ADC_P12 0x82
#define         ADC_P13 0x83
#define         ADC_P14 0x84
#define         ADC_P15 0x85
#define         ADC_P16 0x86
#define         ADC_P17 0x87
#define         ADC_P1f 0x8f
#define     ADC_COUNT 128
/*需要在主程序使用以下变量,可以在变量声明前加上 extern 来声明,就可以直接调用了*/
//──────────────────────────────────────────────────────────────────────────────────

unsigned char                          ADC_LINE;                //ADC通道记录
unsigned long int                 ADC_AN7;                //ADC0数据
unsigned long int                 ADC_ANf;                //ADCf数据                  
//──────────────────────────────────────────────────────────────────────────────────
void Stc8g_Adc_int()//stc8gadc初始化
{
        unsigned int i;
        P1M0=0;
        P1M1=0x80;                //p1.7用作ADC端口       
        ADC_CONTR=0x80;//打开adc电源
        ADCCFG=0x2f;        //设定ADC转换结果保存格式       
        for(i=10000;i>0;i--);            //延时
        ADC_LINE=ADC_P1f;
        ADC_CONTR=ADC_CONTR|0x40;        //启动ADC
        EADC=1;
}
//──────────────────────────────────────────────────────────────────────────────────
void Adc_Isr() interrupt 5                         //Adc中断函数
{

static unsigned char                          count7;                        //ADC通道6转换次数记录
static unsigned char                          countf;                        //ADC通道f转换次数记录,内部参考电压通道
static unsigned long int                 ADC_DATA7;                //ADC0数据,累加
static unsigned long int                 ADC_DATAf;                //ADCf数据,累加               
ADC_CONTR=ADC_CONTR&0xdf;                  //清除中断标志位
                //──────────────────────────────────────────────────────────────────────────
                if(ADC_LINE==ADC_P1f)                                                          //检测触发ADC中断的通道
                        {  
                                if(countf>=ADC_COUNT)                                         //检测ADC转换次数
                                        {
                                                 ADC_ANf=ADC_DATAf/ADC_COUNT;          //取平均值
                                                 ADC_DATAf=0x00;                                          //清除ADC累加结果
                                                 countf=0x00;                                          //清除ADC转换次数记录
                                        }
                                ADC_DATAf+=ADC_RES*256+ADC_RESL;                //ADC结果累加
                                countf++;                          
                                ADC_CONTR=ADC_LINE=ADC_P17;                                //选择下一个ADC通道
                        }
                //──────────────────────────────────────────────────────────────────────────
                else if(ADC_LINE==ADC_P17)
                        {  
                                if(count7>=ADC_COUNT)
                                        {
                                                 ADC_AN7=ADC_DATA7/ADC_COUNT;
                                                 ADC_DATA7=0x00;
                                                 count7=0x00;
                                        }
                                ADC_DATA7+=ADC_RES*256+ADC_RESL;       
                                count7++;                                                          
                                ADC_CONTR=ADC_LINE=ADC_P1f;
                        }
                //──────────────────────────────────────────────────────────────────────────                  
ADC_CONTR=ADC_CONTR|0x40;                                                                //启动ADC
}

回复

使用道具 举报

ID:123289 发表于 2021-11-18 15:02 | 显示全部楼层
采样在中断中进行,计算在主程序是进行。
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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