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.
> 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.
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.
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
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.
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.
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
@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!
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
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
> 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. ;-)
@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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.