Hallo,
Mein µC ist ein ATtiny85
Ich benutze AVRSTudio 6
Ich benötige für einen Ringbuffer in C ein 1024 Bit langes Bitarray.
ist das so:
1
charbuffer[128];
2
unsignedshortintmy_ptr;
3
4
if(buffer[my_ptr>>3]&(1<<(my_ptr&0x07)))//Abfrage
5
6
buffer[my_ptr>>3]|=(1<<(my_ptr&0x07));//Setzen
7
8
buffer[my_ptr>>3]&=~(1<<(my_ptr&0x07));//Löschen
9
10
my_ptr=(my_ptr+1)&0x03FF;//my_pointer++
Die Abfrage, Setzen, Löschen müssen sehr schnell sein.
Kann man das besser schreiben?
Das Thema wurde bestimmt schon öfters behandelt,
leider konnte ich auf die Schnelle nix geeignetes finden...
wenn es schnell sein soll,
Jedes Bit als ein Byte oder 2 Byte oder 4 Byte speichern,
dann wird der Speicherbedarf zwar etwas größer,
aber das Testen der einzelnen Bits fällt weg.
Erst mal machst du aus dem char einen unsigned char, oder gleiche einen
uint8_t
Den Datentyp char reservierst du ausschliesslich für Dinge, die mit
Textverarbeitung zu tun haben und sonst nichts anderes. In allen anderen
Fällen bist du explizit darüber, ob du einen char mit Vorzeichen oder
einen char ohne Vorzeichen haben willst und überlässt es nicht dem
Compiler, was er sich bei einem char so denkt.
Zum anderen willst du diese Operation
1
1<<x
mit einem variablen x auf einem AVR nicht haben, weil das eine teure
Operation ist, da der Compiler das in eine Schleife auflösen muss. Da
bist du mit einem 8 Stück-Array von vordefinierten Konstanten noch
besser bedient
Peter Zz schrieb:> Die Abfrage, Setzen, Löschen müssen sehr schnell sein.> Kann man das besser schreiben?
Evt. kannst du dir die Schiebereien sparen, wenn du eine Lookup Tabelle
verwendest. Den "Pointer" könntest du in eine Struktur packen und dort
Byte und Bit unterscheiden. Z.B. sowas (ungetestet):
@ Peter Zz (bastelboy)
>Ich benötige für einen Ringbuffer in C ein 1024 Bit langes Bitarray.>Die Abfrage, Setzen, Löschen müssen sehr schnell sein.
Du hast mal sicher NICHT 1024 einzelne Statusbist, sondern eher ein
Array mti Daten für LEDs etc., die schnell per Soft-SPI irgendwie
ausgegeben werden sollen? ist das so?
Dafür gibt es schnelle Soft-SPI Routinen. Ansonsten, siehe
Bitmanipulation bzw.
Beitrag "Re: Bits aus einem unsigned char array extrahieren"Beitrag "Re: AtMega 48 Timmer"
Falk Brunner schrieb:> Du hast mal sicher NICHT 1024 einzelne Statusbist, sondern eher ein> Array mti Daten für LEDs etc., die schnell per Soft-SPI irgendwie> ausgegeben werden sollen? ist das so?
Ne, ich will einen Netzsynchronen 50Hz Rechteck definiert verzögern.
Die Verzögerungszeit soll 0 bis 51,15ms betragen.
Das sind 1024 mögliche Werte die mit einem 10-Gang-Poti eingestellt
werden.
Nein, es soll kein Dimmer werden.
Du sprichst von Ringbuffer.
Anstelle der Bitschieberei, solltest du zwei Byte Variablen fuer den
Index haben, also sowas
#define idx_inc if(!(idx_l<<=1)) idx_h++,idx_l++
und dann einfach idx_h im bytearray nehmen und idx_l als and/or maske.
Wenn ich das richtig verstehe willst du mit dem so eine art
schiberegister (als ringpuffer) bauen und indem du die länge veränderst
eine verzögerung einbringen.
Des weiteren hört es sich so an als währen im puffer maximal ~2
netzperioden also 4/5 flanken enthalten.
Falls das so ist würde ich den puffer sozusagen kompimieren und nur
flanken speichern.
Also zb. einen ringpuffer von
1
structbuffElem
2
{
3
uint8_tvalue:1;
4
uint16_tcount:15;
5
}
Beim insert wird dann falls value gleich bleibt nur count erhöht.
Beim entnehmen solange wird dekrementiert bis count 0 ist und dann der
eintrag gelöscht.
Ist sicher nicht die schnellste version. Braucht aber vermutlich weniger
speicher.
Peter Zz schrieb:> Falk Brunner schrieb:>> Du hast mal sicher NICHT 1024 einzelne Statusbist, sondern eher ein>> Array mti Daten für LEDs etc., die schnell per Soft-SPI irgendwie>> ausgegeben werden sollen? ist das so?>> Ne, ich will einen Netzsynchronen 50Hz Rechteck definiert verzögern.> Die Verzögerungszeit soll 0 bis 51,15ms betragen.> Das sind 1024 mögliche Werte die mit einem 10-Gang-Poti eingestellt> werden.> Nein, es soll kein Dimmer werden.
d.h. es wird squentiell eine 0 oder eine 1 in einem bestimmten Takt
eingeschrieben.
Dann braucht es aber doch die allgemeinen Zugriffsfunktionen gar nicht.
Alles was du willst ist doch nichts anderes als das nächste 'Bit' auf
entweder 0 oder 1 zu setzen. Das lässt sich aber recht einfach erreichen
@ Peter Zz (bastelboy)
>Ne, ich will einen Netzsynchronen 50Hz Rechteck definiert verzögern.>Die Verzögerungszeit soll 0 bis 51,15ms betragen.>Das sind 1024 mögliche Werte die mit einem 10-Gang-Poti eingestellt>werden.
Das mit den 1024 Bit als Signalspeicher ist eine Möglichkeit, das zu
machen. Man kriegt das auch recht schnell und effizient hin.
Wenn du bis zu 51,15 ms verzögern willst, sind das bei dir 50us / 20 kHz
Zeitauflösung. In der Zeit kann ein uC fast beliebig schlecht ein Bit
aus einem Array lesen, das ist eine kleine Ewigkeit. Wenn man es clever
macht, sind die Funktionen aber sehr einfach und schnell, wie von den
anderen Schreibern angedeutet.
Für die Einstellung würde ich heute kein 10 Gang Poti mehr nehmen,
sondern einen Drehgeber. Der ist billiger und kann die Einstellung
mit digitaler Genauigkeit und Reproduzierbarkeit eingeben. Ein Poti hat
immer das Problem, dass der Messwert am ADC geringfügig wackelt.