Forum: Mikrocontroller und Digitale Elektronik Mega32 rechnet "falsch"


von Frederik H. (bytejesus)


Lesenswert?

Hallo,

bin gerade dabei die Steuerung für einen Unterwasserglider zu bauen. Um 
die Tiefe zu wissen benötigt er einen Drucksensor (MS5535C), der über 
SPI angeschlossen ist.

Um eine Temperaturkalibration durchzuführen muss ich erst 6 
Koeffizienten auf den mC schieben und kann dann damit den Druck 
errechnen.

Zur Kontrolle der Werte habe ich eine UART verbindung mit dem PC.

Problem: der eine Wert, der errechnet werden muss, kann nicht stimmen.
1
 UT1 = 10000 + (8 * C5);
Die PuTTY Konsole gibt mir: UT1 = -31760

da ich mir C5 übertragen lasse stimmt was nicht: C5 = 2972

laut Datenblatt soll UT1 zwischen 10000 und 42760 liegen.

Ich habe schon versucht UT1, die ganzen Koeefizienten als int32_t zu 
definieren...

Es kann meiner Meinung nach kein SPI sondern entweder ein Rechen- oder 
UARTproblem sein.. ???

Weiss nicht mehr wo ich jetzt noch suchen soll!

Danke für eure Hilfe!

Fred

von Floh (Gast)


Lesenswert?

Frederik H. schrieb:
> Weiss nicht mehr wo ich jetzt noch suchen soll!

Wir auch nicht ohne Quellcode.

von Karl H. (kbuchegg)


Lesenswert?

Frederik H. schrieb:

> Zur Kontrolle der Werte habe ich eine UART verbindung mit dem PC.
>
> Problem: der eine Wert, der errechnet werden muss, kann nicht stimmen.

Meine Kristallkugel ist Spezialistin im Erraten von Code den du nicht 
zeigst.


>
>
1
 UT1 = 10000 + (8 * C5);
> Die PuTTY Konsole gibt mir: UT1 = -31760
>
> da ich mir C5 übertragen lasse stimmt was nicht: C5 = 2972


   8 * 2972   ergibt  23776

da dann noch 10000 dazu: 33776

Oh, oh. Das ist zuviel für einen 16 Bit signed int. Bei 32767 ist 
Schluss, danach gibt es einen Overflow.

Fazit: nächstes Mal die Datentypen dazu zeigen. Höchst wahrscheinlich 
reicht es schon, wann du ein wenig Sogrfalt walten lässt und alles 
unsigned berechnest. Dann hast du Wertebereiche von 0 bis 65535 anstelle 
von -32768 bis +32767 und das sollte dann reichen, wenn zwischendurch 
keine Overflows erfolgen.

von Rudi (Gast)


Lesenswert?

schon mal daran gedacht, dass du deine variablen als 'unsigned' 
deklarien musst? wenn dies als 'signed' deklariert ist, wird die zu 
übertragende Zahl sofort dann als 'negativ' bewertet, wenn das MSB 
gesetzt ist, also größer/gleich 32.768...und du überträgst, wenn ich das 
richtig interprtiere 33.776...also demnach 'negativ'...

Rudi

von Mike R. (thesealion)


Lesenswert?

Karl heinz Buchegger schrieb:
>>
1
 UT1 = 10000 + (8 * C5);
>> Die PuTTY Konsole gibt mir: UT1 = -31760
>>
>
>    8 * 2972   ergibt  23776
>
> da dann noch 10000 dazu: 33776
>
> Oh, oh. Das ist zuviel für einen 16 Bit signed int. Bei 32767 ist
> Schluss, danach gibt es einen Overflow.
>

Oder die Ausgabefunbktion "interpretiert" das Ergebnis einfach falsch. 
Wenn ich [uint16_t] 33776  als [int16_t] auffasse, kommt da genau -31760 
raus.

von Karl H. (kbuchegg)


Lesenswert?

Mike S. schrieb:
> Karl heinz Buchegger schrieb:
>>>
1
 UT1 = 10000 + (8 * C5);
>>> Die PuTTY Konsole gibt mir: UT1 = -31760
>>>
>>
>>    8 * 2972   ergibt  23776
>>
>> da dann noch 10000 dazu: 33776
>>
>> Oh, oh. Das ist zuviel für einen 16 Bit signed int. Bei 32767 ist
>> Schluss, danach gibt es einen Overflow.
>>
>
> Oder die Ausgabefunbktion "interpretiert" das Ergebnis einfach falsch.

Mag sein.
Aber in dem Fall 'interpretiert' sie nicht einfach falsch, sondern es 
wird die falsche Ausgabefunktion aufgerufen (man könnte es auch so 
sagen: Der Programmierer hat seine Ausgabefunktion angelogen).

Ohne Code ist das schwer zu sagen. So gut ist meine Kugel dann auch 
wieder nicht. Sie ist sich aber recht sicher, dass der 'Fehler' in 
diesem Umfeld zu suchen ist, und sich nicht der Mega32 verrechnet hat, 
sondern der Programmierer nicht sorgfältig genug war.

von Mike R. (thesealion)


Lesenswert?

Deswegen war das interpretiert ja auch in Anführungszeichen gesetzt.

Also ich würde sagen, der Mega32 hat hier eindeutig einen Fehler 30 :-)

von Frederik H. (bytejesus)


Lesenswert?

Wow - danke für die zahlreichen Antworten!
Also ich übertrage mit
1
sendUSART(itoa(UT1, s, 10));
 wobei die deklaration:
1
void init_USART(void)
2
{
3
  UCSRB |= (1<<TXEN) | (1<<RXEN);  //UART TX (Transmit - senden) einschalten RX einschalten
4
//  UCSRC |= (1<<URSEL)|(3<<UCSZ0);  //Modus Asynchron 8N1 (8 Datenbits, No Parity, 1 Stopbit)
5
//  UBRRH = 0;        //Highbyte ist 0
6
  UBRRL = 103;      //9600Bd Lowbyte ist 103 (dezimal) -> (Frequenz_in_Hz / (Baudrate * 16)) - 1 <- Quarfrequenz = 16*1000*1000 Hz!!!!
7
}
8
9
10
void sendchar(unsigned char c)
11
{
12
  while(!(UCSRA & (1<<UDRE))); //Warten, bis Senden möglich ist
13
  
14
  UDR = c; //schreibt das Zeichen aus 'c' auf die Schnittstelle
15
}
16
17
void sendUSART(char *s) //*s funktiniert wie eine Art Array - auch bei einem String werden die Zeichen (char) einzeln ausgelesen - und hier dann auf die Sendeschnittstelle übertragen
18
{
19
  while(*s)
20
  {
21
  sendchar(*s);
22
  s++;
23
  }
24
}

Dann liegt das Problem im itoa ? Wie kann man denn am schnellsten nen 
uint in asci wandeln??

Danke!

von Floh (Gast)


Lesenswert?

Frederik H. schrieb:
> Dann liegt das Problem im itoa ? Wie kann man denn am schnellsten nen
> uint in asci wandeln??

[ ] Du hast die Antworten durchgelesen.
Es ging hier um deine Variable UT1, deren Deklaration wäre interessant.
:-)

von Lasse S. (cowz) Benutzerseite


Lesenswert?

Hi Floh, ne, er hat ja schon Recht, dass er ne Alternative zu itoa 
sucht.

Die hätte er aber auch mittels Google oder gar der Forensuche finden 
können.

1
utoa
ist das, was er sucht.

von Karl H. (kbuchegg)


Lesenswert?

Frederik H. schrieb:

> Dann liegt das Problem im itoa ? Wie kann man denn am schnellsten nen
> uint in asci wandeln??

WIe wäre es erst mal damit, die richtige Funktion zu benutzen

  int              ->  itoa
  unsigned int     ->  utoa
  long             ->  ltoa
  unsigned long    ->  ultoa


Wie schon vorher angemerkt: Der Compiler kann nichts dafür, wenn du ihn 
anlügst und ihm sagst du hättest eine Zahl mit Vorzeichen (und deshalb 
benutzt du itoa) wenn du in Wirklichkeit einen unsigned hast.

von Ulrich (Gast)


Lesenswert?

Ganz unschuldig ist der Compiler aber auch nicht. Der hätte immerhin die 
Möglichkeit eine Warnung auszugeben wenn itoa() mit einer unsigned 
Variable aufruft.  Vermutlich verlangt die Spache C aber das man es da 
nicht so genau mit den Typen nehmen muß.

von U.R. Schmitt (Gast)


Lesenswert?

Ulrich schrieb:
> Vermutlich verlangt die Spache C aber das man es da
> nicht so genau mit den Typen nehmen muß.

Eine Sprache 'verlangt' eigentlich nie, daß man Typen wild durcheinander 
benutzt.
C ist relativ milde und überlässt es dem Programmierer das zu tun was er 
für richtig hält. Eine Warning kann man fast immer erhalten wenn man die 
Optionen entsprechend setzt und die Warnings auch liest.
Hier ist es wohl eher ein fehlendes Verständnis der Datentypen und 
entsprechende Wahl der falschen.
Ohne Code ist aber auch das Spekulation.

von Lasse S. (cowz) Benutzerseite


Lesenswert?

Ulrich schrieb:
> Ganz unschuldig ist der Compiler aber auch nicht. Der hätte immerhin die
> Möglichkeit eine Warnung auszugeben wenn itoa() mit einer unsigned
> Variable aufruft.

Wenn er das denn tut. Die Deklaration von UT1 haben wir ja immer noch 
nicht gesehen ;)

von Frederik H. (bytejesus)


Angehängte Dateien:

Lesenswert?

Hi,

also eure Kommentare haben mich schon ein ganzes Stück weitergebracht.

Es lag natürlich an utoa - bei mir liegt die ganze Programmierung aber 
schon 4 Jahre zurück und ich bin gerade wieder dabei mich 
einzuarbeiten...also schon mal danke dafür.

Leider funktioniert die Druckmessung immer noch nicht. Er zeigt zwar 
Werte an und die Koeffizienten liegen jetzt auch im richtigen Bereich, 
nur wenn ich mit meiner Apothekenspritze den Druck verändere passiert im 
Prinzip: Nichts.

Ich hab mal die entscheidenen Dateien angehängt. Vielleicht seht ihr 
mehr als ich... Ist alles ein bisschen doppelt gemoppelt aber halt auch 
noch lange nich fertig...

Danke für die Hilfe!!!

PS: spi.h ist wohl nicht so wichtig :)

Hier noch die ranges aus den Application Notes

MAXIMUM VALUES FOR C1-C6
min typ max
C1 (13 bit) 0 2391 8191
C2 (13 bit) 0 4888 8191
C3 (10 bit) 0 385 1023
C4 (9 bit) 0 221 511
C5 (12 bit) 0 1689 4095
C6 (7 bit) 0 58 127
MAXIMUM VALUES FOR D1, D2
min typ max
D1 0 17000 40000
D2 0 27000 45000
MAXIMUM VALUES FOR CALCULATION RESULTS
min typ max
UT1 10000 28016 42760
dT -11400 0 12350
OFF 9246 14888 18887
SENS 1298 4196 8939
P  0 14000
TEMP -400 1250

von Karl H. (kbuchegg)


Lesenswert?

Sofort nach öffnen von main sprint einem das hier ins Auge

char t[2],p[2],s[2];

Wie willst du denn in t einen vernünftigen String unterbringen? Dort ist 
gerade einmal Platz für 1 Zeichen und das obligatorische \0 Zeichen!

Größer machen!

http://www.mikrocontroller.net/articles/FAQ#Wie_funktioniert_String-Verarbeitung_in_C.3F

von Karl H. (kbuchegg)


Lesenswert?

Du hast schon so schön angefangen, dir die Werte ausgeben zu lassen. 
Führ das fort. Die Konstanten am Programmanfang werden ja jetzt wohl 
stimmen, also kannst du diese Ausgaben wieder rausnehmen.
Allerdings machst du jetzt in derselben Tonart weiter und lässt dir mal 
die gemessenen Werte ausgeben: So wie du sie vom Sensor bekommst (also 
die Rohdaten) und dann deine umgerechneten Werte. Und so kreist du dein 
Problem weiter ein.

von Frederik H. (bytejesus)


Lesenswert?

Moin,

also ich hab mir alle Werte( Wörter, D1, D2) über LEDs bitweise ausgeben 
lassen und alles nachgerechnet. Die UART/ASCII Übertragung stimmt damit 
m.E. vollkommen. Alle Koeffizienten liegen im richtigen Bereich, die 
Rechnungen stimmen... D1 und D2 entsprechen laut Datenblatt 20°C und 
1bar - alles tutti..
t, p , und s habe ich einfach mal 20 groß gemacht , (wobei ja 6 Byte 
reichen sollten für 5 Zahlen und ein \0 !?).

Ich bin jetzt am verzweifeln. Die Druckwerte (D1) ändern sich nicht!

Glaube langsam schon das was mit dem Sensor nicht stimmt.
Kann es sein, das was mit der SPI kommunikation nicht stimmt obwohl die 
Werte immer gut sind? Und wie könnte man das überprüfen?

Vielleicht hats ja auch den Sensor zerschossen und die SPI ist heile 
geblieben???

Keine Ahnung - verdammte microelektronik - und das als 
Maschinenbauer....

Grüße Fred

von Vlad T. (vlad_tepesch)


Lesenswert?

ich würde empfehlen erst mal den simulator anzuwerfen und schritt für 
schritt durchsteppen und schauen, ob nach jeder operation immer noch das 
im Ergebnis steht, was man erwartet.


Was auch noch nicht gesagt wurde (oder ich habs überlesen):

egal, wie UT1 deklariert wurde, die Operationen mit den Kosntanten 
werden in dem größten der beteiligten Typen gerechnet.
deine Konstanten sind 16bit.

wenn c5 auch 16bit breit ist, kommt es hier bereits zum overflow.
vor der Berechnung sollte also C5 auf einen (u)int32 gecastet werden.

Edit:
Tip für den Simulator:
nur den entsprechenden Codeteil testen und Inputwerte (wie Sensor) als 
volatile definieren und einen sinnvollen Wert zum Testen zuweisen.

volatile deswegen, damit der Optimizer dir nicht alle Berechnungen 
rausschmeißt wenn alle Größen von vornhinein bekannt sind.

von Purzel H. (hacky)


Lesenswert?

itoa ... was soll das? Um vernuenftig debuggen zu koennen verwendet man 
ueblicherweise integertohex, oder hex(), da kann viel weniger 
schiefgehen.

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.