Hallo alle miteinander!
Ich sitze aktuell an einem Hobby Projekt, in dem ich möglichst genaue
Frequenzen benötige. Diese sollen einstellbar sein. Mein Ziel ist es
gerade, vier LEDs mit meinen voreingestellten Frequenzen blinken zu
lassen.
Dafür habe ich mich an mein Arduino gesetzt und ein Programm
geschrieben, das fürs bloße Auge zu laufen scheint und in manchen Fällen
die laufende Frequenz sichtbar verfälscht.
Eine genauere Untersuchung des Sachverhaltes hat mir zwei unvermeidbare
Störungen offenbart.
Erstens: Mit dem Arduino kann ich mit der millis() Funktion die
Millisekunden zählen um darüber meine Taktfrequenzen laufen zu lassen,
doch die millis() Funktion läuft asynchron mit einer Ungenauigkeit von
100ppm. Das führt in meinem Programm zu einer Verschiebung der
Taktmuster, was in einem Uneinheitlichen Gesamtmuster der Frequenz
endet. Das heißt, wenn ich 11Hz einstelle, liefert mir der Arduino eine
Frequenz von 10.989Hz für ca 1.365 Sekunden, woraufhin ein einzelner
Puls mit 10.8695Hz folgt. Das ganze wiederholt sich zyklisch. Letzten
Endes habe ich somit keine stabile Frequenz, sondern ein Gemisch von 2
Frequenzen, die sich je nach eingestellter Frequenz in
unterschiedlichen, aber festen Zeitintervallen wiederholen.
Zweitens: Wie im Punkt Erstens zu erkennen, kann ich mit dem Arduino
nicht alle Frequenzen darstellen. Wenn ich z.B. 11Hz haben möchte,
liefert mir der Arduino in der Umsetzung 10.989Hz. Das liegt daran, das
ich die gewünschte Frequenz mit einer float Variable nur auf 2
Nachkomma-Stellen ausrechnen kann, was mit dem Timer jedoch nicht
vereinbar ist da mir die millis() Funktion nur Ganzzahlen liefert. Das
heißt wiederum, dass ich letzten Endes nur ein begrenztes Repertoire an
Frequenzen habe, die ich darstellen kann.
Theoretisch ließe sich das Problem Nummer 1 mit einem externen DS3231
realisieren, da dieser als Echtzeituhr mit einer Abweichung von 2ppm
stabile Millisekunden Werte liefert. Der zweite Punkt ist mit dem
Arduino jedoch leider nicht korrigierbar.
Alles in allem eignet sich der Arduino also nicht für mein Vorhaben.
Darum möchte ich die Schaltung anders realisieren, wozu mir jedoch die
Kenntnisse für passende ICs oder ähnlichem fehlen.
Ich suche eine Komponente, mit der ich stabile Frequenzen im Bereich von
1Hz bis 100Hz darstellen kann.
Als ersten Gedanken hatte ich da einen TLC555 Timer als astabile
Kippstufe. Allerdings ist mir auf diese Weise nicht möglich, die
Frequenzen mit einem Mikrocontroller oder einem Drehgeber zwischen 1Hz
und 100Hz selber einzustellen. Dafür müsste ich ja einen einstellbaren
Kondensator einbauen, der mir in der Einstellung zu ungenau arbeitet
(sofern es überhaupt welche gibt. Eine Softwareseitige Einstellung wäre
optimal.
Programmierbare Oszillatoren finde ich bei Mouser oder ähnlichen Seiten
nur für Frequenzen ab 100kHz.
Der Ausgang muss mir nur ein Rechtecksignal liefern.
Das ist auch schon die Stelle an der ich hängen bleibe. Womit lässt sich
mein Vorhaben realisieren?
Ein paar Ideen wären nett; und seid mir bitte nicht zu böse - ich bin
noch Anfänger
Danke :)
Thomas G. schrieb:> Programmierbare Oszillatoren finde ich bei Mouser oder ähnlichen Seiten> nur für Frequenzen ab 100kHz.
Genau so. Und dann tust du den Ausgang noch durch 100.000 teilen
(Nachteiler) und fertig ist die Laube.
Welcher Arduino?
UNO, oder Nano?
Dann:
Thomas G. schrieb:> liefert mir der Arduino eine> Frequenz von 10.989Hz für ca 1.365 Sekunden, woraufhin ein einzelner> Puls mit 10.8695Hz folgt. Das ganze wiederholt sich zyklisch.
Arduino fügt Schaltmillis ein.
Ca alle 42ms
Thomas G. schrieb:> Womit lässt sich> mein Vorhaben realisieren?
Verwende doch besser Timer 1
Sofern Du einen Arduino verwendest, darfst Du den zumeist bestückten
keramischen Resonator nicht verwenden, da er zu ungenau ist. Beim
Arduino UNO beispielsweise kann man den Takt vom ATmega16U2 verwenden.
Wie man dies umlötet findest Du hier unter Punkt "automatischer Abgleich
..."
http://mino-elektronik.de/fmeter/fm_software.htm#bsp7
Genaue Zeiten - auch und gerade im unteren Frequenzbereich - mit einer
Auflösung von 62,5 ns @ 16 MHz Takt kann man mit einem Timer erzeugen.
Beispiel findest Du hier:
http://mino-elektronik.de/Generator/takte_impulse.htm
Sieh es Dir einfach an. Es sind C-Programme, die man auch auf einem
AVR8-Arduino laufen lassen kann.
Sofern die absoluten Zeiten im ppm-Bereich liegen müssen, kommst Du um
einen stabileren Taktgeber nicht herum. Stichwort: TCXO.
Relative Zeiten kann man dadurch stabil halten, daß alle Oszillatoren
vom gleichen Taktgeber betrieben werden und daher nicht gegeneinander
driften können.
Klingt nach einem Fall für 4 Zustandsautomaten. Dort ist ein Beispiel
mit Erklärungen für 3 blinkende Leuchtdioden:
http://stefanfrings.de/multithreading_arduino/index.html
Das kannst du selbstverständlich auf 4 erweitern. Wenn das auf Basis von
millis() machst, kannst du die Blink-Intervalle natürlich auch nur im
Raster von 1ms einstellen.
Klar könnte man auch 0,1ms oder gar 0,01ms Intervalle benutzen, was aber
nichts daran ändert, dass man damit nicht jede beliebige Frequenz exakt
erzeugen kann.
Für 37 Hz brauchst du z.B. 0,027027027ms pro Intervall wären, die Zahl
hat zu viele Nachkommastellen. Das kriegst du mit keinem digitalen Timer
hin. Und wenn doch, dann scheitert er an anderen Wunsch-Frequenzen.
Überdenke nochmal deine Anforderungen. Vermutlich verlangst du da mehr
als nötig.
Mit cleveren Algorithmen kannst du zumindest näherungsweise an deine
Wunsch-Werte heran kommen. Du musst nur dafür sorgen, dass die
Abweichung sich nicht immer weiter auf-summiert. Denke an den 29.
Februar. Der wird ab und zu eingefügt, um die Abweichung unseres
Kalenders auszugleichen. Spontan fällt mir den Bresenham Algorithmus
ein, mit dem man schräge Linien auf den Bildschirm zeichnet, die nicht
exakt ins Pixelraster passen. Das gleiche Prinzip müsste man auch deine
Zeiten anwenden können. Schau dir das mal an:
https://de.wikipedia.org/wiki/Bresenham-Algorithmus
Stefan ⛄ F. schrieb:> Für 37 Hz brauchst du z.B. 0,027027027ms pro Intervall wären, die Zahl> hat zu viele Nachkommastellen.
Die Nachkommastellen kommen von Deinem Taschenrechner. Hier ist
sinnvolles Runden hilfreich.
m.n. schrieb:> Für 37 Hz brauchst du z.B. 0,027027027ms pro Intervall
Hoppla, es sind Sekunden, nicht ms. Die Zahl ist sogar periodisch, hat
unendlich viele Nachkommastellen!
> Die Nachkommastellen kommen von Deinem Taschenrechner.> Hier ist sinnvolles Runden hilfreich.
Würde ich auch tun, aber der TO will es exakt. Deswegen schrieb ich:
> Überdenke nochmal deine Anforderungen.> Vermutlich verlangst du da mehr als nötig.
Mit einem anstaendigen Controller der ein paar Timer hat,
erledigt sich solch ein "Problem" quasi von selbst.
Ansonsten tut es auch ein wenig richtige Signalverarbeitung
um solche Signale zu erzeugen.
Aber wer nur den Buddelkasten spielt, kennt nichts anderes.
Stattdessen muessen externe Timer bemueht werden.
Da kann man doch nur lachen.
Stefan ⛄ F. schrieb:> Würde ich auch tun, aber der TO will es exakt.
Exakt gibt es in der Physik nicht. Hinreichend genau ist angesagt.
NoArno schrieb:> Da kann man doch nur lachen.
Ja, lach einen Anfänger nur aus. Dummer Mensch!
NoArno schrieb:> Mit einem anstaendigen Controller der ein paar Timer hat,> erledigt sich solch ein "Problem" quasi von selbst.
Leider ziemlich unkonkret, wie soll das dem TO helfen? Und wie machst du
damit exakt 37 Hz?
EAF schrieb:> Welcher Arduino?> UNO, oder Nano?
Ich verwende einen Arduino Klon, den Elegoo UNO R3, mit einem ATMEGA328P
> Thomas G. schrieb:>> Womit lässt sich>> mein Vorhaben realisieren?> Verwende doch besser Timer 1
Eine gute Idee die ich gerne testen würde, bei der ich leider nicht
durchblicke wie ich den Timer 1 einstellen soll. Da verstehe ich nicht
welchen prescaler ich auswählen soll oder was für TOP Werte zu verwenden
sind.
m.n. schrieb:> Sofern die absoluten Zeiten im ppm-Bereich liegen müssen, kommst Du um> einen stabileren Taktgeber nicht herum. Stichwort: TCXO.> Relative Zeiten kann man dadurch stabil halten, daß alle Oszillatoren> vom gleichen Taktgeber betrieben werden und daher nicht gegeneinander> driften können.
Wie genau arbeitet ein TCXO? Angenommen ich verwende einen, der mit
einem Frequenzteiler auf meinen ausgewählten 1Hz bis 100Hz Bereich
runterskaliert. Liefert der mir beispielsweise einen stabilen 3Hz Wert?
Normale Oszillatoren bekommen sowas doch auch hin oder nicht?
Bitte definiere "Exakt" in maximale prozentuale Abweichung.
Genauigkeit: +/- X % (bitte X ausfüllen)
Ein Frequenzbereich von 1Hz bis 100Hz stellt keine Herausforderung dar.
Der Resonator vom Arduino Uno hat eine maximale Abweichung von +/- 0,5
%. So schlecht ist das nun auch wieder nicht. Wenn man 50Hz einstellt,
kommen etwas zwischen 49,75Hz und 50,25Hz raus (im schlimmsten Fall).
Genau genug? Synchronität ist beim Timer kein Problem. Auf jeden Fall
den Timer nehmen!
Wenn das zu ungenau ist, muss ein Quarz her. Sonst fällt mir nur noch
eine Atomuhr ein.
Und: Programm hochladen, das hilft.
Stefan ⛄ F. schrieb:> Klar könnte man auch 0,1ms oder gar 0,01ms Intervalle benutzen, was aber> nichts daran ändert, dass man damit nicht jede beliebige Frequenz exakt> erzeugen kann.
Wie funktioniert das beim Arduino? So würde ich näher an meine
Wunsch-Frequenz kommen können.
> Für 37 Hz brauchst du z.B. 0,027027027ms pro Intervall wären, die Zahl> hat zu viele Nachkommastellen. Das kriegst du mit keinem digitalen Timer> hin. Und wenn doch, dann scheitert er an anderen Wunsch-Frequenzen.
Leider. Genau so sieht es auch bei 3Hz aus - wie machen das die
Oszillatoren im Labor? Sind da mit RC-Schwingkreisen alle Frequenzen
nahtlos darstellbar?
> Überdenke nochmal deine Anforderungen. Vermutlich verlangst du da mehr> als nötig.
Das könnte sein. Andererseits versuche ich möglichst genau zu arbeiten.
Wenns digital an Grenzen stößt müsste es doch analog umsetzbar sein
oder?
> Ich sitze aktuell an einem Hobby Projekt, in dem ich möglichst> genaue Frequenzen benötige.
Nicht schwafeln, sondern konkrete Angaben: wie genau.
> Diese sollen einstellbar sein. Mein Ziel ist es gerade, vier> LEDs mit meinen voreingestellten Frequenzen blinken zu lassen.
Ich denke, das Problem ist eher die Erzeugung der Frequenzen mit
delay().
Das ist nämlich sehr ungenau, eher im Promille-Bereich. TXCO ist der
komplett falsche Weg, dort geht es um ppm, also um Faktor 1000 genauer.
Genauso programmierbare Oszillatoren.
Natürlich kann man das so machen, ist aber für dein "Hobbyprojekt" eher
totaler Overkill, so wie ich das sehe.
Ich denke, dass die absolute Frequenz gar nicht so wichtig ist, sondern
dass die 4 LEDs "synchron" bleiben. Und das geht am besten von einer
Zeitbasis weg. Z.B. wie schon angedeutet mit dem Timer1.
Du errechnest on the fly, wann das nächste Event ist, lässt dann einen
Interrupt generieren und schaltest den entsprechenden Ausgang. Dann
überlegen, wann das nächste Event sein soll. Fertig.
Oder wenn es ein klein wenig jittern darf, ganz ohne Interrupt, einfach
den Zähler periodisch abfragen und bei overflow einen Software-Zähler
hochzählen.
Oder den Overflow-Interrupt die Überläufe zählen lassen für kleine
Frequenzen.
Analog ist noch viel ungenauer (Temperaturabhängigkeit etc.)
Die Zeitbasis bei den Arduinos hängt vom Hersteller ab, manche verwenden
Resonatoren, andere Quarze.
Ein bißchen Gehirnakrobatik vorweg kann eigentlich nicht schaden. Will
man 100Hz mit 10ppm Genauigkeit einstellen können, braucht man 100ns
Auflösung, also 10MHz Zähltakt. Für 10Hz Ausgangssignal muß der Zähler
dann bis 1 Million zählen, also braucht es mindestens einen
20-bit-Zähler.
Will man das mit einem 8-bit AVR erreichen, muß man ziemlich tief in die
Trickkiste greifen, nach einer Anfängerlösung sieht das für mich nicht
aus.
Mehrere Timer braucht man im Übrigen nicht, 4 OutputCompare-Kanäle
reichen.
Auch die Ungenauigkeit des Oszillators kann man mit einer Kalibrierkurve
kompensieren, Temperaturmessung ist ja an Bord. Man muß aber dann mit
passend genauem Frequenzzähler kalibrieren :-)
Eine BluePill wäre hier wohl die bessere Wahl.
Gruß Klaus (der soundsovielte)
Uwe K. schrieb:> Bitte definiere "Exakt" in maximale prozentuale Abweichung.>> Genauigkeit: +/- X % (bitte X ausfüllen)
Idealerweise eine Genauigkeit von +/- 0%. Mir ist bewusst, das dies
nicht möglich ist. Die Abweichung von 10.989Hz auf 10.8695Hz liegt bei
knapp 1.09%. Was sind denn realistische Grenzen, +/- 0.2%? Sie sollte
kleinstmöglich sein.
Thomas G. schrieb:> Eine gute Idee die ich gerne testen würde, bei der ich leider nicht> durchblicke wie ich den Timer 1 einstellen soll. Da verstehe ich nicht> welchen prescaler ich auswählen soll oder was für TOP Werte zu verwenden> sind.
Das kann man doch berechnen...
Oder?
Soweit mir bekannt, sind die Regeln im Datenblatt aufgeführt.
zyxwv schrieb:> Nicht schwafeln, sondern konkrete Angaben: wie genau.
Ich möchte Frequenzen bis 30Hz mit 2 Nachkommastellen wählen können.
>> Diese sollen einstellbar sein. Mein Ziel ist es gerade, vier>> LEDs mit meinen voreingestellten Frequenzen blinken zu lassen.>> Ich denke, das Problem ist eher die Erzeugung der Frequenzen mit> delay().
In meinem Programm arbeite ich nicht mit der delay() Funktion. Hier wird
die BlinkWithoutDelay-Mechanik genutzt, in der ich, wie du schon
sagtest, on the fly die Intervalle ausrechne.. Bzw die Abschnitte
dazwischen. Im Monitor fällt mir allerdings auf, das die Intervalle
nicht eingehalten werden, sondern frequenzabhängig nach gewissen Zeiten,
das Intervall jeweils um 1ms überschreiten. Bei eingestellten 11Hz (was
real etwa 10.989Hz sind), passiert das alle 1,3 Sekunden. Damit sieht
mein Ausgangssignal nicht so aus, wie es aussehen sollte.
> Genauso programmierbare Oszillatoren.> Natürlich kann man das so machen, ist aber für dein "Hobbyprojekt" eher> totaler Overkill, so wie ich das sehe.
Overkill gibts hier für mich nicht. Wenn alles rund läuft, würde ich am
Ende alles gerne auf einer PCB zusammenbringen und mich freuen. PCB
gerber Files erstellen muss ich im Prozess nur auch noch lernen.
> Ich denke, dass die absolute Frequenz gar nicht so wichtig ist, sondern> dass die 4 LEDs "synchron" bleiben. Und das geht am besten von *einer*> Zeitbasis weg. Z.B. wie schon angedeutet mit dem Timer1.> Du errechnest on the fly, wann das nächste Event ist, lässt dann einen> Interrupt generieren und schaltest den entsprechenden Ausgang. Dann> überlegen, wann das nächste Event sein soll. Fertig.
Genau hier liegt ja das Problem..?
> Die Zeitbasis bei den Arduinos hängt vom Hersteller ab, manche verwenden> Resonatoren, andere Quarze.
Beim ELEGOO UNO R3 ist ein metallisches Gehäuse mit einer 16000
Aufschrift. Auf der Rückseite zähle ich nur 2 Pins, deshalb gehe ich
laut anderer Internetseiten mal davon aus, dass es sich hierbei um einen
Quarz handelt.
Thomas G. schrieb:> Uwe K. schrieb:>> Genauigkeit: +/- X % (bitte X ausfüllen)>> Idealerweise eine Genauigkeit von +/- 0%. Mir ist bewusst, das dies> nicht möglich ist.
Natürlich nicht. Alles hat Toleranzen. Auch die Atomuhr hat
Abweichungen. Wichtig ist es genau zu Wünschen. Nennt man spezifizieren.
Du möchtest Frequenzen bis 30Hz. Und wo fangen wir an?
Genau wünschen!
Ich spekuliere mal auf 1Hz bis 30Hz mit 2 Nachkommastellen genau für den
Sollwert.
Kriegt man mit einer Toleranz von +/- 0,001 % hin. Genau genug? An eine
Kalibrierung kommt man wohl nicht vorbei.
Versuche es mit einem Teiler von 8 und CTC mit dem Timer1 (16-Bit
Timer). CTC mehrfach durchlaufen und anpassen.
Bei einem Teiler von 256 schafft man es direkt mit einem CTC. Dann aber
mit +/- 0,025 % maximaler Abweichung. Damit würde ich anfangen.
Hilfreich ist en Frequenzmesser mit 10facher Genauigkeit, um das
Ergebnis zu prüfen.
P.S.: Hobby: mit maximalem Aufwand, den geringsten nutzen erzeugen. Aber
VIEL Spaß gehabt 😉. So viel zum Thema „Overkill“.
Thomas G. schrieb:> Wie funktioniert das beim Arduino? So würde ich näher an meine> Wunsch-Frequenz kommen können.
Der Timer0 wird schon vom Arduno Framework belegt. Aber du kannst einen
anderen Timer verwenden, der z.B. alle 0,1 ms einen Interrupt auslöst
und dann in der ISR einen Counter hochzählen.
Aber da auch das wie gesagt nur eine halbe Lösung wäre, die auf keinen
Fall die von dir geforderten exakten Frequenzen erzeugen könnte, erspare
ich mir hier, dafür ein konkretes Beispiel zu schreiben. Wenn du es
wirklich ernst meinst, wirst du selbst etwas finden. Mit ISR und der
korrekten Nutzung von Variablen in diesem Kontext wirst du dich ohnehin
beschäftigen müssen, sobald du über den Arduino Standard hinaus gehst.
Thomas G. schrieb:> Andererseits versuche ich möglichst genau zu arbeiten.
Typischer Anfängerfehler. Man hat kaum Erfahrung, weniger Ahnung, will
es aber so gut wie möglich machen, auf jeden Fall besser als die Profis.
Jetzt fehlt nur noch, dass es insgesamt nicht mehr 20 Euro kosten darf.
Dabei kann ich dir nicht helfen.
Thomas G. schrieb:> deshalb gehe ich> laut anderer Internetseiten mal davon aus, dass es sich hierbei um einen> Quarz handelt.
Ich behaupte, dass ein in Hochsprache (C++) programmierter µC der
falsche Ansatz ist, eine stabile Frequenz ohne Jitter erzeugen zu
wollen.
Uwe K. schrieb:> Ich spekuliere mal auf 1Hz bis 30Hz mit 2 Nachkommastellen genau für den> Sollwert.
Genau.
> Kriegt man mit einer Toleranz von +/- 0,001 % hin. Genau genug? An eine> Kalibrierung kommt man wohl nicht vorbei.
Das sollte genau genug sein.
> Versuche es mit einem Teiler von 8 und CTC mit dem Timer1 (16-Bit> Timer). CTC mehrfach durchlaufen und anpassen.>> Bei einem Teiler von 256 schafft man es direkt mit einem CTC. Dann aber> mit +/- 0,025 % maximaler Abweichung. Damit würde ich anfangen.
Wenn ich es geschafft habe das umzusetzen, werde ich davon berichten.
> P.S.: Hobby: mit maximalem Aufwand, den geringsten nutzen erzeugen. Aber> VIEL Spaß gehabt 😉. So viel zum Thema „Overkill“.
Haha, Ups
Ganz klassisch macht man das mit einer PLL und einen programmierbaren
Teiler. Damit kann man exakte 1 Hz Schritte ohne jeden prinzipbedingten
Fehler erzeugen, solange die Referenzfrequenz auch exakt ist.
Juri schrieb:> Thomas G. schrieb:>> Programmierbare Oszillatoren finde ich bei Mouser oder ähnlichen Seiten>> nur für Frequenzen ab 100kHz.>> Genau so. Und dann tust du den Ausgang noch durch 100.000 teilen> (Nachteiler) und fertig ist die Laube.
Bisher habe ich nur von irgendwelchen, halbseidenen Tricksereinen
gelesen, die aller mehr oder weniger direkt in die Hose gehen.
Hol dir bei Mouser den programmierbaren Oszillator und schalte einen
Nachteiler nach. Machst du diesen Nachteiler programmierbar, hast du ein
sehr universelles Gerät. Ist sehr hohe Genaugkeit gefragt?
Speise/synchronisiere deinen Oszillator aus einem TCXO oder OCXO.
Aber ich wiederhole mich...
Wenn ich ein genaues Timing brauche, dann nehme ich ein FPGA. Da kann
ich im Mikrosekundenbereich (und kleiner) arbeiten. Die Timerbreite in
Bits ist skalierbar. Es können mehrere Dutzend Timer laufen, die sich
gegenseitig nicht stören. Und wenn eine CPU zufällig im Interrupt ist,
funktioniert das Timing es immer noch.
Aber es muss ja immer ein Bastelarduino sein. Ich bastel mit denen auch,
aber wenn ich verschärfte Anforderungen habe, muss ich andere Werzeuge
benutzen.
PittyJ schrieb:> Wenn ich ein genaues Timing brauche, dann nehme ich ein FPGA.
Beim Blinken einer LED kommt es selten auf genaues Timing (im Sinne von
Jitter) an. Hier geht es wohl eher darum, dass die Phasenlage sich nicht
verschiebt.
Vielleicht reicht schon eine einfache Software-DDS, die mit dem
T0-Overflow getaktet wird und für jeden Output-Kanal einen eigenen
Phasenakkumulator besitzt - hängt von den Anforderungen an die
Frequenzen/Phasenlage ab.
Thomas G. schrieb:> EAF schrieb:>> Welcher Arduino?>> UNO, oder Nano?>> Ich verwende einen Arduino Klon, den Elegoo UNO R3, mit einem ATMEGA328P>>> Thomas G. schrieb:>>> Womit lässt sich>>> mein Vorhaben realisieren?>> Verwende doch besser Timer 1>> Eine gute Idee die ich gerne testen würde, bei der ich leider nicht> durchblicke wie ich den Timer 1 einstellen soll. Da verstehe ich nicht> welchen prescaler ich auswählen soll oder was für TOP Werte zu verwenden> sind.
Hallo,
du schaust ins Manual, Kapitel Timer 1, bspw. CTC Modus, schaust dir die
Formel an und stellst sie nach TOP um. N ist der Prescaler und ins OCR1A
Register käme der TOP Wert rein. Dann rechnest du hin und her mit
welchen Prescaler du einen ganzzahligen TOP Wert für 1Hz bekommst. Ist
TOP keine Ganzzahl hätte man schon eine Abweichung von Haus aus drin.
Das sollte sich mit 16Bit Zählbereich geradeso ausgehen, grob
überschlagen.
>Ich sitze aktuell an einem Hobby Projekt, in dem ich möglichst genaue>Frequenzen benötige.> Dafür habe ich mich an mein Arduino gesetzt und ein Programm>geschrieben, das fürs bloße Auge zu laufen scheint und in manchen Fällen>die laufende Frequenz sichtbar verfälscht.
Wenn du mit bloßem Auge eine Ungenauigkeit siehst, dann liegt es mit
Sicherheit nicht an der Zeitbasis des Arduino sondern an einem Fehler in
deinem Programm.
"Möglichst" genau geht es, wenn eine Atomuhr nimmst. Oder du musst erst
einmal "möglichst genau definieren".
Die nächst einfachere du ein GPS-Signal zur Synchronisation der
Zeitbasis nimmst.
In absteigender Reihenfolge kannst du entweder
- ein Rubidiumnormal
- einen Ofen kontrollierten Oszillator
- oder einen Temperaturkompensierten Oszillator kaufen
Desweiteren gibt es nicht "den Arduino", sondern Haufenweise völlig
unterschiedliche Hardware, auf der das Arduino Framework läuft.
Die Arduinos "Uno" und "Nano" haben einen Resonator, der für
Frequenzmessungen mit mehr als 4 Stellen zu ungenau ist. Nimmst du aber
einen PiPico mit Arduino-Framework, hat der einen sehr stabilen Quartz
und die Systemfrequenz kann auf 150MHz hochgestellt werden, sodass auch
noch kleine Zeitquantisierungen möglich sind.
chris_ schrieb:> Wenn du mit bloßem Auge eine Ungenauigkeit siehst, dann liegt es mit> Sicherheit nicht an der Zeitbasis des Arduino sondern an einem Fehler in> deinem Programm.
sehe ich auch so.
@TO:
Wenn deine 4 LEDs in sync bleiben sollen dann mach einen Takt und leite
davon die Takte der 4 LEDs ab. Das bleibt syncron auch wenn sich mal
deine millis um eine 1ms verschieben würden.
Thomas G. schrieb:> Wie genau arbeitet ein TCXO?
Das ist ein temperaturkompensierter Quarzoszillator, der über einen
weiten Temperaturbereich eine auf ca. 1 ppm (je nach Typ) stabile
Frequenz liefert.
Wie sich jetzt gezeigt hat, hat Deine Schaltung einen Quarzoszillator,
wo man von einer Grundgenauigkeit von <= 50 ppm ausgehen kann.
Daraus folgt, daß er für Deine auf vier Stellen genaue Takterzeugung
ohne weiteren Abgleich ausreichend ist.
Da Du einen ATmega328 verwendest, könntest Du die oben verlinkten
AVR-Programmbeispiele damit laufen lassen. Pro erzeugte Frequenz braucht
man einen OCRx-Ausgang, wovon der 328 insgesamt sechs Stück hat. Daß
jeweils zwei an einem gemeinsamen Timer hängen, stört nicht. Insgesamt
kann man damit also sechs unterschiedliche Blinkfrequenzen erzeugen -
sehr genau und jitterfrei.
Man kann zwar die Arduino-IDE verwenden, sollte aber tunlichst setup()
und loop() vermeiden, damit man alle Timer selbst benutzen kann.
Du brauchst also keinerlei andere oder zusätzliche Hardware, aber ein
wenig Arbeit, um zu verstehen, wie die Timer mit ihren OXRx-Ausgängen
arbeiten.
Bleibt noch die Frage, wie Du die unterschiedlichen Frequenzen
einstellen willst.
Per Poti wäre zu ungenau. Per Tastatur oder per ser. Schnittstelle?
Thomas G. schrieb:> in dem ich möglichst genaue> Frequenzen benötige.
Das ist Wischiwaschi, damit kann keiner was anfangen.
Thomas G. schrieb:> Mein Ziel ist es> gerade, vier LEDs mit meinen voreingestellten Frequenzen blinken zu> lassen.
Hä?
Für Blink-LEDs braucht es überhaupt keine Genauigkeit. Kein Mensch kann
Fehler im ms-Bereich erkennen.
Erzähl mal konkret, was das überhaupt werden soll.
Thomas G. schrieb:> Als ersten Gedanken hatte ich da einen TLC555 Timer als astabile> Kippstufe.
Guter Witz.
Ein RC-Oszillator ist um Längen ungenauer, als ein MC mit Quarz.
Peter D. schrieb:> Das ist Wischiwaschi, damit kann keiner was anfangen.
Der TO hatte mittlerweile beschrieben, wie genau er es haben möchte.
Man muß es nur lesen und verstehen wollen.
Peter D. schrieb:> Für Blink-LEDs braucht es überhaupt keine Genauigkeit. Kein Mensch kann> Fehler im ms-Bereich erkennen.
Der TO möchte es so haben, weil er etwas lernen will. Daß instabile
Blinkschaltungen relativ schnell sichtbar in der Phasenlage
auseinanderlaufen, ist kein Geheimnis. Das ist selbst dem TO als
Programmieranfänger aufgefallen.
Daß Du das nicht brauchst, ist nicht relevant.
m.n. schrieb:> Daß instabile> Blinkschaltungen relativ schnell sichtbar in der Phasenlage> auseinanderlaufen, ist kein Geheimnis.
Wenn sie von einem gemeinsamen Basistakt erzeugt werden, aber schon.
Das Problem ist das Einstellen in kleinen Schritten. Damit kann sich
eine sehr lange Priodendauer ergeben, bis alle 4 Zähler wieder den
Startwert erreicht haben. Mit 4 hohen Primzahlen als Teiler dauert das
eben. Das hat aber nicht das geringste mit der Genauigkeit der Taktbasis
zu tun.
Peter D. schrieb:> Wenn sie von einem gemeinsamen Basistakt erzeugt werden, aber schon.
Lies doch mal, was hier bereits geschrieben wurde.
Deine nutzlose Nörgelei bringt dem TO nichts.
m.n. schrieb:> Lies doch mal, was hier bereits geschrieben wurde.
Auseinander laufen können nur 4 unabhänge RC-Oszillatoren. Sobald man
einen gemeinsamen Basistakt hat, sind alle Abläufe streng
deterministisch.
m.n. schrieb:> Deine nutzlose Nörgelei bringt dem TO nichts.
Nörgeln (Helfen) kann man erst, wenn es einen Quelltext gibt.
Ich habe auch nicht genörgelt, sondern nur gefragt, was da ganze
überhaupt soll.
m.n. schrieb:> Stefan ⛄ F. schrieb:>> Würde ich auch tun, aber der TO will es exakt.>> Exakt gibt es in der Physik nicht. Hinreichend genau ist angesagt.
Naja, Stefan ist weder Physiker noch Mathematiker. Also nicht
übelnehmen.
So, zur Sache:
Wenn man irgendwelche möglichst präzisen Signale erzeugen will, die auch
noch frei wählbar im Betrieb sein sollen, dann greift man der
Einfachheit zuliebe zu einem kleinen DDS-Schaltkreis. Wenn man hingegen
ohne zusätzliche Schaltung auskommen will, dann wären da µC-interne
Timer die Wahl, aber das setzt zusätzliche Überlegungen voraus. Und da
kommt zumindest das Rechnen mit echten Brüchen ins Spiel, womit auch
Teilungsverhältnisse darstellbar sind, die bei Dezimaldarstellung zu
nicht enden wollenden Nachkommastellen führen.
Sowas geht vom Prinzip her auch mit einem Arduino, aber man muß sich
schon etwas mehr mit Rechnen und dem Verwenden von Timern befassen als
nur millis() aufzurufen.
W.S.
W.S. schrieb:> ohne zusätzliche Schaltung auskommen will, dann wären da µC-interne> Timer die Wahl, aber das setzt zusätzliche Überlegungen voraus. Und da> kommt zumindest das Rechnen mit echten Brüchen ins Spiel,
Nö. Das sind einfache Zähler und Modulooperationen. DDS in Software.
Beitrag "Re: auf einfache Weise von 11MHz auf 300kHz teilen/generieren"
Ok, ist Assembler und damit nicht so ganz das Gelbe vom Ei für Arduinos,
aber man erkennt das Prinzip.
Beitrag "Re: SPWM auf Atmega8, bitte um Feedback hinsichtlich Optimierung"
Das ist "Arduino", sprich C++ in einfachster Form. Man muss nur die
Tabelle weglassen und schon hat man seine nahezu X-beliebigen
Frequenzen.
Peter D. schrieb:> Auseinander laufen können nur 4 unabhänge RC-Oszillatoren. Sobald man> einen gemeinsamen Basistakt hat, sind alle Abläufe streng> deterministisch.
Genau.
Schon deshalb kann ich das Problem des TO nicht nachvollziehen.
Und wenn er unabhängige Oszillatoren hat, auch welche vom Typ TCXO, dann
werden die irgendwann merklich auseinandergelaufen sein.
HildeK schrieb:> Genau.> Schon deshalb kann ich das Problem des TO nicht nachvollziehen.
Ich schon. Man kann mit schlechter Software, basierend auf fehlenden
Kenntnissen, JEDEN Murks machen, der scheinbar funktioniert, im Detail
dann aber versagt.
Ich halte es für erwähnenswert, dass die loop Schleife keine while
Schleife ist, wie man sich das als Anfänger vorstellt. Die Loop muss man
sich so vorstellen:
while(1){
loop(); <--- hier wird dein Code ausgeführt
ArduinoKram(); <-- kostet Zeit
}
Auch digitalWrite() etc. benötigt unterschiedlich lange, was auch zu
einer verschiebung führt.
Teste deinen code mal mit
- micros() anstatt millis()
- in einer while(1) Schleife anstatt in der loop()
- evtl. direkten Port Zugriff anstatt digitalWrite()
Die bessere Variante ist jedoch einen Timer zu verwenden und dann über
direkten Port Zugriff die GPIOs schalten.
Thomas G. schrieb:> Idealerweise eine Genauigkeit von +/- 0%.
Eine Genauigkeit von 0% ist leicht zu erreichen. Denn dann ist selbst
das ungenaueste Signal noch genau genug.
Du forderst eine "Ungenauigkeit" oder eine "Abweichung" von 0%.
Aber alle, die so etwas verlangen, ingorieren die Realität. Denn die
einzig relevante Frage ist nicht, was du willst, sondern was die
Anwendung braucht. Und diese Rahmenbedingungen vernüftig zu klären und
darauf basierend eine kostenmäßig taugliche Lösung für diese Anwendung
zu finden, das ist die Aufgabe eines Technikers. Alles andere sind
irgendwelche nutzlosen Gedankenspiele, die man durch Einsatz beliebiger
Geldmengen leicht lösen kann.
Peter D. schrieb:> Ich habe auch nicht genörgelt, sondern nur gefragt, was da ganze> überhaupt soll.
Auf die Antwort bin ich auch gespannt.
Thomas G. schrieb:>> Kriegt man mit einer Toleranz von +/- 0,001 % hin. Genau genug? An eine>> Kalibrierung kommt man wohl nicht vorbei.>> Das sollte genau genug sein.
Ganz doof gefragt: verfügst du überhaupt über die Messtechnik, um dein
Ergebnis zu verifizieren?
Ansonsten ist selbst mit dem Uno noch eine Menge Luft nach oben, wie
schon andere geschrieben haben.
> was da ganze> überhaupt soll.
Das ist doch nun einfach.
Ein Caesium kontrollierter Arduinowurstblinker.
Braucht doch fast jeder (nicht).
Wenn es wenigstens ein Stroboskop waere...
> eine "Abweichung" von 0%.
ist, wie ich schon schrieb, mit einer PLL bezogen auf die
Referenzfrequenz leicht zu erreichen.
Das sollte sich vielleicht auch einmal in "FPGA-Kreisen" herumsprechen.
Das es auch ausserhalb eines FPGA eine oder mehrere PLLs geben kann.
Und nicht nur diese haesslichen DCMs.
Falk B. schrieb:> Nö. Das sind einfache Zähler und Modulooperationen. DDS in Software.
Ach nö. Ein Zählerausgang liefert hi oder lo und damit nur das
Vorzeichen, während ein DDS ein analoges Signal liefert und damit
schlußendlich eine Stützstelle, die nach einem Tiefpaß den richtigen
Signalverlauf (soweit technisch möglich) liefert. Du solltest dringend
mal nachlesen, wie ein DDS funktioniert.
Und wenn man exakte Frequenzverhältnisse mit Timern haben will, dann
kommt man nicht umhin, sich um Rechendinge zu kümmern wie gemeinsame
Teiler von Integers usw. - sonst addieren sich die restlichen
Phasenfehler und die Signale an den Ausgängen laufen langsam
auseinander. Wenn einen das nicht schert, dann ist das Benutzen von
Timern ohne weitere Berechnungen möglich. Sonst eben nicht.
W.S.
Lothar M. schrieb:>> Ich habe auch nicht genörgelt, sondern nur gefragt, was da ganze>> überhaupt soll.> Auf die Antwort bin ich auch gespannt.
Das muß der TO überhaupt nicht beantworten. Er ist Anfänger und kann tun
und lassen, was er will.
Er möchte Programmieren lernen und hat sich ein Ziel gesetzt. Das ist
allemal besser, als irgendwelche, fertigen Entprellroutinen
herunterzuladen und instinktlos einzusetzen.
Klassikradio schrieb:> Ein Caesium kontrollierter Arduinowurstblinker.> Braucht doch fast jeder (nicht).
Noch so ein namenloser Stinkstiefel, bei beim Wiederkäuen seines
Frühstücks Schluckauf bekommen hat.
Klassikradio schrieb:>> eine "Abweichung" von 0%.> ist, wie ich schon schrieb, mit einer PLL bezogen auf die> Referenzfrequenz leicht zu erreichen.
Naja, nicht 0%, sondern eher daß die restliche Frequenzabweichung im
Phasenfehler untergeht. Aber 'leicht' ist was anderes. Es gibt durch den
notwendigen Teiler immer ein Raster.
W.S.
Peter D. schrieb:> Auseinander laufen können nur 4 unabhänge RC-Oszillatoren. Sobald man> einen gemeinsamen Basistakt hat, sind alle Abläufe streng> deterministisch.
Wieder mal eine sprachliche Ungenauigkeit. Meinst du langsame Änderungen
in der Frequenz oder in der Phase? Und es sind nicht nur RC-Oszillatoren
betroffen, sondern im Prinzip alle. Bloß das Ausmaß ist
unterschiedlich.
So. Ich geb dir mal ein Beispiel zum Prinzip: ein Ausgang soll ein
Signal mit 10 Hz ausgeben und ein anderer eines mit 50 Hz. Rein
theoretisch sollten beide Signale gegeneinander nicht phasenmäßig
auseinanderlaufen. Aber wenn bei einem die exakte Frequenz 10.0001 Hz
ist und bei dem anderen die exakte Frequenz 49.9999 Hz, weil sich das
eben aus den Integer-Teilerwerten ergibt, dann laufen die Signale
langsam in der Phase auseinander - obwohl sie aus dem selben Takt
generiert werden.
W.S.
> Er ist Anfänger und kann tun und lassen, was er will.
Dann soll er es auch lassen hier zu fragen.
Mein Fruehstueck habe ich uebrigens schon gut verdaut.
> daß die restliche Frequenzabweichung im> Phasenfehler untergeht
Ist die PLL gelockt, gibt es keinen Frequenzfehler.
Nur einen fixen Versatz in der Phase. Hat das Schleifenfilter einen
I-Anteil, wird disee Phasenabweichung auf ein Minimum geregelt.
Um hier ein paar aufgekommene Fragen zu beantworten:
Bei meinen aufblinkenden LEDs handelt es sich um ein Stroboskop. Alle
LEDs greifen auf den selben Timer zu, haben unterschiedliche Startpunkte
im Intervall, in dem sie sozusagen synchronisieren. Nach einem
Intervalldurchlauf haben die LEDs nämlich gleiche Schaltzeiten, im 4er
Modus haben sie 2 unterschiedliche Schaltzeiten. Zur Verbildlichung,
nach Intervall 1 schaltet die LED 1 ein und LED 3 aus, im zweiten
Intervall schaltet 3 ein und 1 aus. mit 2 Intervallen komme ich so auf
eine Vierteilung der Frequenz.
In meinem Programm blitzen die LEDs nur auf, weil ich sie nicht bis zu
den Flanken eingeschaltet haben möchte.
Warum benutze ich dafür Arduino? Weil ich ein Arduino Board habe und
dachte, dass es sich damit ganz gut umsetzen lässt. Erst nach längerer
Beschäftigung und Umsetzung wurde mir die Ungenauigkeit bewusst.
Da ich für mein Projekt tatsächlich stabile Frequenzen benötige, sehe
ich in den kleinen Abweichungen zu viel Fehler.
Ich möchte meine Idee mit allen Mitteln umsetzen, weshalb ich aufgrund
meiner Problematik andere Lösungen in Betracht ziehe, die genauer aber
eventuell um einiges schwieriger sind. Zu irgendwas muss mein B. Eng. ja
gut sein, harte Elektrotechnik mit Schaltungsentwürfen und
Bauteile-Auswahl habe ich so leider nie gelernt.
Entfernen werde ich mich vom Arduino warscheinlich nicht, da ich damit
immernoch einen Bildschirm, Taster und Drehgeber programmieren kann um
mir mein Objekt so zusammen zu schustern.
Mit der
if (currentMillis - previousMillis >= interval) {
// save the last time you blinked the LED
previousMillis = currentMillis;
Option driftet mein Intervall immer in gewissen abständen 1ms weg.
Mit
if (currentMillis - previousMillis >= interval) {
// save the last time you blinked the LED
previousMillis = previousMillis + interval;
halte ich zwar ein festes Intervallraster ein das per se nicht driftet,
aber meinen Fehler verdoppelt. So kommt nämlich immernoch der Versatz
von 1ms in den gleichen Abständen zusammen, UND zusätzlich wird in der
gleichen Phase 1ms hinten abgezogen. Damit verliere ich also 2ms.
An die micros() Funktion habe ich auch schon gedacht, so sollte ja
eigentlich eine höhere Nachkommastelle darstellbar sein. Ein Blick in
den Monitor hat jedoch gezeigt, dass die micros() Funktion das Intervall
in den gleichen Abständen um 42 Mikrosekunden übersteigt. Heißt, auch
hier ist ein Drift vorhanden.
Ich würde gerne den Ansatz mit dem Timer1 ausprobieren, mit dem die
Auflösung verändert wird und eine ms-genaue Einstellung möglich sein
sollte. Die Register zu verändern stellt für mich leider immernoch eine
kleine Herausforderung dar.
Messinstrumente zur Verifizierung stehen mir leider nicht zur Verfügung.
Zur Analyse steht mir nur der Monitor der Arduino IDE zur Verfügung.
Thomas G. schrieb:> Warum benutze ich dafür Arduino? Weil ich ein Arduino Board habe und> dachte, dass es sich damit ganz gut umsetzen lässt. Erst nach längerer> Beschäftigung und Umsetzung wurde mir die Ungenauigkeit bewusst.
;-)
Die "Ungenauigkeit" liegt zu 99% in deinen Fähigkeiten.
> Da ich für mein Projekt tatsächlich stabile Frequenzen benötige, sehe
WIE Stabil? Atomuhrgenau wird es sicher NICHT sein! Selbst der eher
gurkige Oszillator der kleinen Arduinos mit ca. 0,1% Fehler wird es
VERMUTLICH tun. Ein Quarz, den man auch sehr einfach nachrüsten kann hat
nur 0,01% (100ppm) und weniger Frequenzfehler.
> ich in den kleinen Abweichungen zu viel Fehler.
Wie "siehst" du sie denn? Mit dem alles sehenden Auge von Mordor?
> Ich möchte meine Idee mit allen Mitteln umsetzen, weshalb ich aufgrund
Wieviele Milliarden kannst du investieren? ;-)
> Entfernen werde ich mich vom Arduino warscheinlich nicht, da ich damit> immernoch einen Bildschirm, Taster und Drehgeber programmieren kann um> mir mein Objekt so zusammen zu schustern.
Das kommt der Sache schon näher.
> Mit der> if (currentMillis - previousMillis >= interval) {> // save the last time you blinked the LED> previousMillis = currentMillis;>> Option driftet mein Intervall immer in gewissen abständen 1ms weg.
Das ist auch nicht die optimale Lösung, wenn man im Bereich von 1ms oder
gar darunter arbeiten will.
> An die micros() Funktion habe ich auch schon gedacht, so sollte ja> eigentlich eine höhere Nachkommastelle darstellbar sein. Ein Blick in> den Monitor hat jedoch gezeigt,
Welcher Monitor?
> Ich würde gerne den Ansatz mit dem Timer1 ausprobieren, mit dem die> Auflösung verändert wird und eine ms-genaue Einstellung möglich sein> sollte.
Den kann man auf einen CPU-Takt genau einstellen.
> Die Register zu verändern stellt für mich leider immernoch eine> kleine Herausforderung dar.
Na dann mal los, so viele sind es nicht.
Beitrag "Re: 20 LEDs unterschiedlich blinken lassen"Beitrag "Re: Arduino Micro SPWM"> Messinstrumente zur Verifizierung stehen mir leider nicht zur Verfügung.
AHA! Und wie hast du dann deine behaupteten Abweichungen und Drift
gemessen?
> Zur Analyse steht mir nur der Monitor der Arduino IDE zur Verfügung.
OMG! Und du glaubst, daß du damit in DEM Zeitbereich was gescheit messen
kannst? Dream on.
Du braucht ein einfaches Oszilloskop, zur Not auch ein billiger
Logikanalysator, aber der ist nervig, wenn man periodische Signale
anschauen will.
Falk B. schrieb:> Die "Ungenauigkeit" liegt zu 99% in deinen Fähigkeiten.
Plausibel.
>> ich in den kleinen Abweichungen zu viel Fehler.>> Wie "siehst" du sie denn? Mit dem alles sehenden Auge von Mordor?
Bei 16Hz sehe ich mit dem bloßen Auge, dass die LEDs nicht in Phase
bleiben. Wenn ich 2 LEDs beobachte, sehe ich wie sich eine LED an die
Phase der anderen annähert und dann "überholt". Kann man sich wie einen
Phaser vorstellen, falls dir das was sagt. Nur das es hier kein Ton ist,
sondern blinkende LEDs.
>> Ich möchte meine Idee mit allen Mitteln umsetzen, weshalb ich aufgrund>> Wieviele Milliarden kannst du investieren? ;-)
Ich dachte da eher an wenns digital nicht klappt, dann irgendwie analog.
>> Mit der>> if (currentMillis - previousMillis >= interval) {>> // save the last time you blinked the LED>> previousMillis = currentMillis;>>>> Option driftet mein Intervall immer in gewissen abständen 1ms weg.>> Das ist auch nicht die optimale Lösung, wenn man im Bereich von 1ms oder> gar darunter arbeiten will.
Bisher ist mir neben dem Tipp mit dem Timer1 keine weitere Option
bekannt.
>> An die micros() Funktion habe ich auch schon gedacht, so sollte ja>> eigentlich eine höhere Nachkommastelle darstellbar sein. Ein Blick in>> den Monitor hat jedoch gezeigt,>> Welcher Monitor?
In der IDE unter Werkzeuge > Serieller Monitor, lassen sich Werte mit
printf auf der Konsole anzeigen.
> AHA! Und wie hast du dann deine behaupteten Abweichungen und Drift> gemessen?
Da sieht man im seriellen Monitor die zeitlichen Abstände, wenn man sie
anzeigen lässt. Die einzigen Frequenzen die stabil laufen sind 1Hz und
Vielfache von 5Hz.
> OMG! Und du glaubst, daß du damit in DEM Zeitbereich was gescheit messen> kannst? Dream on.
Sweet dreams are made of this
Stefan ⛄ F. schrieb:> Würde ich auch tun, aber der TO will es exakt. Deswegen schrieb ich:
Das hat er zumindest nicht geschrieben:
Thomas G. schrieb:> Ich suche eine Komponente, mit der ich stabile Frequenzen im Bereich von> 1Hz bis 100Hz darstellen kann.
Und das geht auf jeden Fall.
Thomas G. schrieb:> Bei 16Hz sehe ich mit dem bloßen Auge, dass die LEDs nicht in Phase> bleiben.
Wie sollen die denn blinken?
Zeig doch mal eine Skizze mit einem Diagramm.
W.S. schrieb:> Aber wenn bei einem die exakte Frequenz 10.0001 Hz> ist und bei dem anderen die exakte Frequenz 49.9999 Hz, weil sich das> eben aus den Integer-Teilerwerten ergibt, dann laufen die Signale> langsam in der Phase auseinander
So macht man das ja auch nicht. Man rechnet die Brüche nicht aus,
sondern rechnet einfach direkt mit den gebrochenen Zahlen. Dazu braucht
es nichtmal eine langsame float-Lib, sondern es reicht ein einfacher
Integer-Akku.
Z.B. wir haben 100Hz Basistakt und wollen daraus 7Hz erzeugen, d.h. wir
müßten durch 14,285714285714285714285714285714 teilen. Statt dessen wird
7 (=Ausgangsfrequenz) in den Akku addiert und bei >=100
(=Eingangsfrequenz) 100 abgezogen und ein Puls generiert.
Wollen wir als 2. Frequenz 3Hz, nehmen wir einen 2. Akku und machen es
dort genau so. Wir haben zwar einen Jitter, der aber addiert sich nicht.
Nach 2100 Takten (=kgV) ist alles wieder auf Anfang.
Nimmt man als Basistakt den 16MHz Quarz des MC, dann beträgt der Jitter
max 62,5ns. Das sieht niemand.
Thomas G. schrieb:> Bei 16Hz sehe ich mit dem bloßen Auge, dass die LEDs nicht in Phase> bleiben. Wenn ich 2 LEDs beobachte, sehe ich wie sich eine LED an die> Phase der anderen annähert und dann "überholt". Kann man sich wie einen> Phaser vorstellen, falls dir das was sagt. Nur das es hier kein Ton ist,> sondern blinkende LEDs.>>> Ich möchte meine Idee mit allen Mitteln umsetzen, weshalb ich aufgrund>>>> Wieviele Milliarden kannst du investieren? ;-)>> Ich dachte da eher an wenns digital nicht klappt, dann irgendwie analog.
Quark. Nahezu alle Lösungen sind heute digital und ihren analogen
Brüdern überlegen. Ausnahmen bestätigen die Regel.
> Bisher ist mir neben dem Tipp mit dem Timer1 keine weitere Option> bekannt.
Man muss es einfach richtig (tm) machen, dann geht das auch mit
millis(). Zeig mal deinen Quelltext als Anhang.
> In der IDE unter Werkzeuge > Serieller Monitor, lassen sich Werte mit> printf auf der Konsole anzeigen.
Ja, und dein printf() dauert mehrere Millisekunden und versaut dir an
den kritischen Stellen das Timing. Volle Punktzahl.
> Da sieht man im seriellen Monitor die zeitlichen Abstände, wenn man sie> anzeigen lässt. Die einzigen Frequenzen die stabil laufen sind 1Hz und> Vielfache von 5Hz.
Dann ist deine Software Murks, was auf grund deiner Kenntnisse nicht
verwunderlich ist. Siehe oben.
Klassikradio schrieb:>> eine "Abweichung" von 0%.> ist, wie ich schon schrieb, mit einer PLL bezogen auf die> Referenzfrequenz leicht zu erreichen.
Ja, "auf eine Referenzfrequenz". Und woher kommt die? Hat die auch eine
"Genauigkeit" von 0,0%?
> Das sollte sich vielleicht auch einmal in "FPGA-Kreisen" herumsprechen.
Hach, flach.
> Das es auch ausserhalb eines FPGA eine oder mehrere PLLs geben kann.
Ich glaube eben ganz einfach nicht, das die Aufgabe eine solche Lösung
braucht, sondern eben bestenfalls der Thomas mangels besseren Wissens
es so will.
W.S. schrieb:> Du solltest dringend mal nachlesen, wie ein DDS funktioniert.
Man kann mit DDS auch ein Rechtecksignal erzeugen. Das braucht dann im
einfachsten Fall nicht mal eine großartige Tabelle für die Wellenform,
sondern man gibt einfach das MSB des Akkus aus...
m.n. schrieb:> Das muß der TO überhaupt nicht beantworten. Er ist Anfänger und kann tun> und lassen, was er will.
Klar muss er nicht. Trotzdem bin ich gespannt. Und weil er eine Lösung
sucht, darf er ruhig daran mitwirken.
> Er möchte Programmieren lernen und hat sich ein Ziel gesetzt. Das ist> allemal besser, als irgendwelche, fertigen Entprellroutinen> herunterzuladen und instinktlos einzusetzen.
Lernen heißt aber auch, nicht jeden Fehler selber zu machen, sondern
auch mal auf andere zu hören. Oder wie war das bei dir in der Schule?
Machen wir es mal so: du hilfst ihm und zeigst ihm den Weg, dass er
seinen Wunsch erfüllen kann.
Thomas G. schrieb:> woraufhin ein einzelner Puls mit 10.8695Hz folgt.
Einzelne Pulse haben im Grunde keine Frequenz, denn "Frequenz" heißt
"Häufigkeit" und 1x ist nicht häufig.
> von W.S. (Gast) 30.05.2022 12:46> Du solltest dringend mal nachlesen, wie ein DDS funktioniert.
Das weiß der Falk /sehr genau./
Hier ein präziser Einkanal-Frequenzgenerator z.B. für einen UNO oder
Nano (so genau der 16bit-Timer halt geht):
Ursprünglich verwendete ich die timerOne-Library, die ist aber ungenau,
da sie nur in Mikrosekunden rechnet, und das nicht einmal genau, da sie
als Quarzfrequenz nur Mehrfache von 2 MHz "zulässt".
1
// F_CPU is the frequency of MY arduino uno, change this number for YOUR board
2
//giving this as float forces a precise compile-time calculation of cycles in timerone.h.
3
#define F_CPU 15995000.0
4
//Otherwise calculation is based on frequencies in multiples of 2MHz
5
6
#define msg "enter frequency (mit Punkt statt Komma 0.119 - 4000000) : "
7
///#include <TimerOne.h>
8
voidsetup(){
9
DDRB=0x00;PORTB=0xFF;//alle INPUT_PULLUP
10
DDRC=0x00;PORTC=0xFF;//alle INPUT_PULLUP
11
DDRD=0x00;PORTD=0xFF;//alle INPUT_PULLUP
12
DDRB|=2;//OC1A COM1A1 PB1 output
13
Serial.begin(9600);
14
Serial.print(F("\nprecision frequency generator\n"msg));
MisterX schrieb:> Hier ein präziser Einkanal-Frequenzgenerator z.B. für einen UNO oder> Nano (so genau der 16bit-Timer halt geht):
Naja, ob DAS ein mustergültiges Beispiel ist, wage ich zu bezweifeln.
> Ja, "auf eine Referenzfrequenz". Und woher kommt die? Hat die auch eine
"Genauigkeit" von 0,0%?
Fuer ein mehrkanaliges Stroboskop kann die genaue Einhaltung
der Verhaeltnisse wichtiger sein, als ein absolut genauer Wert.
Wenn man sich z.B. Zahnraduebersetzungen ansehen will.
Zweifelhaft bleibt mir da nur, warum es gerade ganzzahlige
Vielfache von 1 sein muessen.
> Hach, flach.
Selber flach.
Der einzige eingermassen brauchbaren Vorschlag ist vom Peter.
Beitrag "Re: Arduino Timerprobleme - suche programmierbaren Oszillator"
Und natuerlich geht es nicht vernuenftig mit millis() und
Konsorten. Weil eben die Frequenz reziprok zur Zeit ist.
Lothar M. schrieb:> Lernen heißt aber auch, nicht jeden Fehler selber zu machen, sondern> auch mal auf andere zu hören.
Meinst Du die, die ihm sagen wollen, daß er doof und unfähig sei?
> Machen wir es mal so: du hilfst ihm und zeigst ihm den Weg, dass er> seinen Wunsch erfüllen kann.
Oh, das hatte ich bereits getan. Oben sind Beispiele mit einem 8 Bit
Timer (ATtiny25) und einem 16 Bit Timer (ATmega328) verlinkt. Letzteres
nutzt beide Kanäle vom Timer1 und hat sogar eine .ino Endung.
Ich könnte ihm daraus auch ein fertiges Programm zusammenkopieren, was
dann aber keinen Lerneffekt hätte.
Falls der TO die erzeugten Frequenzen mit einem Arduino (328) messen
möchte, hätte ich auch einen Link:
http://mino-elektronik.de/fmeter/fm_software.htm#bsp7
Alternativ natürlich auch mit STM32 oder RP2040 Pico-Board ;-)
Thomas G. schrieb:> Ich möchte Frequenzen bis 30Hz mit 2 Nachkommastellen wählen können.
Also 0,00 bis 30,00Hz oder auch 0 bis 3000 CentiHz.
Wenn du jetzt unsgined-Integer-Zähler mit 32 Bit aufsetzt, der jede alle
100µs inkrementiert wird, dann hast du bei 30Hz einen Jitter von 3%.
Wenn da reicht, dann musst du einen Interrupt erzeugen, der alle 100µs
kommt und darin für jede LED einen 32-Bit-Zähler hochzählen. Und zwar
addierst du dann pro Schritt einen Increment-Wert von 2^32 / (3000 x
WunschfrequenzInCentiHz) auf. Nach einer Formelumstellung ergibt das Inc
= cHz x 1431656.
Wenn du also 20,00 Hz willst, dann musst du einfach in der
100µs-Interruptroutine einen Wert von 2000 x 1431656 = 2863312000
aufaddieren.
Wenn du nur 19,99 Hz willst, dann musst du etwas weniger, nämlich 1999 x
1431656 = 2861880344 aufaddieren.
Und von jedem dieser 32-Bit-Zähler nimmst du das LSB und gibts es auf
die jeweilige LED aus. Damit kannst du deine Wunschfrequenz bis auf 7
Nachkommastellen genau erzeugen. So genau und stabil muss erst mal der
verwendete Quarz sein.
Wenn du keinen 100µs Interrupt hinbekommst, dann musst du "nur" den
Faktor 1431656 so ändern, dass der berechnete Increment-Wert wieder zur
gewünschten Frequenz führt.
Lothar M. schrieb:> dann hast du bei 30Hz einen Jitter von 3%.
Na das ist heftig!
Für eine Stroboskope-Anwendung wohl ein wenig zu viel. Auch sind 50%
Tastverhältnis wohl nicht so zündend. Das müßte auch noch einstellbar
sein.
Mit der Arduino-Hardware bekommt man eine jitterfreie Auflösung von 62,5
ns. Warum soll man darauf verzichten?
m.n. schrieb:> Lothar M. schrieb:>> dann hast du bei 30Hz einen Jitter von 3%.>> Na das ist heftig!> Für eine Stroboskope-Anwendung wohl ein wenig zu viel.
Das glaube ich nicht, schon gar nicht bei der Anwendung des OP. Der hat
mal sich KEINE Super-Duper Anforderungen an den Jitter. Also nicht real,
bestenfalls gefühlt.
> Mit der Arduino-Hardware bekommt man eine jitterfreie Auflösung von 62,5> ns. Warum soll man darauf verzichten?
Weils hier nicht nötig ist? Das Problem des OP liegt auf einer deutlich
höheren Ebene. OSI Layer 8.
Thomas G. schrieb:> it der> if (currentMillis - previousMillis >= interval) {> // save the last time you blinked the LED> previousMillis = currentMillis;>> Option driftet mein Intervall immer in gewissen abständen 1ms weg.>> Mit> if (currentMillis - previousMillis >= interval) {> // save the last time you blinked the LED> previousMillis = previousMillis + interval;Deckenleuchte schrieb:> Ich halte es für erwähnenswert
Noch immer halte ich das für erwähnenswert!
Lothar M. schrieb:> Ja, "auf eine Referenzfrequenz". Und woher kommt die? Hat die auch eine> "Genauigkeit" von 0,0%?
Versuchen wir doch mal einen ernsthaften Überschlag: Wenn der Thomas
irgend etwas per Stroboskop anschauen will, dann vermutlichst deshalb,
weil es für's bloße Auge zu schnell, aber für stroboskopisches
Betrachten (das Auge als Sampler...) noch nicht zu schnell ist. Also ich
tippe mal auf so etwa 500..2000 rpm.
Das Stroboskop muß abstimmbar sein, weil man es für ein so einigermaßen
stehendes Bild an die Bewegunng des Prüflings anpassen muß. Nehmen wir
also mal irgendwas in der Mitte, also z.B. 1000 rpm. Wenn da das
Stroboskop um 1% frequenzmäßig daneben liegt, dann dreht sich das
virtuelle Bild mit 10 rpm, also 1x in 6 Sekunden.
Naja, ein stehendes Bild ist was anderes, aber 1 Umdrehung in 6 Sekunden
kann man als Bastler noch aushalten. Ich denke mal, Abweichungen von 1%
sind die obere Grenze des Zumutbaren. Und ob sich das Bild nun in 5
Minuten einmal um sich selbst dreht, sollte egal sein, also wäre die
untere Grenze so etwa im Bereich von 0.02 %. Genauer braucht's nicht zu
sein.
Bei so etwa 1000 rpm liegt die Periode bei etwa 60 ms und ne Abweichung
von 1% davon liegt bei 600 µs was damit die obere Grenze ist für die
Ungenauigkeit.
Und besser als 12µs braucht man nicht zu sein.
So, da haben wir erstmal ne grobe Abschätzung.
Nochwas zum Verfahren: Wenn besagte LED's so eine Art Folgeblitz sein
sollen, dann reicht es aus, wenn man sie mit einem gewissen zeitlichen
Abstand von der ersten LED einschaltet. Vier separate Timer braucht es
da überhaupt nicht. Insofern sind alle Überlegungen zum Davonlaufen von
Phase usw. überflüssig.
W.S.
W.S. schrieb:> Nochwas zum Verfahren: Wenn besagte LED's so eine Art Folgeblitz sein> sollen, dann reicht es aus, wenn man sie mit einem gewissen zeitlichen> Abstand von der ersten LED einschaltet. Vier separate Timer braucht es> da überhaupt nicht. Insofern sind alle Überlegungen zum Davonlaufen von> Phase usw. überflüssig.
So isses. Wie sich die Einlassungen des TO insgesamt so lesen, soll da
wohl eigentlich ein Motor betrachtet werden und zwar ein Vierzylinder.
Wenn das so ist, sollte man sein Augenmerk eher darauf richten, die
Messung mit dem Messobjekt zu synchronisieren, statt sie freilaufend zu
realisieren. Dann gibt's erstmal kein "Fortlaufen" des Bilds. Der Rest
sind dann keine vier Frequenzen, sondern eine in vier einstellbaren
Phasenlagen.
Thomas G. schrieb:> Ich suche eine Komponente, mit der ich stabile Frequenzen im Bereich von> 1Hz bis 100Hz darstellen kann.Thomas G. schrieb:> Ich möchte Frequenzen bis 30Hz mit 2 Nachkommastellen wählen können.
Die Periodendauer der Signale sollten ganzzahlige Vielfache des
Basistaktes sein. Sonst wird es schwierig.
Thomas G. schrieb:> Bei meinen aufblinkenden LEDs handelt es sich um ein Stroboskop. Alle> LEDs greifen auf den selben Timer zu, haben unterschiedliche Startpunkte> im Intervall, in dem sie sozusagen synchronisieren. Nach einem> Intervalldurchlauf haben die LEDs nämlich gleiche Schaltzeiten, im 4er> Modus haben sie 2 unterschiedliche Schaltzeiten. Zur Verbildlichung,> nach Intervall 1 schaltet die LED 1 ein und LED 3 aus, im zweiten> Intervall schaltet 3 ein und 1 aus. mit 2 Intervallen komme ich so auf> eine Vierteilung der Frequenz.
Textuelle Beschreibungen von Timingabläufen sind immer schlecht. Zeichne
das doch mal auf. Und zeichne auch mal diese unterschiedlichen "Modi" da
mit ein...
c-hater schrieb:> So isses. Wie sich die Einlassungen des TO insgesamt so lesen, soll da> wohl eigentlich ein Motor betrachtet werden und zwar ein Vierzylinder.
Man könnte das Spekulieren auch einfach mal sein lassen und den TO um
eine gescheite Auskunft bitten. Wenn die nicht kommt, geht's halt nicht
weiter.
m.n. schrieb:> Man kann zwar die Arduino-IDE verwenden, sollte aber tunlichst setup()> und loop() vermeiden, damit man alle Timer selbst benutzen kann.
Wieso soll man für vier LEDs mehr als zwei Timer benötigen?
Wolfgang schrieb:> Wieso soll man für vier LEDs mehr als zwei Timer benötigen?
Das frage ich mich auch.
Ich denke, es ist alles gesagt. Man muß es nur lesen.
m.n. schrieb:> Ich denke, es ist alles gesagt. Man muß es nur lesen.
Das sehe ich ganz anders. Mir fallen noch drölfzig Dinge ein, die noch
nicht gesagt wurden. Nur ein Beispiel:
Soll es wirklich so sein, daß ein Vierzylindermotor beobachtet werden
soll, sind zwei Hallsensoren an des Kurbelwelle die einfachste Lösung,
um das Timergeraffel zu umgehen. Also allgemein: soll ein externes Gerät
einsynchronisiert werden, ist ein Positionssensor an diesem Gerät eine
einfache Lösung.
Oder: Statt ArduinoIDE AtmelStudio verwenden, da hat weniger Probleme
mit den Seiteneffekten von Libraryroutinen.
Da der TO aber die unwichtigsten Kleinigkeiten
> Frequenz von 10.989Hz für ca 1.365 Sekunden, woraufhin ein einzelner Puls> mit 10.8695Hz folgt. Das ganze wiederholt sich zyklisch.
mit akribischer Genauigkeit darstellt, die wichtigen Aussagen aber nur
in homöopathischen Dosen rausrückt, können wir alle unserer
Liblingsbeschäftigung Spekulation mit Begeisterung nachkommen.
Vielleicht will er ja nur seine LEDstreifen-Treppenbeleuchtung so
programmieren, daß eventuell eintreffende Außerirdische ein geheimes
Willkommenssignal damit gesendet bekommen.
Nach meiner Vermutung (Spekulation!) ist schon die Eingangsfestlegung
(Frequenz je nach Wetterlage bis 30Hz oder 100Hz auf 2 Nachkommastellen
einstellbar) dem zu bearbeitenden Problem total unangemessen, aber der
TO "will" es so und verfollgt diesen Weg mit Begeisterung. Unzählige
Menschen haben schon versucht, aus Blei Gold zu machen oder endlich das
perpetuum mobile zu erfinden, warum denn nicht? Besser als mit dem
Porsche Rennen in der Stadt zu veranstalten und Fußgänger umzunieten.
Gruß Klaus (der soundsovielte)
Hier das gewünschte Programm mit 4 Kanal-DDS:
4 Outputs auf PB5 .. PB2, auf PB1 zum Test die DDS-Frequenz 31250 Hz
Hänge mal einen Lautsprecher an PB5 (D13)...
chromatische Tonleiter 220 - 440 Hz
D12 - D10 ändern anfangs (nach jedem Durchlauf der Tonleiter) ihre
Frequenz um -1,5, +1,5 und 2,0 Hz, just for fun, damit sich was ändert
Man müsste noch eine serielle Kommunikation dazuprogrammieren, um die
Frequenzen on the fly einstellen zu können.
1
//mikrocontroller.net/topic/537663
2
#define F_CPU 15995000.0
3
#define fre (F_CPU/2/256.0)
4
//15995000/2/256=31240,234375
5
#define kon (4294967296/fre)
6
//4294967296/31240,23=137481,935 DDS-Konstante für 1 Hz
MisterX schrieb:> while(1){> cli();if(t3.ub[3]&128)PORTB|=32;else PORTB&=~32;sei();> cli();if(t2.ub[3]&128)PORTB|=16;else PORTB&=~16;sei();cnt++;> cli();if(t1.ub[3]&128)PORTB|= 8;else PORTB&=~ 8;sei();> cli();if(t0.ub[3]&128)PORTB|= 4;else PORTB&=~ 4;sei();
Eine Sequenz sei(); cli(); ist wirkungslos, da nach dem SEI noch einen
Befehl lang alle Interrupts gesperrt sind, ein CLI aber sofort greift.
Dieses Verhalten ist z.B. wichtig für den Sleep-Mode, damit garantiert
ein Interrupt nicht schon vor dem Sleep-Befehl erfolgt.
Peter D. schrieb:> Eine Sequenz sei(); cli(); ist wirkungslos, da nach dem SEI noch einen> Befehl lang alle Interrupts gesperrt sind, ein CLI aber sofort greift.
"Again what learned" hätt' da Loddar g'sacht, gell ....
Einfach das Programm kopieren (Strg+C) und in die Arduino-IDE pasten
(Strg+V).
Braucht kein Framework, also setup() und loop() sind überflüssig.
Strg+U und los geht's
CPU-Auslastung ist messbar mit
DDRB = 32+16+8+4+2+1;PORTB = 0xFE;
und
ISR(TIMER1_OVF_vect){
PINB=1;t0.ul+=t0add;t1.ul+=t1add;t2.ul+=t2add;t3.ul+=t3add;PINB=1;}
ergibt bei mir 1,1V am Anschluss 8, d.h. nur 22% Auslastung.
Man könnte mit der IRQ-Frequenz noch höher gehen.
Ich habe den Teiler testweise mit 256 (31250 Hz @ 16MHz) gemacht, d.h.
man könnte auch einen 8-bit-Timer (Timer2) verwenden.
Die Frequenzauflösung ist jenseits von Gut und Böse: 7,27368 µHz
Der Frequenzbereich ebenfalls, 1kHz ist kein Problem, jittert aber schon
merklich.
Wichtig ist, dass die 4 Kanäle phasenstarr miteinander verbunden sind.
Nebenbei, es ist schon interessant, welche Anwendung (4-Zylinder-Motor)
hier ohne jeglichen Hintergrund vermutet wird.
Der Threadopener könnte ja mal etwas zur Anwendung sagen, vielleicht ist
es ja auch ganz was anderes.
> Eine Sequenz sei(); cli(); ist wirkungslos,
Stimmt, daher habe ich den cnt++ dazwischen reingesetzt, nachdem ich
mich am Anfang des Programmierens (als die cnt-Geschichte noch nicht
dastand) wunderte, dass plötzlich gar nichts mehr ging.
Also kann man die CPU-Last und den Jitter noch um ein paar Promille
reduzieren:
Veit D. schrieb:> sollte das nicht 16000000UL lauten?
Wer Quelltext-Kommentare lesen und verstehen kann ist klar im Vorteil.
// F_CPU is the frequency of MY arduino uno, change this number for YOUR
board
Das liegt an der ... timerone-Lib (timerone.h). Die glaubt nämlich, wenn
ich eine Quarzfrequenz geringfügig kleiner als 16MHz eingebe, der Quarz
hätte 14MHz und berechnet dann alle Faktoren falsch.
Schuld ist diese Zeile:
const unsigned long cycles = (F_CPU / 2000000) * microseconds;
Fällt natürlich nicht auf, da so gut wie immer 16MHz verwendet wird.
Ich will aber wirklich die vorhandene Oszillator-Frequenz eingeben
können, damit auch die richtige Frequenzen an den 4 Ausgängen
herauskommen.
Daher hatte ich zuerst die Lib lokal geändert, hat auch funktioniert.
const unsigned long cycles = round(F_CPU / 2000000.0 * microseconds);
Dann kam mir aber die Idee, dass ich das Dilemma umgehen kann, wenn ich
die Frequenz in Float (xx.0) angebe, die Lib gezwungen ist, alle
Folgeberechnungen in Float und damit richtig (ohne Abschneiden der
Nachkommastellen) zu berechnen.
Diese Berechnungen finden nicht auf dem UNO, sondern zur Compilezeit im
PC statt, da es sich um Konstanten handelt.
Daher verwenden die späteren Versionen die Lib gar nicht mehr, auch weil
über den Umweg, die Ticks über ganzzahlige Mikrosekunden zu berechen,
Genauigkeit verloren geht.
Hat schon jemand das Programm getestet?
Insgesamt bin ich schon froh, soetwas in C programmieren zu können, auf
der anderen Seite habe ich das Assembler-Listing angesehen und bin
erschrocken, wie ineffektiv (teilweise!) der Compiler das übersetzt. Da
kann ich jeden Asm-Fan (und c-hater ;-) verstehen. In der ISR werden 10
Register (+Statusregister) auf dem Stack gesichert und dann wieder
zurückgeholt, nur weil der Compiler zu doof ist, alle 4 Bytes der
32-bit-Variablen mit einem Register zu addieren. Oh oh.
So könnte man die ISR statt in 8µs leicht in unter 7µs erledigen.
Bei 32µs Zykluszeit eine Einsparung von 14%, die man besser in eine
höhere Abtastrate stecken könnte.
Bei den heutigen Preisen von 32bit-Hardware sollte man sich eigentlich
nicht mehr mit dem umständlichen 8bit-Kram abgeben. Aber er liegt
überall herum...
Die Spekulationen sind sehr interessant, aber einen Motor möchte ich
hier nicht betreiben. Es bleibt ein normales Stroboskop, das die
Frequenzen genauestens einhalten soll.
Was den Timer1 angeht, scheint es mir so als müsste ich ihn
initialisieren und dann bereits vorgefertigt einstellen.
Mit den Registern die Parameter auswählen, dann die Zeiten ausrechnen
und quasi im Bottom to Top loop laufen lassen.
Kann ich den Timer mit dem Programm im Nachhinein die Top-Werte
ausrechnen lassen? Bisher habe ich gedacht ich kann einfach den Timer,
der für das hochzählen in den millis() zuständig ist von einer 8 bit,
auf eine 16 bit Auflösung ändern.
Das es sich als so kompliziert herausstellt hätte ich auch nicht
erwartet. Vorhin habe ich noch kurz die Specs vom Arduino mit dem
raspberry pi Pico verglichen - der ist dem Uno ja haushoch überlegen. An
sich müsste der Arduino mit seinen 16MHz doch trotzdem meinen
Anforderungen gerecht werden oder bin ich da zu grün hinter den Ohren?
Thomas G. schrieb:> Die Spekulationen sind sehr interessant, aber einen Motor möchte ich> hier nicht betreiben. Es bleibt ein normales Stroboskop, das die> Frequenzen genauestens einhalten soll.
Kommt mir sehr komisch vor. Mir fällt nämlich keine Anwendung für ein
solches Stroboskop ein.
> Vorhin habe ich noch kurz die Specs vom Arduino mit dem> raspberry pi Pico verglichen - der ist dem Uno ja haushoch überlegen.
Ach echt?
16MHz vs. 125Mhz, 2kB RAM vs. 264kB RAM, 1x 8Bit-Core vs. 2x 32Bit-Core
(+8 PIO-Statemachines & DMA-Fähigkeit).
Also wen da eine gewisse Überlegenheit überrascht... Tss...
> An> sich müsste der Arduino mit seinen 16MHz doch trotzdem meinen> Anforderungen gerecht werden oder bin ich da zu grün hinter den Ohren?
Ja und ja. Genau das ist das Problem: die Hardware des UNO könnte noch
relativ problemlos leisten, was du willst. Du musst nur das
Arduino-Geraffel weglassen und anfangen, Datenblätter zu lesen und
richtig zu programmieren.
>> ... auf der anderen Seite habe ich das Assembler-Listing angesehen> und bin erschrocken, wie ineffektiv (teilweise!) der Compiler das> übersetzt
Mach's halt so:
MisterX schrieb:> if(t3.ub[3]&128)PORTB|=32;else PORTB&=~32;
> if(t2.ub[3]&128)PORTB|=16;else PORTB&=~16;> if(t1.ub[3]&128)PORTB|= 8;else PORTB&=~ 8;> if(t0.ub[3]&128)PORTB|= 4;else PORTB&=~ 4;
Die Abfragenn können nie wahr werden, weil die "interessanten" Bits
ausmaksiert werden.
Thomas G. schrieb:> Die Spekulationen sind sehr interessant, aber einen Motor möchte ich> hier nicht betreiben. Es bleibt ein normales Stroboskop, das die> Frequenzen genauestens einhalten soll.
Genauer als deine Taktquelle wird es nicht. Ein 08/15 Quarz hat
vielleicht 30ppm Fehler. Reicht das?
Die verschiedenen, per Software und DDS erzeugten Frequenzen haben
ZUEINANDER 0 Fehler, wenn man es richtig macht.
> Was den Timer1 angeht, scheint es mir so als müsste ich ihn> initialisieren und dann bereits vorgefertigt einstellen.> Mit den Registern die Parameter auswählen, dann die Zeiten ausrechnen> und quasi im Bottom to Top loop laufen lassen.
So in etwa, auch wenn eine mehrkanalige DDS anders funktioniert.
> Kann ich den Timer mit dem Programm im Nachhinein die Top-Werte> ausrechnen lassen? Bisher habe ich gedacht ich kann einfach den Timer,> der für das hochzählen in den millis() zuständig ist von einer 8 bit,> auf eine 16 bit Auflösung ändern.
Nö.
> Das es sich als so kompliziert herausstellt hätte ich auch nicht> erwartet.
Was hast du denn erwartet? Daß dir gebratene Tauben in den Mund fliegen?
> Vorhin habe ich noch kurz die Specs vom Arduino mit dem> raspberry pi Pico verglichen - der ist dem Uno ja haushoch überlegen.
Ja und?
"Everything is easy with the right tool. But a fool with a tool is still
a fool."
> An> sich müsste der Arduino mit seinen 16MHz doch trotzdem meinen> Anforderungen gerecht werden
Sicher.
> oder bin ich da zu grün hinter den Ohren?
Das bist du.
>> An>> sich müsste der Arduino mit seinen 16MHz doch trotzdem meinen>> Anforderungen gerecht werden oder bin ich da zu grün hinter den Ohren?
c-hater schrieb:
>Ja und ja. Genau das ist das Problem: die Hardware des UNO könnte noch>relativ problemlos leisten, was du willst. Du musst nur das>Arduino-Geraffel weglassen und anfangen, Datenblätter zu lesen und>richtig zu programmieren.
Nö, muss er nicht. Das hängt alles von der Fähgikeiten ab, mit C umgehen
zu können. Ich vermute, dir fehlt da ein wenig die notwendige Erfahrung.
Gerd schrieb:> Nö, muss er nicht. Das hängt alles von der Fähgikeiten ab, mit C umgehen> zu können.
Na das ist ja mal spannend. Was kann C, was es möglich machen könnte,
die Hardware für eine gegebene Anwendung optimal zu nutzen, ohne sie im
Detail zu kennen?
Also, ich kenne diesen C-Dreck seit nunmehr 40 Jahren, aber eine
derartige Fähigkeit ist mir in der gesamten Zeit NIEMALS aufgefallen.
Was mir allerdings nur zu oft aufgefallen ist: Wenn man C benutzt, hat
man bei der optimalen Nutzung einer gegebenen Hardware immer wieder mit
Restriktionen zu kämpfen, die es ohne C schlicht nicht gäbe.
c-hater schrieb:> diesen C-Dreck
Die alte Leier, wir können es nicht mehr hören.
Wenn jemand diese Aufgabe nicht lösen kann, dann liegt es ganz sicher
nicht an C. Wenn du das nur in Assembler hin bekommst, dann hast du
ein ernsthaftes Problem.
Der einzige, der gegen C kämpft bist du. Alle anderen arbeiten damit,
oder mit etwas anderem. Diese Spinnerei von dir wird von Monat zu Monat
schlimmer.
Stefan ⛄ F. schrieb:> Wenn jemand diese Aufgabe nicht lösen kann, dann liegt es ganz sicher> nicht an C.
Im konkreten Fall nicht, da gebe ich dir vollkommen Recht.
Allerdings: ICH habe auch zu keinem Zeitpunkt behauptet, das hier C
das Problem wäre... Wenn du auch nur LESEN könntest, wäre dir das
klar. Aber: kannst du offensichtlich nicht. Nichtmal das...
> von foobar (Gast) 31.05.2022 18:33
VIELEN Dank, dass Du Dich da reingefuxt hast!
Hab es gleich implementiert. Funktioniert!
20 Bytes kürzer und schneller. Man muss nur die richtigen Tricks kennen.
Wie erzeugst Du das ASM-Listing?
ich mache es mit
"c:\Program Files (x86)\Arduino\hardware\tools\avr\avr\bin\objdump.exe"
-d -S genaueFreq.ino.elf >genFre.lst
schaut aber nicht so schön aus wie Deines
Damit das elf-File erhalten bleibt, muss man in
C:\Users\xxx\AppData\Local\Arduino15\preferences.txt
einen Eintrag ähnlich save-temps ?? oder keep-temps ?? machen, müßte ich
nachschauen.
So lernt jeder vom anderen. Geben und nehmen. Nur so funktioniert es.
Deshalb habe ich diesen Code entwickelt und veröffentlicht.
> von STK500-Besitzer (Gast) 31.05.2022 18:42> Die Abfragenn können nie wahr werden, weil die "interessanten"> Bits ausmaksiert werden.
?!?
Es gibt pro Zeile ein interessantes Bit, und das ist bit7 (MSB) des
höchstwertigen Bytes byte3 des jeweiligen Phasenakkumulators t_.
(ich hätte ihn anderes benennen sollen, pa_ oder a_).
Und das wird nicht ausmaskiert, sondern ausgewertet.
Ich war dann mal wieder so frei, das mal schnell zu demonstrieren. Siehe
Anhang. Einmal mit 10, 20, 30, 40Hz, dann mit 10Hz und 0, 90, 180 und
270 Grad Phasenverschiebung. Viel Spaß.
MisterX schrieb:> So lernt jeder vom anderen. Geben und nehmen. Nur so funktioniert es.> Deshalb habe ich diesen Code entwickelt und veröffentlicht.
Naja, aber dein Code ist arg chaotisch und schwer lesbar, kein gutes
Lehrbeispiel.
MisterX schrieb:> So lernt jeder vom anderen. Geben und nehmen. Nur so funktioniert es.> Deshalb habe ich diesen Code entwickelt und veröffentlicht.
Schön, daß Du es gemacht hast. Es ist aber auch eine "selektive" Lösung,
da das Tastverhältnis nicht auf kurzen Blitz einstellbar ist. Das ist
für ein Stroboskop unabdingbar.
Es wird auch dadurch nicht besser, daß einige Anwender durch
Umdefinition der Anforderungen eine nachlässige Lösung als ausreichend
anbieten.
Thomas G. schrieb:> Vorhin habe ich noch kurz die Specs vom Arduino mit dem> raspberry pi Pico verglichen - der ist dem Uno ja haushoch überlegen.
Als Anfänger solltest Du die Finger von dem Pico lassen, wenn Du schon
Probleme mit einem AVR8 hast.
MisterX schrieb:> Es gibt pro Zeile ein interessantes Bit, und das ist bit7 (MSB) des> höchstwertigen Bytes byte3 des jeweiligen Phasenakkumulators t_.> (ich hätte ihn anderes benennen sollen, pa_ oder a_).> Und das wird nicht ausmaskiert, sondern ausgewertet.
Mein Fehler.
Aber: Leerzeichen, Tabulatoren und Absätze erhöhen die Lesbarkeit.
Ansonsten könnte man in diesem Fall auch statt einer if-Abfrage "?:"
verwenden.
Falk B. schrieb:> Die verschiedenen, per Software und DDS erzeugten Frequenzen haben> ZUEINANDER 0 Fehler, wenn man es richtig macht.
Das hatte ich auch so heraus gelesen. Es ging nie um eine hohe absolute
Genauigkeit, sondern nur darum, daß sich die Fehler nicht akkumulieren
und die Signale auseinander laufen.
Man könnte der AVR also auch gut mit seinem internen 8MHz RC-Oszillator
laufen lassen und der OP wäre glücklich.
Ich sehe auch nirgends die Anforderung, daß ein Parameterwechsel
besonders oft oder schnell erfolgen muß. Man kann also neue Frequenzen
bequem über die langsame UART hinschicken, parsen und die neuen
Parameter berechnen lassen. Ist das erfolgt, switcht man die Ausgabe
einfach auf den neuen Parametersatz um.
m.n. schrieb:> Als Anfänger solltest Du die Finger von dem Pico lassen, wenn Du schon> Probleme mit einem AVR8 hast.
Da stimme ich zu…
… außer wenn er (als ausgewiesener Anfänger) ein microPython drauf
schiebt.
(Tastendruck, UF2 drag'n'drop, fertig)
Dann hätte er (ein wenig Python Grundwissen vorausgesetzt) das Programm
schon lange fertig, ohne Interrupts, Assembler, usw.
Denn ein ganzer Sack voller PWM-Slices (8) stehen zur Verfügung, müssen
nur einmal initialisiert werden, dann läuft das Ding ganz ohne CPU
Interaktion. Rein in Hardware. Der CPU-Kern muss nichts tun. (Der andere
auch nicht.)
Gut, ein Nachteil wäre das er nun nicht nur vier sondern acht
unabhängige Kanäle hätte.
Ein weiterer Nachteil, das Board ist mit sub-4€ preiswerter als so
ziemlich alle Arduino Boards.
Decisions, decisions…
Norbert schrieb:> Denn ein ganzer Sack voller PWM-Slices (8) stehen zur Verfügung, müssen> nur einmal initialisiert werden, dann läuft das Ding ganz ohne CPU> Interaktion. Rein in Hardware.
Das sagt sich immer so leicht und jedesmal, wenn ich den konkreten Code
dazu sehen will, wird gekniffen ;-)
Da die PWM-Kanäle doch recht bescheidene Funktion bieten, wäre meine
Lösung die Verwendung der PIOs, wenn man hohe Auflösung und lange Zeiten
braucht. Aber, um eine SM ein Signal erzeugen zu lassen, muß man sich
zunächst damit auskennen und die passenden x-/y-Register wohl per DMA
nachladen.
Das wäre eine kurze, saubere Lösung und - wie gesagt - ein Selbstläufer,
aber nichts für einen Anfänger.
Solange hier aber Zittersignale mit 50% Tastverhältnis als DIE Lösung
gehandelt werden, muß man nicht einmal Code für die AVR-Timer andenken.
m.n. schrieb:> Norbert schrieb:>> Denn ein ganzer Sack voller PWM-Slices (8) stehen zur Verfügung, müssen>> nur einmal initialisiert werden, dann läuft das Ding ganz ohne CPU>> Interaktion. Rein in Hardware.>> Das sagt sich immer so leicht und jedesmal, wenn ich den konkreten Code> dazu sehen will, wird gekniffen ;-)> Da die PWM-Kanäle doch recht bescheidene Funktion bieten, wäre meine> Lösung die Verwendung der PIOs, wenn man hohe Auflösung und lange Zeiten> braucht. Aber, um eine SM ein Signal erzeugen zu lassen, muß man sich> zunächst damit auskennen und die passenden x-/y-Register wohl per DMA> nachladen.> Das wäre eine kurze, saubere Lösung und - wie gesagt - ein Selbstläufer,> aber nichts für einen Anfänger.>> Solange hier aber Zittersignale mit 50% Tastverhältnis als DIE Lösung> gehandelt werden, muß man nicht einmal Code für die AVR-Timer andenken.
Nö, das sagt sich nicht leicht, das iss so.
1
#!/usr/bin/python3
2
3
frommachineimportPin,PWM,mem32,freq
4
5
freq(16_000_000)
6
7
LED=Pin(25)
8
pwm=PWM(LED)# Pin 25 ist auf Channel 4 B
9
pwm.freq(10)
10
pwm.duty_u16(2**15)
11
# Nu blinkt's schon
12
13
# Bis hier alles einfach, ab hier wird's schrecklich kompliziert.
14
# Man muss nämlich ins Datenblatt schauen
15
16
divint=0# 1…255 teilt durch 1…255 0 teilt durch 256
mem32[PWM_BASE+CH4_CC]=topvalue<<16# LED ist auf Channel B
Das ist jetzt völlig ohne Jitter, aber manche Frequenzen sind nicht
präzise zu erreichen. Im genannten Frequenzbereich 1…30Hz liegen wir
teilweise mehrere 10µHz daneben.
Wenn man nun den divfrac hinzunimmt, dann gibt es 16-fach feinere
Auflösung, aber dafür extrem geringen Jitter im ns Bereich.
Gern geschehen. ;-)
Stefan ⛄ F. schrieb:> Der einzige, der gegen C kämpft bist du. Alle anderen arbeiten damit,> oder mit etwas anderem. Diese Spinnerei von dir wird von Monat zu Monat> schlimmer.
Also, polemisiere du mal nicht gar so sehr. Dabei kommt schlußendlich
nur eines heraus: daß du außer C nix anderes kannst und deshalb gegen
alle Leute wetterst, die auch andere Programmiersprachen können.
Mal zur Sachlage: sogenannte 'höhere' Programiersprachen sind dazu da,
daß man sich damit auf Dinge konzentrieren kann, die keinen Bezug zur
verwendeten Hardware haben. Zum Beispiel wie man eine
Fouriertransformation macht oder wie man eine Datenbank auswertet. Dabei
bleiben selbstverständlich viele Möglichkeiten ungenutzt, die die
verwendete Hardware bietet. Eben deshalb gibt es an vielen Stellen
bessere Lösungen für bestimmte Details, als so etwas in einer 'höheren'
Programmiersprache formulieren zu wollen. Ich geb dir mal ein simples
Beispiel anhand eines Details bei der FFT: versuche mal, einen 8
bittigen Index zu spiegeln, also Bit 7 mit Bit 0 tauschen, dann Bit 6
mit Bit 1 und so weiter, bis alle Bits getauscht sind. Und das in C.
Sowas in Assembler ist vergleichsweise elegant und braucht nur wenige
Maschinenbefehle. Siehste.
Und nochwas: Man kann C auch nutzen und zugleich sich darüber klar sein,
daß diese Programmiersprache eben nicht das Weltbeste ist, sondern
allenfalls das einzige, wofür man einen passablen Compiler kriegt. Man
braucht also kein C-Fan zu sein.
W.S.
m.n. schrieb:> … wäre meine> Lösung die Verwendung der PIOs, wenn man hohe Auflösung und lange Zeiten> braucht. Aber, um eine SM ein Signal erzeugen zu lassen, muß man sich> zunächst damit auskennen und die passenden x-/y-Register wohl per DMA> nachladen.
Geht auch super, aber DMA ist nicht nötig. Nur FIFO.
Sinngemäß:
1
Hat FIFO neuen Wert?
2
Ja: Ins Y-Register damit
3
4
Y nach X transferieren
5
Schleife: Runterzählen bis 0
6
Pin toggeln
7
8
Y nach X transferieren
9
Schleife: Runterzählen bis 0
10
Pin toggeln
11
Zurück auf Start (keine 4000€ einziehen)
Aber ich gebe dir Recht, PIO Programmierung ist nichts für Beginner.
Neues Problem erkannt:
acht Mal PWM und acht Mal PIO. Alle völlig unabhängig.
Jetzt müssen wir schon 16 Pins ackern lassen wo doch nur vier gefragt
waren. ;-)
Norbert schrieb:> m.n. schrieb:>> Norbert schrieb:>>> Denn ein ganzer Sack voller PWM-Slices (8) stehen zur Verfügung, müssen>>> nur einmal initialisiert werden, dann läuft das Ding ganz ohne CPU>>> Interaktion. Rein in Hardware.>>>> Das sagt sich immer so leicht und jedesmal, wenn ich den konkreten Code>> dazu sehen will, wird gekniffen ;-)>> Nö, das sagt sich nicht leicht, das iss so:
Schick!
LG, Sebastian
Mit anderen Masken wären sogar Blinkmuster einstellbar.
Die cli() und sei() sind gar nicht nötig, weil es nur 8-bit-Zugriffe
sind, keine breiteren, die beim 8-Bitter eine Atomisierung erfordern
würden.
Während der ISR sind Interrupts ja gesperrt (falls man sie nicht
explizit freigibt).
Dass ich diese Abfragen in der main mache und nicht im IRQ wie Falk?
Gute Frage! Ich dachte zuerst, dass die ISR möglichst kurz sein sollte.
Ist aber nicht nötig, da sonst ja nichts Zeitkritisches zu tun ist.
Ein kleiner Vorteil könnte Dithering sein, wenn die Ausgänge aynchron
gesetzt werden.
Danke an alle Beitragenden! Wieder viel gelernt.
Norbert schrieb:> Jetzt müssen wir schon 16 Pins ackern lassen wo doch nur vier gefragt> waren. ;-)
Nur bin ich mit Deinem Vorschlag noch nicht ganz zufrieden ;-)
Gut, bei den PWM-Timern kann man zumindest schon mal das Tastverhältnis
einstellen (PWM->CHx_CC anpassen). Der Bereich von >= 60000 erfüllt auch
die Vorgaben des TO für max. 4-stellige Auflösung.
Dein PIO-Programm löst die Frequenz deutlich besser auf, erzeugt aber
wiederum nur 50% Tastverhältnis. Um das zu beheben, müssen x- und
y-Register separat für Pulse-Pause-Zeiten verwendet werden. Da es so
kein freies temp-Register gibt, müssen beide Werte zyklisch per DMA
nachgeladen werden.
Dies läuft dann natürlich sehr elegant, die Auflösung der Impulse kann
selbst bei schlapper 100 MHz Taktfrequenz auf 10 ns genau erzeugt werden
und es wäre eine universelle Lösung auch für höhere Auflösungen und
Frequenzen!
Damit wäre ich dann zufrieden ;-)
m.n. schrieb:> Gut, bei den PWM-Timern kann man zumindest schon mal das Tastverhältnis> einstellen (PWM->CHx_CC anpassen). Der Bereich von >= 60000 erfüllt auch> die Vorgaben des TO für max. 4-stellige Auflösung.
Auf den ersten Blick…
Jedes PWM-Slice kann separat getaktet werden. Damit stehen
DIV 1…255 FRAC 0…15 und TOP 0…65535 zur Verfügung.
8Bit + 4Bit + 16Bit == 28Bit Auflösung
2^28 ~= 268 Millionen mögliche Einstellungen
Allein der Bereich um 1Hz…30Hz schmeißt mir hundert-tausende von
Kombinationen die mit beeindruckender Präzision passen.
Nur mal ein Beispiel:
16MHz ÷ 256 ÷ 2083 ergibt 30,004800768Hz
16MHz ÷ 256 ÷ 2083 ergibt 29,990403071Hz
16MHz ÷ 255 ÷ 2091 ergibt 30,007220487Hz
16MHz ÷ 255 ÷ 2092 ergibt 29,992876692Hz
Lass das mal für alle möglichen Teilerkombination durchrechnen (geht auf
dem pico pi ohne das er kotzen muss)
Das ergibt dann schon mal eine ordentliche Hausnummer. Da nimmt man
einfach die Werte mit der geringsten Abweichung (µHz).
Ohne Jitter!
Wenn wir dann noch FRAC dazu nehmen wird's 16 mal interessanter.
Oh ja, wenn ich dann noch acht Frequenzen von der PIO generieren lasse
und damit die PWMs takte… Also zB. anstatt 16MHz nur 15.999998MHz…
Aber man kann's mit der Genauigkeit auch übertreiben, ab hier wird's
lächerlich.
Norbert schrieb:> Aber man kann's mit der Genauigkeit auch übertreiben, ab hier wird's> lächerlich.
Das nehme ich hiermit zurück. Ist nämlich bestens geeignet um eventuelle
Quarz-Abweichungen direkt mit einzumassieren. ;-)
m.n. schrieb:> Norbert schrieb:>> 2^28 ~= 268 Millionen mögliche Einstellungen>>> 16MHz ÷ 256 ÷ 2083 ergibt 30,004800768Hz>> 16MHz ÷ 256 ÷ 2083 ergibt 29,990403071Hz>> Und welche davon ist richtig?> ;-)
Ja, Tippfeuler. die erste 2082 ist natürlich eine 2082.
Das sieht man doch! ;-)
PS. zwischen 1Hz…30Hz gibt es 231117804 mögliche Kombinationen.
Ich rechne gerad' mal alle durch, wer mag bekommt ein log. Sollte nicht
so groß werden, har,har.
W.S. schrieb:> Dabei kommt schlussendlich nur eines heraus:> dass du außer C nix anderes kannst
Niedlich, nur leider völlig falsch.
> Und nochwas: Man kann C auch nutzen und zugleich sich darüber klar sein,> dass diese Programmiersprache eben nicht das Weltbeste ist, sondern> allenfalls das einzige, wofür man einen passablen Compiler kriegt. Man> braucht also kein C-Fan zu sein.
Da stimme ich dir voll zu. Deswegen nervt mich das Gehabe vom c-hater
so.
Norbert schrieb:> Irgendwann ist der Wurm drin, mach am Besten selbst… ;-)> Datei wird ein paar GB groß!
Und was soll der Unsinn? Die Auflösung einer DDS kann man einfach
ausrechnen, da braucht man keine GB großen Dateien.
Auflösung = Fein / (Akkumulatormaximum+1)
Falk B. schrieb:> Und was soll der Unsinn? Die Auflösung einer DDS kann man einfach> ausrechnen, da braucht man keine GB großen Dateien.> Auflösung = Fein / (Akkumulatormaximum+1)
Du meine Güte.
Jo! Haben wir alle verstanden. Ist auch nicht wirklich schwer.
Ich entgegne da: Infinity
So weit bis du davon entfernt zu verstehen um was es uns eigentlich
ging.
Und das ist noch überaus großzügig geschätzt.
Aber schön das du etwas gesagt hast.
Stefan ⛄ F. schrieb:> Niedlich, nur leider völlig falsch.
Nana, sowas kann jeder behaupten. Das klingt für mich wie ein kindliches
"DOCH".
Nun ja, damit sind wir schon fast vom ursprünglichen Arduino-Problem
abgekommen. Aber auch hier zeigt sich eben genau DAS, was du mit deiner
Antwort unbeabsichtigt zeigst. Wenn man bislang nur fertige
Arduino-Funktionen wie z.B. millis() kennengelernt hat und noch keine
Gedanken über eigene Vorgehensweisen/Algorithmen gedacht hat, dann
verheddert man sich eben in diesen vorgefertigten Dingen und kommt nicht
zum eigentlichen Ziel. Dasselbe gilt auch für "bloß keine mir
unverständlichen (magischen) Zahlen, ich benutze nur Identifier, die mir
jemand anderes vorgekaut hat" - um mal ein relativ junges Thema nochmal
zu nennen.
W.S.
m.n. schrieb:> Dein PIO-Programm löst die Frequenz deutlich besser auf, erzeugt aber> wiederum nur 50% Tastverhältnis. Um das zu beheben, müssen x- und> y-Register separat für Pulse-Pause-Zeiten verwendet werden. Da es so> kein freies temp-Register gibt, müssen beide Werte zyklisch per DMA> nachgeladen werden.
Hat mir keine Ruhe gelassen. ;-)
Ich glaube das geht trotzdem völlig ohne DMA.
Zwei Statemachines agieren auf dem selben Pin.
Statemachine0 bekommt die volle Periodenlänge in den FIFO gestopft
Statemachine1 bekommt die Zeit für den On-Teil in den FIFO gestopft
1
Statemachine0:
2
Hat FIFO neuen Wert?
3
Ja: Ins Y-Register damit
4
IRQ Clear 0
5
SET Pin High
6
Y nach X transferieren
7
Schleife0:
8
JMP X-- Schleife0
9
JMP Statemachine0
10
11
Statemachine1:
12
Hat FIFO neuen Wert?
13
Ja: Ins Y-Register damit
14
IRQ Wait 0
15
Y nach X transferieren
16
Schleife1:
17
JMP X-- Schleife1
18
SET Pin Low
19
JMP Statemachine1
SM0 ist sozusagen der Master
setzt den Pin am Anfang auf High
löscht das PIO-IRQ Flag für SM1
zählt herunter
und hechtet zum Anfang.
SM1 hängt im Lauerzustand
wartet auf PIO-IRQ Freigabe
läuft dann geringfügig versetzt (paar Nanosekunden) los, (xxx)
zählt herunter
schaltet nach On-Periode den Pin auf Low,
und hechtet zum Anfang.
(xxx) Alles noch'n bisschen mit [delay] abgleichen/synchronisieren und
fertig.
Bei schlappen 200MHz erreichen wir präzise 5ns Auflösung.
Norbert schrieb:> Ich glaube das geht trotzdem völlig ohne DMA.> Zwei Statemachines agieren auf dem selben Pin.
Das kann ja jeder, aber bei vier Kanälen wären beide PIOs voll
verwurschtelt. Das gefällt mir nicht!
Lieber nur eine PIO und ein Programm, mit dem alle vier SMs gleichzeitig
laufen.
Norbert schrieb:> Bei schlappen 200MHz erreichen wir präzise 5ns Auflösung.
Und diese Auflösung gibt es eben ohne Jitter. Mir ist eine konstante
Kurzzeitstabilität lieber, als eine vermeintlich auf >= acht Stellen
genaue Frequenz. Der lokale 12 MHz Quarzoszillator taugt auch
abgeglichen sowieso nur für max. 6-stell. Genauigkeit.
W.S. schrieb:> Nun ja, damit sind wir schon fast vom ursprünglichen Arduino-Problem> abgekommen.
Das war doch aber auch schon ausgereizt: 2 x Timer mit je 2 x
OCRx-Ausgängen liefert beste Ergebnisse.
von Norbert (Gast)
01.06.2022 09:44
>m.n. schrieb:>> Als Anfänger solltest Du die Finger von dem Pico lassen, wenn Du schon>> Probleme mit einem AVR8 hast.>Da stimme ich zu…
Ich aber nicht. Mit dem Arduino-Framework ist das so ziemlich egal,
welche Komplexität eines Prozessors darunter liegt.
W.S. schrieb:> Ich geb dir mal ein simples> Beispiel anhand eines Details bei der FFT: versuche mal, einen 8> bittigen Index zu spiegeln, also Bit 7 mit Bit 0 tauschen, dann Bit 6> mit Bit 1 und so weiter, bis alle Bits getauscht sind. Und das in C.> Sowas in Assembler ist vergleichsweise elegant und braucht nur wenige> Maschinenbefehle. Siehste.
Veit D. schrieb:> Gut genug?
Was ist daran gut? Es funktioniert, mehr nicht. Aber es ist halt nicht
sonderlich schnell. Also entweder über ne 256er Tabelle oder per Inline
Assembler die Bits tauschen, macht 8 Bit Load/Store Befehle und 16 Takte
auf dem AVR.
Hallo,
okay, Flash hat man meistens genug zur Verfügung. Assembler ist nicht
mein Fachgebiet. ;-) Ich würde dann eher zur Tabelle greifen. Habe nur
gelesen das es in Assembler ein Shift mit Carry Bit gibt was dafür
genutzt wird.
Gerd schrieb:>>Da stimme ich zu…>> Ich aber nicht. Mit dem Arduino-Framework ist das so ziemlich egal,> welche Komplexität eines Prozessors darunter liegt.
Darum setzen sich Autofahrer in einen A320 ('A' für Arduino) und fliegen
einfach los ;-)
Du kannst Dir gerne etwas zusammenklicken, was PIO und DMA benutzt.
Ohne deren Funktion verstanden zu haben, wird aber nichts Brauchbares
dabei herauskommen - insbesondere wenn es zeitkritisch ist.
Und wenn man die Funktion verstanden hat, ist Arduino da eher im Weg. .
>Gerd schrieb:>>>Da stimme ich zu…>>>> Ich aber nicht. Mit dem Arduino-Framework ist das so ziemlich egal,>> welche Komplexität eines Prozessors darunter liegt.>Darum setzen sich Autofahrer in einen A320 ('A' für Arduino) und fliegen>einfach los ;-)>Du kannst Dir gerne etwas zusammenklicken, was PIO und DMA benutzt.>Ohne deren Funktion verstanden zu haben, wird aber nichts Brauchbares>dabei herauskommen - insbesondere wenn es zeitkritisch ist.
Ja, wird hier aber nicht gebraucht, weil das Problem auch ohne PIO und
DMA mit der Geschwindigkeit des PiPico zu lösen ist.
Es ist ähnlich wie sich ins Knie schießen: Kann man machen, muss man
aber nicht.
> W.S. schrieb:> versuche mal, einen 8 bittigen Index zu spiegeln,> also Bit 7 mit Bit 0 tauschen, dann Bit 6> mit Bit 1 und so weiter, bis alle Bits getauscht sind.> Veit D. schrieb:> … C-code …> Gut genug?
1
#!/usr/bin/python3
2
fromrp2importPIO,asm_pio,StateMachine
3
4
@asm_pio(set_init=rp2.PIO.OUT_LOW)
5
defbitreverse():
6
wrap_target()# 0 Anfang
7
pull(block)# 1 Warte auf FIFO, dann FIFO in OSR
8
mov(isr,reverse(osr))# 1 Bitwise reverse OSR in ISR
9
push(block)# 1 ISR in FIFO
10
wrap()# 0 Schleife zum Anfang
11
12
# Standardfrequenz bei microPython ist 125 MHz (8 ns)
13
# Auf dieser Frequenz laufen auch die SMs (oder langsamer falls gewünscht)
14
# Eine bitreverse() Operation dauert 3 Zyklen á 8ns
15
16
sm=StateMachine(0,bitreverse)
17
sm.active(True)
18
19
value=0b_10000000_11000000_00000111_00001111
20
print(f'{value:032b}')
21
22
# Auf Assembler-Ebene wären das eine 32bit Schreiboperation
23
# ein oder zwei NOPs und eine 32bit Leseoperation
24
value=sm.get(sm.put(value))
25
26
print(f'{value:032b}')
27
sm.active(False)
$ picorun pico_pio_bitreverse.py
10000000110000000000011100001111
11110000111000000000001100000001
32bit in 24ns
Gut genug? ;-)
Norbert schrieb:> $ picorun pico_pio_bitreverse.py> 10000000110000000000011100001111> 11110000111000000000001100000001>> 32bit in 24ns> Gut genug? ;-)
Schön. Wenn das jetzt noch bitte jemand in Assembler für AVR zeigt wäre
schön. :-)
Veit D. schrieb:> Wenn das jetzt noch bitte jemand in Assembler für> AVR zeigt wäre schön.
Dem AVR fehlen die dazu nötigen Befehle - zumindest wenn es elegant
werden soll. Ich brauchte das mal in einer Anwendung mit 8 Bits, dafür
habe ich eine Übersetzungstabelle (array im RAM) genommen.
Stefan ⛄ F. schrieb:> Dem AVR fehlen die dazu nötigen Befehle - zumindest wenn es elegant> werden soll.
Was ist an normalem Assembler unelegant? Weil es nicht mit einem
Super-Duper-DSP Befehl geht?
> Ich brauchte das mal in einer Anwendung mit 8 Bits, dafür> habe ich eine Übersetzungstabelle (array im RAM) genommen.
Im Flash wäre es sinnvoller gewesen, der "Nachteil" des 1 extra Taktes
für den Lesezugriff (lpm) wohl zu verschmerzen.
Falk B. schrieb:> Was ist an normalem Assembler unelegant?
Probiere es aus, dann siehst du es. Der Lookup mittels Tabelle ist im
Schnitt mehr als 8x so schnell, wie eine Berechnung.
Falk B. schrieb:> Im Flash wäre es sinnvoller gewesen, der "Nachteil" des 1 extra Taktes> für den Lesezugriff (lpm) wohl zu verschmerzen.
In meinem Fall nicht, denn da kam es sehr auf Performance an. War schon
scheiße genug, dass der Hersteller der Platine den Ethernet Controller
"Spiegelverkehrt" angebunden hat. Sämtliche Kommunikation musste durch
diesen Konverter laufen.
Stefan ⛄ F. schrieb:> Leider ziemlich unkonkret, wie soll das dem TO helfen? Und wie machst du> damit exakt 37 Hz?
Naja man könnte sich mit einem Controller beschäftigen, auf die
mitgelieferten Bibliotheken weitestgehend verzichten und sich was
Eigenes schreiben. Das macht Anfangs natürlich mehr Arbeit, es gibt
Tiefschläge etc., aber man lernt auch so einiges und ist in Zukunft eben
nicht mehr auf fertige Bibliotheken angewiesen.
Und man sollte auch mal seine Anforderungen überdenken. Um ne LED
blinken zu lassen braucht es ganz bestimmt keinen Quarzoszillator.
Veit D. schrieb:> Norbert schrieb:>> $ picorun pico_pio_bitreverse.py>> 10000000110000000000011100001111>> 11110000111000000000001100000001>>>> 32bit in 24ns>> Gut genug? ;-)>> Schön. Wenn das jetzt noch bitte jemand in Assembler für AVR zeigt wäre> schön. :-)
Siehe Anhang, nix besonderes.
Stefan ⛄ F. schrieb:> Falk B. schrieb:>> Was ist an normalem Assembler unelegant?>> Probiere es aus, dann siehst du es. Der Lookup mittels Tabelle ist im> Schnitt mehr als 8x so schnell, wie eine Berechnung.
Das wage ich zu bezweifeln. Weder in C noch ASM. Außer man vergurkt es
total. Aber das geht immer.
>> Im Flash wäre es sinnvoller gewesen, der "Nachteil" des 1 extra Taktes>> für den Lesezugriff (lpm) wohl zu verschmerzen.>> In meinem Fall nicht, denn da kam es sehr auf Performance an.
Kann sein, muss nicht. Denn die Leistung ist die Summer aller
Bearbeitungsschritte, nicht nur der eine.
Falk B. schrieb:> Siehe Anhang, nix besonderes.
Das Gute daran ist, man braucht keine Stoppuhr um die Ausführungszeit zu
bestimmen.
Ein Abreißkalender reicht völlig aus. ;-)
Falk B. schrieb:> Veit D. schrieb:>> Schön. Wenn das jetzt noch bitte jemand in Assembler für AVR zeigt wäre>> schön. :-)>> Siehe Anhang, nix besonderes.
Danke.
Gerd schrieb:> Und hier noch ein Beitrag der Musikwissentschaften zum Thema Arduino IDE> und Assembler.
Nochmal schnell auf den Kalender geschaut:
1. April ist heute nicht, aber immerhin Freitag.
Gerd schrieb:> Und hier noch ein Beitrag der Musikwissentschaften zum Thema> Arduino IDE und Assembler.
Leider alles Makulatur: Dem TO war der ganze Tinnef zu viel und hat sich
folglich vor einer Woche verpisst.
Viel Spaß noch beim euphorischen Fäzes-Konfundieren - ihr schafft das
schon!
Jester schrieb:> Leider alles Makulatur: Dem TO war der ganze Tinnef zu viel und hat sich> folglich vor einer Woche verpisst.
Nein ich bin noch da. Die Beiträge und entstandene Diskussionen sind
unterhaltsam und interessant, helfen mir bei meinem Problem nur leider
nicht so sehr.
Die letzten Tage hatte ich generell wenig Zeit, mich damit zu befassen.
Gestern sind noch mein kleines Display und der Drehregler angekommen die
ich bestellt habe. Zwar könnte ich jetzt anfangen ein Auswahl-Menü zu
schreiben, stecke aber nach wie vor mit dem Zeitzähler-Problem fest.
Thomas G. schrieb:> stecke aber nach wie vor mit dem Zeitzähler-Problem fest.
Seltsam. Ich hatte den Eindruck das dein Problem sowohl für einen AVR in
C/C++ als auch für einen RP2040 in Python gelöst worden wäre.
Beide Male mit einer Präzision welche weit über deinen Wünschen liegt.
Norbert schrieb:> Thomas G. schrieb:>> stecke aber nach wie vor mit dem Zeitzähler-Problem fest.> Seltsam. Ich hatte den Eindruck das dein Problem sowohl für einen AVR in> C/C++ als auch für einen RP2040 in Python gelöst worden wäre.> Beide Male mit einer Präzision welche weit über deinen Wünschen liegt.
Genau. Das ist so'n typischer Blindflansch, der nur eins akzeptiert:
genau die perfekte Lösung seines Problems und die muss dann auch noch so
gestaltet sein, dass er sie versteht...
Blöd nur, dass er absolut keine Ahnung von irgendwas hat. Das macht es
einigermaßen schwierig, seine Anforderungen zu erfüllen...
Wahrscheinlicher ist allerdings sowieso: Ist nur ein Traffic-Troll...
D.h.: es geht überhaupt nicht um ein Problem oder eine Lösung dafür,
sondern allein darum, Traffic im Forum zu erzeugen.
Der Troll mag's, der Forenbetreiber mag's auch. Genau das ist das
Problem. Wäre die Interessenlage des Betreibers anders, würden derzeit
mindestens 95% der neuen Threads direkt gecancelt werden können.
Allerdings würde das Forum dann ganz_offensichtlich genauso tot
aussehen, wie es effektiv sowieso ist. Garnicht gut für die
Werbeeinnahmen des Betreibers...
Falk B. schrieb:> Wirklich? Oder sind nur die sinnvollen Beiträge im Rauschen des> Wahnsinns untergegangen?>> Beitrag "Re: Arduino Timerprobleme - suche programmierbaren Oszillator"
Ups, ja sind sie. Danke dir :) Den Code muss ich jetzt erstmal studieren
und verstehen.
c-hater schrieb:> Blöd nur, dass er absolut keine Ahnung von irgendwas hat. Das macht es> einigermaßen schwierig, seine Anforderungen zu erfüllen...
Sorry :)
Uwe K. schrieb:> Brauchst Du einen einstallbaren Taktgeber mit einem 50:50 Verhältnis?>> Oder soll pro Takt ein kurzer Impuls ausgegeben werden ?
Pro Takt soll ein kurzer Impuls ausgegeben werden. Das habe ich in
meinem Code mit einem doppelten Takt realisiert, für jeden Profi hier
warscheinlich viel zu umständlich
> Pro Takt soll ein kurzer Impuls ausgegeben werden.
Wieviel ist ein "kurz" in ms?
Beim Takt gehe ich von der einstellbaren Frequenz zwischen 1,00 Hz und
30.00 Hz aus. Ist 4,00 Hz bis 30,00 Hz auch OK?
Und es ist auch nur ein PIN der geschaltet wird?
Uwe K. schrieb:> Wieviel ist ein "kurz" in ms?
Das ist doch völlig wurscht!
Mit einem AVR-Timer kann man separate Pulszeiten für '1' und '0' Pegel
generieren und nach Bedarf einstellen.
http://mino-elektronik.de/Generator/takte_impulse.htm#bsp2
Hier wird beispielsweise mit einem ATtiny4313 ein Signal mit 0,01 Hz -
50 kHz erzeugt, dessen Pulsweite im Bereich von 5 µs - 10 s mit
Auflösung 50 ns per RS232 einstellbar ist.
ISR(TIMER1_COMPB_vect) erledigt die Pulserzeugung.
c-hater schrieb:> Wahrscheinlicher ist allerdings sowieso: Ist nur ein Traffic-Troll...
Aus meiner Sicht ist es wahrscheinlicher, dass er zu den Leuten gehört,
die lieber erstmal anfangen, etwas zu machen und wenn es dann auf Anhieb
nicht so klappt, Schwierigkeiten mit dem Nachdenken haben. Für einen
Troll hat er m.E. schon zu viel selber gemacht. Das einen "Blindflansch"
zu nennen, ist zwar nicht ganz falsch, aber menschliche Blindflansche
können sich durchaus weiterentwickeln, und dazu ist das Forum auch da.
Für mich sieht es eher so aus, daß sein gewählter Lösungsweg völlig
überflüssig komplex ist, weil er aber gerne "macht"
(Stubenfliegenmethode!) und nicht so gerne nachdenkt, kein Interesse an
einer einfachen Lösung hat. Und wir haben unseren Spaß daran, entweder
erratene Wege aufzuzeigen oder lästerhafte Kommentare zu schreiben. So
haben wir alle was davon.
Nur Lothar wendet sich mit Grausen ab, weil seine Anmerkung: "Denn die
einzig relevante Frage ist nicht, was du willst, sondern was die
Anwendung braucht" genüßlich von allen ignoriert wird.
Gruß Klaus (der soundsovielte)
Klaus S. schrieb:> Nur Lothar wendet sich mit Grausen ab, weil seine Anmerkung: "Denn die> einzig relevante Frage ist nicht, was du willst, sondern was die> Anwendung braucht" genüßlich von allen ignoriert wird.
So isses / full ack.
Denn viele Technik-Freaks laufen hier mit Scheuklappen durch
die Gegend. Lieber schreiben sie hier einen hochkarätigen
Lösungsvorschlag anstatt zu fragen und zu überlegen was eigent-
lich erreicht werden soll. Diese Scheuklappen verhindern dass
sie die wahren Bedürfnisse und Fähigkeiten eines TO zwischen
den Zeilen erkennen.
m.n. schrieb:> Uwe K. schrieb:>> Wieviel ist ein "kurz" in ms?> Das ist doch völlig wurscht!
Wollte die Zeit im Beispiel einstellen.
Vieleicht ist das eine Möglichkeit. Ich habe es mit einem alternierenden
CTC-Wert gemacht. Das geht auf +/- 0,003 Hz genau, wenn man es
kalibriert.
> ... anstatt zu fragen und zu überlegen was eigentlich erreicht werden soll.
Man muss ihn wirklich alles aus der Nase ziehen...
weiter weg schrieb:> Denn viele Technik-Freaks laufen hier mit Scheuklappen durch> die Gegend. Lieber schreiben sie hier einen hochkarätigen> Lösungsvorschlag anstatt zu fragen und zu überlegen was eigent-> lich erreicht werden soll.
Na ja, Scheuklappen? Weiß nicht.
Manchmal - gerade wenn's regnet - hat man einfach Spaß daran sich um ein
Problem zu ›kümmern‹, es ›durchzudenken‹ und auf die bestmögliche Art
und Weise zu lösen.
Und ja, ich gehöre - wie vermutlich viele - auch zu denen.
Sehe es mehr als eine Fingerübung an.
Hab's gerade mal mit 5ns Auflösung gemacht. Für Kanäle 0…7. In unter
neunzig Zeilen. Mit der Schlange.
weiter weg schrieb:> Lieber schreiben sie hier einen hochkarätigen> Lösungsvorschlag ....
Ich hätte den Satz noch ergänzen sollen durch:
.... der an den Bedürfnissen und Kenntnissen des TO
voll vorbeigeht ....
Nur um seine eigenen Fähigkeiten brillieren zu lassen.
weiter weg schrieb:> weiter weg schrieb:>> Lieber schreiben sie hier einen hochkarätigen>> Lösungsvorschlag ....>> Ich hätte den Satz noch ergänzen sollen durch:>> .... der an den Bedürfnissen und Kenntnissen des TO> voll vorbeigeht ....>> Nur um seine eigenen Fähigkeiten brillieren zu lassen.
Ärgerst du dich weil so Leute wie du keinerlei substantiellen Beitrag
leisten können?
Oder muss man deine Kommentare eher als ›Finger-Tourette‹ ansehen?
Norbert schrieb:> Ärgerst du dich weil so Leute wie du keinerlei substantiellen Beitrag> leisten können?> Oder muss man deine Kommentare eher als ›Finger-Tourette‹ ansehen?
Keines von beiden wenn du schon so dümmlich fragst.