Forum: Mikrocontroller und Digitale Elektronik Arduino Timerprobleme - suche programmierbaren Oszillator


von Thomas G. (prozerger)


Lesenswert?

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 :)

von Juri (Gast)


Lesenswert?

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.

von EAF (Gast)


Lesenswert?

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

von m.n. (Gast)


Lesenswert?

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.

von Stefan F. (Gast)


Lesenswert?

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

von m.n. (Gast)


Lesenswert?

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.

von Stefan F. (Gast)


Lesenswert?

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.

von NoArno (Gast)


Lesenswert?

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.

von m.n. (Gast)


Lesenswert?

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!

von Stefan F. (Gast)


Lesenswert?

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?

von Thomas G. (prozerger)


Lesenswert?

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.

von Thomas G. (prozerger)


Lesenswert?

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?

von Uwe K. (ukhl)


Lesenswert?

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.

von Thomas G. (prozerger)


Lesenswert?

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?

von zyxwv (Gast)


Lesenswert?

> 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.

von Klaus S. (kseege)


Lesenswert?

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)

von Thomas G. (prozerger)


Lesenswert?

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.

von EAF (Gast)


Lesenswert?

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.

von Thomas G. (prozerger)


Lesenswert?

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.

von Sebastian (Gast)


Lesenswert?

Thomas G. schrieb:
> die millis() Funktion läuft asynchron mit einer Ungenauigkeit von 100ppm

Nimm doch micros().

LG, Sebastian

von Uwe K. (ukhl)


Lesenswert?

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“.

von Stefan F. (Gast)


Lesenswert?

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.

von Manfred (Gast)


Lesenswert?

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.

von Thomas G. (prozerger)


Lesenswert?

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

von Klassikradio (Gast)


Lesenswert?

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.

von Juri (Gast)


Lesenswert?

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...

von PittyJ (Gast)


Lesenswert?

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.

von Wolfgang (Gast)


Lesenswert?

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.

von Veit D. (devil-elec)


Lesenswert?

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.

von chris_ (Gast)


Lesenswert?

>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.

von noiasca (Gast)


Lesenswert?

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.

von m.n. (Gast)


Lesenswert?

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?

von Peter D. (peda)


Lesenswert?

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.

von m.n. (Gast)


Lesenswert?

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.

von Peter D. (peda)


Lesenswert?

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.

von m.n. (Gast)


Lesenswert?

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.

von Peter D. (peda)


Lesenswert?

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.

von W.S. (Gast)


Lesenswert?

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.

von Falk B. (falk)


Lesenswert?

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.

von HildeK (Gast)


Lesenswert?

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.

von Falk B. (falk)


Lesenswert?

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.

von Deckenleuchte (Gast)


Lesenswert?

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.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

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.

: Bearbeitet durch Moderator
von Löppt (Gast)


Lesenswert?

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.

von Klassikradio (Gast)


Lesenswert?

> 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.

von W.S. (Gast)


Lesenswert?

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.

von m.n. (Gast)


Lesenswert?

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.

von W.S. (Gast)


Lesenswert?

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.

von W.S. (Gast)


Lesenswert?

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.

von Klassikradio (Gast)


Lesenswert?

> 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.

von Thomas G. (prozerger)


Lesenswert?

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.

von Falk B. (falk)


Lesenswert?

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.

von Thomas G. (prozerger)


Lesenswert?

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

von Wendels B. (wendelsberg)


Lesenswert?

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.

von Wendels B. (wendelsberg)


Lesenswert?

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.

von Peter D. (peda)


Lesenswert?

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.

von Falk B. (falk)


Lesenswert?

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.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

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.

: Bearbeitet durch Moderator
von MisterX (Gast)


Lesenswert?

>  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
void setup(){
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));
15
///  Timer1.initialize();Timer1.pwm(9,512,round(F_CPU/16.0/51.0));
16
  TCCR1A=128;//COM1A1 COM1A0 Clear OC1A/OC1B on Compare Match (Set output to low level).
17
  TCCR1B=17; //WGM = 1000 (PWM, Phase and Frequency Correct)   clock source CS=001 (no prescaler)
18
  TCCR1C=0;ICR1=15623;OCR1A=7812; // frequency is 511.9055 duty=50%
19
  }
20
void loop(){float f;
21
  if(Serial.available()){
22
    f=Serial.parseFloat();if(f>0.11)if(f<=4100000.0){
23
      Serial.write(32);
24
      Serial.print(f);Serial.write(32);
25
      Serial.print(F_CPU/2/f);Serial.write(32);
26
      Serial.print(F_CPU/16/f);Serial.write(32);
27
//  auf Arduino Uno Anschluss 9 D9 PB1 U1/15 ausgeben
28
///   Timer1.pwm(9,512,round(F_CPU/16/f));
29
///   Serial.print(ICR1);Serial.write(32);
30
///   Serial.print(OCR1A);Serial.write(32);
31
      float //more precision than calculation with microseconds in pwm()
32
      p=        round(F_CPU/   2.0/f);
33
      if(p<65536){TCCR1B=17;ICR1=p;OCR1A=ICR1/2;}else{
34
        p=      round(F_CPU/  16.0/f);
35
        if(p<65536){TCCR1B=18;ICR1=p;OCR1A=ICR1/2;}else{
36
          p=    round(F_CPU/ 128.0/f);
37
          if(p<65536){TCCR1B=19;ICR1=p;OCR1A=ICR1/2;}else{
38
            p=  round(F_CPU/ 512.0/f);
39
            if(p<65536){TCCR1B=20;ICR1=p;OCR1A=ICR1/2;}else{
40
              p=round(F_CPU/2048.0/f);
41
              if(p<65536){TCCR1B=21;ICR1=p;OCR1A=ICR1/2;}else{
42
                Serial.print(F("Frequency too low"));}}}}}
43
      Serial.print(F(" TCCR1A="));Serial.print(TCCR1A);
44
      Serial.print(F(" TCCR1B="));Serial.print(TCCR1B);
45
      Serial.print(F(" TCCR1C="));Serial.print(TCCR1C);
46
      Serial.print(F( " ICR1 ="));Serial.print( ICR1 );
47
      Serial.print(F( " OCR1A="));Serial.print( OCR1A);
48
      if(TCCR1B==17)f=F_CPU/   2.0/ICR1;else //clkI/O/1 (No prescaling)
49
      if(TCCR1B==18)f=F_CPU/  16.0/ICR1;else //clkI/O/8 (From prescaler)
50
      if(TCCR1B==19)f=F_CPU/ 128.0/ICR1;else //clkI/O/64 (From prescaler)
51
      if(TCCR1B==20)f=F_CPU/ 512.0/ICR1;else //clkI/O/256 (From prescaler)
52
      if(TCCR1B==21)f=F_CPU/2048.0/ICR1;     //clkI/O/1024 (From prescaler)
53
      Serial.print(F("  frequency is "));
54
//    Serial.print(f);Serial.write(32);
55
      Serial.print(uint32_t(f));Serial.write(',');
56
      uint16_t frac=uint32_t(10000*f) % 10000;
57
      if(frac<1000)Serial.write(48);
58
      if(frac<100)Serial.write(48);
59
      if(frac<10)Serial.write(48);Serial.print(frac);Serial.write(10);
60
      Serial.print(F(msg));
61
      }else{Serial.print(F(" value out of range"));}
62
    }
63
  }

von Falk B. (falk)


Lesenswert?

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.

von Klassikradio (Gast)


Lesenswert?

> 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.

von m.n. (Gast)


Lesenswert?

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 ;-)

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

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.

: Bearbeitet durch Moderator
von Falk B. (falk)


Lesenswert?

Etwas weniger Prosa, dafür mehr Quelltext.

AVR - Die genaue Sekunde / RTC

von m.n. (Gast)


Lesenswert?

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?

von c-hater (Gast)


Lesenswert?

Klassikradio schrieb:

> Der einzige eingermassen brauchbaren Vorschlag ist vom Peter.
> Beitrag "Re: Arduino Timerprobleme - suche programmierbaren Oszillator"

Unsinn. Nicht der Vorschlag von Peter, sondern deine schwachsinnige 
Behauptung, dass es der einzige einigermaßen brauchbare Vorschlag wäre.

Denn hier im Thread, als vierte Antwort, wurde das Prinzip bereits 
erstmals erwähnt (wenn auch nur am Rande):

Beitrag "Re: Arduino Timerprobleme - suche programmierbaren Oszillator"

Ein weiteres Mal hier (sogar mit Link auf einen länglichen Thread zum 
prinzipiell gleichen Thema, incl. fertiger Lösung für einen Kanal):

Beitrag "Re: Arduino Timerprobleme - suche programmierbaren Oszillator"

von Falk B. (falk)


Lesenswert?

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.

von Deckenleuchte (Gast)


Lesenswert?

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!

von W.S. (Gast)


Lesenswert?

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.

von c-hater (Gast)


Lesenswert?

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.

von Wolfgang (Gast)


Lesenswert?

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.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

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...

von Falk B. (falk)


Lesenswert?

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.

von Wolfgang (Gast)


Lesenswert?

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?

von m.n. (Gast)


Lesenswert?

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.

von Klaus S. (kseege)


Lesenswert?

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)

von MisterX (Gast)


Lesenswert?

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
7
union{uint32_t ul;uint8_t ub[4];} volatile t0,t1,t2,t3;
8
uint32_t t0add=round(1.234*kon),t1add=round(4.567*kon),
9
         t2add=round(16*kon),t3add=round(128*kon);
10
uint16_t cnt;
11
ISR(TIMER1_OVF_vect){
12
  t0.ul+=t0add;t1.ul+=t1add;t2.ul+=t2add;t3.ul+=t3add;}
13
int main(){
14
  DDRB = 32+16+8+4+2;PORTB = 0xFF;
15
//LEDpin 13 D13 PB5  D12 D11 D10 D9 output, D8 INPUT_PULLUP
16
  DDRC = 0x00;PORTC = 0xFF; //alle INPUT_PULLUP
17
  DDRD = 0x00;PORTD = 0xFF; //alle INPUT_PULLUP
18
  Serial.begin(9600);
19
  Serial.print(F("\n 4-channel precision frequency generator \n"));
20
  TCCR1A=128;
21
  //COM1A1 COM1A0 Clear OC1A/OC1B on Compare Match
22
  //(Set output to low level).
23
  TCCR1B=17;
24
  //WGM=1000 (Mode8:PWM, Phase and Frequency Correct)
25
  //clock source CS=001 (no prescaler)
26
  TCCR1C=0;ICR1=256;OCR1A=128;
27
  // frequency is 31250 duty=50%
28
  TIFR1=255;  //clear all by writing 1
29
  TIMSK1=_BV(TOIE1);
30
  //enable Timer1-Overflow-Interrupt  OCIE1B 2  OCIE1A 1  TOIE1 0
31
  sei();
32
  Serial.print( fre );Serial.write(32);
33
  Serial.print( kon );Serial.write(32);
34
  Serial.print(t3add);Serial.write(32);
35
  Serial.print(t2add);Serial.write(32);
36
  Serial.print(t1add);Serial.write(32);
37
  Serial.print(t0add);Serial.write(32);
38
  while(1){
39
    cli();if(t3.ub[3]&128)PORTB|=32;else PORTB&=~32;sei();
40
    cli();if(t2.ub[3]&128)PORTB|=16;else PORTB&=~16;sei();cnt++;
41
    cli();if(t1.ub[3]&128)PORTB|= 8;else PORTB&=~ 8;sei();
42
    cli();if(t0.ub[3]&128)PORTB|= 4;else PORTB&=~ 4;sei();
43
    if(cnt>65000){cnt=0;Serial.write('.');
44
//  t3add+=round(4.0*kon);if(t3add>round(128*kon)){
45
    t3add*=1.059463;if(t3add>round(440*kon)){
46
      t3add=round(220.0*kon);if(t2add>round(10.0*kon)){
47
        t2add-=round(1.5*kon);t1add+=round(1.5*kon);
48
        t0add+=round(2.0*kon);}}}
49
    } //while(1)
50
  } //main

von Peter D. (peda)


Lesenswert?

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.

von da Kaisa (Gast)


Lesenswert?

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 ....

von MisterX (Gast)


Lesenswert?

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.

von MisterX (Gast)


Lesenswert?

> 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:
1
    cli();if(t3.ub[3]&128)PORTB|=32;else PORTB&=~32;
2
          if(t2.ub[3]&128)PORTB|=16;else PORTB&=~16;sei();cnt++;
3
    cli();if(t1.ub[3]&128)PORTB|= 8;else PORTB&=~ 8;
4
          if(t0.ub[3]&128)PORTB|= 4;else PORTB&=~ 4;sei();
5
    if(cnt>65000){cnt=0;Serial.write('.');
oder
1
    cli();if(t3.ub[3]&128)PORTB|=32;else PORTB&=~32;
2
          if(t2.ub[3]&128)PORTB|=16;else PORTB&=~16;
3
          if(t1.ub[3]&128)PORTB|= 8;else PORTB&=~ 8;
4
          if(t0.ub[3]&128)PORTB|= 4;else PORTB&=~ 4;sei();
5
    if(++cnt>65000){cnt=0;Serial.write('.');

von Veit D. (devil-elec)


Lesenswert?

Hallo,

sollte das nicht 16000000UL lauten?
1
#define F_CPU 15995000.0

von Normengremium (Gast)


Lesenswert?

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

von MisterX (Gast)


Lesenswert?

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...

von Thomas G. (prozerger)


Lesenswert?

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?

von c-hater (Gast)


Lesenswert?

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.

von foobar (Gast)


Lesenswert?

MisterX schrieb:
1
> if(t3.ub[3]&128)PORTB|=32;else PORTB&=~32;
2
> if(t2.ub[3]&128)PORTB|=16;else PORTB&=~16;
3
> if(t1.ub[3]&128)PORTB|= 8;else PORTB&=~ 8;
4
> if(t0.ub[3]&128)PORTB|= 4;else PORTB&=~ 4;
>
> ... auf der anderen Seite habe ich das Assembler-Listing angesehen
> und bin erschrocken, wie ineffektiv (teilweise!) der Compiler das
> übersetzt

Mach's halt so:
1
    PORTB = __builtin_avr_insert_bits(0xff7fffff, t3.ub[3],
2
            __builtin_avr_insert_bits(0xfff7ffff, t2.ub[3],
3
            __builtin_avr_insert_bits(0xffff7fff, t1.ub[3],
4
            __builtin_avr_insert_bits(0xfffff7ff, t0.ub[3], PORTB))));
Der dafür erzeugte Assemblercode:
1
        in r24,0x5
2
        lds r25,t0+3
3
        bst r25,7
4
        bld r24,2
5
        lds r25,t1+3
6
        bst r25,7
7
        bld r24,3
8
        lds r25,t2+3
9
        bst r25,7
10
        bld r24,4
11
        lds r25,t3+3
12
        bst r25,7
13
        bld r24,5
14
        out 0x5,r24

von STK500-Besitzer (Gast)


Lesenswert?

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.

von Falk B. (falk)


Lesenswert?

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.

von Gerd (Gast)


Lesenswert?

>> 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.

von c-hater (Gast)


Lesenswert?

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.

von Stefan F. (Gast)


Lesenswert?

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.

von c-hater (Gast)


Lesenswert?

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 Stefan F. (Gast)


Lesenswert?

c-hater schrieb:
> ICH habe auch zu keinem Zeitpunkt behauptet, das hier C
> das Problem wäre...

Du hättest Politiker werden sollen.

von MisterX (Gast)


Lesenswert?

>  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 MisterX (Gast)


Lesenswert?

> 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.

von Falk B. (falk)



Lesenswert?

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ß.

von foobar (Gast)


Lesenswert?

> Wie erzeugst Du das ASM-Listing?

Einfach mit gcc -S:
1
  agcc -Os -S foo.c && less foo.s

Kannst auch noch ein -fverbose-asm dazupacken.

von Falk B. (falk)


Lesenswert?

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.

von m.n. (Gast)


Lesenswert?

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.

von STK500-Besitzer (Gast)


Lesenswert?

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.

von Peter D. (peda)


Lesenswert?

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.

von Norbert (Gast)


Lesenswert?

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…

von m.n. (Gast)


Lesenswert?

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.

von Norbert (Gast)


Lesenswert?

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
from machine import Pin, 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  
17
divfrac = 0     # 0…15 für 0/16 … 15/16
18
mem32[PWM_BASE + CH4_DIV] = (divint<<4) + divfrac
19
20
topvalue = 62500  # für 1Hz
21
mem32[PWM_BASE + CH4_TOP] = topvalue-1  # -1 Datenblatt lesen!
22
23
ccvalue = topvalue // 2  # 1:1 Taktverhältnis
24
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. ;-)

von Norbert (Gast)


Lesenswert?

Ups, Zeile 24 muss natürlich ccvalue schreiben!

von W.S. (Gast)


Lesenswert?

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.

von Norbert (Gast)


Lesenswert?

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. ;-)

von Sebastian W. (wangnick)


Lesenswert?

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

von Norbert (Gast)


Lesenswert?

Sebastian W. schrieb:
> Schick!

Danke!
Geht natürlich auch noch schöner:
1
#!/usr/bin/python3
2
3
from machine import Pin, PWM, mem32, freq
4
5
class AdvancedPWM:
6
7
    # S.550 - 4.5.3. List of Registers
8
    PWM_BASE        = 0x40050000    # the PWM registers
9
    PWM_CH          = [ch*0x14 for ch in range(8)]  # Offsets for each channel
10
    PWM_CSR         = 0x00          # Control and status register
11
    PWM_DIV         = 0x04          # INT(0…255) and FRAC(0…15) form a fixed-point fractional number.
12
    PWM_CTR         = 0x08          # Direct access to the PWM counter
13
    PWM_CC          = 0x0c          # Counter compare values
14
    PWM_TOP         = 0x10          # Counter wrap value
15
    PWM_EN          = 0xa0          # PWM Enable Register
16
17
    def __init__(self, pinnum):
18
        assert type(pinnum) == int and 0 <= pinnum <= 29
19
        self.pin = Pin(pinnum)
20
        self.channel, self.channelshift = divmod(divmod(pinnum,16)[1], 2)
21
        self.channelshift = int(self.channelshift * 16)
22
        self.regbase = self.PWM_BASE + self.PWM_CH[self.channel]
23
        self.pwm = PWM(self.pin)
24
        self.pwm.freq(10)
25
        self.pwm.duty_u16(0) # Aus
26
27
    def set_div(self, divint, divfrac=0):
28
        assert type(divint) == int and 0 <= divint <= 65535
29
        assert type(divfrac) == int and 0 <= divfrac <= 15
30
        mem32[self.regbase + self.PWM_DIV] = (divint<<4) + divfrac
31
32
    def set_top(self, top):
33
        assert type(top) == int and 0 <= top <= 65535
34
        mem32[self.regbase + self.PWM_TOP] = top-1  # -1 Datenblatt lesen!
35
36
    def set_cc(self, cc):
37
        assert type(cc) == int and 0 <= cc <= 65535
38
        mem32[self.regbase + self.PWM_CC] = cc << self.channelshift
39
40
41
freq(16_000_000)
42
43
PinNum = 25  # GPIO der LED auf dem Raspberry Pi pico board
44
advPwm = AdvancedPWM(PinNum)
45
advPwm.set_div(0)  # oder (0,0)
46
advPwm.set_top(62500)
47
advPwm.set_cc(62500 // 2)

Und man kann's beliebig erweitern, beste Einstellungen für gegebene 
Frequenz berechnen, Abweichung berechnen, usw.

von MisterX (Gast)


Lesenswert?

Kürzere Einschaltdauern sind leicht möglich:
1
    if(t3.ub[3]&0x80)PORTB&=~32;else PORTB|=32; //50%
2
    if(t2.ub[3]&0xC0)PORTB&=~16;else PORTB|=16; //25%
3
    if(t1.ub[3]&0xE0)PORTB&=~ 8;else PORTB|= 8; //12,5%
4
    if(t0.ub[3]&0xF0)PORTB&=~ 4;else PORTB|= 4; //6,25%
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.

von m.n. (Gast)


Lesenswert?

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 ;-)

von Norbert (Gast)


Lesenswert?

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.

von Norbert (Gast)


Lesenswert?

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. ;-)

von m.n. (Gast)


Lesenswert?

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?
;-)

von m.n. (Gast)


Lesenswert?

Noch etwas:

Norbert schrieb:
> Ohne Jitter!

Fraktionaler Teiler ohne Jitter?
Wenn das so wäre, würde ich mir eine Rolle davon unters Kopfkissen 
legen.

von Norbert (Gast)


Lesenswert?

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.

von m.n. (Gast)


Lesenswert?

Norbert schrieb:
> Ja, Tippfeuler. die erste 2082 ist natürlich eine 2082.
> Das sieht man doch! ;-)

Oder nicht doch die 2. 2083 eine 2084?

von Norbert (Gast)


Lesenswert?

m.n. schrieb:
> Oder nicht doch die 2. 2083 eine 2084?

Irgendwann ist der Wurm drin, mach am Besten selbst… ;-)
Datei wird ein paar GB groß!
1
#!/usr/bin/python3
2
3
def lass_sehen(untergrenze, obergrenze):
4
    F_CPU = 16_000_000
5
    with open('/tmp/pwm.log', 'w') as fh:
6
        n = 0
7
        for DIV in range(1,256+1):
8
            for FRAC in range(0,15+1):
9
                for TOP in range(1,65536+1):
10
                    f = F_CPU / (DIV + FRAC/16) / TOP
11
                    if untergrenze <= f <= obergrenze:
12
                        print(f'\r {DIV:3d} {TOP:5d} {FRAC:3d}  {f:15.9f}', file=fh)
13
                        n = n + 1
14
                        if not n%100_000:
15
                            print(f'\r {DIV:3d} {n:10d}', end=' ')
16
        print()
17
        print(n)
18
19
lass_sehen(1,30)

von Stefan F. (Gast)


Lesenswert?

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.

von Falk B. (falk)


Lesenswert?

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)

von Norbert (Gast)


Lesenswert?

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.

von W.S. (Gast)


Lesenswert?

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.

von Norbert (Gast)


Lesenswert?

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.

von m.n. (Gast)


Lesenswert?

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 Gerd (Gast)


Lesenswert?

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.

von Veit D. (devil-elec)


Lesenswert?

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.
1
uint8_t mirrorByte(const uint8_t x)
2
{
3
  uint8_t rightBit = x & 0x01;
4
  uint8_t mirror = rightBit;
5
  uint8_t temp = x;
6
7
  for (uint8_t i = 1; i < 8; i++)
8
  {
9
    temp = temp >> 1;
10
    rightBit = temp & 0x01;
11
    mirror = mirror << 1 | rightBit;
12
  }
13
  return mirror;
14
}

Gut genug?

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

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.

von Veit D. (devil-elec)


Lesenswert?

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.

von m.n. (Gast)


Lesenswert?

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. .

von Gerd (Gast)


Lesenswert?

>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.

von Norbert (Gast)


Lesenswert?

> 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
from rp2 import PIO, asm_pio, StateMachine
3
4
@asm_pio(set_init=rp2.PIO.OUT_LOW)
5
def bitreverse():
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? ;-)

von Veit D. (devil-elec)


Lesenswert?

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.  :-)

von Stefan F. (Gast)


Lesenswert?

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.

von Falk B. (falk)


Lesenswert?

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.

von Stefan F. (Gast)


Lesenswert?

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.

von Zeno (Gast)


Lesenswert?

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.

von Veit D. (devil-elec)


Lesenswert?

Hallo,

> Dem AVR fehlen die dazu nötigen Befehle
Das wusste ich nicht. Vielleicht noch ein interessanter Link für alle. 
Bei Bedarf. :-)
https://stackoverflow.com/questions/61179846/reversing-bits-in-a-byte-with-avr
Kennt ihr bestimmt schon.

von Falk B. (falk)


Angehängte Dateien:

Lesenswert?

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.

von Falk B. (falk)


Lesenswert?

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.

von Norbert (Gast)


Lesenswert?

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. ;-)

von Veit D. (devil-elec)


Lesenswert?

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.

von Gerd (Gast)


Angehängte Dateien:

Lesenswert?

Und hier noch ein Beitrag der Musikwissentschaften zum Thema Arduino IDE 
und Assembler.

von m.n. (Gast)


Lesenswert?

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.

von Jester (Gast)


Lesenswert?

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!

von Thomas G. (prozerger)


Lesenswert?

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.

von Uwe K. (ukhl)


Lesenswert?

Brauchst Du einen einstallbaren Taktgeber mit einem 50:50 Verhältnis?

Oder soll pro Takt ein kurzer Impuls ausgegeben werden ?

von Norbert (Gast)


Lesenswert?

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.

von c-hater (Gast)


Lesenswert?

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...

von Falk B. (falk)


Lesenswert?

Thomas G. schrieb:
> 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.

Wirklich? Oder sind nur die sinnvollen Beiträge im Rauschen des 
Wahnsinns untergegangen?

Beitrag "Re: Arduino Timerprobleme - suche programmierbaren Oszillator"

von Thomas G. (prozerger)


Lesenswert?

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

von Uwe K. (ukhl)


Lesenswert?

> 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?

von m.n. (Gast)


Lesenswert?

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.

von Klaus S. (kseege)


Lesenswert?

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)

von weiter weg (Gast)


Lesenswert?

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.

von Uwe K. (ukhl)


Angehängte Dateien:

Lesenswert?

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...

von Norbert (Gast)


Lesenswert?

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.
1
Frequenzbereich 47 mHz … 33333 kHz
2
>>> sig[7].frequenz(frequenz=1.0, taktverhältnis=0.1)
3
Frequenz:1.000000000Hz  200000000 20000000 180000000
4
5
>>> sig[7].frequenz(frequenz=1.0 - 1E-6, taktverhältnis=0.1)
6
Frequenz:0.999998951Hz  200000208 20000022 180000186

von weiter weg (Gast)


Lesenswert?

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.

von Norbert (Gast)


Lesenswert?

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?

von weiter weg (Gast)


Lesenswert?

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.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.