So verschieben Sie 16 Bit schnell auf dem Arduino-Board

Ich codiere ein System, das 16 Bit schnell von einer uint16_t-Variablen in zwei gepaarte 74HC595-Schieberegister verschieben muss. Ich führe den Code auf einem Arduino (atmega328@16Mhz) aus und der ShiftOut im Arduino ist viel zu langsam. Die digitalWrite-Funktion der Bibliothek ist ebenfalls langsam.

Die beste Idee, die ich mir ausgedacht habe, ist eine for-Schleife, die alle 16 Bits der Variablen durchläuft und 1/0 auf den Datenpin schreibt, das Taktbit so kurz wie möglich hoch setzt und dann zum nächsten Bit der Variablen geht.

Ist dies die schnellste Lösung und wenn ja, wie durchlaufe ich die Bits einer uint16_t-Variablen in c++?

Ich habe einige Tests mit SRAM durchgeführt, Sie könnten die Ergebnisse interessant finden: arduino.stackexchange.com/questions/36871/… Fazit: ein digitalRead/WriteFast ist vernachlässigbar, ein shiftOut kostet jedoch 120 us.

Antworten (4)

Dies ist mit der SPI-Bibliothek einfach genug.

Verbinden Sie Ihren Schieberegistereingang mit dem MOSI-Pin (Master Out, Slave In) - Digital Pin 11 - und Sie werden schöne schnelle Übertragungen haben.

Es wird eine sehr geringe Verzögerung zwischen den oberen und unteren 8 Bits jedes übertragenen Wortes geben.

Zum Beispiel:

#include <SPI.h>

void begin()
{
    SPI.begin();
}

void loop()
{
    unsigned int val;

    val = rand()%0xFFFF; // Generate a random 16 bit number

    SPI.transfer(val >> 8);  // Output the MSB first
    SPI.transder(val & 0xFF); // Followed by the LSB

    delay(1000);  // Wait a sec...
}
Was ist mit den Verriegelungsstiften? Dies scheint nur die serielle Datenleitung umzuschalten, aber ich sehe nicht, wie irgendetwas in das Register eingeklinkt wird.
Ich habe noch nie eines der fraglichen Schieberegister verwendet, daher weiß ich nicht, was erforderlich ist. Normalerweise packen Sie den SPI in ein digitalWrite (x, LOW) und digitalWrite (x, HIGH), um eine digitale IO-Leitung Ihrer Wahl als "Chip Select" oder "Latch Toggle" oder was auch immer umzuschalten (offensichtlich den Schalter umkehren für aktiv hoch ). Verwenden Sie einen beliebigen Pin.

Wer eine Software-Datenübertragung nutzen möchte, möchte die Funktionen von digitalWrite nicht nutzen. Sie sind sehr langsam, weil sie die Pin-Nummer über eine Tabelle in ein tatsächliches Register (PORTx) übersetzen, das richtige Bit maskieren und ändern müssen. Alle Pins in Arduino sind Zahlen zugeordnet, während sie darunter zu Port A, B, C und noch mehr auf der MEGA-Version des Arduino gehören können.

Es ist viel schneller, die AVR-Register direkt zu ändern. Wie PORTB und ähnliches. Sie müssen tatsächlich jedes Bit durchlaufen. Ich würde eine for-Schleife von 0 bis 15 erstellen und einige Bitverschiebungen und Maskierungen vornehmen.

Da ich die Pinning-Konfiguration nicht kenne, kann ich kein genaues Beispiel geben. Allerdings wird es wahrscheinlich sehr nahe daran aussehen. Mit 'sehr nah' meine ich, dass dies ungetestet ist.

void ShiftOut(UI16_t data)
{
 // Initialize (you may want to set CLK to low) - as we're toggling later on.

// step from bit 0 to 15
 for(UI08_t i = 0; i < 15; i++)
 {
  // Check the content of this data bit
  // Shift data so this bit is LSB, and mask it with 1 so we only look at this bit.
  if ((data >> i) & 0x1 == 1)
  {
    // set data pin high, like PORTB |= 1<<4;
    // when pin 4 of portB is your data pin
    // Doing an OR will make pin B4 always high
  }
  else
  {
    // set data pin low, like PORTB &= ~(1<<4);
    // Doing an AND with the inverse means all pins except B4 will be unchanged
  }

// Generate clk to 'transfer' the bit:
  // This can likely be done by using PORTB ^= 1 << 5; (pin B5 in this example)
  // ^= toggle 
  // Do this TWICE, so CLK goes high/low
 }

// as you're using a shift register, you may want to toggle LATCH pin as well..
}
Um herauszufinden, welche Hardware-Pin-Nummer (nehmen Sie nicht an, dass Pin 4 Pin B4 oder A4 ist!) Sie müssen sich das Schema von Arduino ansehen.

Ich habe einen ähnlichen Code auf einem PIC32 ausgeführt (läuft mit 80 MHz). Der PIC32 konnte dies mit etwa 1,5 MHz tun, aber in main() liefen ein paar zusätzliche Codezeilen, um eine neue Ausgabe zu berechnen. Trotzdem kann es sehr schnell gemacht werden.

Danke für die ausführliche Antwort, ich werde zuerst den SPI-Ansatz ausprobieren, da dieser schneller erscheint. Weitere Beispiele für den Software-Ansatz habe ich auch unter bildr.org/2011/02/74hc595 gefunden

Sie müssen das SPI-Peripheriegerät verwenden, anstatt die Software zu wechseln. Ich habe noch nie ein Arduino verwendet, aber die Online- Referenz schlägt vor, dass es eine SPI-Bibliothek gibt, die Sie verwenden können. Wenn das Ihren Anforderungen nicht entspricht, können Sie das SPI-Peripheriegerät im ATMega-Datenblatt nachschlagen. SPI-Peripheriegeräte sind normalerweise ziemlich einfach einzurichten und zu verwenden.

Ich bin von der alten Schule und codiere seit 100-kHz-Prozessoren. Verwenden Sie Inline-Code für die Bit-Manipulation direkt zum Port, statt einer Schleife. Loop erfordert Overhead, Inline ist schneller, nimmt aber mehr Programmspeicherplatz in Anspruch. Siehe AVR035: Effiziente C-Codierung für AVR zur Bitmanipulation der Ports.