Shadowplay LED Watch auf der Arduino Uno Plattform

Anstatt mitzumachen




Unser dreiköpfiges Team hatte also die Aufgabe, in kürzester Zeit ein kleines Hardwareprojekt zusammenzustellen, vorzugsweise auf der Arduino-Plattform. Es ist erwähnenswert, dass wir bis zu diesem Moment zum größten Teil theoretisch mit Schaltkreisen vertraut waren. Und das bedeutet - weder Erfahrung mit einem Lötkolben (praktisch) noch insbesondere Erfahrung mit Arduino.

Plötzlich stießen wir auf einen Artikelgewidmet dem Shadowplay Clock Projekt. Dies ist eine Wanduhr, die von einem Team von Wiener Designern entworfen wurde. Die Zeit, zu der Sie sehen können, indem Sie einen Finger auf ihre Mitte legen. Die LEDs leuchten so, dass der Schatten des Fingers in der Mitte die Zeit anzeigt. Es wurde beschlossen, dasselbe (oder sehr ähnliche) zu erstellen, aber zu Hause. Wie Sie sehen, enthält der obige Artikel keine detaillierte Beschreibung des Projekts. Daraus folgte, dass wir selbst herausfinden mussten, wie dieses Gerät funktioniert, und es zum Leben erwecken mussten. Was wir tatsächlich getan haben.

Materialien


Um eine Uhr zu erstellen, benötigen Sie:

  • Faserplattenrohlinge
  • 60 LED Diodenstreifen
  • Arduino uno
  • Echtzeituhrmodul RTC DS1307
  • Taste
  • Steckbrett
  • Schieberegister 74HC595 (x2)
  • 8-Bit-Register-Latch 74HC573N (x8)
  • Decoder 4-16 K155ID3
  • offener Abflusswechselrichter IN74HC05AN (x10)
  • Netzteil

Fangen wir an


Also, der Algorithmus des Geräts:

  1. Wenn Strom angelegt wird, leuchten die LEDs in einer vorgegebenen Kombination. Im ursprünglichen Shadowplay leuchteten alle LEDs auf, aber es schien uns interessanter, eine Kombination als Bildschirmschoner zu starten.
  2. Wenn die Taste gedrückt wird (ja, wir haben uns auch vom Original entfernt und eine kleine Taste in die Mitte eingefügt), wird die Zeit vom RTC-Modul abgelesen.
  3. Die Lesezeit wird in Binärcode (Maske) umgewandelt und in Register eingetragen.
  4. Je nach Maske wird die gewünschte Diode gezündet.

Hardware


Als wir uns schließlich für die Idee des Projekts entschieden hatten, versuchten wir zunächst, ungefähre Versionen der Schemata für deren Umsetzung zu skizzieren. Die Hauptfrage war, wie 60 LEDs angesprochen werden sollen. Tatsächlich bestimmte die Antwort auf diese Frage die Methode, fast das gesamte Schema zu konstruieren.

Die erste Option, die mir in den Sinn kam, war die Verwendung von Decodern. Die kompilierte Schaltung bestand aus einer Kaskade von vier Decodern 4-16 und einem Decoder 2-4, beide mit Entschlüsselungsfreigabeeingängen. Eine solche Kaskade ermöglichte die Adressierung von 64 Ausgängen, was mehr als genug war, um 60 LEDs anzuschließen.

Dann stellte sich jedoch die Frage, wie mehr als eine LED gleichzeitig funktionieren kann (Adresse) (schließlich mussten wir der Uhr mindestens die Minuten- und Uhrzeiger zur Verfügung stellen). Hier zeigte sich der Hauptnachteil dieses Schemas - der Decoder kann per Definition nicht mehr als einen Ausgang gleichzeitig adressieren.

Dieser Fehler zwang uns, die Idee mit einer Kaskade von Decodern aufzugeben. Darüber hinaus haben wir jetzt eine weitere Anforderung für die zukünftige Schaltung - die Unterstützung für den gleichzeitigen Betrieb einer anderen Anzahl von LEDs.

Um diese Anforderung zu erfüllen, dachten wir, dass es möglich ist, jeder LED zu ermöglichen, ihren Zustand zu speichern. Register sind für diesen Zweck gut geeignet, wobei jede einzelne Entladung dem Zustand einer der LEDs entspricht. Wir haben uns für 8-Bit-Register entschieden, da diese häufiger und praktischer sind. Dementsprechend benötigen wir in unserer Schaltung 8 solcher Register, um 60 LEDs zu unterstützen.

Als nächstes haben wir darüber nachgedacht, wie der Status von LEDs mit Arduino über Register gesteuert werden kann. Jedes Register für den normalen Betrieb sollte alle 8 Bits in seiner Gesamtheit empfangen. Arduino Uno bietet natürlich genügend Ausgänge, um mehrere Bits gleichzeitig zu übertragen, aber dieser Ansatz ist nicht rational. Darüber hinaus enthält das Schema nur 8 Register, was bedeutet, dass Sie sie irgendwie adressieren müssen. Zu diesem Zweck haben wir einen Decoder und zwei 8-Bit-Schieberegister hinzugefügt, die in Kaskade mit der Schaltung verbunden sind. Ein Schieberegister speichert eine 8-Bit-Zustandsmaske, die in eines von 8 regulären Registern geladen wird, deren Nummer im zweiten Schieberegister gespeichert ist. Dementsprechend ist ein Decoder mit dem zweiten Schieberegister verbunden. Für diese Zwecke reicht ein 3 x 8-Decoder völlig aus.

Um die Inversion von der erforderlichen Anzahl von Ausgängen zu entfernen, haben wir zwei KR1533LN1-Wechselrichterschaltungen verwendet. Dies hat das Schema natürlich etwas kompliziert.

Eine weitere Aufgabe war die Arbeitsspannung der LEDs von 12 Volt im Vergleich zu 5 Volt Logikschaltungen. Die vorgeschlagene Lösung bestand darin, einen Wechselrichter mit offenem Abfluss zu verwenden. Eine solche Mikroschaltung spielt die Rolle eines Schlüssels, der einen der Kontakte der LED mit der Erde schließt (mit logischer 1) oder öffnet (mit logischer 0), wodurch die LED ein- oder ausgeschaltet wird. Die Schaltung nimmt einen Betrieb von 12 Volt entsprechend der Betriebsspannung der LEDs an. Um 5 Volt für Logikschaltungen zu erhalten, wurde der Schaltung der Stabilisator KR142EN5A mit zwei Kondensatoren hinzugefügt.

Einige Eingänge bestimmter Mikroschaltungen implizieren einen konstanten Wert am Eingang, sodass sie mit Masse oder einer Stromquelle verbunden waren. In diesem Fall sind dies die folgenden Eingaben:

  • Der inverse MR-Reset-Eingang in beiden Schieberegistern ist über das Lastregister mit dem Stabilisatorausgang bei 5 Volt verbunden.
  • Der inverse OE-Ausgangsfreigabeeingang in beiden Schieberegistern ist direkt mit Masse verbunden.
  • Inverser Decoder-Freigabeeingang E0 mit Masse verbunden




Die Schaltung wird von vier Eingängen (E1, SH, ST, DS) gesteuert. Der Zweck und die Signalpegel von jedem von ihnen werden nachstehend ausführlicher erörtert:

Der Eingang E1 dient zur Aktivierung des Decoders. In unserem Fall befinden sich anfangs am Decoder zwei Steuereingänge E1, E0, und beide sind invers. Es wird genug einen Ausgang geben, so dass der zweite (E0) zu Boden gebracht werden kann. Der "Standard" -Decoderstatus ist betriebsbereit, bis ein hoher Signalpegel an E1 angelegt wird. Um das Gegenteil zu erreichen, haben wir diesen Eingang mit dem Wechselrichter verbunden. Ohne dies kann der Decodierer den Registern beispielsweise zum Zeitpunkt der Aktualisierung der Daten im Schieberegister falsche Steuersignale geben. Wie bereits erwähnt, kann in der Schaltung ein 3 × 8-Decoder verwendet werden, der einen nicht inversen Steuereingang haben kann, wodurch es einfach wird, alle oben beschriebenen Probleme ohne zusätzliche Drähte und einen Lötkolben zu lösen.

Wenn ein einzelner Signalpegel an E1 angelegt wird, decodiert der Decodierer die im entsprechenden Schieberegister befindliche Registeradresse und sendet ein Signal an den gewünschten Ausgang. Danach schaltet der Decoder wieder ab, indem er einen niedrigen Signalpegel an E1 anlegt. Ein solcher Schalter des Decoders erzeugt ein Signal am gewünschten Ausgang, dessen Flanke und Abfall als Registertaktimpuls zum Einrasten der auf dem Bus gespeicherten Daten in sich selbst dient.

Die nächsten drei Eingänge sind bereits zur Steuerung von Schieberegistern vorgesehen. Es lohnt sich, mit der einfachsten Sache zu beginnen - der DS-Dateneingabe. Diese Eingabe ist, wie der Name schon sagt, für die Datenübertragung vorgesehen. Da die Schieberegister in der Schaltung in Kaskade geschaltet sind, repräsentiert der DS den entsprechenden Ausgang von einem von ihnen. Der Eingang des zweiten Schieberegisters ist mit dem Ausgang des letzten Bits des ersten Registers verbunden. Das Ergebnis ist ein Schieberegister für 16 Bit, von denen nur 12 Bit verwendet werden.

Der Eingang SH ist ein Takteingang. Diesem Eingang wird eine Rechteckwelle zugeführt, die für das Laden und Verschieben von Daten in jedes der Register verantwortlich ist. Dieser Kontakt der Schaltung ist mit den SHCP-Pins beider Register verbunden.

Der letzte ST-Pin dient als Daten-Latch an den Ausgängen des Registers. Dieser Eingang erhält einen Impuls, der jedoch erst dann geliefert wird, wenn die Daten im Schieberegister endgültig geladen sind und am Ausgang der Register fixiert werden müssen. Erst nach diesem Signal gelangen die heruntergeladenen Daten innerhalb des Registers in der ersten Triggerreihe in die zweite Triggerreihe und werden auf dem Bus verfügbar. ST ist ein Pin, der mit den STcp-Pins beider Register verbunden ist.

Es bleibt die Verdrahtung der beiden Pins der Schieberegister MR und OE zu erklären. Der erste Eingang (MR) ist für das Speichern der Daten im Register verantwortlich. In dieser Schaltung ist eine solche Möglichkeit nicht erforderlich, daher wird diesem Ausgang über die Last ein hoher Signalpegel zugeführt.

Der zweite Registereingang (OE) ist dafür verantwortlich, die zweite Reihe von Triggern innerhalb des Schieberegisters vom Bus zu trennen, d. H. Den Freigabeeingang. Diese Funktion ist ebenfalls nicht erforderlich, daher wird der Ausgang auf Masse gewickelt.

Ein anderer Kontakt, der oben nicht beschrieben wurde, dient zum Entfernen des Signalpegels von der Taste in der Mitte der Uhr. Die Tastenschaltung ist typisch und stellt eine Last und einen Schlüssel dar, abhängig von der Position, von der ein niedriger oder hoher Signalpegel an das Arduino gesendet wird. Je nach Status der Taste arbeitet die Uhr entweder im Bildschirmschonermodus oder im Zeitanzeigemodus.
Die Verbindung zum Arduino weist keine besonderen Merkmale auf, außer dass der SH-Pin idealerweise mit dem digitalen SCK-Pin verbunden ist. Die restlichen Schaltungsausgänge können an jeden der verfügbaren digitalen Allzweckeingänge angeschlossen werden. In unserem Fall hat die Verbindung die folgende Form:

  • Arduino pin13 (SCK) – SH
  • Arduino pin 11 – ST Arduino pin 8 – DS Arduino pin 5 – E1 Arduino pin 3 – Arduino pin GND – ( )
    , .

    : 36 — ; 36 ( ) \ 26 ( ) — . Shadowplay 72 , 36. , 60 ( + ). . , , , .



    , . , . , . , «» 50 — 60, . , 60 . : — .



    , , , . — . , , . , — .

    .


    -, .

    Shadowplay. , , . , , . , .. . , , 100% . , . . , . , .

    , ( ), , — . , , ! . , - - . , , . , , . , , , . ., - . , , , , , .



    , . . .. , , ( , , ), .


    , (). Arduino. , RTC, — . DS1307, — I2C. 2100 . . RTC Arduino, . RTC.



    , RTC, .

    #include <Time.h>
    #include <DS1307RTC.h>
    
    char REG [8];
    tmElements_t te;
    int c,reset=1;
    
    void setup() {
      pinMode(13, OUTPUT); 
      pinMode(11, OUTPUT); 
      pinMode(8, OUTPUT);  
      pinMode(5, OUTPUT);  
      pinMode(3, INPUT);   
      Serial.begin(57600);
      
      //      RTC  
      //te.Hour = 18;
      //te.Minute = 50;
      //te.Second = 0;
      //te.Day = 20; //
      //te.Month = 4; // 
      //te.Year = CalendarYrToTm(2016); 
      //RTC.write(te);
    }
    
    void loop()
    { 
    if(digitalRead(3))                    // ,     
      {RTC.read(te);
       SetShadowTime(te.Hour,te.Minute,te.Second,2);        //         
       delay(900);
       reset=1;
      }
    
    else                                   //    ,  
      {wait1();
       reset=1;
      }
                                             //  
      for(int j = 0; j<8 ; j++) SetUpLightByMask(j,0); 
       
     
    }
    
    
    //======================================================================= 
    
    void SetUpLightByMask(int RegNum, char LightMask) //         
    {
      
      digitalWrite(5, LOW);
      digitalWrite(11, LOW);
      shiftOut(8, 13, MSBFIRST, LightMask);
      shiftOut(8, 13, LSBFIRST, RegNum);
      digitalWrite(11, HIGH);
      digitalWrite(5, HIGH);
    }
    
    void digitalClockDisplay() {  //    RTC  ,    RTC  
      RTC.read(te);
      Serial.print(te.Hour);
      Serial.print(" : ");
      Serial.print(te.Minute);
      Serial.print(" :");
      Serial.print(te.Second);
      Serial.print(" ");
      Serial.print(te.Day);
      Serial.print(" ");
      Serial.print(te.Month);
      Serial.print(" ");
      Serial.print(tmYearToCalendar(te.Year));
      Serial.println();
    }
    
    //     ,     , ,        :
    //0 -  ,1 -   , 2 -    
    
    void SetShadowTime(int Hours, int Minutes, int Seconds, int param){   
      int h,hshift,m,s;
      for(int j = 0; j<8 ; j++) REG[j] = 0;
    
      if(Hours >= 12) Hours -= 12;
      h = Hours + 6;
      if(h >= 12) h -= 12;
        
      hshift = (int) Minutes / 12;
      
      REG[(int)(((h*5)+hshift)/8)] = REG[(int)(((h*5)+hshift)/8)] | 1<<(((h*5)+hshift)%8);
                 
       
      if(param == 1)
      {m = Minutes + 30;
       if(m >= 60) m -= 60;
       REG[(int)(m/8)] = REG[(int)(m/8)] | 1<<(m%8);
       }
    
      if(param == 2)
      {m = Minutes + 30;
       if(m >= 60) m -= 60;
       REG[(int)(m/8)] = REG[(int)(m/8)] | 1<<(m%8);
         
       s = Seconds + 30;
       if(s >= 60) s -= 60;
       REG[(int)(s/8)] = REG[(int)(s/8)] | 1<<(s%8);
      }
    
      for(int j = 0; j<8 ; j++) SetUpLightByMask(j,REG[j]);
      }
      
    void wait1() //    
    {for(int a = 0; a < 8; a++)
        {c=0;
         for(int b = 0; b < 8; b++)
          {c = c << 1;
           c = c | 1;
           SetUpLightByMask(a, c);  
           delay(10);   
          }
       }
      for(int a = 0; a < 8; a++)
        {c=255;
          for(int b = 0; b < 8; b++)
          {c = c << 1;
           SetUpLightByMask(a, c);
           delay(10);     
          }
        }  
    }
    



    . . (Arduino, RTC) . , . , «- ». — . :

    .



    , «»:



    , , :



    , , , .

    , , . , ? . : ( , , ..). , , , . . , .


    ?

    • , , .
    • .
    • Die Möglichkeit, die Reihenfolge der blinkenden LEDs einfach programmgesteuert zu ändern, bietet eine unendliche Vielfalt an Kombinationen.

    Wir beanspruchen nicht die absolute Richtigkeit unserer Schaltungs- und Softwarelösungen. Wie bereits erwähnt, ist negative Erfahrung auch Erfahrung. Vielleicht hilft dieser Artikel jemandem, unsere Fehler zu vermeiden.

    Vielen Dank für Ihre Aufmerksamkeit!

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


All Articles