搜索
bottom↓
回复: 2

请教马老师 ADC中断 取六次去掉最大值最小值再取平均值程序是否合理

[复制链接]

出0入0汤圆

发表于 2009-11-14 18:22:10 | 显示全部楼层 |阅读模式
马老师,你好,在论坛里找不到中断取ADC值,用平均值法的程序,我看了几天资料,写了下面的程序,但我也不确定正确,希望得到马老师的指点。
当然我学习AVR单片机时间不久,或许这样的处理方法不是最佳的

#include <mega88.h>
#include <delay.h>
#include <cvavr1602.h>

unsigned char num[4];
unsigned char tab_num[]={"0123456789"};

void port_init(void);
void inter_init(void);
void adc_init(void);
void transport(unsigned int aaa);

unsigned int adc_data;
#define ADC_VREF_TYPE 0x40

// ADC interrupt service routine
interrupt [ADC_INT] void adc_isr(void)
{
// Read the AD conversion result
adc_data=ADCW;
ADCSRA|=0x40;//希望启动中断取ADC值之后,以62.5KHz的频率不断取ADC值,16us取一次。在read_adc中,连续取6次,间隔30us
}
// Read the AD conversion result
unsigned int read_adc(unsigned char adc_input)
{
        unsigned int adc_data1,adc_value[6],adc_min,adc_max;
        unsigned char i;
        ADMUX=adc_input | (ADC_VREF_TYPE & 0xff);
        // Delay needed for the stabilization of the ADC input voltage
        delay_us(10);
        for(i=0;i<6;i++)
        {
        adc_value=adc_data;       
        delay_us(30);//延时30us,下一次取的ADC值是新中断产生的data
    }
        adc_min=adc_value[0];
        adc_max=adc_value[0];
        for(i=0;i<6;i++)
        {
                if(adc_min>adc_value)
                adc_min=adc_value;
                if(adc_max<adc_value)
                adc_max=adc_value;       
        }
        adc_data1=(adc_value[0]+adc_value[1]+adc_value[2]+adc_value[3]+adc_value[4]+adc_value[5]-adc_min-adc_max)/4;
return adc_data1;
}

// Declare your global variables here

void main(void)
{
// Declare your local variables here

unsigned int adcvalue;
unsigned char i,j;


port_init();
inter_init();
adc_init();
lcd_init();

// Crystal Oscillator division factor: 1
#pragma optsize-
CLKPR=0x80;
CLKPR=0x00;
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif
// Global enable interrupts
#asm("sei")

while (1)
      {
      // Place your code here
      
      ADCSRA|=0x40;//启动ADC中断转换
      
      adcvalue=read_adc(0x00);//读ADC0端口
      transport(adcvalue);//把数值转换为数字符号,放入num[4]中
      setxy(0,0);//写入LCD1602第一行,0~3位
        for(i=0;i<4;i++)
        {
        j=num;
        write_data(tab_num[j]);
        }
      delay_ms(200);//延时,防止LCD刷屏过快,看不清
      
        adcvalue=read_adc(0x01);//读ADC1端口
        transport(adcvalue);
        setxy(5,0);
        for(i=0;i<4;i++)
        {
        j=num;
        write_data(tab_num[j]);
        }
      delay_ms(200);
      
      adcvalue=read_adc(0x02);//读ADC2
        transport(adcvalue);
        setxy(10,0);
        for(i=0;i<4;i++)
        {
        j=num;
        write_data(tab_num[j]);
        }
      delay_ms(200);
      
        adcvalue=read_adc(0x03);
        transport(adcvalue);
        setxy(0,1);
        for(i=0;i<4;i++)
        {
        j=num;
        write_data(tab_num[j]);
        }
      delay_ms(200);

        adcvalue=read_adc(0x04);
        transport(adcvalue);
        setxy(5,1);
        for(i=0;i<4;i++)
        {
        j=num;
        write_data(tab_num[j]);
        }
        
        delay_ms(200);
        adc1value=read_adc(0x05);
        transport(adc1value);
        setxy(10,1);
        for(i=0;i<4;i++)
        {
        j=num;
        write_data(tab_num[j]);
        }
      delay_ms(200);
      
      };
}

void port_init(void)
{
// Input/Output Ports initialization
// Port B initialization
// Func7=Out Func6=Out Func5=Out Func4=Out Func3=Out Func2=Out Func1=Out Func0=Out
// State7=0 State6=0 State5=0 State4=0 State3=0 State2=0 State1=0 State0=0
PORTB=0x00;
DDRB=0xFF;

// Port C initialization
// Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTC=0x00;
DDRC=0x00;

// Port D initialization
// Func7=Out Func6=Out Func5=Out Func4=In Func3=In Func2=In Func1=Out Func0=Out
// State7=0 State6=0 State5=0 State4=T State3=T State2=T State1=0 State0=0
PORTD=0x00;
DDRD=0xE3;
}

void adc_init(void)
{
//(1)设置ADCSR的最低三位,确定分频因子
//(2)设置ADIE为1,打开中断模式
//(3)设置ADEN为高电平,使ADC有效
//(4)设置ADSC,以马上开始转换
   // Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
ACSR=0x80;
ADCSRB=0x00;

// ADC initialization
// ADC Clock frequency: 62.500 kHz
// ADC Voltage Reference: AVCC pin
// ADC Auto Trigger Source: None
// Digital input buffers on ADC0: On, ADC1: On, ADC2: Off, ADC3: Off
// ADC4: Off, ADC5: Off
DIDR0=0x00;
ADMUX=ADC_VREF_TYPE & 0xff;//设置参考电压
ADCSRA=0x8F;//ADEN=1/ADIE=1
}

void transport(unsigned int aaa)//转换数字为字符
{
        unsigned int bbb;       
bbb=aaa;
num[3]=bbb%10;
    bbb=bbb/10;
    num[2]=bbb%10;
    bbb=bbb/10;
    num[1]=bbb%10;
    bbb=bbb/10;
    num[0]=bbb%10;       
}

void inter_init(void)
{
// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: Timer 0 Stopped
// Mode: Normal top=FFh
// OC0A output: Disconnected
// OC0B output: Disconnected
TCCR0A=0x00;
TCCR0B=0x00;
TCNT0=0x00;
OCR0A=0x00;
OCR0B=0x00;

// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: Timer 1 Stopped
// Mode: Normal top=FFFFh
// OC1A output: Discon.
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer 1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
TCCR1A=0x00;
TCCR1B=0x00;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;

// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: Timer 2 Stopped
// Mode: Normal top=FFh
// OC2A output: Disconnected
// OC2B output: Disconnected
ASSR=0x00;
TCCR2A=0x00;
TCCR2B=0x00;
TCNT2=0x00;
OCR2A=0x00;
OCR2B=0x00;

// External Interrupt(s) initialization
// INT0: Off
// INT1: Off
// Interrupt on any change on pins PCINT0-7: Off
// Interrupt on any change on pins PCINT8-14: Off
// Interrupt on any change on pins PCINT16-23: Off
EICRA=0x00;
EIMSK=0x00;
PCICR=0x00;

// Timer/Counter 0 Interrupt(s) initialization
TIMSK0=0x00;
// Timer/Counter 1 Interrupt(s) initialization
TIMSK1=0x00;
// Timer/Counter 2 Interrupt(s) initialization
TIMSK2=0x00;

}   

这个程序有几个问题:
1.在LCD1602显示,有错位。ADC0显示在5~8,ADC1显示在 10~13位置。依次类推
2.LCD显示的数字与万用表测的数字有0.2V左右的差值
这两个问题,我会查找原因。并在后续更新

最后还是希望得到马老师的指点,关于read_adc部分是否可行。一直都在论坛学习,这次贡献微薄之力。

出0入0汤圆

 楼主| 发表于 2009-11-14 20:35:37 | 显示全部楼层
更新了一版
/*****************************************************
This program was produced by the
CodeWizardAVR V2.03.4 Standard
Automatic Program Generator
?Copyright 1998-2008 Pavel Haiduc, HP InfoTech s.r.l.
http://www.hpinfotech.com

Project : test ADC interrupt
Version :
Date    : 2009-11-14
Author  :
Company :
Comments:
interrupt ADC


Chip type           : ATmega88
Program type        : Application
Clock frequency     : 8.000000 MHz
Memory model        : Small
External RAM size   : 0
Data Stack size     : 256
*****************************************************/

#include <mega88.h>
#include <delay.h>
#include <cvavr1602.h>


unsigned char num[4];
unsigned char tab_num[]={"0123456789"};

void port_init(void);
void inter_init(void);
void adc_init(void);
void transport(unsigned int aaa);



unsigned int adc_data;
#define ADC_VREF_TYPE 0x40

// ADC interrupt service routine
interrupt [ADC_INT] void adc_isr(void)
{
// Read the AD conversion result
adc_data=ADCW;
ADCSRA|=0x40;
}

// Read the AD conversion result
// with noise canceling
unsigned int read_adc(unsigned char adc_input)
{
        unsigned int adc_data1,adc_value[6],adc_min,adc_max;
        unsigned char i;
       
        ADMUX=adc_input | (ADC_VREF_TYPE & 0xff);
        // Delay needed for the stabilization of the ADC input voltage
        delay_us(10);
        ADCSRA|=0x40;
        ADCSRA|=0x08;//启动中断
        ADCSRA|=0x40;
       
        for(i=0;i<6;i++)
        {
        while(~(0x08&ADCSRA))
        adc_value=adc_data;       
            }
       
        adc_min=adc_value[0];
        adc_max=adc_value[0];
        for(i=0;i<6;i++)
        {
                if(adc_min>adc_value)
                adc_min=adc_value;
                if(adc_max<adc_value)
                adc_max=adc_value;       
        }
        adc_data1=(adc_value[0]+adc_value[1]+adc_value[2]+adc_value[3]+adc_value[4]+adc_value[5]-adc_min-adc_max)/4;
        ADCSRA&=0xF7;
return adc_data1;
}

// Declare your global variables here

void main(void)
{
// Declare your local variables here
unsigned int adc1value;
unsigned char i,j;

port_init();
inter_init();
adc_init();
lcd_init();

// Crystal Oscillator division factor: 1
#pragma optsize-
CLKPR=0x80;
CLKPR=0x00;
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif
// Global enable interrupts
#asm("sei")

while (1)
      {
      // Place your code here
      
      adc1value=read_adc(0x00);
      transport(adc1value);
      setxy(0,0);
        for(i=0;i<4;i++)
        {
        j=num;
        write_data(tab_num[j]);
        }
      delay_ms(200);
      
      adc1value=read_adc(0x01);
        transport(adc1value);
        setxy(5,0);
        for(i=0;i<4;i++)
        {
        j=num;
        write_data(tab_num[j]);
        }
      delay_ms(200);
      
      adc1value=read_adc(0x02);
        transport(adc1value);
        setxy(10,0);
        for(i=0;i<4;i++)
        {
        j=num;
        write_data(tab_num[j]);
        }
      delay_ms(200);
      
        adc1value=read_adc(0x03);
        transport(adc1value);
        setxy(0,1);
        for(i=0;i<4;i++)
        {
        j=num;
        write_data(tab_num[j]);
        }
      delay_ms(200);  
        adc1value=read_adc(0x04);
        transport(adc1value);
        setxy(5,1);
        for(i=0;i<4;i++)
        {
        j=num;
        write_data(tab_num[j]);
        }
        
        delay_ms(200);
        adc1value=read_adc(0x05);
        transport(adc1value);
        setxy(10,1);
        for(i=0;i<4;i++)
        {
        j=num;
        write_data(tab_num[j]);
        }
      delay_ms(200);
      
      };
}

void port_init(void)
{
// Input/Output Ports initialization
// Port B initialization
// Func7=Out Func6=Out Func5=Out Func4=Out Func3=Out Func2=Out Func1=Out Func0=Out
// State7=0 State6=0 State5=0 State4=0 State3=0 State2=0 State1=0 State0=0
PORTB=0x00;
DDRB=0xFF;

// Port C initialization
// Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTC=0x00;
DDRC=0x00;

// Port D initialization
// Func7=Out Func6=Out Func5=Out Func4=In Func3=In Func2=In Func1=Out Func0=Out
// State7=0 State6=0 State5=0 State4=T State3=T State2=T State1=0 State0=0
PORTD=0x00;
DDRD=0xE3;
}

void adc_init(void)
{
//(1)设置ADCSR的最低三位,确定分频因子
//(2)设置ADIE为1,打开中断模式
//(3)设置ADEN为高电平,使ADC有效
//(4)设置ADSC,以马上开始转换
   // Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
ACSR=0x80;
ADCSRB=0x00;

// ADC initialization
// ADC Clock frequency: 62.500 kHz
// ADC Voltage Reference: AVCC pin
// ADC Auto Trigger Source: None
// Digital input buffers on ADC0: On, ADC1: On, ADC2: Off, ADC3: Off
// ADC4: Off, ADC5: Off
DIDR0=0x00;
ADMUX=ADC_VREF_TYPE & 0xff;
ADCSRA=0x87;//ADEN/ADIE=1
}

void transport(unsigned int aaa)
{
        unsigned int bbb;       
bbb=aaa;
num[3]=bbb%10;
    bbb=bbb/10;
    num[2]=bbb%10;
    bbb=bbb/10;
    num[1]=bbb%10;
    bbb=bbb/10;
    num[0]=bbb%10;       
}

void inter_init(void)
{
// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: Timer 0 Stopped
// Mode: Normal top=FFh
// OC0A output: Disconnected
// OC0B output: Disconnected
TCCR0A=0x00;
TCCR0B=0x00;
TCNT0=0x00;
OCR0A=0x00;
OCR0B=0x00;

// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: Timer 1 Stopped
// Mode: Normal top=FFFFh
// OC1A output: Discon.
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer 1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
TCCR1A=0x00;
TCCR1B=0x00;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;

// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: Timer 2 Stopped
// Mode: Normal top=FFh
// OC2A output: Disconnected
// OC2B output: Disconnected
ASSR=0x00;
TCCR2A=0x00;
TCCR2B=0x00;
TCNT2=0x00;
OCR2A=0x00;
OCR2B=0x00;

// External Interrupt(s) initialization
// INT0: Off
// INT1: Off
// Interrupt on any change on pins PCINT0-7: Off
// Interrupt on any change on pins PCINT8-14: Off
// Interrupt on any change on pins PCINT16-23: Off
EICRA=0x00;
EIMSK=0x00;
PCICR=0x00;

// Timer/Counter 0 Interrupt(s) initialization
TIMSK0=0x00;
// Timer/Counter 1 Interrupt(s) initialization
TIMSK1=0x00;
// Timer/Counter 2 Interrupt(s) initialization
TIMSK2=0x00;

}

出0入0汤圆

 楼主| 发表于 2009-11-14 21:09:28 | 显示全部楼层
unsigned int read_adc(unsigned char adc_input)
{
        unsigned int adc_data1,adc_value[6],adc_min,adc_max;
        unsigned char i;
       
        ADMUX=adc_input | (ADC_VREF_TYPE & 0xff);
        // Delay needed for the stabilization of the ADC input voltage
        delay_us(100);
        ADCSRA|=0x40;
        ADCSRA|=0x08;//启动中断
        ADCSRA|=0x40;
       
        for(i=0;i<6;i++)
        {
        delay_us(30);
        adc_value=adc_data;       
            }
       
        adc_min=adc_value[0];
        adc_max=adc_value[0];
        for(i=0;i<6;i++)
        {
                if(adc_min>adc_value)
                adc_min=adc_value;
                if(adc_max<adc_value)
                adc_max=adc_value;       
        }
        adc_data1=(adc_value[0]+adc_value[1]+adc_value[2]+adc_value[3]+adc_value[4]+adc_value[5]-adc_min-adc_max)/4;
        ADCSRA&=0xF7;
return adc_data1;
}

不论采用什么的算法,第一次采集ADC0的时候,是没有值的,第一次采集ADC1的时候是0000,第二次采集ADC0的时候读取的值是ADC1上次采样的,第二次采集ADC1的时候是上一次采集ADC0的值,所以才会造成错位。
哪里错了呢?
寻找答案中
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-5-3 04:52

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

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