Verständnis Problem folgender code-Zeile

Gast #366537
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.
Gast #366540
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
#366541
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.
Gast #366542
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.
Gast #366544
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
Gast #366545
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!
Gast #366546
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
#366547
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
Moderator Persönliche Seite #366548
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. ;-)

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren