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++?
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...
}
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.
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.
Michel Keijzers