Leider gab es lange keine Updates in diesem Blog. Das liegt im wesentlichen daran, daß ich mich in den vergangenen Monaten in Qt und C++ eingearbeitet habe. Darüber nachfolgend ein kurzer Bericht.
Qt ist ein Anwendungsframework und GUI-Toolkit zur plattformübergreifenden Entwicklung von Programmen und grafischen Benutzeroberflächen. Qt setzt das Programmieren in C++ voraus, was ich bisher immer vermeiden konnte. Privat und auch in meinem gesamten Berufsleben kam ich stets mit Ansi‑C aus und habe auch immer die jeweils neuesten Erweiterungen in C95, C99 und zuletzt C11 mitverfolgt und z.T. gerne genutzt. Die Limitierung auf Ansi‑C liegt schlichtweg daran, daß ich im wesentlichen hardwarenahe embedded Programme geschrieben habe und für die wenigen Windows-Programme auch die Win32-API nicht unbedingt C++ verlangt.
Die Win32-API ist naturgemäß nur unter Windows lauffähig, mit Einschränkungen wohl auch mit Wine unter Linux, was ich aber nie getestet habe. Ich bin kein Linux-Jünger und habe nur die eine oder andere virtuelle Ubuntu-Maschine laufen, damit ich da nicht ganz abgehängt werde. Freundlicherweise gibt es Visual Studio von Microsoft für Privatanwendungen kostenlos. Es hat kleine nicht relevante Einschränkungen, mit denen man als Hobbyist gut leben kann. Dennoch möchte ich mich nicht allzu abhängig von Windows machen, schon garnicht, wenn es um meine Hobbyanwendungen geht. Außerdem wird der von mir immer noch verwendete Ressourcen-Editor namens Resedit nicht mehr gewartet. Die Website ist verschwunden. Ein Schwenk auf eine neue und zukunftssichere Cross-Plattform Entwicklungsumgebung war daher überfällig.
Es gibt dafür mehrere Lösungen, die letztendlich für kostensensible Hobbyanwendungen aber nur auf zwei konkurrierende Pakete hinauslaufen, nämlich wxWidgets und Qt. Nach dem Lesen vieler Artikel im Internet habe ich mich für Qt entschieden. Jeder mag persönlich zu einer anderen Entscheidung finden. Klar ist, daß man für jedes Paket mit einer mehrwöchigen oder auch mehrmonatigen Einarbeitungsphase rechnen muß.
Für Qt gibt es viele Youtube-Videos, die mir die Einarbeitung sehr erleichtert haben. Erste Erfolge hat man damit im Grunde in wenigen Stunden oder Tagen, aber bis man sinnvolle Applikationen schreiben kann, wird man doch mehrere Wochen investieren müssen. Bei mir kam noch die neue Programmiersprache C++ hinzu. Sie ist natürlich aus C entstanden und sehr ähnlich, aber die objektorientierte Herangehensweise war mir neu und ist mir immer noch etwas mysteriös. Insbesondere hadere ich damit, daß hinter den Kulissen Dinge passieren, die ich nicht überblicke. Das schöne ist, daß sie funktionieren, aber ich habe oft (noch) kein Gefühl dafür, welche Ressourcen bezüglich CPU-Zeit oder Speicherbedarf eine gewisse Operation benötigt. Vielleicht ist das aber auch eine Krankheit aus der Beschränkung von embedded Systemen, die man einfach überwinden muß. Auf einem PC hat man von allem genug, CPU-Zeit, Speicher und CPU-Kerne. Und wenn nicht, dann wartet man einfach auch die nächste Prozessorgeneration. QStrings sind beispielsweise eine sehr schöne Sache, die ich gerne verwende. Aber wie sie hinter den Kulissen funktionieren, ohne daß man explizit eine maximale Länge angeben muß, wie z.B. bei char-Arrays in C, ist mir im Moment noch ein Rätsel. Der Overhead ist sicherlich nicht gering, aber in einer PC-Umgebung ist das wohl völlig vernachlässigbar. Das sind wahrscheinlich Reflexe aus der Embedded-Programmierung, die man halt einfach überwinden muß.
Zur Dokumentation meines bisherigen Fortschritts sollen hier nur zwei Screenshots eines Kommunikationsprogramms gezeigt werden, das über einen USB-RS485-Konverter mit den an anderer Stelle in diesem Blog vorgestellten Modbus-Geräten (Antennentuner und Antennenumschalter) kommuniziert.
Diagnose-Tab des KommunikationsprogrammsConfig-Tab des Kommunikationsprogramms
Qt unterstützt die Gestaltung der Benutzeroberfläche mit dem Qt Creator und stellt die notwendigen Bibliotheken für das Ziel-Betriebssystem zur Verfügung. Diese Bibliotheken unterstützen nicht nur die grafische Ein- und Ausgabe, sondern z.B. auch die Kommunikation über eine serielle Schnittstelle. Man bindet sich also nirgends direkt an das Betriebssystem.
Als Nachteil empfinde ich im Moment, daß Qt zumindest in der Standardkonfiguration seine Bibliotheken nicht statisch linked. So muß man selbst bei einem kleinen „Hello World“ Programm etwa 10 DLLs mit knapp 50 MB Größe mitliefern. Das macht das Handling etwas schwierig, gerade bei kleinen „Kiki-Programmen“. Da gibt es bestimmt bessere Lösungen, z.B. indem man die DLLs irgendwo zentral speichert und mit einer Environment-Variablen darauf zeigt. Da muß ich noch etwas forschen, hat aber keine hohe Priorität.
Ich bin noch Anfänger bezüglich Qt und C++, aber ich kann Qt auf jeden Fall sehr empfehlen. Meine zukünftigen Projekte werden Qt-basiert sein. Die Unterstützung im Internet lässt keine Wünsche offen.
Schon vor ein paar Monaten habe ich ein kleines Programm geschrieben, das eine PNG Grafik-Datei in eine Audio-Datei umwandelt.
Sample input file
Spectrum of output file
Dieses Programm ist nun soweit, daß man es weitergeben kann. Es hat sicher hier und da noch ein paar Macken, daher will ich das nicht als „Release“ bezeichnen und bleibe bei einer Versionsnummer kleiner als 1.0. Es ist eine reine Spielerei.
Die Audiodatei lässt sich mit dem VLC Media Player abspielen, der es gestattet, einen anderen Audio-Ausgang zu wählen, als den Lautsprecher am PC. Im Menü Audio -> Audiogerät kann man den Audio-Eingang eines angeschlossenen Transceivers wählen und so die Audiodatei direkt senden.
Transmitted spectrum (start)
Transmitted spectrum (middle)
Transmitted spectrum (end)
Aber bitte nicht die Mitmenschen damit ärgern. Beim ersten- und zweitenmal ist das ganz spaßig, aber dann nervt es…
In der Entwicklungsphase des noch zu beschreibenden Frequenzzählers habe ich einige Meßreihen erstellt. Eine davon war der Frequenzgang eines 8 MHz Quarzes auf dem CPU-Board, die andere der Frequenzgang eines 100 MHz Quarzoszillators auf dem Frequenzzähler selbst. Beide Frequenzgänge wurden über die Temperatur gemessen, die mit Kältespray (Butangas, nicht Rauchen, kein offenes Feuer aber offene Fenster!) bzw. einem Föhn geändert wurde.
In beiden Fällen wurde die Temperatur mit dem Temperatursensor auf dem CPU-Board gemessen, einem TMP275. Zwischen ‑40 °C und +125 °C hat er eine Toleranz von +/- 1 °C. Die tatsächliche Temperatur des Quarzes und besonders des Quarzoszillators dürften um einige °C von der gemessenen Temperatur abweichen, weil sie etwas entfernt davon montiert sind. Es soll hier aber nicht um die Präzision der Messung gehen, sondern einzig und allein um die Auswertung mit Libreoffice Calc. Der Frequenzzähler speichert die Meßdaten in einem CSV-File ab, das mit LibreOffice direkt eingelesen werden kann. Die beiden OpenOffice Calc Dateien stehen als Referenz und für eigene Experimente zum Download bereit:
In der ersten Tabelle der jeweiligen Datei stehen die original Meßdaten. Die weiteren Tabellen sind nachfolgend beschrieben.
Auswertung
Zur Auswertung empfiehlt es sich, zunächst eine Pivot-Tabelle („Daten->Pivot-Tabelle->Einfügen) zu erstellen. Als Zeilenfelder wählt man die Temperatur und als Datenfelder die gemessene Frequenz Fcheck. Für die Datenfelder interessiert uns aber nicht die Summe, sondern der Mittelwert. Das muß vor dem Erzeugen der Pivot-Tabelle eingestellt werden. Nun sucht Calc alle in der Tabelle vorkommenden Temperaturen, sortiert sie aufsteigend und ordnet jeder Temperatur den Mittelwert aller für diese Temperatur gefundenen Meßwerte zu. So erhalten wir eine Tabelle der gemittelten Meßwerte von etwa ‑30 °C bis +70 °C (Tabelle: „Pivot-Tabelle“).
Da wir einen 8 MHz bzw. einen 100 MHz Quarzoszillator gemessen haben, liegen alle Meßwerte ziemlich nahe bei 8.000.000 Hz oder 100.000.000 Hz. Ohne vernünftige Skalierung sieht man da nur eine horizontale Linie über der Temperatur. Damit die Meßwerte sinnvoll dargestellt werden können, erstellt man in diesem Fall am besten eine Spalte mit der Differenz der Meßwerte zum Nominalwert, denn alle Werte weichen nur sehr wenig davon ab. Dieses Delta läßt sich dann grafisch über der Temperatur darstellen.
Originaldaten des 8 MHz Quarzoszillators
nur langsame Phase
Originaldaten des 100 MHz Quarzoszillators
nur langsame Phase
Die linken Diagramme zeigen die unveränderten Originaldaten. Man erkennt deutlich den Temperaturgang, aber die vielen Ausreißer sind erschreckend. Die Originaldaten enthalten die sehr schnelle Abkühlphase mit Kältespray und die fast genauso schnelle Aufheizphase mit dem Föhn. Daran schließt sich jeweils eine Phase langsamen Aufheizens bzw. langsamen Abkühlens auf Zimmertemperatur an.
Die rechten Diagramme zeigen nur die langsamen Phasen und die Ausreißer sind hier komplett verschwunden (Tabellen: „Auswahl“ und „Pivot-Tabelle_1“). Die Kurvenform bleibt unverändert. Offensichtlich tun in beiden Fällen die schnellen Temperaturänderungen nicht gut, die Schwingung reißt vermutlich kurzzeitig ab.
Erzeugen einer Ausgleichskurve
Alle weiteren Auswertungen erfolgen nun mit den beiden „langsamen Kurven“, denn sie spiegeln offensichtlich die wahren Verhältnisse. Das Ziel ist nun, die jeweilige Kurve so zu glätten, daß die geglättete Kurve möglichst genau der gemessenen Kurve entspricht, ohne deren Meßabweichungen abzubilden. Die Standardmethode zum Erzeugen einer sogenannten Ausgleichskurve ist die Ausgleichsrechnung. Für ein mathematischen Lösungsverfahren muß dieser Ausgleichsrechnung ein Modell zugrunde liegen. Im allgemeinen Fall ist das ein Polynom der Form
y = a0 + a1 * x + a2 * x2 + … + an * xn
In der Praxis muß man diese Reihe natürlich frühzeitig irgendwo abbrechen, denn sonst wird der Rechenaufwand immer größer. Es sei vorab verraten, daß bei den gezeigten Kurven mindestens ein Polynom dritten Grades nötig ist, also n = 3. Das liegt an den zwei lokalen Minima bzw. Maxima (jeweils grob bei 0 °C und bei 60 °C), bei denen die erste Ableitung des Polynoms null sein muß. Um zwei Nullstellen zu haben, muß die erste Ableitung aber mindestens einen quadratischen Term haben.
Probieren wir dennoch zum Spaß und zu Übungszwecken einfach mal eine Gerade aus, brechen also nach n = 1 ab (Tabelle „Ausgleichsgerade“):
y = a0 + a1 * x
Wir tragen wenn möglich gut erratene Startwerte für die Parameter a0 und a1 in jeweils eine Zelle der Tabelle ein (hier C2 und C3). In eine Spalte (hier: Spalte E) neben den Meßwerten tragen wir dann die Formel für die Gerade ein, mit Bezug auf die Parameter ($C$2 und $C$3) und füllen diese Spalte nach unten auf (obere Zelle und alle Zellen bis zum Ende der Daten auswählen und Strg‑D drücken).
In einer weiteren Spalte berechnen wir dann das Quadrat des Fehlers, den der so errechnete Punkt zum tatsächlich gemessenen Wert hat (hier: Spalte F). Auch diese Spalte füllen wir nach unten auf und errechnen in einer weiteren Zelle (G2) die Summe all dieser Fehlerquadrate. Das Ziel ist nun, a0 und a1 (C2 und C3) so zu bestimmen, daß die Summe der Fehlerquadrate minimal wird.
Von Hand ist das ausgesprochen mühsam, aber zum Glück bietet Calc dafür eine automatische Lösung, den „Solver“. Man startet Extras->Solver und gibt die Zelle mit der Summe der Fehlerquadrate (hier G2) als Zielzelle an. Der Zielwert soll minimal werden und als veränderliche Zellen geben wir C2 und C3 in der Form $C$2:$C$3 an. Der Solver rechnet nun einige Sekunden, denn er muss die Werte in C2 und C3 solange anpassen, bis er einen Minimalwert findet.
8 MHz Quarzoszillator mit Ausgleichsgerade
100 MHz Quarzoszillator mit Ausgleichsgerade
Wie die beiden Diagramme zeigen, findet der Solver nach einigen Sekunden einen plausiblen Wert. Die orange dargestellten Geraden nähern die gemessene Kurve bestmöglich an. Bei nur zwei Variablen und den linearen Eigenschaften einer Geraden kann man auch sicher sein, ein echtes Minimum gefunden zu haben.
Ausgleichskurve mit Polynomen
Die Ausgleichsgerade aus dem vorigen Kapitel ist besser als nichts, aber sie befriedigt nicht wirklich. Für bessere rechnerische Annäherung an die Meßkurve kommt man nicht umhin, höhergradige Polynome zu verwenden. Der Rechenweg unterscheidet sich dabei nicht grundlegend von dem der Ausgleichsgeraden, nur die Formel wird etwas komplizierter. Wir nehmen einfach weitere Terme der Form anxn dazu.
Je größer n wird, je höher also die Ordnung des Polynoms wird, umso genauer können wir die Meßkurve annähern. Probieren wir es der Reihe nach durch, zunächst mit einem Polynom zweiten Grades:
8 MHz Quarzoszillator mit Polynom zweiten Grades
100 MHz Quarzoszillator mit Polynom zweiten Grades
Aus den oben schon genannten Gründen verwundert es nicht, daß das die Meßkurve noch nicht trifft. Wie erwartet gibt es nur einen lokalen Extremwert, ein Minimum bei etwa 20 °C. Versuchen wir es nun mit einem Polynom dritten Grades:
8 MHz Quarzoszillator mit Polynom dritten Grades
100 MHz Quarzoszillator mit Polynom dritten Grades
Damit kommen wir der Form der gemessenen Kurve schon sehr nahe. Gleichzeitig wird die Summe der Fehlerquadrate mit steigendem Grad des Polynoms immer kleiner.
Um es auf die Spitze zu treiben, kann man für den 100 MHz Quarzoszillator auch ein Polynom vierten und fünften Grades ausprobieren, das weitere kleine Verbesserungen bringt:
8 MHz Quarzoszillator mit Polynom vierten Grades
100 MHz Quarzoszillator mit Polynom vierten Grades
8 MHz Quarzoszillator mit Polynom fünften Grades
100 MHz Quarzoszillator mit Polynom fünften Grades
Temperaturkompensation per Software
Das sind nette Spielereien mit einem Spreadsheet-Programm, aber was bringt das ganze nun? Ganz einfach, das so gefundene Polynom gestattet uns eine softwaregesteuerte Temperaturkompensation. Wir können die mutmaßliche tatsächliche Frequenz des Oszillators bei einer bestimmten Temperatur aus seiner Nominalfrequenz annähern.
Das zeigt die Tabelle Poly_n5 für beide Quarzoszillatoren. In der Spalte H wurde die nach der Kompensation verbleibende Abweichung zur gemessenen Frequenz errechnet und in Spalte I in ppm (parts per million) umgerechnet. Die verbleibende Abweichung liegt nun außer an den Temperaturgrenzen bei weniger als 1 ppm. Die unkompensierte Abweichung ist zum Vergleich in Spalte J dargestellt und deren Maximum liegt bei knapp 40 ppm bzw. gut 16 ppm, was für einen mit +/- 25 ppm spezifizierten Quarz auch schon recht gut ist.
8 MHz Quarzoszillator unkompensiert
8 MHz Quarzoszillator temperaturkompensiert
100 MHz Quarzoszillator unkompensiert
100 MHz Quarzoszillator temperaturkompensiert
Man beachte die unterschiedliche Skalierung der y‑Achsen. Von den extremen Temperaturbereichen abgesehen, hat die Temperaturkompensation die Frequenzstabilität also mindestens um den Faktor 10 verbessert. Die deutlichen Abweichungen bei etwa 25 °C liegen an der Meßmethode, denn die Zimmertemperatur war jeweils der Endpunkt der Messungen. Hier gab es mutmaßlich Meßfehler durch den abgesetzten Temperatursensor auf dem CPU Board, der durch die Eigenerwärmung einige Grad mehr anzeigt, als beim Quarz wirklich herrschen.
Suchstrategien
Bei der hier gezeigten Meßdatenanalyse kommt der Calc-Solver schnell an seine Grenzen. Am Ende steht ein Polynom fünfter Ordnung mit sechs unbekannten Parametern a0 .. a5. Der Solver muß im Prinzip alle möglichen Parameter-Werte durchprobieren, die Quadratsumme bilden und versuchen, diese Summe zu minimieren. Ohne halbwegs passend gewählte Startwerte ist das ein Unterfangen, das auf heutigen Rechnern nicht lösbar ist. Der Suchraum ist unendlich groß und der Solver muß ihn auf irgendeine Weise einschränken. Seine Suche gilt als beendet, wenn die Quadratsumme bei jeder kleinen Änderung eines Parameters wieder größer wird. Dabei besteht aber immer die Gefahr, ein lokales Minimum zu finden, das weit weg vom tatsächlichen Minimum liegt. Es kann immer sein, daß hinter den Bergen bei den sieben Zwergen ein Minimum liegt, das tausendmal schöner als das bisher gefundene ist. Man sollte dem Solver also durch geeignete Anfangswerte helfen. Wie macht man das?
Sukzessive Erhöhung des Polynom-Grades
Die einfachste Methode, die hier auch angewendet wurde, ist die sukzessive Erhöhung des Polynom Grades. Man startet mit niedriger Ordnung und lässt den Solver dazu passende Parameter suchen. Geht man schrittweise zu höheren Ordnungen, dann sind diese Parameter zwar nicht mehr ganz richtig, aber auch nicht ganz falsch. Sie sind ein guter Startwert. Man kann auch zunächst mal nur den besten neuen Parameter suchen und erst dann eine weitere Suche über alle bisherigen Parameter starten. So verbessert sich das Ergebnis nach und nach.
Kurvendiskussion
Eine Kurvendiskussion kann beim Erraten günstiger Anfangswerte für die Parameter helfen. Zur Kurvendiskussion benötigt man die Ableitungen der Funktion. Gehen wir zunächst von einem Polynom dritten Grades aus, so ergeben sich folgende Ableitungen:
y = a0 + a1 * x + a2 * x2 + a3 * x3
y‘ = a1 + 2 * a2 * x + 3 * a3 * x2
y“ = 2 * a2 + 6 * a3 * x
Aus der ersten Gleichung erkennt man sofort, daß a0 = y(0) ist, denn wenn x = 0 ist, dann fallen alle anderen Terme weg. a0 ist beim 8 MHz Oszillator also etwa 212 und beim 100 MHz Oszillator etwa 355.
Die erste Ableitung einer Funktion ist an lokalen Extremwerten gleich null. Beim 100 MHz Oszillator finden wir ein lokales Minimum etwa bei x=3 und ein lokales Maximum bei etwa x=60. Mit der ersten Ableitung erhalten wir daraus zwei Gleichungen:
y‘ = a1 + 2 * a2 * 3 + 3 * a3 * 32 = 0
y‘ = a1 + 2 * a2 * 60 + 3 * a3 * 602 = 0
Aus zwei Gleichungen mit drei Unbekannten kann man durch Multiplikation mit einem geeigneten Faktor und anschließender Addition beider Gleichungen eine Gleichung mit zwei Unbekannten machen. Eliminieren wir zunächst a2 durch Multiplikation der ersten Gleichung mit ‑20 und anschließender Addition:
Damit haben wir eine direkte Abhängigkeit zwischen a1 und a3 bzw. a2 und a3 gefunden. Diese beiden Formeln kann man direkt in die Zellen für a1 und a2 eingeben und braucht sie dann nicht mehr in die Liste der Unbekannten für den Solver aufzunehmen. Der Suchraum ist also weiter deutlich eingeschränkt.
Können wir noch mehr tun? Ja klar, wir kennen nun Näherungswerte für a0, a1 und a2 und können die in die Gleichung des Polynoms einsetzen:
y = 355 + 540 * a3 * x – 94,5 * a3 * x2 + a3 * x3
Ohne zu vergessen, daß alles sowieso nur Näherungswerte sind, suchen wir aus der Meßreihe einen Wert x und den zugehörigen Wert y heraus. Dabei versuchen wir einen repräsentativen Wert zu finden, also Sonderfälle an den Temperaturgrenzen und auch die lokalen Extremwerte zu vermeiden. Wie wär’s, mehr oder weniger willkürlich, mit x=40 und y=773? Mit diesen Werten können wir nun einen plausiblen Startwert für a3 ausrechnen:
Aus dieser Gleichung ergibt sich a3 = ‑0,006372 und durch Einsetzen dieses Wertes in die oben schon gefundenen Gleichungen a1 = ‑3,44088 und a2 = 0,602154.
Damit haben wir dem Solver das Leben leichtgemacht. Wir haben plausible Startwerte für alle Parameter des Polynoms dritter Ordnung. Ohne den Solver auch nur zu bemühen, deckt sich diese Kurve schon erstaunlich gut mit der Meßkurve (links):
100 MHz Quarzoszillator mit Polynom dritten Grades aus der Kurvendiskussion
100 MHz Quarzoszillator mit Polynom dritten Grades
Rechts ist nochmal zum Vergleich das oben schon gezeigte Diagramm des mit dem Solver gefundenen Polynoms derselben Ordnung gezeigt. Über große Teile des Diagramms ist die Deckung des von Hand gefundenen Polynoms sogar besser. Allerdings ist die Summe der Fehlerquadrate dennoch höher, denn um den Diagrammteil bei hohen Temperaturen korrekt zu modellieren fehlen die höhergradigen Terme.
Ganz am Schluß kann man dann a0 bis a3 nochmal durch den Solver verbessern lassen. Der findet dabei tatsächlich eine bessere Lösung, als bei der Suche aufs Geratewohl im ersten Ansatz. Die geringste Summe der Fehlerquadrate ergibt sich bei a0 = 339,27, a1 = ‑3,023, a2 = 0,703 und a3 = ‑0,00858.
Mit demselben Vorgehen kann man natürlich auch den Fall des 8 MHz Oszillators nochmal durchspielen, was aber hier keine neuen Erkenntnisse mehr bringt. Das sei daher dem geneigten Leser überlassen.
Wie bereits im vorigen Beitrag über nützliche Websites in Aussicht gestellt, habe ich nun doch ein kleines Programm zum Erstellen von Timing Diagrammen im Text-Format geschrieben: DrawTimingDiagram.
Das Programm öffnet ein Eingabe- und ein Ausgabefenster. In das Eingabefenster können Kommandos geschrieben werden, die beim Klick auf den Start-Knopf in ein Timing-Diagramm im Ausgabefenster umgewandelt werden. Ein kleines Beispiel zeigt der folgende Screenshot:
Das so erzeugte Diagramm kann über das Clipboard aus dem Ausgabefenster in eine UTF8-Textdatei übernommen werden.
Eine kurze Beschreibung der unterstützten Eingabekommandos mit einem etwas komplexeren Timing Diagramm Beispiel findet sich in der Online-Hilfe.
Anlässlich meiner diversen Designs in den vergangenen Monaten, brauchte ich immer wieder mal die Möglichkeit, einfache Grafiken, Tabellen und Formeln als Text in die Quelltexte der C‑Programme und Verilog-Dateien als Kommentarblöcke einzubetten. Bisher habe ich mehr schlecht als recht mit AACircuit gearbeitet, das allerdings schon reichlich angestaubt ist und auch seine Macken hat. Eine Suche im Internet förderte ein paar sehr hilfreiche Online-Tools zu Tage.
Diagon – ASCII art diagram collection
Diagon (Diagram Online) ist ein Online-Tool, um mathematische Ausdrücke, Tabellen, Flußdiagramme und sonstiges in ASCII- oder UTF-8-Format umzuwandeln. Einfach mal die Website aufrufen und ausprobieren. Man wählt zunächst das Werkzeug aus und kann dann im Eingabefenster die Rohdaten eingeben. Sie werden dann sofort im Ausgabefenster dargestellt und können mit Copy&Paste in den eigenen Code übernommen werden. Für jedes Tool gibt es ein oder mehrere Beispiele, die zeigen, wie es geht.
ASCIIFLOW
ASCIIFLOW ist ein weiteres Online-Tool, das auf das Zeichnen einfacher geometrischer Formen spezialisiert ist. Man kann Rechtecke, Linien und Pfeile zeichnen und natürlich auch Texte eingeben. ASCIIFLOW unterstützt außer dem ASCII-Zeichensatz auch den erweiterten Zeichensatz, der schöne Linien und Ecken darstellen kann. Darüberhinaus kann man das Ergebnis direkt als Kommentare in /* und */ einbetten. Das zeigt, was der Entwickler im Sinn hatte.
Textik
Textik funktioniert ähnlich wie ASCIIFLOW. Auch hier kann man auf einer Leinwand einstellbarer Größe Rechtecke, Linien, Pfeile und Text zeichnen. Anders als ASCIIFLOW kennt Textik unterschiedliche Ebenen in z‑Richtung. Man kann also wählen, ob ein Objekt über oder unter anderen Objekten liegt. Dafür unterstützt Textik aber nur den Standard ASCII Zeichensatz.
Was noch schön wäre…
Ich hätte noch ein Tool gesucht, das einfache (extended-) ASCII-Timing Diagramme darstellen kann. Auch das ist in Quelltexten immer wieder mal nötig. Bisher zeichne ich sowas von Hand, dabei bricht man sich die Finger. Est recht, wenn man daran etwas ändern muß. Wer sowas kennt, kann mich gerne kontaktieren. Ich habe auch schon überlegt, sowas selber zu schreiben.
Hier soll nun kurz die Software beschrieben werden, über die ein Windows PC mit den Busteilnehmern über RS-485 kommuniziert. Es wurde das freie und weit verbreitete Modbus-RTU-Protokoll verwendet. Es ist gut dokumentiert, wegen Parity und 16-bit CRC hinreichend fehlerresistent und es gibt mit QModMaster ein freies Windows-Programm, das bei der Implementierung und Fehlersuche sehr hilfreich ist. Sowohl für den Windows-PC wie auch für das Arduino Biotop gibt es fertige Software.
Vorbemerkungen
Mit Arduino habe ich selbst nichts zu tun, einfach weil es das noch nicht gab, als ich zum erstenmal mit Atmel Bausteinen gearbeitet habe. Gelegentlich werde ich mir das mal anschauen. Die Modbus-Bibliothek für Windows habe ich mir einen halben Tag lang angeschaut und sie nicht zum Laufen bekommen. Sie ist sicher gut und kann alles, aber die paar Funktionen die ich brauche, habe ich dann doch selber geschrieben. Das schien mir schneller zu gehen, zumal die Funktionen auf der Gegenseite, dem Atmel Baustein, schon fertig war und sich nicht grundsätzlich unterscheidet. Damit ist nun die komplette Software sowohl auf der Host- wie auf der Device-Seite selbstgeschrieben und kann hier ohne Einschränkungen im Quelltext veröffentlicht werden:
Wer will, kann beides gerne uneingeschränkt weiterbenutzen, eine Garantie für die fehlerfreie Funktion gibt’s natürlich nicht. Es sind sicherlich hier und da noch Fehler eingebaut. Außerdem ist nur ein Subset des Modbus-Protokolls implementiert, auch die eine oder andere Funktion, die in der Spec als „mandatory“ bezeichnet wird, ist nicht vorhanden (z.T. implementiert, aber auskommentiert da ungetestet).
Als Entwicklungsumgebung für Atmel verwende ich „Atmel Studio 7.0“, für Windows „VS Express 2013“. Beide Versionen sind etwas älter, Atmel gehört inzwischen zu Microchip, und von VS Express gibt es neuere Versionen, die aber nicht mehr mit Windows 7 laufen, sondern Windows 10 benötigen. Sollte ich jemals auf Win 10 umsteigen, werde ich mir eine neuere Version besorgen. Es gibt im Moment für mich keinen Grund zum Umsteigen.
Beide Programme sind sehr spezifisch für meinen Anwendungsfall geschrieben, daher habe ich auch keine ausführbare Datei beigefügt. Die Quelltexte sollen als Muster dienen, wie man es machen kann, aber nicht muß. Das Windows Programm mag gleichzeitig als Beispiel dienen, wie man die serielle Schnittstelle mit Windows-Funktionen bedient.
Alle Programme sind in ANSI‑C geschrieben, der ATMEGA nutzt ein paar winzige Assembler-Funktionen. Für Windows wird lediglich das Win32-API verwendet und ResEdit als Ressourcen Editor, weil die kostenlose Version von VS Express zumindest bis 2013 keinen Ressourcen Editor dabei hatte.
Host-Software
Ganz phantasielos habe ich die Host-Software SerCom genannt. Da zur Zeit nur der Antennenumschalter angeschlossen ist, ist dies der erste Tab, der nach dem Start angezeigt wird:
Die Bedienung des Antennenumschalters
Hier wird lediglich eine der bis zu sechs Antennen ausgewählt. Die Namen sind in der Registry konfigurierbar und oben nur Beispiel ohne reale Bedeutung. Die momentan aktive Antenne wird mit dem Icon angezeigt, nur eine kann zu einem Zeitpunkt aktiv sein. Port Status ist eigentlich eine verzichtbare Diagnosemeldung. Hier wird der physikalische Status des Ports A angezeigt, der die Relais ansteuert. Die beiden Tabs „Rotor“ und „Antennentuner“ sind leer und hier nur Platzhalter für zukünftige Steuerungen, die am selben Bus hängen sollen.
Mit dem Config-Tab wird einer der Busteilnehmer konfiguriert:
SerCom Config
Beim Start ohne Parameter werden hier die Konfigurationsdaten des PCs und des ausgewählten Devices angezeigt, also Baudrate, Device ID und verwendeter COM-Port. Wird SerComm mit dem Paramter „-c“ gestartet, läuft es im Konfigurationsmodus und die hier dunkel geschalteten Felder werden weiß und können geändert werden. In diesem Tab wird ein Zähler gezeigt, der angibt, wie oft das EEPROM programmiert wurde, denn die Anzahl der Programmierzyklen ist endlich (allerdings werden mindestens 100k-Zyklen garantiert).
Auch eine Uhr ist implementiert, deren Datum und Uhrzeit hier gesetzt und ausgelesen werden können. Mit dem Wert bei „RTC correction“ kann im Config-Modus ein Korrekturwert eingegeben werden, mit dem eine Frequenzabweichung des Quarzes für die Uhrzeit kompensiert wird. Mit „Restart Device“ wird auf dem Device ein Watchdog Reset provoziert, also ein echter Hardware-Reset. „Refresh“ liest die angezeigten Daten erneut aus dem Device aus.
Der Diagnose-Tab zeigt einige Daten an, die etwas über den Gesundheitszustand des Devices aussagen:
SerCom Diagnose
Zunächst wird der Typ des Moduls, seine Taktfrequenz und die Version der implementierten Software angezeigt. Verschiedene Zähler zeigen dann die Anzahl der unterschiedlichen Resets, die Anzahl fehlerfrei empfangener eigener und fremder Nachrichten und die Anzahl von Kommunikationsfehlern an. Auch die Versorgungsspannung und die Temperatur auf der Device-Seite werden angezeigt. Trotz des nur etwa 30mA großen Versorgungsstroms erwärmt sich das Board merklich. Nunja, bei 12V sind es ja auch immerhin 360 mW. Der Temperatursensor (TMP275) hat übrigens eine Genauigkeit von 0.5 K und 1⁄16 K Auflösung. Daß drei Stellen hinter dem Komma angezeigt werden, deutet eine höhere Genauigkeit an.
Außerdem werden die Namen und Zeitstempel der Quelldateien und der Zeitpunkt des Compilerlaufs angezeigt. Auch hier lässt sich mit der Refresh-Taste der angezeigte Inhalt erneuern. Durch Anklicken der „Continuous“ Checkbox wird der Refresh dauerhaft ausgeführt. Das ist für Dauertests hilfreich. Ein über Nacht ausgeführter Dauertest brachte keinen einzigen Fehler hervor. Daß die Fehlerzähler funktionieren, zeigte allerdings ein erster Test mit 100 W HF auf dem Antennenumschalter.
Seit einigen Tagen und Nächten ist die Software im Einsatz und hat sich bewährt. Für das Interface zwischen dem USB-RS485-Wandler und dem Bus habe ich auch zum Einkoppeln der 12V Versorgungsspannung eine kleine Box gebaut:
RS485 PC-Interface Box.
Sie fügt nochmal kleine Tiefpässe in die Kommunikationsleitung ein und entstört die Versorgungsspannung eines externen Steckernetzteils. Das Gehäuse ist übrigens ein sehr preiswertes Eurobox-Gehäuse, das ich auch für andere Dinge gerne verwende.
Here you can download some of my utilities. This site replaces the former download page. I will publish any new version or new utility here. It is just easier to maintain. Please check the Freeware Archive for older versions.
ParSer:
ParSer is a utility to construct a non-standard resistance or capacitance value from a set of standard resistors or capacitors. ParSer supports different topologies of up to three individual components. ParSer can also calculate voltage dividers and find a set of suitable resistors. The minimum and maximum shunt current can be specified as well as the nominal load current.
The name ParSer is misleading. It stands for parallel/serial connection of resistors or capacitors. I’m not very happy myself with this name, but now it’s out and I’m not going to change it.
Bin2C:
Bin2C is a utility to convert binary files to C source code. It provides a simple way to include binary files (e.g. images or audio files) in embedded projects, which often do not support any file system.
Change history: V2.20, Dec 2021: Compiled with Visual Studio 2019, fixed some Code Analysis complaints, no functional changes
DrawTimingDiagram:
During my recent (mostly Verilog) developments, I felt the need for a simple timing diagram generator with text output. Such a thing is very helpful to document the behavior of modules inside the source code rather than in a separate file. For this purpose I wrote DrawTimingDiagram. Here is the DrawTimingDiagram Online Help.
Change history: V1.01, Dec 2021: Initial release
Waterfall:
Mostly all modern amateur radio transceivers are software defined radios (SDR). As such, they come with a built-in waterfall diagram display, which in turn invites for stupid and useless experiments. Since retired, I have time for a little fun and I wrote a small program, which converts a PNG graphics file to a wave file. That wave file can be transmitted and it generates a waterfall display, which resembles the PNG input file. This is strictly for fun and shall not be used to annoy anyone, so use it at your own discretion. Here is a sample:
Sample input file
Spectrum of output file
Transmitted spectrum (start)
Transmitted spectrum (middle)
Transmitted spectrum (end)
The result is obviously limited by the low frequency- and amplitude-resolution of the waterfall diagram. Anyway, it works.
There is no help file, but the operation should be self-explanatory. Here is the user dialog:
Waterfall User Dialog
Time per row specifies the transmit duration of one PNG row. The total transmit time is the number of rows multiplied by this value. The ramp specifies the duration for linearly fading in and out a single row. Without such ramps, the signal will become rather distorted due to many harmonics.
Note that there are a number of different PNG file formats and not all of them are supported. I did not do extensive testing. If you encounter any problems, please let me know. In such a case, please send me sample file for testing.
General Comments:
All utilities are written for Windows and should run on all current versions. Please let me know if you encounter any problems or if you have any recommendation for improvements. None of the utilities needs to be installed. Just copy the .exe file to your preferred path and remove the file for uninstalling it.
The utilities store some parameters in the registry or in an ini-file. See the respective help file for details. Earlier versions used the key „HKEY_CURRENT_USER\SOFTWARE\Michael Krämer Freeware“ but I recently changed this to „HKEY_CURRENT_USER\SOFTWARE\DK8PP Freeware\“. I’m sorry for any inconvenience.
All files are compressed with 7‑zip, which ensures integrity by a built-in CRC32. If the file is corrupted by the download, 7‑zip should complain during unpacking. For some additional degree of file authenticity, I added the MD5 hash codes for the compressed files. I agree that downloading and running executables from unknown sources is generally not a good idea. I’m also reluctant to do that myself. Let me therefore suggest the following:
Scan the downloaded executable with a local or online virus scanner.
Run the executable in a virtual machine.
Review the provided source code and compile it yourself. I appreciate if you report any errors that you find and I also value any suggestions to improve my programming style.
By the way, feel free to use and modify the source code as you like. I don’t reserve any copyrights. But if you distribute modified code, say that it is yours, not mine. I simply want to avoid any liability issues. Life is too short to fight with hungry lawyers.
Sometimes I receive more or less mild complaints for programming under Windows rather than Linux. Well, I had some experience with Linux in the late 90es. I then decided to stay with Windows, simply because it works reliably. Again, life is too short to lose time with immature environments. I’m sure that Linux has improved since the old days, but I will not change any more. I don’t use any sophisticated tools, just the Win32 API and plain C, not even C++. Therefore the executables should also run under Wine.
Es hat mich mal wieder in den Fingern gekribbelt. Nachdem wir die vergangenen zwei Jahre nur mit unserem neuen Haus beschäftigt waren, musste ich mal wieder ein kleines Board entwickeln.
Ich habe ja wieder mit dem Amateurfunk angefangen und zwei Transceiver von Icom gekauft. Die Antennenanlage lässt allerdings sehr zu wünschen übrig. Ich will verschiedene Antennen aufbauen, für Kurzwelle vorläufig nur Mono- und Dipole. Da nicht jede Antenne ein eigenes Kabel bekommen kann, werde ich also einen Antennenumschalter installieren müssen, der von der Station aus elektrisch schaltbar sein soll. Sowas kann man fertig kaufen oder auch selberbauen, aber auch die gekauften brauchen eine Steuerung.
Zur Kommunikation zwischen Antennenumschalter und Shack bietet sich die RS485 Schnittstelle an. Sie setzt auf einer asynchronen seriellen Schnittstelle auf und unterstützt Leitungslängen von vielen hundert Metern (bis 1,2 km nach der Norm) bei Baudraten bis 12 MBd. Durch die Verwendung eines Leitungspaars im Gegentakt wird eine hohe Störsicherheit erreicht. Ein Leitungspaar gestattet die Kommunikation im Halbduplex-Mode, für Vollduplex sind zwei Leitungspaare nötig. RS485 ermöglicht auch den Aufbau eines Bussystems, bei dem bis zu 32 Teilnehmer angeschlossen werden können. Bei der hier geplanten Antennenumschaltung könnten also mehrere Antennenumschalter über ein einziges Leitungspaar angeschlossen werden.
Weil ich gerade noch einige Exemplare des Mikrocontrollers in der Kiste liegen hatte, habe ich ein kleines Board mit dem ATtiny1634 und einem RS485-Transceiver gebaut. Hier die KiCad 3D-Vorschau:
Unterseite des RS485 Moduls mit einem ATtiny1634.Oberseite des RS485 Moduls.
Da die Umschaltrelais des Antennenschalters typischerweise mit 12V arbeiten, ist auf der Oberseite ein einfacher Linearregler implementiert. Es passen 3V- und 5V-Typen. Da der 1634 bei 3V nur bis 8 MHz getaktet werden kann, habe ich auf dem Prototypen 5V-Regler eingelötet. Damit läuft der Controller mit bis zu 12 MHz. Hier ist der Schaltplan, es gibt keinerlei erwähnenswerte Besonderheiten.
In der Wahl des Kommunikationsprotokolls ist man ziemlich frei, aber warum etwas eigenes erfinden, wenn es schon weitverbreitete Standards gibt. Ich habe mich für den Modbus entschieden, der auch beispielsweise bei der Kommunikation mit PV-Wechselrichtern verwendet wird. Es gibt ein schönes Utility für Windows, QModMaster, das Modbus-Nachrichten senden und empfangen kann. Das war sehr hilfreich bei der Implementierung des Modbus Protokolls in den ATtiny1634. Ich bin noch nicht komplett mit der Implementierung fertig, daher will ich die Software im Moment noch nicht hier veröffentlichen. Das hole ich nach, wenn’s fertig ist. Da die wesentlichen Dinge aber bereits funktionieren, hier mal nur kurz der Ressourcenverbrauch:
Program Memory Usage : 2892 bytes 17,7 % Full Data Memory Usage : 85 bytes 8,3 % Full EEPROM Memory Usage : 2 bytes 0,8 % Full
Daran wird sich im Endausbau nicht mehr viel ändern. Vielleicht braucht er mit weiteren Funktionen 25 – 30% Flash Speicher, aber die vorhandenen 16 kB werden auf jeden Fall ausreichen. Wenn genügend Platz bleibt, werde ich die Sende- und Empfangspuffer etwas vergrößern, was dann den Datenspeicher Verbrauch um ein paar Prozent ansteigen lassen wird. Auch hier wird das 1 kB SRAM allemal ausreichen.
Über ein 25m Kabel lief die Kommunikation bei 38 kBd wie erwartet mehrere Stunden fehlerfrei, allerdings kann QModMaster auch leider nur eine Nachricht pro Sekunde absetzen. Das ist also nicht wirklich ein hoher Durchsatz. Auf der PC-Seite verwende ich übrigens einen „WaveShare USB TO RS232 RS485 TTL Industrial Isolated Converter“, der bisher zuverlässig funktioniert.