mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik WINAVR und CarryFlag


Autor: Jean Player (fubu1000)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
habe ein kleines Problem beim addieren von bytes. Programmiere in WINAVR 
unter AVRSTUDIO, einen Atmega32.

Beispiel:
unsigned char Zahl1 = Zahl2 = 0xAA;
unsigned char Zahl3 = 0;

Zahl1 = Zahl1 + Zahl2;
Zahl3 = Zahl3 + CARRY;

In Assembler gabs so schöne Befehle die add und adc, aber in C stehe ich 
gerade total aufm Schlauch.
Hoffe das klar geworden ist was ich meine.
Also 2 Zahlen addieren und die nächste Zahl soll mit dem Carry Flag 
zusammen addiert werden, falls es einen Übertrag gab.

Vielen Dank und Gruß, fubu.

Autor: Läubi .. (laeubi) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich erinnere mich dunkel das das nicht ging, warum willst du die Anzahl 
an carrys zählen?
Du könntest z.B. einfach nen größeren Datentyp nehmen:

int ZahlN, Zahl2

ZahlN += Zahl2

Dann ist ZahlN & 0xFF = dein bisheriges Zahl1
(ZahlN & 0xFF00)>>8 dein bisheriges Zahl3

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich sehe darin zwar keinen Sinn, aber unter C geht es z.B. so:
unsigned char Zahl1 = Zahl2 = 0xAA;
unsigned char Zahl3 = 0;
unsigned short temp;  // 16 bit

Zahl1 = Zahl1 + Zahl2;
temp = Zahl1 + Zahl2;
Zahl3 += temp >> 8;


Peter

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Fabian Ostner (fubu1000)

>Also 2 Zahlen addieren und die nächste Zahl soll mit dem Carry Flag
>zusammen addiert werden, falls es einen Übertrag gab.

Dazu musst du grössere Variablen verwenden und von Hand den Übertrag 
behandeln. Ist zwar ziemlich ineffizient, geht in C aber nicht anders.

Etwa so.

uint16_t z1 = z2 =0xAA;
uint16_t z3;

z1 = z1 +z2;
if (z1>255) {
  z1 = z1 - 256;
  z3 = Z3 +1;
}

MFG
Falk

Autor: Jean Player (fubu1000)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
bin gerade wieder daheim, habs mir fast gedacht.
Ziemlich uneffizient alles, glaube programmiere wieder Assembler.
NENE.
Super Dank an alle und Gruß Fabian.

Autor: Jean Player (fubu1000)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Damit Ihr mich nicht für total verrückt haltet warum ich sowas frage.
Ich lese aus einem Fat16 , z.B. VolumeBootRecord aus wieviele Sektoren 
reserviert sind. Möchte diese natürlich mit dem Start der 
VolumeBootRecord addieren, damit ich weiß, wo die die FAT beginnt.

In Assembler schmeiss ich einfach das letzte ausgelesene Byte weg 
(höchste Byte), füge hinten 0x00 an und mach einen "lsl" des untersten 
Bytes und "adc" mit den folgenden Bytes (Registern).

In Assembler super effektiv, aber in C muss ich da mit "long" rumspielen 
und dann wieder in chars wandeln für Addressierung.
Super Uneffektiv !

In Assembler hab ich FAT16 schon in Read und Write umgesetzt und funzt 
super.
Wollte es mal aber ebenso effektiv in C umsetzen.
Aber keine Chance  ;-(

Werde es aber weiter versuchen, muß gehen irgendwie ;-(

GRUß UND DANK AN ALLE , FABIAN.

Autor: Läubi .. (laeubi) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Erstmal heißt es ineffizient ;)
Außerdem effektiv != effizient, effektiv ist das alles! :P

So Spaß beiseite: Du kannst natürlich inline ASM für die betreffende 
Stelle verwenden, man kann dort auch auf C Variablen zugreifen. 
(http://www.mikrocontroller.net/articles/AVR-GCC-Tu...).

Außerdem so ineffizient wie das scheint ist das alles nicht, vieleicht 2 
- 3 Takte langsamer, und wenn du das als Ausdruck formulierst kann der 
Compiler da ggf. auch optimieren.

Autor: risu (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

hier eine mögliche Umsetzung des Vorschlags von Läubi Mail@laeubi.de:
#include <inttypes.h>

uint8_t  carry(uint8_t z1, uint8_t z2) {
    uint8_t carry;
    asm volatile(
        "clr %0" "\n\t"
        "add %1,%2" "\n\t"
        "adc %0, %0"
        : "=r" (carry)
        : "r" (z1), "r" (z2), "0" (carry)
    );
    return carry;
}

int main(void){
uint8_t Zahl1, Zahl2;
volatile uint8_t Zahl3 = 0;

Zahl1=Zahl2=0xAA;
Zahl3+=carry(Zahl1, Zahl2);
return 1;
}

Gruß
  risu

Autor: risu (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
PS: "Zahl3" habe ich nur zum Testen "volatile" gemacht.

MfG
 risu

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Fabian Ostner wrote:
> In Assembler super effektiv, aber in C muss ich da mit "long" rumspielen
> und dann wieder in chars wandeln für Addressierung.
> Super Uneffektiv !

Du weißt wohl nicht, wie man Effektivität berechnet?

Du berechnest ne Adresse und liest dann z.B. 512 Byte von dieser ein.
Ein Memcopy dauert 7 Zyklen pro Byte, also 3584 Zyklen.
Nun ärgert Dich tierisch, daß die Adreßberechnung vielleicht 5 Zyklen 
länger dauert, d.h. gerade mal 0,13%.

Also ein Unterschied von 0,13% ist nicht super, sondern nur ein 
Fliegenschiß.


Bevor also etwas optimiert, sollte man erstmal prüfen, ob das überhaupt 
einen merkbaren Effekt hat.


Peter


P.S.:
Man kann einen Quellcode nicht verbal beschreiben.
Daher wäre der Assemblerquelltext dieser Funktion sinnvoll, damit man 
sieht was da überhaupt passiert und wie man das in C machen könnte.

Aber wenn eine Funktion nicht mindestens 10% der CPU-Zeit verbraucht, 
lohnt sich eine Optimierung in den seltensten Fällen.

Autor: risu (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Peter,

> Man kann einen Quellcode nicht verbal beschreiben.
> Daher wäre der Assemblerquelltext dieser Funktion sinnvoll,...

das sehe ich auch so. Mir war anhand der Beschreibung des OPs z.B. nicht 
klar, ob er die Summe, deren Übertrag er benötigt, verwirft oder 
verwendet. Deshalb habe ich meine Inline-Assembler-C-Stub-Funktion (oder 
wie immer man die nennt) so ausgerichtet, dass zwar die Summe gebildet, 
aber nur der Übertrag zurückgegeben wird.

Gruß
  risu

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@  Peter Dannegger (peda)

>Aber wenn eine Funktion nicht mindestens 10% der CPU-Zeit verbraucht,
>lohnt sich eine Optimierung in den seltensten Fällen.

Richtig. Alte Programmiererregel.

90% der CPU-Leistung werden in 10% des Programms verbraucht.

Diese 10% müssen optimiert werden, der Rest "nur" solide hingeschieben. 
Siehe Soft-PWM, dort lohnt sich eine Optimierung nur in der ISR.

MFg
Falk

Autor: risu (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

hier die korrigierte Version (nur eine Spielerei; wenn die Funktion 
wirklich zeitkritisch wäre, würde ich einen größeren Teil des Codes als 
"*.S" Assembler-Code verpacken):
#include <avr/io.h>

#include <inttypes.h>

uint8_t  f_carry(uint8_t z1, uint8_t z2) {
    uint8_t carry;
    asm volatile(
        "clr %0" "\n\t"
        "add %1,%2" "\n\t"
        "adc %0, %0"
        : "=r" (carry)
        : "r" (z1), "r" (z2), "0" (carry)
    );
    return carry;
}


int main(void){
    uint8_t Zahl1, Zahl2;
    volatile uint8_t Zahl3 = 0;


    Zahl1=Zahl2=0xAA;

    Zahl3+=f_carry(Zahl1, Zahl2);
    return 1;
}
Gruß
 risu

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.