PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Immernoch Probleme mit dem Atmel ADC



LC-HC
21.02.2006, 20:48
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.




// 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

Sternthaler
21.02.2006, 23:17
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:


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:


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.

Sternthaler
09.03.2006, 19:05
@LC-HC
Hallo, wollte mal wissen, ob du noch irgendwelche Infos brauchst, oder ob du weitergekommen bist?