- LiFePO4 Speicher Test         
Ergebnis 1 bis 3 von 3

Thema: Immernoch Probleme mit dem Atmel ADC

  1. #1
    Benutzer Stammmitglied
    Registriert seit
    15.03.2004
    Beiträge
    94

    Immernoch Probleme mit dem Atmel ADC

    Anzeige

    LiFePo4 Akku selber bauen - Video
    HI, ich nochmal. Mittlerewile bin ich weitergekommen ud hab jetzt mal was gemacht:
    Poti 1 erfasst einen Messwert, der sobald ein vorher festgelegter wert überschritten wird, eine LED auslöst.
    Poti 2 stellt diesen Schwellenwert zur verfügung.
    Jetzt hab ich aber das Problem, das die LED konstant bei einem Messwert am POti 1 von 1,25 V ausgelöst wird, egal in welcher Stellung sich poti 2 befindet.
    Den Code poste ich mal hier.

    Code:
    // Prototypenfunktionen:
    void io_init(void);
    void adc_init(void);
    int adc_data(int channel); // ADC im SC Modus betreiben, um die kanäle wechseln zu können.
    
    // Prototypen LCD:
    int LCD_init(void); // mit Rückgabe 1 / 0 für Schleifenanwendung
    void LCD_data(char data);
    void LCD_command(char cmd);
    void LCD_enable(void);
    
    
    
    int main(void)
    {
    	
    	
    	io_init();			// I/O init
    	adc_init();			// ADC init
    	
    	
    	for(;;)
    	{
    			
    		if( adc_data(1) > adc_data(2) ) // falls ADC Wert größer als Einstell- / Schwellwert ...
    		{
    			if( PORTB != (1<<1) )			// 	Und LED aus ...
    				PORTB = (1<<1);				// 		dann LED einschalten
    			else{}									//		Und LED an ... dann nichts tun !
    		}
    		else										// falls ADC Wert kleiner als Einstell- / Schwellwert ...
    		{
    			if( PORTB == (1<<1) )			// 	und LED an...
    				PORTB ^= (1<<1);				// 		dann LED ausschalten
    			else{}								// wenn LED bereits aus, dann nichts tun !
    		}
    		
    	}	
    	
    	return 0;
    }
    
    void io_init(void)
    {
    	DDRB = 0xFF;	// Ausgang
    	DDRC = 0x00;	// Eingang	
    	DDRD = 0xFF;	// LCD - Ausgang
    }
    
    
    void adc_init(void)
    {
    	// init im SC Modus
    	ADCSRA = (1<<ADEN) | (1<<ADIF) | (1<<ADIE) | (1<<ADPS2) | (1<<ADPS0);
    	ADMUX = (1<<ADLAR);
    }
    	
    	
    	
    int adc_data(int channel)	// es wird kein kanal ausgewählt !
    {
    	int i;
    	int result = 0;
    	
    	switch(channel)
    	{
    		case 1:			// Messwert
    	
    			ADMUX = 0x00;
    					
    					
    			// Dummy readout:
    			ADCSRA |= (1<<ADSC);
    					while( ADCSRA & (1<<ADSC) );
    			// Dummy readout ende
    			
    			
    			for( i = 0; i < 2; i++)/* eigentliche Messung ( arithmet. Mittelwert aus i Messungen ) */	
    			{
    				ADCSRA |= (1<<ADSC);// ADC starten:
    					while( ADCSRA & (1<<ADSC) )
    				result += ADCH; 
    			}
    			result /= i;
    			
    		case 2:			// Einstell- / Schwellwert
    		
    			ADMUX |= (1<<MUX0); //ADC Kanal wechseln
    			
    			// Dummy readout:
    			ADCSRA |= (1<<ADSC);
    					while( ADCSRA & (1<<ADSC) );
    			// Dummy readout ende
    			
    			
    			for( i = 0; i < 2; i++)/* eigentliche Messung ( arithmet. Mittelwert aus i Messungen ) */	
    			{
    				ADCSRA |= (1<<ADSC);// ADC starten:
    					while( ADCSRA & (1<<ADSC) )
    				result += ADCH; 
    			}
    			result /= i;
    			
    			ADMUX = 0x00;	// ADMUX zurücksetzen
    		
    		
    		default:
    			break;
    		}
    			
    	return result;
    }
    
    int LCD_init(void)
    {	
    	
    
    	return 1;
    }
    
    
    
    void LCD_enab
    danke für die hilfe,

    mfg

    LC

  2. #2
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    29.05.2005
    Beiträge
    1.018
    Hallo LC-HC,
    wenn ich das richtig sehe, dann benötigst du nur eine 8-Bit-Auflösung vom Wandler (Du lässt die beiden untersten Bits weg). Aus diesem Grund hast du in der adc_init()-Funktion ja auch richtigerweise das Bit ADLAR im Register MUX gesetzt und liesst nur aus ADCH.

    Nun setzt du in der Funktion adc_data(..) das Register ADMUX aber am Anfang vom case-1-Fall und am Ende vom case-2-Fall komplett auf 0 und löschst damit das Bit ADLAR.
    Ich könnte mir vorstellen, dass dies merkwürdige Effekte gibt, da du ja nun nur noch die höchsten 2 Bit bei den nächsten Messungen in ADCH bekommst. (Ich bin mir sicher, dass die Bits 7 bis 2 in ADCH immer gelöscht werden, wenn ADLAR nicht gesetzt ist.)
    Somit bekommst du dann immer nur sehr kleine Werte zurück.

    Ein weiteres Problem in der Funktion scheint mir dein switch zu sein.
    Ich schreib mal 'gekürzten' Code um zu zeigen was ich meine:
    Code:
    switch (channel)
    {
    case 1:
       tu dies hier wenn channel = 1 ist;
    case 2:
       tu dies hier wenn channel = 2 ist;
       tu es aber auch wenn channel = 1 ist, da vor case 2 kein "break;" steht;
    case default:
       break;
    }
    Es müsste eigendlich eher so aussehen:
    Code:
    switch (channel)
    {
    case 1:
       tu dies hier wenn channel = 1 ist;
       break;
    case 2:
       tu dies hier wenn channel = 2 ist;
       break;
    case default:
       break;
    }
    Um nur Bits in ADMUX zur Auswahl des ADC-Kanals zu setzten geht folgender Code:

    char_variable = ADMUX;
    char_variable &= ~0x0F; // Löscht die 4 rechten Bits (Kanalauswahl)
    char_variable |= channel; // setzt die channel-Bits hinzu
    ADMUX = char_variable;

    oder ohne Variable:

    ADMUX = (ADMUX & ~0x0F) | channel;

    Ich hoffe, dass dir das erst einmal weiter helfen kann.
    Lieber Asuro programieren als arbeiten gehen.

  3. #3
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    29.05.2005
    Beiträge
    1.018
    @LC-HC
    Hallo, wollte mal wissen, ob du noch irgendwelche Infos brauchst, oder ob du weitergekommen bist?
    Lieber Asuro programieren als arbeiten gehen.

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •  

MultiPlus Wechselrichter Insel und Nulleinspeisung Conrad