logo elektroda
logo elektroda
X
logo elektroda
REKLAMA
REKLAMA
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

[Atmega8][c] ADC 1024 na niepodpiętym porcie, błędne wyniki

overheat 09 Lut 2011 00:48 1526 4
REKLAMA
  • #1 9124707
    overheat
    Poziom 9  
    Witam! Mam spory problem z ADC, który nie pozwala mi zasnąć:

    Konfiguracja sprzętowa:
    - Wybrane wewnętrzne źródło napięcia 2.56V
    - Kondensator na AREF-GND (zgodnie z instrukcją)
    - AVCC wolne (niepodpięte)
    - Źródło napięcia na PC0 (ADC0)
    - Wyjście na wyświetlacz LCD

    Konfiguracja software:
    - Pomiar na przerwaniu
    - Uśrednienie z 10 wyników dla lepszej stabilności

    Problem:
    - Po pierwsze ADC działa (manipulacja napięciem na ADC0 zmienia wyświetlaną wartość) - daje wyniki, ale absurdalne (patrz niżej)
    - Gdy ADC0 jest niepodłączone, uC mierzy wartość 1024 (a powinna być 0, prawda?)
    - Gdy zewrę ADC0 do masy jest 0
    - Gdy podłączę pod ADC0 źródło napięcia (np. bateria AA, bo zakres jest 0-2.56 - nie używam dzielnika napięcia), pojawiają się wyniki z kosmosu, które nijak nie dają się przeliczyć na rzeczywiste napięcie (sprawdzane multimetrem)

    Załączam poniżej kod źródłowy i bardzo proszę o pomoc. W czym tkwi problem?

    #include <stdlib.h>
    #include <avr/io.h>                 
    #include <avr/interrupt.h> 
    #include <avr/sleep.h>
    
    #include "HD44780.h"
    
    volatile float result = 0;
    volatile float values[10] = {0,0,0,0,0,0,0,0,0,0};
    volatile unsigned int current = 0;
    char text[12];
    
    void init_adc() {
    	sei();
    	PORTC = 0x00;
    	DDRC = 0x00;
    	ADMUX |= _BV(REFS0) | _BV(REFS1); //internal reference 2.56V
    	//ADMUX |= _BV(MUX3) | _BV(MUX2) | _BV(MUX1); // calibration test
      	ADCSRA |= _BV(ADEN) | _BV(ADFR) | _BV(ADPS0) | _BV(ADPS1);
    }
    
    void adc_start_conversion()
    {
    	ADCSRA |= _BV(ADSC) | _BV(ADIE);
    }
    
    ISR(ADC_vect)
    {
    	result = (float)(ADCL | (ADCH << 8));	
    	values[current] = result;
    	current+=1;
    	if(current==10)
    		current = 0;
    
    	//stop ADC
    	ADCSRA &= ~(1<<ADIE);
    }
    
    void calculateAvg() {
    	float avg = (values[0] + values[1] + values[2] + values[3] + values[4] + values[5] 
    			+ values[6] + values[7] + values[8] + values[9])/10;
    	dtostrf(avg,6,2,text);
    	//text[6]='V';
    }
    
    int main()
    {
    	_delay_ms(200);
    	LCD_Initalize();
    	LCD_Clear();
    	LCD_Write1x16Text("Waiting...");
    
    	// blink LED
    	DDRD |= _BV(PD7);
    	PORTD |= _BV(PD7);
    
    	init_adc();
    	adc_start_conversion();
    
    	while(1){
    		_delay_ms(100);
    		// blink LED
    		PORTD ^= _BV(PD7);	
    		
    		adc_start_conversion();
    		calculateAvg();
    		LCD_Clear();
    		LCD_Write1x16Text(text);
    		set_sleep_mode(SLEEP_MODE_ADC);
    	}
    
    	return 0;
    }
    
  • REKLAMA
  • #2 9124776
    Pentryt
    Poziom 15  
    Z noty katalogowej:
    Atmel napisał:
    AVCC is the supply voltage pin for the A/D Converter, Port C (3..0), and ADC (7..6). It should be
    externally connected to VCC, even if the ADC is not used. If the ADC is used, it should be connected
    to VCC through a low-pass filter. Note that Port C (5..4) use digital supply voltage, VCC.
  • REKLAMA
  • #3 9124927
    Terminator
    Poziom 23  
    Podłącz AVCC przed dławik np 10uH do zasilania atmegi.
  • REKLAMA
  • #4 9125888
    overheat
    Poziom 9  
    Podłączyłem dławik + kondensator, tak jak mówicie (nota techn.). Teraz na pustym ADC0 pokazuje ~0.13V. Pomiar jest dość niedokładny (ok. -0.1), ale jakiś jest.

    To co mnie martwi natomiast to, że gdy do ADC0 podłączony jest jakikolwiek kabel bez obciążenia (zapewne działa jak antena i indukuje się w nim prąd), to pomiar szaleje w zasadzie po całej skali, a tak przecież nie powinno być. Wszak do multimetru mogą być podłączone półmetrowe kable bez obciążenia i wciąż jest zero. Jak wyeliminować to zjawisko?
  • #5 9126089
    tmf
    VIP Zasłużony dla elektroda
    Owszem, powinno tak być. Niepodłączone wejście pływa, niezależnie czy jest to ADC czy port IO. Naucz się w swoich układach unikać takich sytuacji. Można ten problem rozwiązać polaryzujące wejście przy pomocy rezystora podłączonego do jakiegoś potencjału, np. masy.
    A przy okazji - w twoim programie w sposób niepoprawny odczytujesz wartość ADC (podana formuła nie gwarantuje określonej kolejności dostępu do ADCL i ADCH), a użycie float to już ogólnie kosmos...
REKLAMA