INFO: Dieses Forum nutzt Cookies...
Cookies sind für den Betrieb des Forums unverzichtbar. Mit der Nutzung des Forums erklärst Du dich damit einverstanden, dass wir Cookies verwenden.

Es wird in jedem Fall ein Cookie gesetzt um diesen Hinweis nicht mehr zu erhalten. Desweiteren setzen wir Google Adsense und Google Analytics ein.

Antwort schreiben 
 
Themabewertung:
  • 0 Bewertungen - 0 im Durchschnitt
  • 1
  • 2
  • 3
  • 4
  • 5
10x10x10 LED Würfel
27.05.2016, 17:22
Beitrag #17
RE: 10x10x10 LED Würfel
Zitat:Alternative ist shiftOut(), wird intern auch wesentlich besser optimiert.
Das kann ich mir sehr schlecht vorstellen, das dies schneller sein soll.
Code:
void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val)
{
    uint8_t i;

    for (i = 0; i < 8; i++)  {
        if (bitOrder == LSBFIRST)
            digitalWrite(dataPin, !!(val & (1 << i)));
        else    
            digitalWrite(dataPin, !!(val & (1 << (7 - i))));
            
        digitalWrite(clockPin, HIGH);
        digitalWrite(clockPin, LOW);        
    }
}
Dies ist der Original-Code von Arduino.


Zitat:digitalWrite() ist eine Funktion, die im Verhätlnis zum direkten Zugriff auf das AVR-Register "ewig" braucht. Das liegt daran, daß jedesmal intern erst die Zuordnung der Arduino Pinnummer zu Port und Bit erfolgt.
Dies kann ich mir sehr gut vorstellen.

Verstehe ich dich richtig, das zB. Port 0-7 aus einem Byte (Register) besteht ?
Wen ich auf dieses Byte $FF schreibe, sind alle 8 Ports auf HIGH und bei $00 alle auf LOW ?

Das man mit Assembler viel rausholen kann, ist mir bekannt, ich hatte unter das viele Funktionen in Assembler geschrieben. Vor allem mit direktem Register-Zugriff hat man viel rausgeholt.
Alle Beiträge dieses Benutzers finden
Diese Nachricht in einer Antwort zitieren
28.05.2016, 07:57 (Dieser Beitrag wurde zuletzt bearbeitet: 28.05.2016 07:57 von amithlon.)
Beitrag #18
RE: 10x10x10 LED Würfel
Hallo,
(27.05.2016 17:22)Mathias schrieb:  
Zitat:Alternative ist shiftOut(), wird intern auch wesentlich besser optimiert.
Das kann ich mir sehr schlecht vorstellen, das dies schneller sein soll.
Code:
void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val)
{
    uint8_t i;

    for (i = 0; i < 8; i++)  {
        if (bitOrder == LSBFIRST)
            digitalWrite(dataPin, !!(val & (1 << i)));
        else    
            digitalWrite(dataPin, !!(val & (1 << (7 - i))));
            
        digitalWrite(clockPin, HIGH);
        digitalWrite(clockPin, LOW);        
    }
}
Dies ist der Original-Code von Arduino.

Da hätte ich wohl erst reinschauen sollen...
So ist da natürlich nichts schneller.
Bliebe also Hardware-SPI, die Schiebergister an SCK und MOSI und dann mit
SPI.transfer() rausschieben. Habe da aber jetzt auch nicht reingeschaut.

(27.05.2016 17:22)Mathias schrieb:  Verstehe ich dich richtig, das zB. Port 0-7 aus einem Byte (Register) besteht ?
Wen ich auf dieses Byte $FF schreibe, sind alle 8 Ports auf HIGH und bei $00 alle auf LOW ?
[quote]

Ja, ist ja letzlich auf den kleinen Arduinos meist ein ATMega328 drauf.
Die Arduino-Pinnummern sind manchmal nur etwas willkürlich zu den Portbits sortiert. Die Schaltpläne bzw. die Listen der Zuordnung liegen ja im Netz.

[quote='Mathias' pid='29736' dateline='1464366163']
Das man mit Assembler viel rausholen kann, ist mir bekannt, ich hatte unter das viele Funktionen in Assembler geschrieben. Vor allem mit direktem Register-Zugriff hat man viel rausgeholt.

Teilweise. Der GCC-Compiler optimiert für die meisten Fälle schon ganz brauchbar.
Das Schöne and er Arduino-IDE ist für mich ja gerade, daß man nehmen kann, was gerade Sinn macht.

Beim UNO sind eben Pin 8...13 die Protbits PB0...PB5 vom AVR.
Wenn die auf 101010 sollen, kann ich 6x digitalWrite() schreiben oder eben auch
PORTB = 0x55;
Genauso, wie eben varible = PINB den Port komplett liest.
Die ganzen #defines für den AVR werden ohnehin eingebunden, werden ja sowieso gebraucht.
Wenn was fehlt, kann man es eben selber include.

Wenn man im Sketch setup() und loop() komplett wegläßt, muß man eben alles selber einbauen:
Code:
#include <util/delay.h>
#include <avr/io.h>          
int main (void) {            
  DDRB  = 0xff;            
  while(1) {                
    PORTB |= (1<<PB1);    //Bit setzen
    _delay_ms(500);       // halbe sekunde warten
    PORTB &= ~(1<<PB1);   // Bit loeschen
    _delay_ms(500);       // halbe sekunde warten
  }                        
return 0;                
}

Das Beispiel von hier
https://www.mikrocontroller.net/topic/206119
sollte sich eigentlich übersetzen lassen. PB1 auf PB5 ändern, beim UNO hängt die LED an 13, also Port B Bit 5.

Gruß aus berlin
Michael

[/code]

Gruß aus Berlin
Michael
Alle Beiträge dieses Benutzers finden
Diese Nachricht in einer Antwort zitieren
28.05.2016, 17:27 (Dieser Beitrag wurde zuletzt bearbeitet: 28.05.2016 19:46 von Mathias.)
Beitrag #19
RE: 10x10x10 LED Würfel
Ich habe dein Sketch probiert, es scheint zu laufen. Dazu habe BP1 auf BP5 geändert und die LED blinkt.

Wen ich dein Code angucke, wird genau eine Zeile für ein digitalWrite gebraucht.
Ich werde dies demnächst auf die Schieberregister ausprobieren, mal gucken, ob diese dann schneller laufen. Wink

Ich habe mir digitalWrite genauer anguckt, da hat es Code, das es nicht mehr schön ist.
Wird da soviel Code gebraucht, weil man die Pins auch Analog nutzen kann ?
Wen das so ist, braucht ein Analoger-Ausgang sehr viel CPU-Power.

PORTB ist anscheinend nur 5Bit gross, wieso nicht 8 ?
Ich habe es grade gesehen wieso, darum: https://www.arduino.cc/en/Reference/PortManipulation

Meine Schieberegister hängen momentan an Pin 2, 3, 4.
Somit sollte eigentlich PORTD gehen oder ?


Hier sieht man gut, wie viel Leistung nur mit loop(); flöten geht : http://tronixstuff.com/2011/10/22/tutori...ipulation/

Ich habe ein bisschen Code optimiert, mit dieser Änderung, kann ich den Timer-Intervall für den Multiplex annähern halbieren, von 495 auf 255.

Code:
void dw(char Pin, bool val) {
    if (val) {
        PORTD |= (1 << Pin);
    } else {
        PORTD &= ~(1 << Pin);
    }
}

void ShiftRegister::update() {

    dw(latchPin, false);
    for (int i = shiftCount - 1; i >= 0; i--) {

        dw(dataPin, reg[i]);

        dw(clockPin, true);
        dw(clockPin, false);
    }
    dw(latchPin, true);

//    digitalWrite(latchPin, LOW);
//    for (int i = shiftCount - 1; i >= 0; i--) {
//
//        digitalWrite(dataPin, reg[i]);
//
//        digitalWrite(clockPin, HIGH);
//        digitalWrite(clockPin, LOW);
//    }
//    digitalWrite(latchPin, HIGH);
}
Alle Beiträge dieses Benutzers finden
Diese Nachricht in einer Antwort zitieren
29.05.2016, 09:14
Beitrag #20
RE: 10x10x10 LED Würfel
Hallo,

(28.05.2016 17:27)Mathias schrieb:  Ich habe dein Sketch probiert, es scheint zu laufen. Dazu habe BP1 auf BP5 geändert und die LED blinkt.
...
Ich habe mir digitalWrite genauer anguckt, da hat es Code, das es nicht mehr schön ist.
Wird da soviel Code gebraucht, weil man die Pins auch Analog nutzen kann ?
Wen das so ist, braucht ein Analoger-Ausgang sehr viel CPU-Power.

Wenn man seinen EInstieg in die µC Welt mit Arduino und der IDE macht, hat es den großen Vorteil, daß man ferige Baugruppen preiswert bekommt, die Schaltungen nicht komplett selber löten muß und eine gewisse Sicherheit hat, daß es spielt.
Die IDE hat den großen Vorteil, daß man sie einfach installieren kann, so gut wie nicht einrichten muß und anfangen kann.
Der Nachteil ist, man muß sich mit vielm nicht auseinandersetzen...
"Ich benutze einen Arduino UNO, einen Arduino Nano, einen ProMini" liest man dann oft.
Stimmt eigenlich nicht. Alle drei sind einfach ein ATMega, wo jemand schon einen 16MHz Quarz und ein paar Kondensatoren rumgelötet hat, damit er spielt.
Der ATMEga hat schon einen Bootloader raufgespeilt bekommen und die Fuses für Takt, Bootbereich usw. wurden schon gesetzt.
Die Teile kann man auch einzeln kaufen, auf ein Steckbrett zusammenstecken, einen billigen ISP-Programmer kaufen (dazu kann man auch einen vorhandenen UNO/Nano usw. nehmen mit dem passenden Sketch) und den Bootloader selber raufschreiben.
UNO und Nano haben zusätzlich noch einen USB-seriell Wandler gleich mit drauf, den kann man auch einzeln kaufen.
Inzwischen ist es durch die China-Module einfach billier und zeitsparenden auch für mich, Arduinos und Zubehör zu kaufen, obwohl ich auch einen AVR aus dem Vorrat nehmen könnten, das STK500 oder den Dragon zum Programmieren ranstecken könnte usw.

Bei der IDE ist es ähnlich. Unten drunter werkelt ein C-Compiler (GCC), der genauso von AVR-Studio, Atmel-Studio usw. genutzt wird.
Den Blink-Code kannst Du genauso ins Atmel-Studio kopieren und compilieren.
Umgekehrt kann man auch die meisten C-Projekte direkt in die Arduino-IDE werfen und compilieren.
Man kann das in der IDE auch ziemlich bunt mischen, die kümmert sich da ganz gut drum, was wie übersetzt werden muß.

So, nun endlich zum Code: wenn man mit Portzugriffen auf den Prozessor losgehen will, müsssen die natürlich zum jeweiligen Prozessor passen, der muß die ausführen können den Port muß es geben, er muß so heißen usw.
Arduino sind aber eben nicht nur Mega328, Arduino-Boards gibt es auch mit ganz anderen Prozessoren. Damit ein Programm mit PORTD |= (1 << Pin); da dann auch funktioniert, muß der µc auch einen PortD haben usw.
Die Arduino-IDE abstrahiert hier nur, wenn am Arduino als Pinnummer 10 steht, kann ich eben mit digitalWrite(10,HIGH) diesen Pin auf H setzen, völlig unabhängig davon, an welchem Pin und Port des konkreten µC das überhaupt hängt und welche Register wie benutzt werden müssen, damit da ein H rauskommt.
Spart dem User das Nachdenken und kostet u.U. CPU-Zeit, weil es auf dem Mega328 viel einfacher geht als z.B. auf einem ESP8266.

Ich nutze die Vorteile der IDE mit ihren Klassen inzwischen sehr gern. Wenn es eben nötig ist, wird mal etwas handotimiert.
In 95% der Fälle stört es nicht, wenn es ein paar µs länger braucht.

(28.05.2016 17:27)Mathias schrieb:  PORTB ist anscheinend nur 5Bit gross, wieso nicht 8 ?
Ich habe es grade gesehen wieso, darum: https://www.arduino.cc/en/Reference/PortManipulation

Meine Schieberegister hängen momentan an Pin 2, 3, 4.
Somit sollte eigentlich PORTD gehen oder ?

Naja, der Chip hat eben nicht mehr Pins, um alle rauszuführen...

(28.05.2016 17:27)Mathias schrieb:  Hier sieht man gut, wie viel Leistung nur mit loop(); flöten geht : http://tronixstuff.com/2011/10/22/tutori...ipulation/

Ich habe ein bisschen Code optimiert, mit dieser Änderung, kann ich den Timer-Intervall für den Multiplex annähern halbieren, von 495 auf 255.

Code:
void dw(char Pin, bool val) {
    if (val) {
        PORTD |= (1 << Pin);
    } else {
        PORTD &= ~(1 << Pin);
    }
}

void ShiftRegister::update() {

    dw(latchPin, false);
    for (int i = shiftCount - 1; i >= 0; i--) {

        dw(dataPin, reg[i]);

        dw(clockPin, true);
        dw(clockPin, false);
    }
    dw(latchPin, true);

//    digitalWrite(latchPin, LOW);
//    for (int i = shiftCount - 1; i >= 0; i--) {
//
//        digitalWrite(dataPin, reg[i]);
//
//        digitalWrite(clockPin, HIGH);
//        digitalWrite(clockPin, LOW);
//    }
//    digitalWrite(latchPin, HIGH);
}

Solche Sachen bei Bedarf anzupassen ist nie ein Fehler.
Socleh Programme sind dann aber eben nicht ohne weiteres auf einem Arduino mit einem anderen µC zum Laufen zu bekommen.

Allgemein: in einer Schleife zu optimieren ist immer sinnvoll, weil die ja mehrfach durchlaufen werden soll und jede Einsparung das Mehrfache an Zeit bringt.
Optimieren nur weil es ginge ist oft nutzlos.
Wenn ein AVR alle 30s aufwacht, um eine Teperatur zu messen und zu schicken, ist es egal, ob die Messung 5ms oder eine halbe Sekunden braucht.

Nochwas zu Deiner Funktion: eine Funktion ist der Aufruf einer Subroutine, die erledgit was und kehert dann zurück hinter den Aufruf um weiterzumachen.
Damit das klappt, muß der Compiler dafür sorgen, das der Zustand und der Rückkehrpunkt gesichert und wieder hergestellt werden. Das kostet Zeit und Ram.

Du könntest hier z.B. testen, wieviel schneller es wird, wenn Du die Funktionsaufrufe durch die Abragen direkt ersetzt.
Es gibt 2 Möglichkeiten: es wird erkennbar schneller oder es ändert sich nichts.
Wenn sich nichts ändert, hat der Compiler von der Möglichkeit gebrauch gemacht, geeignete Sachen zu "inlinen". Das heißt, er hat nicht Deinen Funktionsruf übersetzt, sondern von sich auf die IF-Abfrage jedesmal an die Stelle gepackt und übersetzt.
Das kann man dem Compiler auch direkt sagen:
Code:
inline void dw(char Pin, bool val) {
    if (val) {
        PORTD |= (1 << Pin);
    } else {
        PORTD &= ~(1 << Pin);
    }
}


Sowas ist schneller, kostet aber dafür mehr Flashspiecher.

Letztlich ist es einfach eine Frage, wie weit Du aus eigenem Interesse den Dingen auf den Grund gehen willst. Bei mir war es meist so, das ich tiefer eindrineg, wenn ich es für ein Projekt gerade brauchte und die Alternative, einen AVR mit mehr Flash und Ram usw. wegen Kosten oder Beschaffbarkeit oder eigener Dickköpfigkeit Wink ausfiel.
Wenn ein Tiny25 eigentlich gereicht hätte und da war, mußten eben 2k Flash und 128Byte Ram reichen...
Da wäre bei mir auch heute noch durchaus AVR-Studio und ASM angesagt, obwohl letztens eben der Tiny45 in C/C++r ArduinoIDE programmiert wurde.

Ist jetzt etwas lang geworden alles.
Leute, die mit Arduino anfangen sind meist etwas ungeliebt bei den "alten Hasen", weil sie eben gern einen Arduino2560 nehmen, weil der genug Pins hat, obwohl ein PorMini mit einem MCP23S17 Port-Expander auch getan hätte oder wie bei Dir ein paar Optimierungen.
Liegt auch daran, daß Arduino-User meist nur ein Projekt fertig bekommen wollen und eigentlich an µC und Elektronik wenig Interesse haben.
Genauso, wie die IDE gern abgewertet wird, für mich ohne wirklich Begründung.
Sie ist etwas spartanisch, beitet aber weit mehr, als man auf den ersten Blick wahrnimmt.

Gruß aus Berlin
Michael
Alle Beiträge dieses Benutzers finden
Diese Nachricht in einer Antwort zitieren
29.05.2016, 17:08
Beitrag #21
RE: 10x10x10 LED Würfel
Danke erst mal für deine Infos.

Zitat:Leute, die mit Arduino anfangen sind meist etwas ungeliebt bei den "alten Hasen", weil sie eben gern einen Arduino2560 nehmen, weil der genug Pins hat,
In den meisten Fällen ist so was überflüssig, vieles kann man mit Schieberegistern lösen.

Zitat: obwohl ein PorMini mit einem MCP23S17 Port-Expander auch getan hätte oder wie bei Dir ein paar Optimierungen.
Interessanter Baustein, so wie ich dies sehe, ist das eine Art Schieberegister, welches In- und Out-puts hat.

Zitat:"Ich benutze einen Arduino UNO, einen Arduino Nano, einen ProMini" liest man dann oft.

Bis jetzt habe ich erst einen Nano, ich werde aber sicher später noch was dazu kaufen.

Zitat:Der ATMEga hat schon einen Bootloader raufgespeilt bekommen und die Fuses für Takt, Bootbereich usw. wurden schon gesetzt.
Die Teile kann man auch einzeln kaufen, auf ein Steckbrett zusammenstecken, einen billigen ISP-Programmer kaufen (dazu kann man auch einen vorhandenen UNO/Nano usw. nehmen mit dem passenden Sketch) und den Bootloader selber raufschreiben.
Sowas werde ich sicher auch mal probieren. Unter anderem auch mal einen Attiny probieren.

Zitat:So, nun endlich zum Code: wenn man mit Portzugriffen auf den Prozessor losgehen will, müsssen die natürlich zum jeweiligen Prozessor passen, d
Dies sollte klar sein, das ist etwa das gleiche wie unter BASIC mit PRINT"Hello World", das ist egal welcher Computer, ob PC oder C64, aber in Assembler ist das ein grosser Unterschied.

Zitat:Nochwas zu Deiner Funktion: eine Funktion ist der Aufruf einer Subroutine, die erledgit was und kehert dann zurück hinter den Aufruf um weiterzumachen.
Diese habe ich gestern zum Teil noch raus geworfen und noch ein bisschen Zeit raus schlagen. Inline wäre auch eine Möglichkeit gewesen.

Zitat:Da wäre bei mir auch heute noch durchaus AVR-Studio und ASM angesagt, obwohl letztens eben der Tiny45 in C/C++r ArduinoIDE programmiert wurde.
Unterstützt die Arduino-IDE auch die Tiny ?

Zitat:Liegt auch daran, daß Arduino-User meist nur ein Projekt fertig bekommen wollen und eigentlich an µC und Elektronik wenig Interesse haben.
Sowas sieht man oft, Hauptsache es läuft irgendwie.
Das sieht man auch gut Programmieranfänger, da werden zB. Hundert Button einzeln erstellt, dabei kann man so was optimiert mit einer ForTo-Schleife lösen.

Zitat:Genauso, wie die IDE gern abgewertet wird, für mich ohne wirklich Begründung.
Da gehöre ich auch dazu. Cool
Seit ich mit Eclipse arbeite, macht mit der Arduino einiges mehr Spass, da man viel effizienter programmieren kann.
Alle Beiträge dieses Benutzers finden
Diese Nachricht in einer Antwort zitieren
29.05.2016, 22:14 (Dieser Beitrag wurde zuletzt bearbeitet: 29.05.2016 22:15 von Mathias.)
Beitrag #22
RE: 10x10x10 LED Würfel
Ich noch weiter optimiert, in dem ich meine ShiftRegister-Classe weggelassen habe.
Jetzt ist der Timer bei 90, ursprünglich war er bei 496 Wink

Ich wollte noch ein 16Bit-Shift machen, so das ich d[?] weglassen könnte, aber komischerweise ist dies kontra produktiv.
Liegt die evtl. daran, das es eine 8-Bit CPU ist ?
Code:
void shiftOut2(char dataPin, char clockPin, unsigned char val) {

    for (char i = 0; i < 8; i++) {

        if (!!(val & (1 << (7 - i)))) {
            PORTD |= (1 << dataPin);
        } else {
            PORTD &= ~(1 << dataPin);
        }

        PORTD |= (1 << clockPin);
        PORTD &= ~(1 << clockPin);
    }
}

void multiplex() {

    static unsigned char c = 0;
    unsigned char d[2];
    if (c >= 8) {
        d[0] = 0;
        d[1] = 1 << (c - 8);
    } else {
        d[0] = 1 << c;
        d[1] = 0;
    }

    PORTD &= ~(1 << latchPin);
    shiftOut2(dataPin, clockPin, ~digit[c]);
    shiftOut2(dataPin, clockPin, d[1]);
    shiftOut2(dataPin, clockPin, d[0]);
    PORTD |= (1 << latchPin);

    c += 1;
    if (c == maxSegment) {
        c = 0;
    };
}
Alle Beiträge dieses Benutzers finden
Diese Nachricht in einer Antwort zitieren
Antwort schreiben 


Möglicherweise verwandte Themen...
Thema: Verfasser Antworten: Ansichten: Letzter Beitrag
  Code für Würfel korrekt? JanGamer11 12 812 12.01.2016 19:41
Letzter Beitrag: Claus_M

Gehe zu:


Benutzer, die gerade dieses Thema anschauen: 1 Gast/Gäste