mikrocontroller.net

Forum: Compiler & IDEs AVR + 47HC164 Code-Optimierung


Autor: Stefan Noack (stefan_n)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

Ich benutze den ATtiny2313 zusammen mit 3 Schieberegistern (74HC164) um 
24 LEDs anzusteuern. Dabei soll das laden der Bits in das 
Schieberegister natuerlich so schnell wie moeglich vonstatten gehen, da 
man sonst auch die ausgeschalteten LEDs kurz aufblinken sieht.

Seht ihr noch optimierungsmoeglichkeiten?

leds.h
#ifndef LEDS_H
#define LEDS_H

#include <avr/io.h> 

#define LEDS_PORT PORTB
#define LEDS_CLK PB0  // clock pin for all three 74HC164 registers
#define LEDS_AB0 PB1  // data in for register 0
#define LEDS_AB1 PB2  // data in for register 1
#define LEDS_AB2 PB3  // data in for register 2
#define LEDS_MASK (_BV(LEDS_CLK) | \
                   _BV(LEDS_AB0) | \
                   _BV(LEDS_AB1) | \
                   _BV(LEDS_AB2))
                   
void set_leds(uint8_t row0, uint8_t row1, uint8_t row2);
                   
#endif

leds.c
#include <avr/io.h> 

#include "leds.h"

void set_leds(uint8_t row0, uint8_t row1, uint8_t row2) {
 
  for (uint8_t bit = 0x80; bit; bit>>=1) {  

    // clear, also sets clock to low
    LEDS_PORT &= ~LEDS_MASK;
    
    if (row0 & bit)
      LEDS_PORT |= _BV(LEDS_AB0);
  
    if (row1 & bit)
      LEDS_PORT |= _BV(LEDS_AB1); 
  
    if (row2 & bit)
      LEDS_PORT |= _BV(LEDS_AB2);   

    // clock to high
    LEDS_PORT |= _BV(LEDS_CLK);
  
  }
  
}

Gruss,
Stefan

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Warum nimmst Du denn keinen 74HC595 ?


Peter

Autor: Stefan Noack (stefan_n)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

> Warum nimmst Du denn keinen 74HC595 ?

Oh.. den kannte ich noch nicht. Beim naechsten mal nehme ich natuerlich 
den. Das mit dem kurzen Aufblinken ist auch nicht so schlimm, ich wollte 
nur wissen, ob man nicht vielleicht noch einbisschen optimieren 
koennte..

Gruss,
Stefan

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@  Stefan Noack (stefan_n)

>den. Das mit dem kurzen Aufblinken ist auch nicht so schlimm, ich wollte
>nur wissen, ob man nicht vielleicht noch einbisschen optimieren
>koennte..

Ja, siehe unten. Der direkte Zugriff auf den Port ist volatile, das ist 
so in den Include Files definiert. Mit einer Hilfsvariable gehts noch 
etwas schneller.

#include <avr/io.h> 

#include "leds.h"

void set_leds(uint8_t row0, uint8_t row1, uint8_t row2) {
  uint8_t tmp;
 
  for (uint8_t bit = 0x80; bit; bit>>=1) {  
    
    // clear, also sets clock to low
    LEDS_PORT &= ~LEDS_MASK;
    tmp=0;

    if (row0 & bit)
      tmp |= _BV(LEDS_AB0);
  
    if (row1 & bit)
      tmp |= _BV(LEDS_AB1); 
  
    if (row2 & bit)
      tmp |= _BV(LEDS_AB2);   

    // clock to high
    LEDS_PORT |= tmp | _BV(LEDS_CLK);
  
  }

}

Autor: Max (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn du auf assembler zurückgreifst wird es schneller, aber 
inkompatibler.

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Falk Brunner schrieb:

> Ja, siehe unten. Der direkte Zugriff auf den Port ist volatile, das ist
> so in den Include Files definiert. Mit einer Hilfsvariable gehts noch
> etwas schneller.

Nicht ratsam, weil dadurch data setup time = 0, muss aber mehr sein. 
Wenn schon dann sowas wie
    unsigned char temp = PORTB & ~...;
    if (row0 & bit)
      temp |= _BV(...);
    if (row1 & bit)
      temp |= _BV(...);
    if (row2 & bit)
      temp |= _BV(...);
    PORTB = temp;
    PORTB |= _BV(...);

Bringt aber zumindest in 4.3.4 ziemlich wenig.

Was mehr bringen dürfte: -O3. Aber auch mehr Platz, weil vollständiges 
unrolling.

Autor: Stefan Noack (stefan_n)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das mit der Hilfsvariable verstehe ich ehrlich gesagt nicht.

Laut der Doku von avr-libc wird aus
PORTB |= _BV(...)

einfach eine set-bit instruction:

>Access to the AVR single bit set and clear instructions are provided via
>the standard C bit manipulation commands. The sbi and cbi macros are no
>longer directly supported. sbi (sfr,bit) can be replaced by sfr |= BV(bit)
>
>i.e.: sbi(PORTB, PB1); is now PORTB |= _BV(PB1);
>
>This actually is more flexible than having sbi directly, as the optimizer
>will use a hardware sbi if appropriate, or a read/or/write operation if
>not appropriate. You do not need to keep track of which registers sbi/cbi
>will operate on.
>
>Likewise, cbi (sfr,bit) is now sfr &= ~(_BV(bit));

Mit der Zwischenvariable habe ich doch dann anstatt der SBI-instructions 
erstmal variablenzuweisungen und dann noch zusaetzlich einmal eine 
OUT-instruction, oder?

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Stefan Noack schrieb:

> Laut der Doku von avr-libc wird aus
> ...
> einfach eine set-bit instruction:

Das schon, aber die braucht 2 Takte auf Port und nur 1 Takt auf 
Register. Ausserdem gilt das nicht wenn es mehrere Bits sind. Da die 
Maskierung folglich als load/and/store ausgeführt werden muss kann man 
das auch explizit codieren und das Tempregister weiterverwenden.

> erstmal variablenzuweisungen

Diese Variable sitzt allerdings in einem Register.

Autor: Falk Brunner (falk)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
@  Stefan Noack (stefan_n)

>Laut der Doku von avr-libc wird aus

>PORTB |= _BV(...)

>einfach eine set-bit instruction:

Ach so stimmt. Ist mir irgendwie entfallen :-0
Gilt aber in erster Näherung für den AVR und andere Prozessoren, die das 
so schnell können.
Moment, SBI dauert aber 2 Takte, ein einfaches ORI nur 1. Der Vergleich 
ist der selbe. Also ist meine Version doch schneller ;-)
Hmm, nöö, doch nicht, am Ende ist es wieder gleich, siehe Anhang.

>Mit der Zwischenvariable habe ich doch dann anstatt der SBI-instructions
>erstmal variablenzuweisungen

Die wird aber in ein CPU-Register gelegt und ist damit maximal schnell.

> und dann noch zusaetzlich einmal eine OUT-instruction, oder?

Ja, aber die dauert nur 1 Takt. Aber vorhwr muss man laden und ODERn.

MfG
Falk

Autor: Stefan Noack (stefan_n)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>> Laut der Doku von avr-libc wird aus
>> ...
>> einfach eine set-bit instruction:
>
> Das schon, aber die braucht 2 Takte auf Port und nur 1 Takt auf
> Register.

Ah.. stimmt! (Datenblatt lesen hilft...)

> Ausserdem gilt das nicht wenn es mehrere Bits sind. Da die
> Maskierung folglich als load/and/store ausgeführt werden muss kann man
> das auch explizit codieren und das Tempregister weiterverwenden.

Stimmt.. Ich maskiere sowieso, d.h. ich habe sowieso einen 
load/and/store-zyklus, den kann ich natuerlich gleich aufweiten und 
zwischendrin direkt mit dem register arbeiten, was doppelt so schnell 
ist.

>
>> erstmal variablenzuweisungen
>
> Diese Variable sitzt allerdings in einem Register.

..und das ist schneller.. habe kapiert.

Es hat auch was gebracht. Mit der Variable ist das aufblitzen kaum noch 
zu sehen. Mit -O3 sieht man es dann nur im dunkeln und bei ganz scharfem 
hingucken.

Naja naechstes mal nehme ich gleich den 595er..

Danke!

Autor: Stefan Noack (stefan_n)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Falk: wie erzeugst du die .lss-Datei?

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Originalversion 24-27 Takte (datenabhängig) pro Iteration, die 
modifizierte Version 23 Takte (gcc 4.3.4). Nicht wirklich der Brüller. 
Ergibt zusammengerechnet also an die 200 Takte.

Mit -O3 sind es jedoch für alle 8 Iterationen insgesamt nur knapp 90 
Takte.

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@  Stefan Noack (stefan_n)

>@ Falk: wie erzeugst du die .lss-Datei?

Einfach im AVR-Studio in den Projektoptionen den Haken setzen.

Autor: Sauger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Moin,

Falk Brunner schrieb:
> void set_leds(uint8_t row0, uint8_t row1, uint8_t row2) {
>   uint8_t tmp;

wenn man tmp durch eines der 3 GPIOR ersetzt, ist vielleicht noch was 
rauszukitzeln.

MfG

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du meinst, ein I/O-Port sei effizienter als ein Prozessorregister??

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@  Sauger (Gast)

>wenn man tmp durch eines der 3 GPIOR ersetzt, ist vielleicht noch was
>rauszukitzeln.

Nö, das Setzen der Bits in tmp als CPU-Register ist schon maximal 
schnell, ori dauert 1 Takt.
Aber SBI dauert nur 2 Takte. Die drei zusätzlichen Takte durch 3x sbi 
werden in der tmp-Variante am Ende wieder kompensiert, wo der Port 
gelesen, modifiziert und wieder geschrieben wird.
Wie gewonnen, so zerronnen. ;-)

Die tmp-Variante ist dann schneller, wenn man auf variable Bits per 
Bitmasken zugreifen muss, dann geht kein sbi/cbi.

http://www.mikrocontroller.net/articles/Bitmanipul...

MfG
Falk

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Falk Brunner schrieb:

> Die tmp-Variante ist dann schneller, wenn man auf variable Bits per
> Bitmasken zugreifen muss, dann geht kein sbi/cbi.

Die I/O-Bits liegen fest, was fehlt ist die passende Operation zum Test 
ob gesetzt. Auch ein TEST Befehl, d.h. ein AND ohne Resultat, wäre 
hilfreich.

In der -O3 Variante ändert insbesondere diese Aspekt, denn bei 
vollständigem unrolling liegen die Bits fest und damit wird die 
Testoperation von MOV/AND/BREQ zu SBIC.

Autor: jw (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Was spricht gegen USI, wenn's dann ganz schnell gehen muß?
Laut Atmel Doku "SPI Master Operation Example" (der zweite Teil mit 
"enrolled loop") schaft man damit F_CPU/2.
Gruß,
Jürgen

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
jw schrieb:

> Was spricht gegen USI, wenn's dann ganz schnell gehen muß?

Vermutlich der Umstand, dass er 3 davon bräuchte ;-).

Autor: Sauger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Moin,

A. K. schrieb:
> Du meinst, ein I/O-Port sei effizienter als ein Prozessorregister??

unter umständen schon. Betrachte die GPIOR's als globale Variablen die 
in einen Register liegen. Dieses dürfte für den Compiler/Optimizer ein 
gefundenes Fressen sein, wenn der Funktionsaufruf von set_leds(...) und 
was davor kommt, inline wird. Ist aber zugegebenermaßen stark vom 
Programmfluss abhängig.

MfG

Autor: Stefan Noack (stefan_n)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
A. K. schrieb:
> jw schrieb:
>
>> Was spricht gegen USI, wenn's dann ganz schnell gehen muß?
>
> Vermutlich der Umstand, dass er 3 davon bräuchte ;-).

Und sobald es 4 werden wird es langsamer als die Variante mit der 
Variable.

Autor: jw (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Naja, deshalb doch seriell, oder?
(164(Q7) an (in)164(Q7) an (in)164, paralleler Takt)

Autor: Stefan Noack (stefan_n)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sauger schrieb:
> unter umständen schon. Betrachte die GPIOR's als globale Variablen die
> in einen Register liegen. Dieses dürfte für den Compiler/Optimizer ein
> gefundenes Fressen sein, wenn der Funktionsaufruf von set_leds(...) und
> was davor kommt, inline wird. Ist aber zugegebenermaßen stark vom
> Programmfluss abhängig.

Der aufruf an set_leds() ist vollkommen unkritisch (davor und danach 
wird eh 250ms gepennt). Es geht nur darum, die bits so schnell wie 
möglich in das Register reinzukrachen, damit man es nicht sieht, dass 
ich zu blöd war, ein register mit Output Latches zu verwenden.

Autor: Stefan Noack (stefan_n)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
jw schrieb:
> Naja, deshalb doch seriell, oder?
> (164(Q7) an (in)164(Q7) an (in)164, paralleler Takt)

Nein, hat jeder einen eigenen pin (bleiben eh genug übrig). Clock ist 
gemeinsam.

Egal.. Ich löte jetzt Kondensatoren an die LEDs und dann hat sichs... 
;-)

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sauger schrieb:

> unter umständen schon. Betrachte die GPIOR's als globale Variablen die
> in einen Register liegen.

In einem I/O-Register, ja.

> Dieses dürfte für den Compiler/Optimizer ein
> gefundenes Fressen sein, wenn der Funktionsaufruf von set_leds(...) und
> was davor kommt, inline wird.

Inwieweit es sinnvoll sein könnte, ein Prozessorregister durch ein 
GPIORx zu ersetzen, das kann ich absolut nicht erkennen. Mit ist kein 
einziger Befehl bekannt, der mit GPIORx kürzer und/oder schneller ginge 
als mit einem Prozessorregister.

Die GPIORs sind genau dann sehr praktisch wenn man globale(!) Flagbits 
irgendwo unterbringen will, weil man dann die CBI/SBI/SBIC/SBIS-Befehle 
an Stelle LDS/.../STS verwenden kann. Gegenüber Byte-Variablen sind die 
Lade/Speicheroperationen immerhin ein bissel schneller. Beide Fälle sind 
hier nicht gegeben.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Stefan Noack schrieb:
> jw schrieb:
>> Naja, deshalb doch seriell, oder?
>> (164(Q7) an (in)164(Q7) an (in)164, paralleler Takt)
>
> Nein, hat jeder einen eigenen pin (bleiben eh genug übrig). Clock ist
> gemeinsam.
>
> Egal.. Ich löte jetzt Kondensatoren an die LEDs und dann hat sichs...
> ;-)

Und das nächste mal Schieberegister mit getrenntem Ausgangsregister. 
Dann stellt sich das Problem erst gar nicht.

Autor: Stefan Noack (stefan_n)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger schrieb:
> Stefan Noack schrieb:
>> jw schrieb:
>>> Naja, deshalb doch seriell, oder?
>>> (164(Q7) an (in)164(Q7) an (in)164, paralleler Takt)
>>
>> Nein, hat jeder einen eigenen pin (bleiben eh genug übrig). Clock ist
>> gemeinsam.
>>
>> Egal.. Ich löte jetzt Kondensatoren an die LEDs und dann hat sichs...
>> ;-)
>
> Und das nächste mal Schieberegister mit getrenntem Ausgangsregister.
> Dann stellt sich das Problem erst gar nicht.

Ich habs ja verstanden...

Ich glaube nun ist alles gesagt, was hierzu gesagt werden kann.

Autor: Sauger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mahlzeit,

A. K. schrieb:
> Die GPIORs sind genau dann sehr praktisch wenn man globale(!) Flagbits
> irgendwo unterbringen will, weil man dann die CBI/SBI/SBIC/SBIS-Befehle
> an Stelle LDS/.../STS verwenden kann. Gegenüber Byte-Variablen sind die
> Lade/Speicheroperationen immerhin ein bissel schneller. Beide Fälle sind
> hier nicht gegeben.

Wenn man die Flagbits zwecks Visualisierung auf Leuchtidoten legen 
möchte schon :-). Wird aber OT dem TE wurde geholfen, damit kann das 
Thema knitterfrei abgeschlossen werden.

MfG

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenns schnell schieben soll, bastele zuerst die 8 Portbytes zusammen und 
gebe dann aus:
void fast_out( uint8_t d0,
               uint8_t d1,
               uint8_t d2,
               uint8_t d3,
               uint8_t d4,
               uint8_t d5,
               uint8_t d6,
               uint8_t d7 )
{
    LEDS_PORT = d0;
    LEDS_PORT |= _BV(LEDS_CLK);
    LEDS_PORT = d1;
    LEDS_PORT |= _BV(LEDS_CLK);
    LEDS_PORT = d2;
    LEDS_PORT |= _BV(LEDS_CLK);
    LEDS_PORT = d3;
    LEDS_PORT |= _BV(LEDS_CLK);
    LEDS_PORT = d4;
    LEDS_PORT |= _BV(LEDS_CLK);
    LEDS_PORT = d5;
    LEDS_PORT |= _BV(LEDS_CLK);
    LEDS_PORT = d6;
    LEDS_PORT |= _BV(LEDS_CLK);
    LEDS_PORT = d7;
    LEDS_PORT |= _BV(LEDS_CLK);
}

Das Schieben dauert dann nur 24 Zyklen.


Peter

Autor: Stefan Noack (stefan_n)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter Dannegger schrieb:
> Wenns schnell schieben soll, bastele zuerst die 8 Portbytes zusammen und
> gebe dann aus
>
> Das Schieben dauert dann nur 24 Zyklen.
>

Passiert das bei -O3 nicht sowieso?

EDIT:

oh.. und wenn man die mit CLK geODERten auch noch vorher ausrechnet sind
es nur noch 16 takte :D Ich denke, ich werde das mal probieren...

2nd EDIT:

Könnte man die eingabewete auch als Array übergeben, ohne dass es 
langsamer wird?

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Stefan Noack schrieb:
> Passiert das bei -O3 nicht sowieso?

Der Compiler ist doch kein Hellseher, er weiß nicht auf was es Dir 
ankommt.

Ein Compiler wird immer so wenig wie möglich Variablen verwenden.
Das Aufblasen von 3 auf 8 Register-Variablen mußt Du erzwingen.

Es kann durchaus sein, daß Du fast_out() noch als noinline definieren 
mußt, damit es nicht wieder zurückoptimiert wird.


Peter

Autor: Stefan Noack (stefan_n)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
verliere ich etwas, wenn ich ein array verwende?
void fast_out( uint8_t d[16]) __attribute__ ((noinline))
{
    LEDS_PORT = d[0];
    LEDS_PORT = d[1];
    LEDS_PORT = d[2];
    LEDS_PORT = d[3];
    LEDS_PORT = d[4];
    ...
}

da würde mir das zusammenpacken vorher einfacher fallen.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Stefan Noack schrieb:
> verliere ich etwas, wenn ich ein array verwende?

Ich denke, ja.
Schau mal ins Listing.

Die 8 Variablen müssen in Registern vorliegen, sonst gewinnst Du nichts.


Peter

Autor: Stefan Noack (stefan_n)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So. Schneller geht es mit dem Schieben nicht (16 out-Anweisungen 
hintereinander):
static uint8_t get_bits(uint8_t d, uint8_t bit,
                 uint8_t row0, uint8_t row1, uint8_t row2)
{
  if (row0 & bit)
    d |= _BV(LEDS_AB0);
  
  if (row1 & bit)
    d |= _BV(LEDS_AB1); 
  
  if (row2 & bit)
    d |= _BV(LEDS_AB2);
      
  return d;
}
               
void set_leds(uint8_t row0, uint8_t row1, uint8_t row2) 
{ 
  uint8_t d = LEDS_PORT & ~LEDS_MASK;
  
  uint8_t d0 = get_bits(d, _BV(7), row0, row1, row2);
  uint8_t d1 = d0 | _BV(LEDS_CLK);
  uint8_t d2 = get_bits(d, _BV(6), row0, row1, row2);
  uint8_t d3 = d2 | _BV(LEDS_CLK);
  uint8_t d4 = get_bits(d, _BV(5), row0, row1, row2);
  uint8_t d5 = d4 | _BV(LEDS_CLK);
  uint8_t d6 = get_bits(d, _BV(4), row0, row1, row2);
  uint8_t d7 = d6 | _BV(LEDS_CLK);
  uint8_t d8 = get_bits(d, _BV(3), row0, row1, row2);
  uint8_t d9 = d8 | _BV(LEDS_CLK);
  uint8_t dA = get_bits(d, _BV(2), row0, row1, row2);
  uint8_t dB = dA | _BV(LEDS_CLK);
  uint8_t dC = get_bits(d, _BV(1), row0, row1, row2);
  uint8_t dD = dC | _BV(LEDS_CLK);
  uint8_t dE = get_bits(d, _BV(0), row0, row1, row2);
  uint8_t dF = dE | _BV(LEDS_CLK);
  
  asm("out %0, %1"  "\n\t"
      "out %0, %2"  "\n\t"
      "out %0, %3"  "\n\t"
      "out %0, %4"  "\n\t"
      "out %0, %5"  "\n\t"
      "out %0, %6"  "\n\t"
      "out %0, %7"  "\n\t"
      "out %0, %8"  "\n\t"
      "out %0, %9"  "\n\t"
      "out %0, %10" "\n\t"
      "out %0, %11" "\n\t"
      "out %0, %12" "\n\t"
      "out %0, %13" "\n\t"
      "out %0, %14" "\n\t"
      "out %0, %15" "\n\t"
      "out %0, %16" "\n\t"
      :
      : "I" (_SFR_IO_ADDR(LEDS_PORT)),
        "r" (d0), "r" (d1), "r" (d2), "r" (d3),
        "r" (d4), "r" (d5), "r" (d6), "r" (d7),       
        "r" (d8), "r" (d9), "r" (dA), "r" (dB),
        "r" (dC), "r" (dD), "r" (dE), "r" (dF)                
     );
}

Damit ist die Optimierung nun offiziell abgeschlossen ;-)

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du darfst natürlich keine Wunder erwarten. Das Auge ist logarithmisch.
Wenn die Schiebezeit halbiert wird, hast Du nicht den Eindruck, daß das 
Aufblitzen der ausgeschalteten LEDs auch nur halb so hell ist.

Sinnvoll ist auch, alle 100Hz eine neue Ausgabe zu machen. Dann sieht 
man das Aufblitzen nicht mehr.


Peter

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.