Rechteck Erzeugung mit stegeinder Frequenz

Gast #130526
Ich hab nun einiges ausprobiert.  Leider alles ohne den erwünschten
Erfolg.
Es muss ein Rechteck erzeugt werden, bei dem sich die Frequenz ständig
erhöht. Die Frequenz läuft aber leider nicht linear, sondern nach einer
e-Funktion. Die immer aktuell berechnet werden muss.

T=1/(10*2^(t/60))

Kann mir da jemand Möglichkeiten nennen.?
Gast
10-500 Hz und das ganze soll über 340 sek. langsam hochlaufen.
Das grösste Problem ist, das Die Berechnung schon 3mS in Anspruch
nimmt.
Im Moment berechne ich einfach die Impulsdauer in einen Timerinterrupt.
Funktioniert auch ganz gut, aber ich sehe halt diese 3mS immer als Pause
in meinen Signal.
Gast
Ich würde die gar nicht aktuell berechnen, sondern EIN mal berechnen und
in einer Tabelle (im Flash oder ext. EEPROM) ablegen. Dann brauchst du
nur noch einen Timer mitlaufen zu lassen, der dafür sorgt, dass du
jeweils den korrekten Wert aus deiner Tabelle liest. Ein Flash-Zugriff
dauert ein paar ns; das ist ja schon ein ziemlicher Gewinn gegenüber
deinen 3ms ... ;-)
Gast
Hab auch schon über eine Tabelle nachgedacht, aber es wäre schon eine
ganze Reihe an Werten.
340S lang ist die Reihe. Es sollten wohl 3 Aktualisierungen pro Sekunde
sein. Das macht dann ca. 1000 Werte.
Du meinst also die Werte sollten im Programm berechnet werden, oder
eher extern von Hand berechen und dann in das Programm eingeben?
Wie lege ich die denn in den Flash/EEPROM.
Gast
vorher berechnen und im Flash ablegen. Kann man prima mit Excel machen.
Geht aber auch mit Berechnung zur Laufzeit. Wenn du sagst, 3
Aktualisierungen/s hast du doch 333ms Zeit, den nächsten Wert zu
berechnen.
Gast
Ich lasse im Main aber eine Schleife laufen. Diese NOP-Schleife
bestimmt einfach die Länge des Impulses. Im Timerinterrupt wird die
Länge berechnet. Und währende die Berechnung im Timerinterrupt läuft
geht eben nix in der Schleife.

Siehe Anhang
Angehängte Dateien:
Gast
Mit einem AVR würde ich folgendes machen:
Timer0  auf PWM einstellen,der läuft dann alleine.
Timer2 Interrupt:output compare register 0 mit Werte aus Tabelle oder
berechnete Werten füttern.

Arno
Gast
Du solltest es genau umgekehrt machen: Die Impulserzeugung mit dem
Timer, Berechnung des nächsten Wertes in der Main, dann warten. Ich
würde soagar  2 Timer benutzten:
Timer0 für die Erzeugung des update-Taktes, Timer1 für die eigentliche
Erzeugung des Signals.
Timer0: 333ms Interrupt, bewirkt nichts weiter, als einen (vorher
berechneten) Wert in eine Variable zu schreiben (nennen wir sie mal
reload) und ein Bit (timer_ready) zu setzen.
Timer1: Modus toggle OC1 on compare, Interrupt bei compare.
Der compare-int macht auch nichts weiter, als den Timer zurückzusetzen
und das OCR-Register mit dem reload-Wert zu laden.
Ganz einfach, und noch jede Menge Zeit für den MC, sich zu langweilen.

main: warten, bis das timer_ready-Bit gesetzt ist, das Bit wieder
löschen, den nächsten Wert (reload_next) berechnen, und dann von vorne.
Gast
@ crazy horse

Wo ist denn der Modus "toggle OC1 on compare" im Danteblatt
beschrieben. Es geht um einen ATMEGA8.
Ich hab leide nix im Datenblatt gefunden.
Sorry, wenn ich heute viel Frage, aber die Zeit drückt extrem.
Gast
Mit dem Mega8 wirds noch einfacher (war nicht irgendwo die Rede von
90S2313?), da kannst du noch die CTC-Funktion nutzen (automatisches
Rücksetzen des Zählers bei OCR1A).

TCCR1A=1<<COM1A0;
TCCR1B=(1<<WGM12 | 1<<CS11);
TIMSK =1<<OCIE1A;

Timer 1 läuft mit clk/8, toggle on OCR1A, Int on OCR1A
Den OCR-Int brauchst du eigentlich gar nicht mehr (timer1 reset wird
automatisch durchgeführt), die neuen Werte nach OCR1A könntest du von
der Timer0-ISR aus reinschreiben. Allerdings musst du dann aufpassen
(Zähler liegt bereits über dem neuen OCR-Wert, aber unter dem alten ->
in diesem Zyklus wird der Ausgang gar nicht angesteuert). Besser mit
OCR-Interrupt, dann kann gar nichts passieren.
Gast
TCCR1A=1<<COM1A0;      // Toggle OC1A/OC1B
TCCR1B=(1<<WGM12 | 1<<CS11);     // CTC & clk/8  Takt=2.17014µS
TIMSK =1<<OCIE1A;      // Timer/Counter Output
                                      compare a Match Interrupt enable
OCR1AL=943;


sollte mir eigentlich 500 Hz bringen  - stimmt das?
Gast
nö.
Der Timer erzeugt ja jeweils nur eine halbe Periode des
Ausgangssignals.
Willst du 500Hz, brauchst du eine Peridendauer von 2ms, OCR muss also
nach 1ms kommen.
1000µs/2.17014µs=475.
Gast
1000µs/2.17014µs=460         sagt mir zumindest mein Taschenrechner.

Ich messe eine Frequenz von 1124 Hz --->  sagt mir mein MC und das
Ozsil.

Seltsamer Weise erhalte ich auch bei einem doppeltem Wert von 920 nicht
die halbe Frequenz, sondern 1504 Hz.
Gast
Nunja, das wird wohl daran liegen, daß für OCR1AL bei 0xFF schluss ist
;)

OCR1AL = (460 & 0xFF);
OCR1AH = (460 >> 8);

Oder bin ich da jetzt auf dem Holzweg?
Gast
jo, 460 ist korrekt, hatte ich wohl einen Tipfehler.
Hast wahrscheinlich noch einen Fehler beim Laden des OCR1A-Registers.
Du musst einen 16bit-Wert schreiben, dabei unbedingt die Reihenfolge
beachten (ganz beliebter Anfängerfehler), erst OCR1AH (0x01), dann
OCR1AL (0xCC) für 460dez.
Einige Compiler unterstützen direkt den 16bit-Zugriff:

unsigned int reload;
OCR1A=reload;
Gast
"ganz beliebter Anfängerfehler" !!!!
Was ich gerade damit bewiesen hab!!
Dachte ich köönte einfach in das L Byte reinschreiben und es wird dann
in H Byte weitergeschreiben.

500 Hz sind da!!  Juhu

Dann geben ich mich nun mal an die Berechnung meiner Werte.
Neben bei mal ganz herzlichen Dank für die Info`s hier.
Gast
Ok die Teimer laufen nun, aber ich erhalte leider keinen Wert aus dem
Timer0 zurück.
Ich möchte damit die Programmlaufzeit bestimmen um den Wert (t)  in die
Berechnung der aktuellen Frequenz einfliessen zu lassen.
Aber der Wert n_overflows, der mir die Anzahl der der Overflows zurück
geben soll, ändert sich nicht.

Kann mir da nochmal jemand weiterhelfen?
Angehängte Dateien:

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 21 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.