Forum: Compiler & IDEs Probleme mit Arithmetik in C - WinAVR


von Matthias W. (matt007)


Lesenswert?

ein RTC-Baustein DS1302 wird ausgelesen. Dabei kommt es zu Fehlern. Die 
bits werden korrekt in ein unsigned char byte eingelesen.

In den oberen 4 bit stehen Sekunden*10 und in den unteren 4 bit die 
Sekunden. Es werden folgende Operationen durchgeführt:
1
unsigned char byte, temp, temp1;
2
((byte &= 0x0f) + ((byte >>=4) * 10));

dies klappt so leider nicht. Jedenfalls scheint das Ergebnis 0 oder 
falsch zu sein, obwohl Sekunden ungleich 0 da sind.

als Beispiel wird in byte abgelegt: 0101 1001 = 0x59
so weit so gut. Daraus müsste nun 5*10=50 + 9 =59 werden.
1
temp = (byte &= 0x0f); liefert als Ausgabe 9. Dies ist ok.
1
temp1 = ((byte >>=4) * 10); liefert jedoch 0, was falsch ist.

Ist das byte beim ersten Rechenvorgang ungewünscht verändert worden?
Legt sich der Compiler keine Kopie davon an?

Das Ergebnis von temp = temp + temp1 wird als unsigned int über USART 
ausgeben. Es erscheint über USART die falsche Ausgabe 90909. Wie ist das 
möglich?

Die Ausgabe von temp macht USART_Tx_int((unsigned int)temp) die ich 
schon länger nutze. Siehe den folgenden Code der Ausgabe:
1
void USART_Tx_int(unsigned int data){
2
   unsigned long temp;
3
   unsigned char tmp;
4
   unsigned char ziff=0; // fuehrende Null da? fuer Unterdrueckung
5
   
6
   signed char i;  // signed, damit for-Schleife beendet wird mit <0 !
7
8
   temp = INT2BCD5(data); 
9
   
10
   for (i=16; i>=0; i-=4)   {
11
     tmp= (((unsigned char) (temp>>i)) &0x0f)+'0'; 
12
     if (tmp=='0') { // eine Ziffer = Null da?
13
        if (ziff==0) { // ist es eine fuehrende 0?
14
           if (i==0) { // ist die letzte Ziffer eine 0?
15
              USART_Tx (tmp); // diese Null ausgeben
16
           }
17
           else { // nein, also unterdruecken
18
              USART_Tx (' '); // fuehrende Null als Space ausgeben
19
           }
20
        }
21
        else {
22
           USART_Tx (tmp); // Nullen in der Zahl als Nullen ausgeben
23
        }
24
     }
25
     else { // eine Ziffer ungleich Null da
26
       ziff=1;
27
       USART_Tx (tmp); // Ziffer 0-9 als ASCII ausgeben
28
     }
29
   }
30
}

Vielleicht hat jemand eine Idee warum und wo es hier klemmt?

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Matthias W. schrieb:
> temp = (byte &= 0x0f); liefert als Ausgabe 9. Dies ist ok.

Das mag auf den ersten Blick OK sein, aber es verändert Deine Variable 
"Byte". Schreib' & statt &= - und lies' Dir in Deinem C-Buch mal durch, 
welche logischen Operatoren es gibt, und was ein Zuweisungsoperator 
ist.

von B e r n d W. (smiley46)


Lesenswert?

> lies' Dir in Deinem C-Buch mal durch, welche logischen Operatoren es
> gibt, und was ein Zuweisungsoperator ist.

Volle Zustimmung!

Probiers mal so:
temp = ((byte >> 4) & 0x0F) * 10 + (byte & 0x0F);

von Matthias W. (matt007)


Lesenswert?

die BCD-Routine sieht so aus:
1
const unsigned int unit[]={10000,1000,100,10};
2
#define UNIT_TEN_THOU 0
3
#define UNIT_THOU     1
4
#define UNIT_HUNDRED  2
5
#define UNIT_TEN      3
6
7
unsigned long INT2BCD5(unsigned int input)
8
{
9
  return (unsigned long) convertBCD(UNIT_TEN_THOU,input);
10
}
11
12
13
unsigned long convertBCD(char digit, unsigned int input){
14
  unsigned long high = 0;
15
  char i;
16
17
  for (i=digit;i<=UNIT_TEN;i++){ 
18
     while (input >= unit[(int)i]){
19
        high++;
20
        input -= unit[(int)i];
21
     }
22
     high <<= 4;
23
  }
24
  return high | input;
25
}

von Matthias W. (matt007)


Lesenswert?

Rufus Τ. F. schrieb:
> Das mag auf den ersten Blick OK sein, aber es verändert Deine Variable
> "Byte".

Danke Rufus, Du hast vollkommen recht. Manchmal ist man blind für 
einfachste Fehler. Es ist mir schon klar daß i += 1 bedeutet i=i+1. Hier 
jedoch habe ich das übersehen. Gleich zweifach.

von Matthias W. (matt007)


Lesenswert?

B e r n d W. schrieb:
> Probiers mal so:

Vielen Dank Bernd !

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.