Forum: Compiler & IDEs Verständnis Problem folgender code-Zeile


von Thomas (Gast)


Lesenswert?

Hallo

Habe ein kleines Verständnisproblem mit folgenden code - es geht darum,
den 10 BIT Wert des ADC's eines AVR's in ein Register zu lesen.

uint16_t value;   //Sonnenklar
value = ADCL;     //Sonnenklar
value += ADCH<<8; //keine Ahnung

Was mir klar ist, ist selbstverständlich das "+=" - sowie auch das
Schieben um 8 BIT-Positionen nach Links. Aber wie kann das
Funktioneren. Es wird doch erst Addiert und zugewiesen und dann
geschoben - so dass die erste Zuweisung mit ADCL eigentlich verloren
ist.

Wie wird die Zeile übersetzt?
Ergebnis ist genau dass, was ich benötige - aber wieso?

Das Listing-File habe ich mir auch angesehen - hilft aber auch nicht.

von Karl H. (kbuchegg)


Lesenswert?

> Es wird doch erst Addiert und zugewiesen und dann
> geschoben

Nein. Es wird erst der Ausdruck rechts vom = ausgewertet.
Wie bei jeder normalen Zuweisung auch. Nur dass halt
bei einem += nicht einfach zugewiesen wird, sondern
aufaddiert. Das ist alles.

von Thomas (Gast)


Lesenswert?

eben - es wird aufaddiert - das ist ja noch ok.

Aber - wie kommt ADCHigh auch wirklich in das Highbyte von value? ->
das wird ja über das schieben realisiert - und das verstehe ich nicht.

von Fabian Scheler (Gast)


Lesenswert?

Wo ist das Problem??? Beispiel:

uint_16 value = 0;

ADCL = 0xcd;
ADCH = 0xab;

value = ADCL;

/* value = 0xcd */

value += (ADCH << 8)

/* ADCH      = 0xab =>
   ADCH << 8 = 0xab00
   value(old)= 0x00cd
   value(new)= 0xabcd
*/

Alles klar?

Ciao, Fabian

von Karl H. (kbuchegg)


Lesenswert?

value = value + ( ADCH << 8 );

ADCH wird um 8 Bit nach links geschoben und dann
zu value (welcher bereits 8 Bit von ADCL enthält)
addiert:

ADCL   1010 0011
ADCH   0000 0010

value = ADCL:
    0000 0000 1010 0011

ADCH << 8:
    0000 0010 0000 0000

value += ADCH << 8:
   beides addieren
    0000 0010 1010 0011
   und value zuweisen.

von Thomas (Gast)


Lesenswert?

Ok - dann frage ich mich nun, wie kann ich in einer Variable, die nur
8-BIT breit ist einen Wert um 8-Bit nach links schieben? In Windows
nennt man sowas overflow!

Das folgendes so einfach gemacht wird ist mir wirklich suspekt - das
wusste ich nicht.

ADCH      = 0xab
ADCH << 8 = 0xab00

Danke euch beuden.

von Alex (Gast)


Lesenswert?

uint16_t

Rat mal, wofür die 16 steht!

von Fabian Scheler (Gast)


Lesenswert?

Zum einen hast du uns nicht verraten, welchen Typ 'ADCH' hat, das
könnte durchaus ein 16-Bit Typ sein (ich habe keine Ahnung was sich
dahinter nun wirklich verbirgt), außerdem kommt es natürlich darauf an,
was für ein Typ 'ADCH << 8' eigentlich ist und das hat was mit
'Integer Promotion' (oder?) zu tun. Wenn du folgendes machst

uint_16 value = 0;
value = (uint_8)(ADCH << 8);

dürfte value freilich immer der Wert '0' zugewiesen werden.

Ciao, Fabian

von Thomas (Gast)


Lesenswert?

@Alex - kein Kommentar - dein Beitrag ist sinnlos!

@Fabian - bei ADCH handelt es sich um das High-Byte des Ergebnisses des
AD-Wandlers - ADCH ist defenetiv 8-BIT breit! Type uint_8!

Und nun nochmal - warum kann ich in einer 8-BIT Variable 8-BITS nach
links schieben und erhalte dann eine 16-BIT Variable?

Keine Ahnung!

von Fabian Scheler (Gast)


Lesenswert?

Das habe ich in meiner Antwort doch eigentlich erklärt - was sich hinter
'Integer Promotion' bzw. 'impliziten Typumwandlungen' verbirgt,
kannst du über google oder K&R selbst herausfinden, das gehört dazu!

Ciao, Fabian

von Peter D. (peda)


Lesenswert?

Formal müßte man (uint_16)ADCH << 8 schreiben, d.h. vorher auf 16Bit
erweitern und schaden tuts ja nicht, macht es nur besser lesbar.


Aber der C Standart schreibt vor, daß Berechnungen so ausgeführt werden
müssen, daß das gleiche Ergebnis rauskommt, als wären sie mindestens
16bittig ausgeführt worden.

Deshalb kann man auch oft sehen, daß der AVR-GCC unnötig auf 16Bit
erweitert, obwohl alle Operanden 8bittig sind. Der AVR-GCC ist da
leider etwas optimierungsfaul.


Peter

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

> Der AVR-GCC ist da
> leider etwas optimierungsfaul.

Es hat ihm einfach nur niemand beigebracht.  Für die meisten
GCC-Architekturen ist das kein Thema, weil deren natürliche
Verarbeitungsbreite größer ist (32 bits) als die vom Standard
geforderten 16 bits.  Dadurch ist bei ihnen die Verarbeitung
von 8-Bit-Werten nicht schneller als die von 16- oder 32-bit-
Werten (oft eher noch langsamer).

Kommt hinzu, dass wohl die AVR-GCC-Implementierung insgesamt
eher vorgaukelt, eine 16-bit-Implementierung zu sein, d. h. die
internen Befehle (insns) sind in der Zwischensprache als
16-bit-Befehle organisiert, die dann jeweils in den Assemblercode
für eine 16-bit-Operation direkt auflösen.  Hier liegt sicher
Optimierungspotenzial, leider jedoch in einer Form, dass man
praktisch einen Großteil der existierenden Implementierung
neu anfangen müsste, wollte man das ändern.

Übrigens schreibt der Standard nicht "Promotion auf mindestens
16 bits" vor, sondern "Promotion auf int".  D. h. obige Rechnung
bewirkt zwischenzeitlich ein Ergebnis, das mit einem u. U.
fehlerhaften Vorzeichen behaftet sein könnte, welches anschließend
bei der Zuweisung auf uint16_t wieder vernichtet wird.  In
diesem speziellen Fall nur ,,könnte'', da ADCH nur einen
Wertebereich von 0 bis 3 hat, mithin immer positiv ist.  Aber
solche impliziten Vorzeichenmutation bergen eine Gefahr in
sich, siehe

http://www.mikrocontroller.net/forum/read-2-368138.html

An den OP:
1
value = ADCW;

hätte es übrigens auch getan. ;-)

von Thomas (Gast)


Lesenswert?

@Jörg:

Danke für den Hinweis ADCW - wieder was dazu gelernt ;-)

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.