Forum: Mikrocontroller und Digitale Elektronik Soft-PWM und AD-Wandler parallel


von Martin (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,

ich habe mir eine RGB Leiste besorgt und betreibe sie an einem Atmega 8 
(interner Takt 8MHz) + IRLZ34N MOSFETs per Soft PWM. Die Soft-PWM habe 
ich von http://www.mikrocontroller.net/articles/Soft-PWM weitestgehend 
übernommen und angepasst.

Das Programm (siehe Anhang) blendet bis jetzt die verschiedenen Farben 
ineinander über. Soweit so gut.

Nun möchte ich über einen Poti der am AD-Wandler angeschlossen ist die 
Geschwindigkeit des Farbwechsels bestimmen und dass wenn der Poti auf 
"ganz langsamm" steht, die aktuelle Farbe beibehalten wird, spricht der 
Farbwechsel erst weiter geht wenn der Poti wieder auf "schneller" 
gestellt wird.

Die AD Wandlung an sich funktioniert auch.

Das Problem, das ich habe ist folgendes: Es wird für die Soft-PWM 
regelmäßig ein Interrupt ausgelöst, jetzt müsste aber gleichzeitig, 
kontinuierlich der AD-Wandler abgefragt werden.

Zu Beginn habe ich versucht die AD Wandlung in den Interrupt mit 
einzubinden, jedoch flackern dann die LED's... anscheinend dauert die 
Wandlung zu lange.

Die AD Wandlung in einen zweiten Interrupt einbinden?

Für Lösungsansätze wäre ich euch sehr dankbar. Oder ist mein Vorhaben in 
der Art gar nicht realisierbar?

Schon mal Danke für euere Mühe.

von Karl H. (kbuchegg)


Lesenswert?

Martin schrieb:

> Das Problem, das ich habe ist folgendes: Es wird für die Soft-PWM
> regelmäßig ein Interrupt ausgelöst, jetzt müsste aber gleichzeitig,
> kontinuierlich der AD-Wandler abgefragt werden.

Du brauchst den AD-Wandler nicht kontinuierlich abfragen.
Wenn der ADC in der Sekunde vielleicht 100 mal drann kommt reicht das 
völlig aus.
Du könntest zb anstatt dem _delay_ms(1) in den for-Schleifen jeweils 
eine ADC Wandlung machen und abhängig vom ADC Wert noch zusätzliche 
Wartezeit drannhängen. Ob dein µC im _delay Däumchen dreht oder den ADC 
befragt ist ja dem µC wieder egal

von Karl H. (kbuchegg)


Lesenswert?

Martin schrieb:

> Für Lösungsansätze wäre ich euch sehr dankbar. Oder ist mein Vorhaben in
> der Art gar nicht realisierbar?

Solange die meiste Rechenzeit in einem Programm für _delay_ms draufgeht, 
gibt es immer eine andere Lösung :-)

von Klaus W. (mfgkw)


Lesenswert?

Ich weiß jetzt nicht, ob es zeitlich passt, aber eventuell
geht es auf, wenn man im Interrupt am Ende die AD-Wandlung
startet und beim nächsten Mal dann das Ergebnis holt.

von Karl H. (kbuchegg)


Lesenswert?

Ach und noch was:

Du darfst bei _delay_ms keine Variablen benutzen. Das Argument zu 
_delay_ms muss eine Konstante sein, ansonsten stimmen die Zeiten hinten 
und vorne nicht.

Du kannst das so lösen
1
void my_delay( int time )
2
{
3
  int i;
4
  for( i = 0; i < time; ++i )
5
    _delay_ms( 1 );
6
}

und dann diese Funktion anstelle von
1
   _delay_ms( dauer );

aufrufen.

Du kannst aber auch die ADC Abfrage mit in diese Wartefunktion aufnehmen
1
void my_delay()
2
{
3
  int time = AD_Wandlung();
4
  int i;
5
6
  for( i = 0; i < time; ++i )
7
    _delay_ms( 1 );
8
}

von Zaphod B. (brezel) Benutzerseite


Lesenswert?

Klaus Wachtler schrieb:
> Ich weiß jetzt nicht, ob es zeitlich passt, aber eventuell
> geht es auf, wenn man im Interrupt am Ende die AD-Wandlung
> startet und beim nächsten Mal dann das Ergebnis holt.

wozu den Aufwand?

Tu uns allen und dir selber doch bitte den gefallen und rücke deinen 
Quelltext richtig schön ein und pack die #defines an den Anfang, danke!

Nimms mir nicht bitte nicht übel, aber den Arschlochkommentar konnte ich 
mir nicht verkneifen ;)

Und noch was Konstruktives von mir:
mach in deine Endlosschleife statt
"_delay_ms(dauer)"
einfach
"_delay_ms(AD_Wandlung())"
bzw
"_delay_ms(AD_Wandlung() * (long)dauer / 1024)"
rein.

von Zaphod B. (brezel) Benutzerseite


Lesenswert?

Karl heinz Buchegger schrieb:
> Du darfst bei _delay_ms keine Variablen benutzen. Das Argument zu
> _delay_ms muss eine Konstante sein, ansonsten stimmen die Zeiten hinten
> und vorne nicht.

mist. Dann eben so -.-

von Martin (Gast)


Lesenswert?

Vielen Dank für eure sehr schnellen und vorallem hilfreichen Antworten.

Ich habe das ganze nun mit der Funktion

void my_delay()
{
  int time = AD_Wandlung();
  int i;

  for( i = 0; i < time; ++i )
    _delay_ms( 1 );


while(time > 585)  //Zum anhalten der Farbe, AD Wandlung max = 600
  {
    time = AD_Wandlung();
     _delay_ms( 20 );
  }

}

(Tipp von Karl Heinz Buchegger)

Funktioniert einwandfrei.

von Martin (Gast)


Lesenswert?

Nun habe ich allerdings noch ein paar Verständnis fragen an euch.

Karl heinz Buchegger schrieb:
> Du darfst bei _delay_ms keine Variablen benutzen. Das Argument zu
> _delay_ms muss eine Konstante sein, ansonsten stimmen die Zeiten hinten
> und vorne nicht.

Der Prototyp der Funktion sieht doch so aus:  void _delay_ms(double 
__ms)

Warum kann ich keine double Variable übergeben sondern nur eine 
Konstante?


Und die zweite Frage, warum muss ich den Interrupt nicht mit cli(); vor 
der AD Wandlung unterbrechen? Kann es so nicht Probleme geben, wenn 
während einer Wandlung der Interrupt zuschlägt?

Nochmal Danke für eure Hilfe.

von Karl H. (kbuchegg)


Lesenswert?

Martin schrieb:
> Nun habe ich allerdings noch ein paar Verständnis fragen an euch.
>
> Karl heinz Buchegger schrieb:
>> Du darfst bei _delay_ms keine Variablen benutzen. Das Argument zu
>> _delay_ms muss eine Konstante sein, ansonsten stimmen die Zeiten hinten
>> und vorne nicht.
>
> Der Prototyp der Funktion sieht doch so aus:  void _delay_ms(double
> __ms)
>
> Warum kann ich keine double Variable übergeben sondern nur eine
> Konstante?

Weil diese Zeit in eine Berechnungsformel eingeht, aus der die Anzahl 
von Schleifenwiederholungen hervorgeht. Diese Berechnung ist eine 
Floting Point Berechnung und es ist wichtig, dass der Optimizer diese 
Berechnung optimieren kann, so dass er zum Schluss nur mit einem 
Zahlenwert da steht. Das geht aber nur dann, wenn er auch alle Zahlen 
während des Compilierens kennt.
Kann der Optimizer die Berechnungsformel nicht während des Compilierens 
auflösen, so muss das zur Laufzeit gemacht werden. Und bei kleineren 
Wartezeiten ist es nicht ungewöhnlich, dass dann diese Berechnung schon 
länger dauert, als das Abarbeiten der daraus berechneten 
Schleifenwiederholungen. :-)


> Und die zweite Frage, warum muss ich den Interrupt nicht mit cli(); vor
> der AD Wandlung unterbrechen? Kann es so nicht Probleme geben, wenn
> während einer Wandlung der Interrupt zuschlägt?

Während eine ISR läuft, sind Interrupts sowieso automatisch gesperrt.
Wenn du dich da mit cli() / sei() einmischt machst du die Dinge im 
Extremfall nur schlimmer, weil dann durch den sei() die Interrupts zu 
früh freigegben werden.

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.