Forum: Mikrocontroller und Digitale Elektronik WINAVR und CarryFlag


von Jean P. (fubu1000)


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.

von Läubi .. (laeubi) Benutzerseite


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

von Peter D. (peda)


Lesenswert?

Ich sehe darin zwar keinen Sinn, aber unter C geht es z.B. so:
1
unsigned char Zahl1 = Zahl2 = 0xAA;
2
unsigned char Zahl3 = 0;
3
unsigned short temp;  // 16 bit
4
5
Zahl1 = Zahl1 + Zahl2;
6
temp = Zahl1 + Zahl2;
7
Zahl3 += temp >> 8;


Peter

von Falk B. (falk)


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.

1
uint16_t z1 = z2 =0xAA;
2
uint16_t z3;
3
4
z1 = z1 +z2;
5
if (z1>255) {
6
  z1 = z1 - 256;
7
  z3 = Z3 +1;
8
}

MFG
Falk

von Jean P. (fubu1000)


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.

von Jean P. (fubu1000)


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.

von Läubi .. (laeubi) Benutzerseite


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-Tutorial#Assembler_und_Inline-Assembler).

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.

von risu (Gast)


Lesenswert?

Hi,

hier eine mögliche Umsetzung des Vorschlags von Läubi Mail@laeubi.de:
1
#include <inttypes.h>
2
3
uint8_t  carry(uint8_t z1, uint8_t z2) {
4
    uint8_t carry;
5
    asm volatile(
6
        "clr %0" "\n\t"
7
        "add %1,%2" "\n\t"
8
        "adc %0, %0"
9
        : "=r" (carry)
10
        : "r" (z1), "r" (z2), "0" (carry)
11
    );
12
    return carry;
13
}
14
15
int main(void){
16
uint8_t Zahl1, Zahl2;
17
volatile uint8_t Zahl3 = 0;
18
19
Zahl1=Zahl2=0xAA;
20
Zahl3+=carry(Zahl1, Zahl2);
21
return 1;
22
}

Gruß
  risu

von risu (Gast)


Lesenswert?

PS: "Zahl3" habe ich nur zum Testen "volatile" gemacht.

MfG
 risu

von Peter D. (peda)


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.

von risu (Gast)


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

von Falk B. (falk)


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

von risu (Gast)


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):
1
#include <avr/io.h>
2
3
#include <inttypes.h>
4
5
uint8_t  f_carry(uint8_t z1, uint8_t z2) {
6
    uint8_t carry;
7
    asm volatile(
8
        "clr %0" "\n\t"
9
        "add %1,%2" "\n\t"
10
        "adc %0, %0"
11
        : "=r" (carry)
12
        : "r" (z1), "r" (z2), "0" (carry)
13
    );
14
    return carry;
15
}
16
17
18
int main(void){
19
    uint8_t Zahl1, Zahl2;
20
    volatile uint8_t Zahl3 = 0;
21
22
23
    Zahl1=Zahl2=0xAA;
24
25
    Zahl3+=f_carry(Zahl1, Zahl2);
26
    return 1;
27
}
Gruß
 risu

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.