mikrocontroller.net

Forum: Compiler & IDEs Schiebeoperation mit int16_t-Variable


Autor: Dennis (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich möchte eine Division durch 4 mittels Schiebeoperation durchführen, 
da der Compiler (Optimierung -Os), das wohl nicht automatisch macht, 
sondern eine rechenzeitintensivere Division durchführt.
Wenn ich das richtig verstanden habe, funktioniert das Schieben 
folgendermaßen:

1<<3 bedeutet: 0000 0001 -> 0000 1000
3<<4 bedeutet: 0000 0011 -> 0011 0000

Eigentlich sollte ich das dann ja auch einach für eine als int16_t 
deklarierte Variable so anwenden können?

also:
int16_t mean;
mean = mean>>2

Wird das so funktionieren?

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ja

Autor: Dennis (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Alles klar, vielen Dank!

Autor: Andreas K. (a-k)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Kommt bloss nicht das gleiche Ergebnis raus. Jedenfalls nicht bei 
negativen Werten. >> rundet nach unten, / gegen 0.

Autor: Steffen (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bei positiven geht es, bei negativen ist es nicht so einfach, da diese 
(glaube ich) im 2er Komplement oder einer ähnlichen Schweinerei abgelegt 
sind.

Steffen.

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

Bewertung
0 lesenswert
nicht lesenswert
Dennis wrote:
> Hallo,
>
> ich möchte eine Division durch 4 mittels Schiebeoperation durchführen,
> da der Compiler (Optimierung -Os), das wohl nicht automatisch macht,

Was, zumindest beim gcc, im Übrigen nicht stimmt.
Der Compiler achtet nur darauf, nicht den gleichen Fehler zu
machen und bei negativen Zahlen in die falsche Richtung zu gehen :-)

Wenn die Variable aber sowieso nicht negativ werden kann, erhebt
sich die Frage, warum sie dann ein int16_t ist und kein uint16_t.
Denn dann klappts beim gcc auch wieder mit dem einfachen Schieben.

Ich bleibe dabei: Solche Low-Level Optimierungen überlässt man
sinnigerweise dem Compiler. Der kann das besser.

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@  Karl heinz Buchegger (kbuchegg) (Moderator)

>Ich bleibe dabei: Solche Low-Level Optimierungen überlässt man
>sinnigerweise dem Compiler. Der kann das besser.

Nur bedingt. Ich hab vor kurzen ein kleines Projekt gemacht, Soft-PWM 
mit 20 Kanälen. Dort wird im Interrupt ein uint32_t gelesen und 
byteweise auf die Ports geschrieben.

ISR(TIMER1_COMPA_vect) {

    static uint8_t pwm_cnt;
    uint32_t tmp;


    OCR1A   += isr_ptr->time[pwm_cnt];
    tmp      = isr_ptr->mask[pwm_cnt];
    
    if (pwm_cnt == 0) {
        PORTA = tmp;                            // set ports at begin of PWM
        PORTC = tmp>>8;
        PORTD = tmp>>16;
        pwm_cnt++;
    }
    else {      
        PORTA &= tmp;                       // clear ports
        PORTC &= tmp>>8;
        PORTD &= tmp>>16;                        
        if (pwm_cnt == pwm_cnt_max) {
            pwm_sync = 1;                           // update now possible
            pwm_cnt=0;
        }
        else pwm_cnt++;
    } 
}

GCC ist in allen Optimierungsstufen NICHT clever genug, einfach die 
richtigen Register in die IO-Ports zu schreiben. Er erkennt zwar, dass 
man das per Bytekopie machen kann, kopiert und löscht aber noch 
unsinnigerweise Register, die in der realen Schiebeoperation gelöscht 
werden.

Erst der (halblegale) Trick per Union erreicht das gewünschte, optimale 
Ergebnis.

ISR(TIMER1_COMPA_vect) {
    typedef union {                 // little trick, to speed up data access
        uint32_t d32;
        uint8_t ary[4];
        } ut_t;

    static uint8_t pwm_cnt;
    ut_t tmp;


    OCR1A   += isr_ptr->time[pwm_cnt];
    tmp.d32  = isr_ptr->mask[pwm_cnt];
    
    if (pwm_cnt == 0) {
        PORTA = tmp.ary[0];                         // set ports at begin of PWM
        PORTC = tmp.ary[1];
        PORTD = tmp.ary[2];
        pwm_cnt++;
    }
    else {      
        PORTA &= tmp.ary[0];                        // clear ports
        PORTC &= tmp.ary[1];
        PORTD &= tmp.ary[2];                        
        if (pwm_cnt == pwm_cnt_max) {
            pwm_sync = 1;                           // update now possible
            pwm_cnt=0;
        }
        else pwm_cnt++;
    } 
}

Mfg
Falk

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.