mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik pwm modi beim mega8


Autor: noob (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
folgendes Problem:

um erst mal potentielle Verständnis Schwierigkeiten auszuräumen - also
der mega8 hat 3 pwm Kanäle, entsprechend den Pins OC1A, OC1B, OC2.
Dabei entspricht OC2 dem Timer2 im pwm Modus. Timer1 im pwm Modus hat
zwei Register zur pwm Erzeugung, die OC1x zugeordnet sind. OCR1A/B sind
16 bit register.

Das bedeutet, daß OC1A und OC1B pwm mit 16 bit Genauigkeit erzeugen
können?

Der Hintergrund ist, daß ich zwei Servos ansteuern will und überlege,
ob ich OC1A/B dafür nehme oder eventuell direkt einen größeren mega
wähle und zwei 8bit Zähler dafür benutze. Eigentlich reichen mir bei
den Servos ja 8bit Genauigkeit.

Was sagt ihr dazu? Und hab ich OC1A/B soweit richtig verstanden?

Autor: ...HanneS... (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Für Modellbau-Servos würde ich keine Haedware-PWM nutzen. Das geht in
Software fast besser. Lass dafür einen Timer mit 10kHz "klappern" und
steuere in dessen Interrupt deine Servoimpulse. 100 Timertakte
entsprechen dann 1ms, 200 sind 2ms. Die Auflösung ist ausreichend.

Ein einfaches Beispiel mit AT90S4433 findest du hier:
http://www.brummbaerhannes.de/hannes/avr/7ksend/7k...
Es lässt sich leicht an den Mega8 anpassen.

...

Autor: noob (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke, werds ausprobieren.
Ich habe außerdem gerade anhand des Datenblattes festgestellt, daß ich
wohl die pwm Modi nicht ganz verstanden hatte.
Ich denke da sind Hausaufgaben fällig.... Sollte ich da auf Probleme
stoßen mach ich dann noch nen thread auf.

Autor: ...HanneS... (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Fürs Aufmachen von Threads gibts aber keine Prämien. Mach (bei Bedarf)
lieber hier weiter. Neue Threads zu alten Themen müllen nur unnötig das
Forum zu.

Nochmal zum Fernsteuerimpuls und zur PWM.
Du willst (für Servos) Impulse erzeugen, die 1ms...2ms breit sind
(H)und einen Abstand (L) von etwa 18ms...20ms haben (wie in einer
Funkfernsteuerung). Mit einer herkömmlichen PWM (Hardware) stellst du
mit Taktquelle, Vorteiler und Zählumfang die Frequenz ein (bzw.
Periodendauer). Mit dem Vergleichswert stellst du ein, wieviel Prozent
(oder besser: wieviele Teile des Zählumfangs) dein Ausgang H sein soll.
Für die Helligkeit einer Lampe oder das Tempo eines Motors würdest du
0%...100% brauchen. Für ein Servo würdest du bei Periodendauer von 20ms
5% (1ms)...10% (2ms) brauchen. Du hättest also innerhalb des
Stellbereiches von 1ms bis 2ms eine sehr grobe Abstufung (5% von 256),
da sich der Zählumfang der PWM auf die Periodendauer (20ms) bezieht.

Eine Impulserzeugung per Software wird von einem geeigneten Timer alle
20ms angestoßen. Daraufhin wird in der Timer-ISR alle 10µs ein Zähler
hochgezählt und mit dem Sollwert des Servos (100...200) verglichen.
Beim Start (0) wird der Impulspin auf H gelegt, bei Erreichen des
Sollwertes wieder auf L. Dabei wird der Zähler auf 0 gesetzt, der Pin
des nächsten Kanals auf H gesetzt und mit dem nächsten Sollwert
verglichen. Sind alle Kanäle durch, dann hält man die Impulserzeugung
an. Nach Ablauf der 20ms (Synchronisation) wird die Impulserzeigung
wieder mit dem ersten Kanal gestartet.
Bei 8MHz Taktfrequenz erfolgt der Timer-Interrupt alle 80 Takte, da
würde sogar noch etwas Rechenzeit für ein Hauptprogramm
(Impulsbreitenmanipulation) übrig bleiben.

...

Autor: noob (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
;-))))

Oki Doki, also hier. Erstaunlicherweise hat sich auch schon ein Problem
aufgetan. Nach Studium des Datenblattes möchte ich diesen ctc Modus
benutzen. Da sollte bei compare match ja das Zählregister automatisch
wieder bei 0 beginnen. Richtig verstanden?
Funktioniert nur nicht, vielleicht kann mich jemand auf den fehler
aufmerksam machen.
Um das Prinzip auszuprobieren, habe ich zunächst ohne Zeitvorgaben
versucht einen Port klingeln zu lassen. Und zwar so:

SIGNAL(SIG_OUTPUT_COMPARE1A)
{
        PORTB = ~PORTB;
}
int main(void)
{
  TIMSK  |= (1<<OCIE1A); //Compare Int an. richtig????
  TCNT1   = 0;
  TCCR1B |= (1<<WGM12);  //ctc. richtig???
  OCR1A   = 2000;        //beliebig.

  DDRB  = 0xFF;
  PORTB   = 0;
  while(1){}
}

Autor: noob (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
OK, ich habe wohl sei() vergessen. Forsche weiter.

Autor: ...HanneS... (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich halte mich raus, mit C habe ich nix am Hut.

...

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.