Hallo Leute! Ich möchte in meinem Code gern eine einfache Prüfsumme über 3 Byte berechnen. Alles soweit kein Problem! Aber jetzt kommts: 0xFF + 0x01 ist beim anschliesenden Test != 0x00 wegen dem Carry. Gibt es eine Möglichkeit in C ohne Übertrag zu addieren? MfG Marc
Marc schrieb: > Aber jetzt kommts: 0xFF + 0x01 ist beim anschliesenden Test != 0x00 > wegen dem Carry. sicher nicht wegen dem Carry. Eher schon weil du die falschen Datentypen benutzt hast, bzw. dir die angewendeten C-Regeln nicht klar sind. > Gibt es eine Möglichkeit in C ohne Übertrag zu addieren? Zeig deinen Code. Schuss ins Blaue: Deine Berechnung wird im Zahlenraum int durchgeführt, während du eigentlich unsigned char haben willst. Mit einem Cast sollte sich das Problem beheben lassen.
Code geht leider grad nicht, bin nicht am Entwicklungsrechner. Der Zahlenraum soll natürlich unsigned char sein. Ich habs mit uint8_t gemacht, was ja eigentlich stimmen müsste!? Und es liegt am Carry, da im erzeugten ASM Code immer erst die normale Addition und dann nochmal die Carry-Addition durchgeführt wird. Beim anschliessenden Test zeigt der ASM Code, dass zwar das Ergebnis ==0x00 ist, aber die Carryflags unterschiedlich sind und der Test somit negativ ist.
Hier funktionierts. Ich glaub, du musst nochmal über Typenerweiterung nachdenken :->
Hier der Code:
1 | #include <avr/io.h> |
2 | #include <avr/interrupt.h> |
3 | #include <stdint.h> |
4 | #include <util/delay.h> |
5 | |
6 | #include "USI_TWI_Slave.h" |
7 | |
8 | #define SLAVE_ADDRESS 0x10
|
9 | |
10 | uint8_t command, value, checksum; |
11 | |
12 | |
13 | |
14 | void Process_Data(void) |
15 | {
|
16 | if((SLAVE_ADDRESS + command + value) == checksum) |
17 | {
|
18 | .
|
19 | .
|
20 | .
|
Wo funktionierts??
Ich vermute, du speicherst die Prüfsumme nich in einer uint8_t Variable vor dem Vergleich, sondern machst den direkt. Berechnungen werden in C im Gültigkeitsbereich von int durchgeführt. Du könntest aber die unteren 8 Bit mit einem binären UND maskieren.
Marc schrieb: > Und es liegt am Carry, da im erzeugten ASM Code immer erst die normale > Addition und dann nochmal die Carry-Addition durchgeführt wird. Beim Also macht er die Karl-Heinz schon erwähnt hat die Berechnung auf 16-Bit Basis. :-)
Und hier gleich mal noch der Assemblercode:
1 | @00000030: Process_Data |
2 | 45: { |
3 | +00000030: 91400086 LDS R20,0x0086 Load direct from data space |
4 | +00000032: 91800089 LDS R24,0x0089 Load direct from data space |
5 | +00000034: E090 LDI R25,0x00 Load immediate |
6 | +00000035: 0F84 ADD R24,R20 Add without carry |
7 | +00000036: 1D91 ADC R25,R1 Add with carry |
8 | +00000037: 9640 ADIW R24,0x10 Add immediate to word |
9 | +00000038: 91200088 LDS R18,0x0088 Load direct from data space |
10 | +0000003A: E030 LDI R19,0x00 Load immediate |
11 | +0000003B: 1782 CP R24,R18 Compare |
12 | +0000003C: 0793 CPC R25,R19 Compare with carry |
13 | +0000003D: F4F9 BRNE PC+0x20 Branch if not equal |
Idiotensicher geklammert:
1 | if ( ((uint8_t) (SLAVE_ADDRESS + command + value)) == checksum) |
Detlev T. schrieb: > Ich vermute, du speicherst die Prüfsumme nich in einer uint8_t Variable > vor dem Vergleich, sondern machst den direkt. Berechnungen werden in C > im Gültigkeitsbereich von int durchgeführt. Du könntest aber die unteren > 8 Bit mit einem binären UND maskieren. Dem würde ich mich anschließen. Das nennt sich übrigens "integral promotion". IAR hat einen schönen Beitrag über das Problem gemacht: http://supp.iar.com/Support/?note=12582&from=search+result
Marc schrieb: > if((SLAVE_ADDRESS + command + value) == checksum) dir ist hoffentlich klar, dass der linke Teil (die Berechnung) als int Berechnung gemacht wird, laut C-Spezifikation Damit wird auch der rechte Teil auf int hochgehoben und der Vergleich auch als int Vergleich gemacht. > Und es liegt am Carry Es liegt eben nicht am Carry. In C gibt es gar keinen Carry. Es liegt daran, dass du fälschlicherweise annimmst, dass 2 unsigned char zusammenaddiert wieder einen unsigned char ergeben. Dem ist aber nicht so! Berechnungen werden in C niemals in einem kleineren Datentyp als dem Datentyp int gemacht (*). In diesem Sinne sind
1 | if((SLAVE_ADDRESS + command + value) == checksum) |
und
1 | uint8_t summ = SLAVE_ADDRESS + command + value; |
2 | if(summ == checksum) |
3 | ...
|
2 völlig verschiedene Paar Schuhe! (*) Es sei denn, der Optimizer kann beweisen, dass sich das Ergebnis nicht verändert, wenn er (bei einem 16 Bit int) das High-Byte ignoriert und nicht berechnet. Bei dir unterscheiden sich aber die Ergebnisse, daher muss die Berechnung als int-Berechnung gemacht werden.
Jetzt ist mir alles klar! Vielen Dank für die Antworten! Wieder was gelernt :-) Welche Variante erzeugt (vermutlich) weniger Code? Die von Sven P. oder die von Karl Heinz?
Marc schrieb: > Welche Variante erzeugt (vermutlich) weniger Code? > Die von Sven P. oder die von Karl Heinz? Im Zweifelsfall im Assemblercode ansehen. Bei aktiviertem Optimizer erwarte ich aber keinen Unterschied.
Eventuell ergibt das ja kürzeren Code:
1 | uint8_t summ = SLAVE_ADDRESS; |
2 | summ += command; |
3 | summ += value; |
4 | summ -= checksum; |
5 | if(summ == 0) |
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.