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

Atmega16 - nie działa jedno z ADC

sq1gqp 06 Maj 2010 12:29 1365 8
REKLAMA
  • #1 8042157
    sq1gqp
    Poziom 23  
    Witam. Mam zrobioną obsługę pomiaru napięć na 4 wejściach układu.
    Inicjuję w taki sposób:
    void adc_init(void)
    {
    	ADCSRA=_BV(ADEN) | _BV(ADIE) | _BV(5) | _BV(ADSC) | _BV(ADPS0) | _BV(ADPS1) | _BV(ADPS2); //bit 5 - ADFR FreeRunning
    	ADMUX = _BV(MUX0);
    }
    


    Następnie odczytuję napięcie z 4 wejść (adc0-3) w przerwaniu:

    ISR(ADC_vect)                        // przerwanie z przetwornika ADC
    {	
      uint8_t uiLoByte;
      uiLoByte=ADCL;
      //fConvResult = (double) (uiLoByte | (ADCH << 8 )) / 1024 * VREF;
    
      uiConvCounter++;
    
      if(uiConvCounter == 50 )
      {
    
      	if     	(ADMUX & _BV(MUX0))
    	{
    		fMeasSensor[0]=(double) (uiLoByte | (ADCH << 8 )) / 1024 * VREF5;
    
    		ADMUX = _BV(MUX1);
    	}
    	else if (ADMUX & _BV(MUX1))
    	{
    		fMeasSensor[1]=(double) (uiLoByte | (ADCH << 8 )) / 1024 * VREF12;
    		ADMUX = _BV(MUX2);
    	}
    	else if (ADMUX & _BV(MUX2))
    	{
    		fMeasSensor[2]=(double) (uiLoByte | (ADCH << 8 )) / 1024 * VREF12;
    		ADMUX = _BV(MUX3);
    	}
    	else if (ADMUX & _BV(MUX3))
    	{
    		fMeasSensor[3]=(double) (uiLoByte | (ADCH << 8 )) / 1024 * VREF5;
    		ADMUX = _BV(MUX0);
    	}
    
    	uiConvCounter=0;
      }
    }


    Problem jest w tym, że mam poprawny odczyt napięć z ADC 0-2 ale ADC3 pokazuje mi ciągle maksymalny stan - tu 5V niezależnie co podam na wejście.
    Co może być źle?
  • REKLAMA
  • #2 8042199
    tadzik85
    Poziom 38  
    Złe warunki w obsłudze przerwania. W takiej postaci sprawdzasz kanały: 1,2,4,8
  • REKLAMA
  • REKLAMA
  • #4 8042222
    tadzik85
    Poziom 38  
    a nie jest tak ze mux3 to oznaczenie botu w rejestrze?
    Stosujesz to _BV() ponieważ? ładnie wygląda? od razu widać ze nie wiesz co ta funkcja robi.
  • #5 8042225
    sq1gqp
    Poziom 23  
    Ok, wszystko jasne, to jest adres. Dzięki

    Dodano po 9 [minuty]:

    Czy tak będzie OK?
    Nie jestem pewien warunku (ADMUX & !_BV(MUX2) & !_BV(MUX1) & !_BV(MUX0) )
    ISR(ADC_vect)                        // przerwanie z przetwornika ADC
    {	
      uint8_t uiLoByte;
      uiLoByte=ADCL;
      //fConvResult = (double) (uiLoByte | (ADCH << 8 )) / 1024 * VREF;
    
      uiConvCounter++;
    
      if(uiConvCounter == 50 )
      {
    
      	if     	(ADMUX & !_BV(MUX2) & !_BV(MUX1) & !_BV(MUX0) ) //000 (2,1,0)
    	{
    		fMeasSensor[0]=(double) (uiLoByte | (ADCH << 8 )) / 1024 * VREF5;
    
    		ADMUX = _BV(MUX0);
    	}
    	else if (ADMUX & !_BV(MUX2) & !_BV(MUX1) & _BV(MUX0) ) //001
    	{
    		fMeasSensor[1]=(double) (uiLoByte | (ADCH << 8 )) / 1024 * VREF12;
    		ADMUX = _BV(MUX1) ;
    	}
    	else if (ADMUX & !_BV(MUX2) & _BV(MUX1) & !_BV(MUX0)) //010
    	{
    		fMeasSensor[2]=(double) (uiLoByte | (ADCH << 8 )) / 1024 * VREF12;
    		ADMUX = _BV(MUX1) | _BV(MUX0);
    	}
    	else if (ADMUX & !_BV(MUX2) & _BV(MUX1) & _BV(MUX0) )  //011
    	{
    		fMeasSensor[3]=(double) (uiLoByte | (ADCH << 8 )) / 1024 * VREF5;
    		ADMUX = 0x00;
    	}
    
    	uiConvCounter=0;
      }
    }


    Dodano po 2 [minuty]:

    Tadzik, stosuję makro _BV ponieważ jest wygodne i tak się składa że wiem "co ono robi".
    Inna sprawa, że nie jestem jeszcze biegły w operacjach na bitach.
  • REKLAMA
  • #8 8048311
    sq1gqp
    Poziom 23  
    Zrobiłem tak:
    	volatile int kanal= ADMUX&0x03;
    
    	if     	(kanal==0) //000 (2,1,0)
    	{
    		fMeasSensor[0]=(double) (uiLoByte | (ADCH << 8 )) / 1024 * VREF5;
    
    		ADMUX = 0x01;
    	}
    	else if (kanal==1) //001
    	{
    		fMeasSensor[1]=(double) (uiLoByte | (ADCH << 8 )) / 1024 * VREF12;
    		ADMUX = 0x02;
    	}
    	else if (kanal==2) //010
    	{
    		fMeasSensor[2]=(double) (uiLoByte | (ADCH << 8 )) / 1024 * VREF12;
    		ADMUX = 0x03;
    	}
    	else if (kanal==3)  //011
    	{
    		fMeasSensor[3]=(double) (uiLoByte | (ADCH << 8 )) / 1024 * VREF12;
    		ADMUX = 0x00;
    	}


    I ma taki efekt że tablica fMeasSensor[] wypełnia się:
    index 0 0V
    index 1 12V - stabilne
    index 2 11V - zależne od napięcia na wejściu 1
    index 3 0 V

    coś jest nie tak, bo pod adc0 mam podłączone napięcie zasilania układu, pod acd 1 12v z instalacji auta przez dzielnik.
    Tu widać, że pomiary są przesunięte o jedno miejsce, co zrobiłem nie tak.
    Btw jak zrobić operację wpisania w rejestrze ADMUX tylko 2 ostatnich bitów?
    Nie chciałbym robić ADMUX = 0x01 itp bo to nadpisuje mi mniej znaczące bity.
  • #9 8048397
    tadzik85
    Poziom 38  
    |= 1<<nr bitu //(ustawienie)
    &= ~(1<<nr bitu) //zerowanie
REKLAMA