Ich habe ein Gerät, das ich mit dem Arduino steuern möchte.
Es funktioniert so.
Das Problem, das ich habe, ist, den Arduino mit den Taktimpulsen zu synchronisieren. Derzeit habe ich eine if-Anweisung, die die Datenleitung setzt, wenn sie die Taktleitung hoch sieht, aber das scheint nicht zu funktionieren. Ich denke, ich sollte stattdessen nach der steigenden Flanke suchen.
Wie kann ich diese beiden Geräte richtig synchronisieren?
Fügen Sie Ihrem Algorithmus diese Schritte hinzu: 0. Bereiten Sie das erste Datenbit vor ... 3. Verwenden Sie einen externen Interrupt bei steigender Flanke, um das vorbereitete Bit auszugeben, und legen Sie das nächste Bit in Ihre Bithaltervariable. Ausgegebene Bits zählen. * Schritt 3 wird automatisch 16 Mal wiederholt (durch externes Gerät ausgelöst). 4. Wenn der Bitzähler 16 erreicht, Ext-Interrupt deaktivieren und Bereitschaftsleitung zurücksetzen.
Hinweis: Auf atmega168/328 kann jeder Pin als externe Interruptquelle bei eingehenden Flankenübergängen mit recht einfacher Technik verwendet werden.
Ich hoffe, Ihr externes Gerät treibt die Taktimpulse nicht zu schnell. Arduino ist bei Reaktionsgeschwindigkeiten von mehr als 1 MHz nicht sehr gut. Ich würde sagen, Sie sollten erwarten, dass dieser Ansatz bis zu einem Takt von 100 kHz zuverlässig funktioniert. Bei höheren Geschwindigkeiten sollte entweder Hardware-SPI verwendet werden, um Ihre Daten auszutakten, oder eine enge Assembler-Codierung. In jedem Fall sind mehrere MHz das Maximum, das Sie hier mit nacktem AVR erreichen können.
Das SPI hat zwei Modi: Arduino Stock Library unterstützt nativ nur Master. Ihr Szenario klingt genau wie SLAVE, da das andere Ende die Uhr antreibt.
Sie können Ihr Ready mit dem SS (als Eingang) verbinden und den SPI mit dem richtigen Phasen-/Polaritätsmodus einrichten. Stellen Sie dann den SPCR als Slave ein. Aktivieren Sie Ihr Ready und warten Sie dann, bis die 8-Bit-Übertragung abgeschlossen ist, entweder durch Interrupt oder Abfrage. Lassen Sie dann die Bereitschaft los.
ATmega328 Datenblatt beachten Abschnitt 18.2 und 18.3.2
Das Problem hier ist alles über das Timing, also holen wir alle unsere Oszilloskope raus! Grundsätzlich (und etwas zu stark vereinfacht) können die meisten Standard-C-Flusssteuerungsanweisungen keine Timing-Garantien auf einem Mikrocontroller geben. Hardwarebasierte Interrupts garantieren, dass der Code innerhalb einer festen Anzahl von Taktzyklen mit der Ausführung beginnt.
Der Arduino (genauer gesagt der Arduino Uno mit einem ATmega328) hat viele Möglichkeiten, Hardware-Interrupts auszulösen, die manchmal als "Interrupt-Vektoren" bezeichnet werden (Seite 57 des ATmega-Datenblatts). Welche wollen wir? Wir möchten den Code unmittelbar nach dem Übergang des Cock-Pins ausführen, also suchen wir nach einem Pin-Change-Interrupt oder einem externen Interrupt. Abschnitt 12 im Datenblatt geht viel zu sehr ins Detail, aber das Wichtigste ist, dass jeder Port mit 8 Pins einen Interrupt-Vektor teilt! ( arduino.cc/en/Hacking/PinMapping168 ) Dies macht es schwierig, besonders wenn Sie neu bei Mikrocontrollern sind. Die Arduino-Community hat für genau eine solche Situation eine großartige Bibliothek namens PinChangeInt erstellt . (Haftungsausschluss: Ich habe zu PinChangeInt beigetragen)
Das eingebauteDie Interrupt-Creator-Funktion von Arduino (attachInterrupt(interrupt, ISR, mode)) und der Interrupt-Creator von PinChangeInt (PCintPort::attachInterrupt(PIN1, &ISRfunc, EDGE)) verwenden sehr ähnliche Argumente. Die Pin- und Flanken-/Modus-Argumente sind selbsterklärend - Der Pin, an dem Sie den Interrupt wünschen, und die Flanke, die Sie interessiert (höchstwahrscheinlich steigend, aber überprüfen Sie das Zeitdiagramm für Ihre Uhr). Der von Ihnen angegebene Funktionsname wird als Interrupt Service Routine (ISR) angehängt. Immer wenn die Hardware diesen Interrupt sieht, beginnt die ISR mit der Ausführung. Diese Funktion (ISRfunct() oben) akzeptiert keine Argumente und gibt keine Werte zurück (Typ VOID). Sie kann wie jede Funktion auf globale und andere Variablen im Gültigkeitsbereich zugreifen. Um die von Ihnen beschriebene Logik zu implementieren, benötigen Sie eine globale Variable für Ihre Daten und eine für den "Übertragungsindex" oder das letzte gesendete Bit.
Weitere Hintergrundinformationen zu Interrupts auf dem Arduino finden Sie unter den folgenden Links:
uchobby.com/index.php/2007/11/24/arduino-interrupts/
gonium.net/md/2006/12/20/handling-external-interrupts-with-arduino/
Ignacio Vazquez-Abrams
Jippie
blarg
blarg