Forum: Mikrocontroller und Digitale Elektronik int16_t addieren


von Kolja L. (kolja82)


Lesenswert?

Hallo

Ich habe drei Variablen, die alle zusammen addiert und in der vierten 
gespeichert werden sollen:

int16_t gx, gy, gz, g_1;


mpu_2.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);
g_2 = abs(gx) + abs(gy) + abs(gz);

Da ich nur positive Werte haben möchte, die abs() Funktion.

Hier aber mal ein Stück aus der Ausgabe:
(Die erste Spalte ist die Summe)

227  22  29  6
244  2  75  0
223  10  48  6
226  11  42  21
218  7  30  1
242  3  59  8
225  4  55  3
247  24  60  3
246  3  36  5
261  35  68  13
226  1  34  15


Warum verrechnet sich der µC?

von Karl M. (Gast)


Lesenswert?

Wie ist denn abs() definiert?
D.h. für welche Datentypen?

von Karl M. (Gast)


Lesenswert?

>Warum verrechnet sich der µC?

schau bitte mal in die Assemblerausgabe was da passiert.

Und zeige bitte das komplette Testprogramm.

von (prx) A. K. (prx)


Lesenswert?

Wie wärs mit echtem Code?

von Kolja L. (kolja82)


Lesenswert?

Karl M. schrieb:
> D.h. für welche Datentypen?

Da steht nix: 
https://www.arduino.cc/reference/en/language/functions/math/abs/

Und heir der ganze Code:
1
// WiFi & OTA Update
2
#include <ESP8266WiFi.h>
3
#include <ESP8266mDNS.h>
4
#include <WiFiUdp.h>
5
#include <ArduinoOTA.h>
6
7
// I2C & MPU6050
8
#include "Wire.h"
9
#include "I2Cdev.h"
10
#include "MPU6050.h"
11
12
// WiFi & OTA Update
13
const char* ssid = "xxx";
14
const char* password = "xxx";
15
16
// I2C & MPU6050
17
MPU6050 mpu_1;
18
MPU6050 mpu_2(0x69);
19
int16_t gx, gy, gz, g_1, g_2, zaeler;
20
int16_t ax, ay, az;
21
unsigned long Zeit_alt = 0;
22
unsigned long Zeit_neu = 0;
23
const long Dauer = 1000;
24
25
26
void setup() {
27
  Serial.begin(115200);
28
29
  // WiFi & OTA Update
30
  ArduinoOTA.setHostname("xxx");
31
  ArduinoOTA.onError([](ota_error_t error) {
32
    ESP.restart();
33
  });
34
  ArduinoOTA.begin();
35
36
  // I2C & MPU6050
37
  Wire.begin();
38
  mpu_1.initialize();
39
  mpu_2.initialize();
40
}
41
42
void loop() {
43
  // WiFi & OTA Update
44
  ArduinoOTA.handle();
45
46
47
  // I2C & MPU6050
48
  mpu_1.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);
49
  int g1 = gx + gy + gz;
50
  g_1 = abs(gx) + abs(gy) + abs(gz);
51
  mpu_2.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);
52
  g_2 = abs(gx) + abs(gy) + abs(gz);
53
54
55
  Serial.print(g_1);
56
  Serial.print("  ");
57
  Serial.print(abs(gx));
58
  Serial.print("  ");
59
  Serial.print(abs(gy));
60
  Serial.print("  ");
61
  Serial.println(abs(gz));
62
63
  delay(50);
64
65
66
67
} // loop

von Dirk B. (dirkb2)


Lesenswert?

Die Werte für gx, gy, gz werden durch den Aufruf von mpu_2 
überschrieben.

von Stefan E. (sternst)


Lesenswert?

Kolja L. schrieb:
> Und heir der ganze Code:

Die ausgegebenen Werte gehören doch gar nicht zusammen.
Die Summe kommt von mpu_1 und die Einzelwerte von mpu_2.

von Kolja L. (kolja82)


Lesenswert?

Danke :-)
Vielleicht sollte ich doch lieber nen Töpferkurs machen :-(

von Dirk B. (dirkb2)


Lesenswert?

Kolja L. schrieb:
> Danke :-)
> Vielleicht sollte ich doch lieber nen Töpferkurs machen :-(

Da lernt man aber nicht logisch zu denken.

von Kolja L. (kolja82)


Lesenswert?

Noch was komisches.
Eigentlich sollten aus einer Addition von den drei Beträgen (abs)) ja 
keine negativen Zahlen hervorgehen können:

for (int i = 0; i<200; i++){
  // I2C & MPU6050
  mpu_1.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);
  g_1 = abs(gx) + abs(gy) + abs(gz);
  mpu_2.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);
  g_2 = abs(gx) + abs(gy) + abs(gz);

  sum_g_1 = sum_g_1 + g_1;
  sum_g_2 = sum_g_2 + g_2;
}

g_1 = sum_g_1/200;
g_2 = sum_g_2/200;


  Serial.print(g_1);
  Serial.print("  ");
  Serial.println(abs(g_2));

  delay(50);


Ausgabe:


-46  153
-133  69
101  13
6  99
-87  142
144  61
52  18
-41  101
-135  144
100  62
5  21
-87  103


Warum nur?

von (prx) A. K. (prx)


Lesenswert?

Überlauf?

von Kolja L. (kolja82)


Lesenswert?

Dann müsste die Summe größer als 32767 sein?

von (prx) A. K. (prx)


Lesenswert?

Kolja L. schrieb:
> Dann müsste die Summe größer als 32767 sein?

200 Durchläufe à 3 Werte = Summe von 600 positiven Zahlen. Ich kenne 
deine Werte nicht, aber meinst du nicht, das könnte reichen?

von Stefan E. (sternst)


Lesenswert?

A. K. schrieb:
> 200 Durchläufe à 3 Werte. Meinst du nicht, das könnte reichen?

Sicherlich.
Die positiven Werte liegen zum Teil ja auch nah dran:
153 * 200 = 30600

von Frederic K. (warfley)


Lesenswert?

Ganz dumme Frage, wenn die Fragen rein Positiv sein sollen, warum 
benutzt du dann nicht einfach einen unsigned integer? Damit hast du 
doppelt so viele Zahlen zur verfügung bevor es überläuft
1
#define ABS16(X) ((uint16_t)(abs(X)))
2
uint16_t g_1 = ABS16(gx) + ABS16(gy) + ABS16(gz);
3
#undef ABS16

bzw in C++ (was ja die arduino sprache eigentlich ist)
1
#define ABS16(X) static_cast<uint16_t>(abs(X))
2
auto g_1 = ABS16(gx) + ABS16(gy) + ABS16(gz);
3
#undef ABS16
(C style casts in C++ sorgen dafür das der Compiler alle Casts 
ausprobiert, wenn es also Klassen Pointer sind wird der Compiler einen 
Dynamic cast draus machen, welcher zur runtime evaluiert wird, daher 
programm memory und runtime benötigt. Daher willst du eigentlich fast 
immer static_casts machen)

von Kolja L. (kolja82)


Lesenswert?

Frederic K. schrieb:
> Ganz dumme Frage, wenn die Fragen rein Positiv sein sollen, warum
> benutzt du dann nicht einfach einen unsigned integer? Damit hast du
> doppelt so viele Zahlen zur verfügung bevor es überläuft

Die Idee hatte ich auch schon, aber die MCU Librarie will nur int16_t.

von (prx) A. K. (prx)


Lesenswert?

Nicht mal bei den Summen ist mehr als int16_t erlaubt?

von Frederic K. (warfley)


Lesenswert?

Kolja L. schrieb:
> Die Idee hatte ich auch schon, aber die MCU Librarie will nur int16_t.

Daher mein define, die Zahlen selbst sind zwar int16_t, aber das Makro 
ruft nicht nur abs auf, sondern sagt dem compiler gleichzeitig noch das 
das ergebnis als unsigned integer verwendet werden soll, also die 
Addition unsigned ist

von (prx) A. K. (prx)


Lesenswert?

Lib oder nicht: Deine Summen benötigen einen ausreichend grossen 
Datentyp. Das dividierte Ergebnis darf dann wieder int16_t sein.

von Walter (Gast)


Lesenswert?

Frederic K. schrieb:
> #define ABS16(X) static_cast<uint16_t>(abs(X))
> auto g_1 = ABS16(gx) + ABS16(gy) + ABS16(gz);
> #undef ABS16

ist ein bißchen mit Kanonen auf Spatzen und so,
es reicht auch

int32_t sum_g_1;

von (prx) A. K. (prx)


Lesenswert?

Frederic K. schrieb:
> #define ABS16(X) ((uint16_t)(abs(X)))

Ich bin kein grosser Freund von Typecasts und ziehe es vor, sie nur da 
zu verwenden, wo sie wirklich zwingend sind. Die haben nämlich die 
Neigung, kommentarlos praktisch alles zu fressen, was man ihnen 
vorsetzt. Pointer inklusive. Dem Compiler nimmt man damit Möglichkeiten, 
auf Fehler hinzuweisen.

von Frederic K. (warfley)


Lesenswert?

A. K. schrieb:
> Ich bin kein grosser Freund von Typecasts und ziehe es vor, sie nur da
> zu verwenden, wo sie wirklich zwingend sind. Die haben nämlich die
> Neigung, kommentarlos praktisch alles zu fressen, was man ihnen
> vorsetzt. Pointer inklusive. Dem Compiler nimmt man damit Möglichkeiten,
> auf Fehler hinzuweisen.

Ich caste lieber zu viel als zuwenig. Beispiel, wenn er jetzt das 
ergebnis statt in einer Variable zwischen zu speichern irgendwann direkt 
in eine Funktion speisen will, welche sowohl für signed als auch 
unsigned überladen ist, kracht es. So kann man sich sicher sein, jede 
Formel die ABS16 enthält wird auf unsigned "aufgewertet". Somit ist die 
Addition selbst unsigned, unabhängig vom Kontext. Außerdem ermöglicht 
der cast die verwendung von auto, damit spart man sich ein paar zeichen 
im gegensatz zu uint16_t (wobei ich mir für gewöhnlich eh die typen i8, 
i16, i32, i64 und u8, u16, ... definiere)

Das mit den Warnings kann ich aber verstehen, daher arbeite ich fast 
immer mit den Flags -Wpedantic -Werror -Wall. Lieber mehr Warnings als 
zu wenige (außer ich verwende fremden code wie Header only Libraries, da 
kann Werror ganz schnell in die Hose gehen)

von A. S. (Gast)


Lesenswert?

Frederic K. schrieb:
> Lieber mehr Warnings als zu wenige

Und genau deshalb keine casts. Alternativ z.b. typsichere 
Inline-funktionen mit expliziter Zuweisung.

von Kolja L. (kolja82)


Lesenswert?

Walter schrieb:
> int32_t sum_g_1;

Danke :-)

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.