Forum: Mikrocontroller und Digitale Elektronik uin16_t ist/wird negativ bei 0x8000.


von Felix N. (felix_n888)


Angehängte Dateien:

Lesenswert?

Guten Abend,
Ich bin im Moment etwas ratlos, ich arbeite momentan daran mein altes 
Projekt auf Basis eines ATMega1284P auf mein neuen Prozessor 
(ATMega2560) zu "importieren".

Im Moment teste ich mein 16 Bit ADC auf der Platine. Als ADC kommt ein 
ADS1115 zum Einsatz, welcher direkt als IC auf die Platine gelötet ist 
also kein Breakout Board oder so. Der IC selbst scheint Problemlos zu 
funktionieren bei einem "Respond I2C Test" wo ich einmal alle Adressen 
von 0 bis 255 angesprochen habe mit i2c_start(address) wird auf 4 
Adressen reagiert einmal auf auf 0x90 und 0x91 was der ADS1115 ist(0x90 
mit Write Befehl und 0x91 mit Read Befehl). Wenn ich das letzte Bit 
davon entferne was für die Read/Write Option ist dann kommt da 0x48 raus 
das ist auch das was ich so festgelegt habe mit dem Address Pin. Und 
einmal 0xA0 und 0xA1(Ist mein 16kbit EEPROM Chip). F_SCL liegt bei 400 
KHz. An sich scheint er auch wohl zu tun habe kurz mal ein Arduino 
Sketch hochgeladen um den ADC zu testen.

Nun zu meinen, für mich kuriosen, Problem:
An sich habe ich für das Projekt die ADS1115.c/h Datei aus dem alten 
Projekt nur kopiert und wieder eingefügt als Datei an sich nur die 
includes geändert am Code selber nix. Der Code funktionierte sonst immer 
Problemlos.

In der ADS1115.h sind diverse Definierungen vorhanden zB. um den 
passenden Eingang etc.. auszuwählen. In der read Funktion baue ich mir 
die Config zusammen die in das Pointer Register gesendet werden muss des 
ADS1115.

An sich funktioniert dieses zusammenbauen auch bis zum punkt
1
In ADS1115.h File
2
#define ADS1015_REG_CONFIG_OS_NOTBUSY   (0x8000)  // Read: Bit = 1 when device is not performing a conversion
3
In ADS1115.c File
4
config |= ADS1015_REG_CONFIG_OS_SINGLE;

Nur ist dieser Makro wenn man sich über serielle ausgibt negativ! 0x8000 
ergibt ja 32768 im Dezimalsystem. Im Seriellen Terminal wird er aber als 
-32768 ausgegeben. Somit wird die ganze Config negativ obwohl sie vom 
Typ uint16_t ist ???? Wie kann das sein uint16_t geht doch nur von 0 bis 
65535. Zumal 32768 ja nur knapp die Hälfte ist. Verstehe ich nicht.

Ich habe mal die Makro die ich als Config sende in binär aufgeschlüsselt 
und geschaut was eig. am Ende rauskommen soll:
1
ADS1015_REG_CONFIG_CQUE_NONE      0x0003 -> 0000 0000 0000 0011
2
ADS1015_REG_CONFIG_CLAT_NONLAT    0x0000 -> 0000 0000 0000 0000
3
ADS1015_REG_CONFIG_CPOL_ACTVLOW   0x0000 -> 0000 0000 0000 0000
4
ADS1015_REG_CONFIG_CMODE_TRAD     0x0000 -> 0000 0000 0000 0000
5
ADS1015_REG_CONFIG_DR_128SPS      0x0000 -> 0000 0000 0000 0000
6
ADS1015_REG_CONFIG_MODE_SINGLE    0x0100 -> 0000 0001 0000 0000
7
ADS1015_REG_CONFIG_PGA_4_096V     0x0200 -> 0000 0010 0000 0000
8
ADS1015_REG_CONFIG_MUX_SINGLE_0   0x4000 -> 0100 0000 0000 0000
9
ADS1015_REG_CONFIG_OS_SINGLE      0x8000 -> 1000 0000 0000 0000
10
11
                                         -> 1100 0011 0000 0011(49923)

Wenn ich die Zahl 49923 anstatt die config sende (Was ja die Konfig ist 
nur manuell von mir geschrieben) funktioniert der ADC auch.

Was auch komisch ist die Funktion hat als Rückgabe typ den uin16_t also 
auch wieder von 0 bis 65535. Wenn ich jetzt den Eingang auf 0 Volt lege 
erwarte ich eigentlich dort eine 0 zu bekommen anstatt bekomme ich dort 
ein Wert zwischen -1 und -2. -168 war auch einmal dabei. Wenn ich das 
Register direkt ausgebe ist alles daran auf 0 gesetzt also 16 mal 0. Wie 
kann dann ja -1 oder -2 rauskommen. Der Teil mit ">> bitShift" steht auf 
0 hat also keine Funktion ist dafür gedacht wenn man nur die ersten oder 
letzten 8 Bit braucht.

Warum wird die Zahl negativ?

Mfg

von Nop (Gast)


Lesenswert?

Felix N. schrieb:

> Nur ist dieser Makro wenn man sich über serielle ausgibt negativ!

Ist es nicht. Allerdings mußt Du Deiner Ausgabefunktion schon sagen, daß 
die übergebenen 16 bit als unsigend zu verstehen sind. Wenn Du das nicht 
machst, und das höchstwertigste Bit gesetzt ist, mißversteht die 
Funktion das als vorzeichenbehaftete 16 bit, und das ist dann negativ.

von yesitsme (Gast)


Lesenswert?

Du könnest dich einmal in das Zweierkomplement einlesen.

Wie gibst du die Zahl auf der Seriellen aus?

von M. K. (sylaina)


Lesenswert?

Felix N. schrieb:
> Warum wird die Zahl negativ?

Weil du das uint16_t als int16_t behandelst. Und wenn dann beim MSB ne 1 
steht bedeutet das (also alles über den 32k), das man eine negative Zahl 
hat.

von Axel S. (a-za-z0-9)


Lesenswert?

Felix N. schrieb:
> Somit wird die ganze Config negativ obwohl sie vom
> Typ uint16_t ist ????

1. deine "?" Taste prellt

2. wie kommst du darauf, daß das Makro vom Typ uint16_t wäre?

Da wird kein Typ angegeben. Und damit ist das Makro für den Compiler 
von Typ int. Von welcher "Funktion" du sprichst ist nicht klar, ich kann 
jedenfalls keine sehen.

: Bearbeitet durch User
von Felix N. (felix_n888)


Lesenswert?

Hallo an alle!

Nop schrieb:
> Ist es nicht. Allerdings mußt Du Deiner Ausgabefunktion schon sagen, daß
> die übergebenen 16 bit als unsigend zu verstehen sind. Wenn Du das nicht
> machst, und das höchstwertigste Bit gesetzt ist, mißversteht die
> Funktion das als vorzeichenbehaftete 16 bit, und das ist dann negativ.

M. K. schrieb:
> Weil du das uint16_t als int16_t behandelst. Und wenn dann beim MSB ne 1
> steht bedeutet das (also alles über den 32k), das man eine negative Zahl
> hat.

Ja gut an diese Option hatte ich ja auch schon gedacht da ja bei 0x8000 
nur das erste Bit gesetzt ist und bei einem vorzeichenbehaften Integer 
das für negativ ja steht bzw. im Negativen Bereich anfängt. Aber selbst 
wenn ich es zu einem uint16_t caste also so:
1
snprintf_P(strBuffer, sizeof(strBuffer), PSTR("Config 3: %d VAR: %d\r\n"), config, (uint16_t)ADS1015_REG_CONFIG_OS_SINGLE);

bleibt das Ergebnis unverändert. Also immer noch negativ. Dadurch sollte 
der Compiler doch wissen das es sich bei 0x8000 um vorzeichenlosen 
Integer handelt oder nicht?

yesitsme schrieb:
> Du könnest dich einmal in das Zweierkomplement einlesen.

Schaue ich mir mal an.

yesitsme schrieb:
> Wie gibst du die Zahl auf der Seriellen aus?

So:
1
        snprintf_P(strBuffer, sizeof(strBuffer), PSTR("Config 3: %d VAR: %d\r\n"), config, (uint16_t)ADS1015_REG_CONFIG_OS_SINGLE);
2
  sendToSerial(COMM_INTERNAL, strBuffer);

Comm_Internal gibt nur an das die Daten über den USART2 übertragen 
werden da dieser über ein FTDI an meinen PC angeschlossen ist. Vorher 
war es ohne das "(uint16_t)" cast vor dem Makro.

Axel S. schrieb:
> 2. wie kommst du darauf, daß das Makro vom Typ uint16_t wäre?

Gar nicht. Habe ich ja auch nie behauptet. Wenn ich doch jetzt eine 
Variable habe die vom Typ uint16_t ist und dann ein Wert hinzufüge der 
versehentlich vom Typ int32_t sein könnte gibt der Compiler dann nicht 
ne Warnung aus?

Axel S. schrieb:
> 1. deine "?" Taste prellt

Oh da muss ich dann wohl noch ein paar Kondensatoren mehr anschließen :)

Mfg

von Erklehr Behr (Gast)


Lesenswert?

Felix N. schrieb:
> wenn ich es zu einem uint16_t caste also so:
> snprintf_P(strBuffer, sizeof(strBuffer), PSTR("Config 3: %d VAR:
> %d\r\n"), config, (uint16_t)ADS1015_REG_CONFIG_OS_SINGLE);
>
> bleibt das Ergebnis unverändert. Also immer noch negativ. Dadurch sollte
> der Compiler doch wissen das es sich bei 0x8000 um vorzeichenlosen
> Integer handelt oder nicht?

Der Format Specifier für unsigned int ist %u!

von Robin (Gast)


Lesenswert?

Lies dir Mal die Doku zum printed durch und wofür das %d steht

von mh (Gast)


Lesenswert?

Erklehr Behr schrieb:
> Der Format Specifier für unsigned int ist %u!

Und für uint16_t ist er PRIu16.

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.