Forum: Mikrocontroller und Digitale Elektronik LED Impulse Atmega8 Analog


von Ganui K. (Firma: BOSCH) (zmx2000)


Angehängte Dateien:

Lesenswert?

Hallo

Ich hab da ein kleines Problem mit dem ADC Channel des Atmega8 µC.
Folgendes Problem: Ich erzeuge eine lineare Rampe von 0V...5V innerhalb 
einer Sekunde und versuche anhand der eingelesenen analogwerte die LEDs 
blinken zu lassen (siehe anhang). Um auch hohe Frequenzen mitzubekommen 
habe ich ein Oszi angeschlossen.

Doch leider funktioniert es nicht so wie ich gehofft hatte. Der ADC 
scheint irgendwas einzulesen oder mein Code ist blödsinn (hab den code 
aus dem tutorial):

--------------------------------------------------
#include <avr/io.h>
//#ifndef F_CPU
/* prevent compiler error by supplying a default */

//#define F_CPU 8000000UL
//#endif
#include <util/delay.h>


uint16_t adc;

uint16_t ReadADC(uint8_t mux)
{
  uint8_t i;
  uint16_t result;

  ADMUX = mux;                                      // Kanal waehlen 
(ADC0)
  ADMUX |= (0<<REFS1) | (1<<REFS0);                 // AVCC als 
Referenzspannung nutzen

  ADCSRA |= (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1) |(0<<ADPS0);        // 
Frequenzvorteiler 64 (40 - 160)



  // First Read Out um den ADC warmlaufen zu lassen //

  ADCSRA |= (1<<ADSC);                              // Start 
ADC-Wandlung
  while ( ADCSRA & (1<<ADSC) ) {
     ;
  }
  result = ADCL;
  result += (ADCH << 8);                          // ADCW muss einmal 
gelesen werden,

  result = 0;

//// Eigentliche Messung - Mittelwert aus 4 aufeinanderfolgenden 
Wandlungen //////////

  for( i=0; i<2; i++ )
  {
    ADCSRA |= (1<<ADSC);            // eine Wandlung "single conversion"
    while ( ADCSRA & (1<<ADSC) ) {
      ;   // auf Abschluss der Konvertierung warten
    }
  result = ADCL;
    result += (ADCH << 8);        // Wandlungsergebnisse aufaddieren
  }
  ADCSRA &= ~(1<<ADEN);             // ADC deaktivieren (2)

  result /= 4;                     // Summe durch vier teilen = arithm. 
Mittelwert

  return result;
}
////////////////////////////////////////////////////////////////////////

int main()
{

while(1)
{

adc = ((ReadADC(0)));

if (PIND & (1<<PIND4))
{

    PORTD |= (1<<PD0);
    _delay_ms(adc);
    PORTD &= ~(1<<PD0);
    _delay_ms(adc);

}
else PORTD &= ~(1<<PD0);
}

return 0;
}

-----------------------------------------------

Also ich sehe am Oszi nicht die Pulsbreitenänderung wie gedacht 
(hochfrequente impulse sinkend bis zu niederfrequente impulse (zum 
beispiel bei 5 V = 1023 entspricht 1023 ms)

Müsste doch so funktionieren oder?

Gruss

von hans (Gast)


Lesenswert?

for( i=0; i<2; i++ )
daraus werden nie!! 4 Messungen.

Tipp: 1023ms > 1 Sekunde ==>> Timing überdenken

ADC in C kann in einem Rutsch gelesen werden result = ADC;

Delay mit Variabler Zeit ==>> Speicherfresser, da Zeitberechnung 
eingebunden wird.

Nach mehr such ich jetzt mal nicht!!

von Ganui K. (Firma: BOSCH) (zmx2000)


Lesenswert?

Ohh danke hans..kleiner tippfelher. war ja vorher auf 4.
bin noch relativ neu auf disem gebiet :)

wenn nicht mit delay, wie macht man es sonst? Kenne leider nur diese 
Funktion..

von Hubert G. (hubertg)


Lesenswert?

Wo hast du deine Ports definiert.
Den ADC bei jedem Durchgang neu zu initialisieren ist nicht notwendig.
Als Abfrage genügt ein result = ADC;
Der ADC wird zu einem nicht definierten Zeitpunkt aufgerufen.
Variable als delay-Wert zu verwenden bläst den Code ziemlich auf.
Mit den delay wirst du  nicht glücklich werden, verwende Timer.

von Ganui K. (Firma: BOSCH) (zmx2000)


Lesenswert?

hallo hubert

die ports habe ich natürlich definiert, die habe ich nur ausgelassen:


int main()
{
DDRD |= (1 << PD0) | (1 << PD1);
....usw

Timer?
ich habe leider noch nie mit timern gearbeitet...wüsste jetzt nicht wie 
man da rangehen muss :(
wird der timer genauso gefüttert mit dem adc-wert wie der delay?

von Hubert G. (hubertg)


Lesenswert?

Wenn du nur den Codeteil postest von dem du glaubst das er fehlerhaft 
ist, ist es halt schwer festzustellen wo der Wurm liegt. Wer sagt was 
Absicht oder Fehler ist.
Die Timer sind im Tutorial ebenso gut beschrieben wie der ADC.
Du machst dir z.B. einen Timer mit 1ms Takt und wartest dann bei einem 
ADC-Wert von 500 diese Anzahl von Takte.

von Ganui K. (Firma: BOSCH) (zmx2000)


Lesenswert?

Ja, hast natürlich recht.
Gibt es denn beispiele? Muss doch bestimmt jemand geben der das selbe 
problem hatte bzw eine lineares signal erzeugt und anhand dieser leds 
blinken lässt?

Das Tutorial lese ich mir auch durch :)

von Ganui K. (Firma: BOSCH) (zmx2000)


Lesenswert?

Aber nebenbei: Mit dem delay müsste es doch auch funktionieren oder? 
ausser dass er den speicher belastet. rein funktionstehnisch müsste es 
doch gehen. der niedrigste digitale wert ist 1 und der höchste ist 
1023....müsste doch auch so gehen ohne timer oder? :)

von hans (Gast)


Lesenswert?

Es sollte auch mit delay gehen, aber:

Deine Rampe läuft 1 Sek. deine Pausen/Impulse von 0-1023 ms.
Und wo dann gemessen wird weis keiner außer Gott.
Es können alle werte für die nächste Ausgabe rauskommen.
Wenn die Rampe extrem langsam ist (ein paar Minuten) hast du
den gewünschten Effekt.

von Karl H. (kbuchegg)


Lesenswert?

> Aber nebenbei: Mit dem delay müsste es doch auch funktionieren oder?

So auf jeden Fall nicht. delay_ms braucht einen konstanten Wert!

Das kannst du zb so machen
1
void delay( uint8_t ms )
2
{
3
  uint8_t i;
4
5
  for( i = 0; i < ms; ++i )
6
    delay_ms( 1 );
7
}

Aber back doch zunächst einfach mal kleinere Brötchen.
Vergiss die Rampe fürs erste, leg eine konstante Spannung an und sieh 
nach ob der ADC die korrekt einliest (= der Wert stimmt)

von Ganui K. (Firma: BOSCH) (zmx2000)


Lesenswert?

OK, ich back erstmal kleine brötchen :) schritt für schritt....
danke für die tipps...

werde eure hilfe sicher noch benötigen..

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.