Rechteck Erzeugung mit stegeinder Frequenz

Gast #130526
Lesenswert?

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 #130528
Lesenswert?

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 #130529
Lesenswert?

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 #130530
Lesenswert?

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 #130531
Lesenswert?

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 #130533
Lesenswert?

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 #130537
Lesenswert?

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 #130538
Lesenswert?

@ 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 #130540
Lesenswert?

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 #130541
Lesenswert?

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 #130542
Lesenswert?

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 #130543
Lesenswert?

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 #130546
Lesenswert?

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 #130547
Lesenswert?

"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 #130550
Lesenswert?

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

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren