Geschenk Engineering



Vor dem Fenster regnet es, der Dezember steht auf dem Kalender. Die Zeit für Feiertage rückt näher und daher die Zeit für Geschenke. Kollege Pavel wünscht sich einen neuen Laptop und Freundin Masha ein Haus am Meer. Und trotz des würdigen Gehalts des Berufs des Programmierers leben wir nicht in einer Welt der unbegrenzten Möglichkeiten, was bedeutet, dass ich diesen Menschen nicht genau das geben kann, was sie am meisten wollen (auch wenn Pascha möglicherweise mein bester Pawel ist, der Ich weiß, aber Mascha geht es gut.

Hier taucht das Problem der „billigen Geschenke“ auf. Es ist nicht gut, jedem ein teures Geschenk zu machen, aber ich möchte nicht noch eine Schachtel Pralinen, eine Kerze oder eine undeutliche Figur geben. Sie müssen also Geschäft mit Vergnügen verbinden - ich mache Dinge gerne mit meinen eigenen Händen, und das Ergebnis ist großartig als Geschenk. Dies ist eine Geschichte darüber, wie ich wieder einmal vorgab, ein Ingenieur zu sein und verschiedene Geschenke handgefertigt zu haben.

Ein kleiner Exkurs vom Hauptthema


Ich kann nicht sofort zum Hauptthema gehen, also fange ich von weitem an. Vor einigen Jahren wurde das Spiel „The Witcher 3“ veröffentlicht. Mein Freund riet mir zu spielen, und im Allgemeinen habe ich das Spiel wirklich bewundert. Dann habe ich entschieden, was zu tun ist, und ihr etwas zum Thema des Spiels gegeben ... Ich werde nicht zu tief in die Beschreibung des Spiels eingehen (Google wird allen helfen) oder sagen, dass mir nicht viele Dinge in den Sinn gekommen sind für die Schlüsselwörter "The Witcher, Engineer, Gift."

Die Hauptfigur des Spiels hat ein Pferd namens "Roach" (in russischer Sprache), der Held treibt sie von Zeit zu Zeit mit der Phrase "Move, Roach". Ich beschloss, ein mechanisches Spielzeug zum Thema „Kakerlaken rühren“ herzustellen.

Natürlich wurde das Geschenk als eine völlig nutzlose, dumme, aber lustige Sache konzipiert, daher lautete der Plan wie folgt:

  1. Es gibt eine Box, die den Mechanismus in sich verbirgt.
  2. Der Mechanismus ist eine Welle, die sich dreht und die das Pferd bewegt.
  3. Die maximale "Hartnäckigkeit" der Pferdebewegung ist willkommen. Anfangs dachte man sogar, dass sich das Pferd wie ein Fisch bewegen sollte und nicht wie ein Pferd (immerhin Rotauge), aber das Ergebnis war „etwas dazwischen“.
  4. All dies wird aus Sperrholz gefertigt, das gemäß den Zeichnungen mit einem Laser präzise auf Bestellung zugeschnitten werden kann.

Der Hauptnachteil der Materialauswahl und der Tatsache, dass das Zuschneiden auf Bestellung erfolgt, war die Tatsache, dass ich die Gelegenheit zur Erstellung eines Prototyps verpasst habe, was bedeutet, dass sich alle Probleme mit krummen Händen und die Nichteinhaltung der Regel des „Siebenfachen Maßes“ schnell bemerkbar machten:



Obwohl am Ende die Tatsache, dass viele Details des Spielmechanismus aufgrund zu großer Lücken dazu beigetragen haben, die Tatsache zu kompensieren, dass ich die Teile und die Welle ziemlich schief verbunden habe. Hier, wie sie sagen, "minus minus gibt plus" und der Mechanismus als Ganzes hat funktioniert, wie es beabsichtigt war:



Nachdem es nur ein kleines Gemälde gab und das Ergebnis so eine Schachtel war:



Dann wird jemand sagen, dass es notwendig war, die Schachtel transparent zu machen, um die Arbeit der Innenseiten beobachten zu können, aber tatsächlich vermutete ich zunächst, dass ich den gesamten Mechanismus und die Schachtel von innen nicht so sauber und ordentlich zusammenbauen konnte, dass es nicht wehtat schau durch die transparenten Wände der Kiste. Daher ist eine lichtundurchlässige Box eine notwendige Maßnahme.

Es bleibt nur noch zu packen, einen Bogen auf eine Schachtel zu binden und das Geschenk ist fertig:



Um das innere Kind nicht zu verärgern, das sich in einer Situation wie ein Ingenieur fühlen wollte, in der ich tatsächlich ein paar Sperrholzstücke geklebt hatte, beschloss ich, eine „Zeichnung“ anzufertigen. Verzeihen Sie mir alle, die etwas in den technischen Zeichnungen verstehen, denn Ich verstehe, dass dies mehr eine Parodie der Zeichnung als eine echte Zeichnung ist, aber wie es mir schien, hat er einem einfachen Spielzeug einen Mehrwert verliehen:



Heute habe ich ...


Manchmal spielt das Schicksal mit uns und deutet irgendwie an, dass bald etwas passieren sollte. Die Geschichte eines meiner Geräte beginnt genauso. Ich bestellte eine kleine Elektronik im Wert von ungefähr 5 USD, die wie üblich einen Monat unterwegs war. Danach erhielt ich eine SMS, dass das Paket bei der örtlichen Post auf mich wartete. Die Schachtel erwies sich als viel größer als erwartet und ließ sofort Zweifel am Inhalt aufkommen. Zweifel wurden bestätigt - im Inneren befand sich neben den Kleinigkeiten, die ich bestellt hatte, auch ein dreifarbiges E-Ink-Display mit einer Diagonale von 4,2 Zoll. Ich habe den Verkäufer kontaktiert, er hat bestätigt, dass er beim Packen etwas durcheinander gebracht hat, sagte aber, dass ich dies als Geschenk betrachten und es verwenden kann, wie ich es für richtig halte.

Das Schicksal wies mich darauf hin, dass es an der Zeit ist, ein neues Projekt zu starten, und dieses Projekt wird etwas mit einem E-Ink-Display sein. Nachdem ich mich kurz mit den technischen Daten des Geräts vertraut gemacht und das Display an die Steuerung angeschlossen hatte, stellte ich sicher, dass die technischen Daten nicht über die Aktualisierungszeit lagen. Der Bildschirm wurde für mehr als 10 Sekunden aktualisiert, blinkte und versuchte, einen epileptischen Anfall zu verursachen:


(Ich habe keine frühen Fotos zum Anschließen des Displays, daher hat das Gerät hier bereits ein aussagekräftigeres Aussehen.)

Es wurde klar, dass Sie ein einfaches Gerät benötigen, das keine komplexen Animationen (und Animationen im Allgemeinen) erfordert. Und dann bin ich auf einen Stimmungskalender gestoßen:


Der Stimmungskalender besteht aus einfachen Bildern und ironischen Signaturen. Ich habe beschlossen, einen Kalender mit dem Namen "Today I" zu erstellen (der eigentlich überhaupt kein Kalender ist). Es wird ein einfaches Gerät sein, das jeden Tag ein Bild anzeigt, das den heutigen "Geisteszustand" charakterisiert, und eine Beschreibung davon. Zusätzlich könnte der Kalender einige andere Funktionen haben, aber der Hauptkalender wäre genau der "Kalender" - ein eigenes Bild für jeden Tag.

Das elektronische Papiermodul erlaubte die Anzeige von drei Farben (schwarz, rot und weiß), die wie zwei Bilder - schwarz und weiß und rot und weiß - auf das Modul übertragen werden sollten. Tatsächlich wäre es richtiger zu sagen, dass der Bildschirm einfach eine monochrome Bitmap erwartet, bei der jedes Bit die Farbe eines Pixels bestimmt (ich bin mir nicht sicher, ob dieser Begriff auf elektronisches Papier anwendbar ist, aber ich hoffe, dass die Idee klar ist). Für den schwarzen oder roten Kanal kann eine separate Bitmap festgelegt werden. Somit gibt es eine Menge von Bytes, bei denen jedes Bit, das auf 1 gesetzt ist, einem Farbpixel entspricht, und alle Bits, die 0 bleiben, sind weiße Pixel auf dem Bildschirm. Die Bildschirmauflösung beträgt 400 x 300 Pixel, d.h. Für ein Schwarzweißbild sind 15.000 Byte erforderlich (8 Pixel werden in einem Byte codiert). Für die drei Farben werden 30.000 Byte benötigt, wenn Sie nicht versuchen, das Bild kompakter zu packen. Unter dem Gesichtspunkt der Implementierung könnten die Ersteller des Displays einfach zwei Bits pro Pixel auswählen und den tatsächlichen Zustand der Dinge (wo rot ist, wo schwarz ist und wo weiß ist) speichern, aber dies würde dieselben 30.000 Bytes erfordern, aber selbst für monochrome Bilder würde die Übertragung von 30.000 Bytes erfordern.

Wie in jedem meiner anderen „Handwerke“ begann ich, Aufgaben für mich selbst zu erfinden, damit sich nicht alles in „Verkabelung einstecken und Bibliothek herunterladen“ verwandelte. Selbst wenn wir die Möglichkeit in Betracht ziehen, eine Art Bildkomprimierungsalgorithmus auf der Controllerseite zu implementieren, wurde klar, dass der Controller ohne externen Speicher für Bilddateien sehr deprimiert wäre. Es wurde beschlossen, eine SD-Karte zu nehmen und einen einfachen Code-Wrapper für die Arbeit mit FAT32 zu schreiben. Natürlich wäre es möglich, auf ein Dateisystem zu verzichten und Daten direkt auf eine Speicherkarte zu schreiben, aber es schien mir weniger praktisch, neue Dateien hinzuzufügen, und es war für mich interessant, die grundlegenden Vorgänge für die Arbeit mit FAT32 mit meinen eigenen Händen zu implementieren.

Es ist wichtig klarzustellen, dass ich es gewohnt bin, Dinge selbst zu schreiben (Sie sollten mir nicht sagen, dass es ein Meer von Bibliotheken gibt, ich weiß darüber Bescheid und mit Google), wenn ich solche Dinge mache, aber seitdem Vorher hatte ich nicht das Vergnügen, mit FAT32 auf einem niedrigen Niveau zu arbeiten, es war ein ziemlich unterhaltsamer Prozess.

Ich werde nicht näher auf die Arbeit mit FAT32 und der SD-Karte als Ganzes eingehen Das Internet ist voll von Artikeln zu diesem Thema (und ich möchte meine Geschichte nicht in eine Nacherzählung von Spezifikationen verwandeln), aber ich werde über einige Dinge sprechen, die implementiert werden mussten. Es ist notwendig, nicht nur die Funktionen zum Lesen aus einer Datei und zum Schreiben in eine Datei zu implementieren (ich habe beschlossen, einige Einstellungen und Zustände auf derselben SD-Karte und nicht im EEPROM zu speichern), sondern auch die Funktionen zum Suchen nach einer Datei im Dateisystem, wenn Sie arbeiten müssen auf die übliche Weise.

Alle Daten auf der Speicherkarte sind in Cluster unterteilt (die wichtigste adressierbare Einheit im FAT32-Dateisystem), und die Cluster sind bereits in Sektoren unterteilt. Um die Datei „habr.txt“ von der SD-Karte in FAT32 zu lesen, benötigen Sie:

  1. Initialisieren Sie die Speicherkarte.
  2. Lesen Sie den Sektor an der Nulladresse und überprüfen Sie, ob das FAT32-Dateisystem einen bestimmten Header hat (Sie können diesen Schritt überspringen, wenn wir an Glück glauben).
  3. Lesen Sie den Sektor bei Adresse Null und erhalten Sie "Logical Block Addressing" (LBA).
  4. Lesen Sie den Sektor an der empfangenen Adresse (LBA) und rufen Sie die erforderlichen Daten ab (welcher Cluster ist das Stammverzeichnis, wie viele Sektoren befinden sich im Cluster usw.).
  5. Lesen Sie den Cluster "Root Directory" (tatsächlich erfolgt das Lesen nach Sektoren, Sie müssen nur so viele Sektoren lesen, wie Sektoren im Cluster vorhanden sind) nach seiner Nummer. Es hat eine eigene Formel zum Konvertieren von Cluster-Seriennummern in physikalische Adressen. Dateiinformationen werden hier gespeichert, sodass wir die Daten auf der Suche nach der gewünschten Datei lesen. Bei Dateinamen gibt es noch eine Kleinigkeit: Der Name kann kurz oder lang sein, abhängig davon werden die Daten entweder an einem Ort (in der gleichen Struktur) oder in einem zusätzlichen Datensatz gespeichert, der auch separat gelesen werden muss. Wenn eine Datei mit dem gewünschten Namen gefunden wird, erhalten wir den Cluster, in dem sich der Anfang befindet (oder möglicherweise die gesamte Datei, wenn sie in die Clustergröße passt), sowie die Dateigröße. Wird die Datei in diesem Cluster nicht gefunden, suchen wir nach dem nächsten Cluster und wiederholen den Dateisuchvorgang.
  6. Lesen Sie den Cluster an der gefundenen Adresse. Lesen Sie die Cluster weiter und suchen Sie nach dem nächsten Cluster, bis alle Daten gelesen wurden.

Es scheint mir, dass es einfacher ist, das Prinzip des Dateisystems denen zu erklären, die verknüpfte Listen mindestens einmal implementiert haben, weil Tatsächlich besteht das FAT32-Dateisystem aus einer Reihe von Datenblöcken und einer Art Tabelle, in der angegeben ist, wo nach dem nächsten Datenblock gesucht werden soll. Das Lesen von Daten aus FAT32 ist ein Prozess, bei dem wir die Daten lesen, nach der Adresse des nächsten Blocks suchen, die Daten lesen, nach der Adresse des nächsten Blocks suchen usw.

Ich habe nicht alle möglichen Szenarien implementiert und einige Dinge vereinfacht:

  • Alle Dateien befinden sich im Stammverzeichnis der Speicherkarte, und das Durchsuchen von Verzeichnissen wird nicht verwendet.
  • Alle Dateien haben Kurznamen.
  • Die Steuerung liest beim Start eine Liste von Dateien und speichert sie im Speicher, um nicht erneut nach jeder Datei zu suchen.
  • Die maximale Anzahl von Dateien ist durch eine Konstante begrenzt (und tatsächlich habe ich nur ein paar Dutzend Bilder gezeichnet).

Kurz gesagt, all das ist ein überzeugender Grund, eine fertige Bibliothek zu nehmen und nicht viel Zeit mit dem Lesen, Entwickeln und Debuggen von Dokumentationen zu verbringen. Ich würde mir raten, solche Dinge nur für pädagogische Zwecke oder "zum Spaß" zu implementieren.

Das Display hat auch einige Einschränkungen auferlegt, wie Jedes Bild darauf wird folgendermaßen angezeigt:

  1. Wir wachen auf und initialisieren das Display (um dessen Lebensdauer zu verlängern und Energie zu sparen, schläft das Display grundsätzlich).
  2. Wir belichten den notwendigen Kanal (zum Beispiel schwarz).
  3. Wir leiten 15000 Bytes des Bildes weiter.
  4. Wir belichten den notwendigen Kanal (zum Beispiel rot).
  5. Wir leiten 15000 Bytes des Bildes weiter.
  6. Wir weisen das Display an, Daten aus dem Puffer zu ziehen.
  7. Wir warten, bis die Anzeige fertig ist.
  8. Wir sagen dem Display, dass es schlafen soll.

Bei Schwarzweißbildern können Sie die Schritte 4 und 5 überspringen. Bei einem Dreifarbenbild ist die Übertragungsreihenfolge von Schwarzweiß- und Rotweißbildern nicht wichtig, da Rot wird immer über Schwarz gemalt, Schwarz ist nur über Weiß, und nur die weißen Pixel sind weiß und schwarz und weiß und rot und weiß.

Der Einfachheit halber (um die Gesamtzahl der Dateien nicht zu erhöhen) habe ich beschlossen, die Schwarzweiß- und Rotweißbilder als einzelne Datei zu speichern, auf die das Schwarzweißbild unmittelbar das Rotweißbild folgt:



Das Ergebnis des Vergleichs dieser Bilder war ungefähr so ​​(es scheint mir, dass sich jeder von uns mindestens einmal in seinem Leben wie ein Reh mit Hörnern anfühlte - ein Bein):



Tatsächlich folgte auf die beiden Bilder ein weiteres Bild, das eine Beschreibung des Zustands enthielt (durch Klicken auf die Schaltfläche erhalten Sie eine Beschreibung, die mit dem heute angezeigten Bild übereinstimmt).

Aufgrund des begrenzten Speichers der Steuerung werden Daten von der Speicherkarte niemals vollständig in den Speicher der Steuerung eingelesen. Das Bild von der Speicherkarte wird in Fragmenten gelesen, die von der Größe des Sektors bestimmt werden (der Einfachheit halber nehmen wir an, dass diese Größe immer statisch ist und sich nicht von Karte zu Karte ändern kann) und in den Prozess der Datenverarbeitung von der Karte fallen. In meiner Implementierung werden beim Lesen einer Datei die Clusternummer, die Dateigröße und der Rückruf für jeden gelesenen Sektor als Eingabe verwendet. Dieser Ansatz ermöglichte es uns, verschiedene Funktionen der Dateiverarbeitung zum Lesen und Anzeigen des Bildes selbst oder seiner Beschreibung zu verwenden.

Die folgende Logik ist auf die Rückruffunktion beim Lesen von Bildern von einer Speicherkarte zurückzuführen:

  1. Stellen Sie den gewünschten Kanal ein (der Kanal wird zufällig bestimmt), bevor Sie Daten an das Display senden.
  2. Verfolgen Sie die übertragenen Daten, um den Kanal zu wechseln, wenn das Senden der Daten für den vorherigen Kanal abgeschlossen ist.
  3. Senden Sie die von der Karte empfangenen Daten.
  4. Stellen Sie fest, dass die erforderlichen Daten übertragen wurden und dass der Rest der Daten (Bild mit Beschreibung) ignoriert werden kann.

Die Tatsache, dass ich Bilder eingegeben habe, die mehr Daten enthielten, als auf dem Bildschirm angezeigt werden sollten, hat mich erschwert. Das heißt Es gibt ein Bild, das der Hintergrund ist und immer statisch ist und der Größe des Bildschirms entspricht, und es gibt ein viel größeres Bild, von dem Sie einen zufälligen Bereich (die Größe des Bildschirms) und die Anzeige aufnehmen müssen.

Ein solches Bild stellte zusätzliche Anforderungen an den Handler - es musste berechnet werden, wie viele Bytes von der aktuellen Zeile des Bildschirms übertragen wurden, wie viele weitere beim nächsten Aufruf hinzugefügt werden mussten (wenn die Zeile an den Rand der Sektorgröße fiel) und wie viele übersprungen werden sollten.

Visuell kann diese Situation wie folgt dargestellt werden:



Es gibt einen bestimmten Puffer, in dem sich ein "Fenster" der erforderlichen Größe befindet (grüner Bereich), und Sie müssen nur die Daten aus diesem Fenster lesen und die Daten aus dem Puffer in Fragmenten von N Bytes lesen. Es wäre möglich, einen solchen Lesevorgang so zu visualisieren:



Im Allgemeinen hat es sich als nicht so einfach herausgestellt, die Logik der Arbeit mit dem Bildschirm zu einer Funktion hinzuzufügen, die immer einen 512-Byte-Puffer erhält und die bestimmen sollte, welches dieser 512 Byte benötigt wird (wenn überhaupt etwas benötigt wird) "Auf der Stirn". Genauer gesagt war die Aufgabe im Vergleich zu alltäglichen Lösungen weniger kompliziert als ungewöhnlich, weshalb es überraschenderweise sehr interessant war, sie zu lösen. Für mich war es wie eine „Olympiadenaufgabe“, bei der die Menge an Strom berechnet werden musste, die zum Kontrahieren der Muskeln benötigt wird, um mit zwei Löffeln (je einem Löffel in jeder Hand) Wasser von einem Eimer in einen anderen zu übertragen.

Um die Schwierigkeit besser zu verstehen, füge ich hier eine weitere Animation hinzu, die sich nur auf den Inhalt des Clusters und nicht auf die gesamte Datei bezieht (alle anderen Informationen müssen separat gespeichert werden):



Wie geplant sollte der Kalender jeden Tag ein neues Bild anzeigen, d. H. es muss in der Lage sein, die Zeit zu überwachen (auch wenn es ausgeschaltet ist), was bedeutet, dass auch ein Echtzeituhrmodul (RTC) benötigt wird. Und trotz der Tatsache, dass mein Controller eine eingebaute Echtzeituhr hat, ist es fast unmöglich, eine Batterie dafür zu finden, weil Kontakte sind nicht mit der Platine verbunden. Ich beschloss, die Beine des Controllers nicht zu vergewaltigen, um sie anzulöten, und nahm die externe chinesische RTC. Die Arbeit mit RTC sollte ganz einfach sein:

  • Wenn eingeschaltet, erhalte die Zeit von der chinesischen RTC.
  • Uhrzeit in interner RTC einstellen.
  • Verwenden Sie die interne Echtzeituhr, um die Zeit zu zählen und die Chinesen bis zum nächsten Herunterfahren zu vergessen.

Aber hier stellte sich heraus, dass alles nicht so einfach war, da die interne RTC des Controllers mit der Zeit im üblichen Format (UNIX-Zeitstempel) arbeitet und sein chinesischer Freund Binary Coded Decimal (BCD) verwendet. Zuvor bin ich nicht auf dieses Format gestoßen und war sehr überrascht, dass es auch von modernen Modulen für Arduino verwendet wird. Die Essenz des Formats ist recht einfach - es gibt ein Byte, in dem beispielsweise die Anzahl der Sekunden gespeichert wird. Die vier höherwertigen Bits speichern zehn und die vier niederwertigen Bits speichern Einheiten. Es stellt sich heraus, dass die hexadezimale Darstellung dieses Bytes selbst eine lesbare Zeit enthält - Byte 0x49 entspricht einem Wert von 49 Sekunden (obwohl dieses Byte im Dezimalsystem 72 entspricht).

So wie ich es verstehe, passierte es so historisch, dass es einfacher war, RTC direkt mit Bildschirmcodierern zu verwenden, um eine Uhr zu erstellen, aber ich musste BDC mit Stiften in UNIX-Zeitstempel konvertieren.

Zusätzlich zu der Anzeige, dem Echtzeituhrmodul, der Speicherkarte und dem Dateisystem war es notwendig, alle diese Drüsen in einem Gehäuse zu verpacken, das ebenfalls hergestellt werden musste, d. H. "Zeichnen". Sie können ausführlicher über all die Schmerzen lesen, die mir in meiner letzten Veröffentlichung begegnet sind. Hier war alles genau das gleiche:


(Ich hatte keine Massenproduktion geplant, alle Details sind das Ergebnis falscher Messungen oder schlecht durchdachter Lösungen.)

Als Ergebnis wurden der Fall und die notwendigen Details gezeichnet (es gibt keine vordere Abdeckung im Bild):



(, - - ):



( ) :



. , .

( ):



, — :



, , :



!


-, : “ ?! 100500 , !”. , , — ( - ), , , , .

, , , .

Jetzt ist es allgemein in Mode, Dinge auf einem 3D-Drucker zu drucken. Druckgeräte sind viel zugänglicher geworden, und die Software zum Erstellen von Modellen ist für Kinder einfach genug, um verstanden zu werden.

Hilfeschrei


, , - . , , , , , - .

, , . “--”, “MP3 Music Player Module for Arduino”, Arduino Nano, , mp3 .

, , , , , , / , . “” , .

3 , . :

  1. , .
  2. “” (, , , ).

( ):



, , .. , ( : playSound(rand() & 3);).

. “” ( , ), USB , “ ”:



?


, , . 3 :



— . , :



!


, :

  1. .
  2. 3 2 , ~0.4.
  3. — .
  4. 3 ( ).
  5. .

… :



:



“”:



?


“ - , - .” , , -. “”, , , FAT32, BCD , RTC.

, - ( ) : “ , , !” - .

, . , . , , __!

Source: https://habr.com/ru/post/de480792/


All Articles