Forum: Mikrocontroller und Digitale Elektronik Sensor daten über UART verschicken (mit PIC)


von Leonidas T. (helpleo)


Lesenswert?

Hey zusammen. Ich habe grad ein kleines Problem.
Ich versuche die daten meines SCD30 CO2 Sensors in ein array zu 
speichern (via I2C an meinem PIC) und die daten dann über UART an mein 
Travos3 modul zuschicken.
Das gleiche Modul habe ich auch an meine PC angeschloßen und will die 
Werte dann auf HTerm lesen können.

Nur leider klappt es nicht so ganz, I2C funktioniert aber wenn ich die 
Daten dann schicken sehe ich nur Nuller auf HTerm.

Ich habe schon probiert nur gewissen Bytes zu schicken, wo der wirkliche 
Inhalt (laut Datenbaltt) drin ist. Funktioniert aber leider auch nicht.

Danke für euere Hilfe im vorraus.

von R42 (Gast)


Lesenswert?

Check mal die Zeile 42 von main.c in deinem Code.

von STK500-Besitzer (Gast)


Lesenswert?

Hast du schon probiert, deinen Quellcode hier zu posten?
Alles andere klingt nach "Mach mir das mal jemand!"

von FOp (Gast)


Lesenswert?

Kannst Du einen festen Text, wie z.B. "Hallo Welt !" an HTerm schicken ?

Wenn nein, gelingt es ohne die Module dazwischen ?

P.S. : Es gibt hier kaum jemanden im Forum, der per Gedankenübertragung 
in Deinen Quelltext schauen kann.

von Martin (Gast)


Lesenswert?

Du musst vor dem Senden das "SendNotNull" Bit setzen.

von Leonidas T. (helpleo)



Lesenswert?

Ein Hello World kann ich an meine modul schicken und sehe es auch auf 
HTerm.

Das wär meine while loop;
Wieso ich diese Bytes gewählt hab zum schicken liegt im Anhang beim 
Datenblatt. (Seite 12)


        uint8_t data[3];
        data[0] = 0xC2;
        data[1] = 0x03;
        data[2] = 0x00;

        I2C1_WriteNBytes(0x61, data, 3);


        I2C1_ReadNBytes(0x61, i2c_payload, 19);



        UART5_Write(0x02);
        UART5_Write(0x00);
        UART5_Write(0x0C);



        UART5_Write(i2c_payload[1]);
        UART5_Write(i2c_payload[2]);
        UART5_Write(i2c_payload[4]);
        UART5_Write(i2c_payload[5]);
        UART5_Write(i2c_payload[7]);
        UART5_Write(i2c_payload[8]);
        UART5_Write(i2c_payload[10]);
        UART5_Write(i2c_payload[11]);
        UART5_Write(i2c_payload[13]);
        UART5_Write(i2c_payload[14]);
        UART5_Write(i2c_payload[16]);
        UART5_Write(i2c_payload[17]);

        uint8_t summe = 0;
        summe = summe ^ 0x02;
        summe = summe ^ 0x00;
        summe = summe ^ 0x0C;
        summe = summe ^ i2c_payload[3];
        summe = summe ^ i2c_payload[6];
        summe = summe ^ i2c_payload[9];
        summe = summe ^ i2c_payload[12];
        summe = summe ^ i2c_payload[15];
        summe = summe ^ i2c_payload[18];

        UART5_Write(summe);

von Leonidas T. (helpleo)


Lesenswert?

Okay ich schau mir das mal an, danke euch :)

von STK500-Besitzer (Gast)


Lesenswert?

Dass Du in hterm die byte-Werte und keine ASCII-Zeichen mit dieser 
Methode empfängst, ist dir klar?

von Leonidas T. (helpleo)


Lesenswert?

STK500-Besitzer schrieb:
> Dass Du in hterm die byte-Werte und keine ASCII-Zeichen mit dieser
> Methode empfängst, ist dir klar?

Verzeih aber kannst du mir das erklären.

von STK500-Besitzer (Gast)


Lesenswert?

Leonidas T. schrieb:
> Verzeih, aber kannst du mir das erklären.

Sofern dein I²C-Device keine ASCII-Zeichen sendet (von Menschen lesbare 
Zeichen), steht im Empfangfenster nur Kauderwelsch, sofern du die 
Anzeige nicht auf Hex oder Dezimal gestellt hast.

von Sebastian R. (sebastian_r569)


Lesenswert?

Leonidas T. schrieb:
> Verzeih aber kannst du mir das erklären.

Wenn ein Wert 0 sein soll, gibt es bei der Übertragung entweder den 
Byte-Wert 0, also 0x00, oder das Ascii-Zeichen für "0", das wäre 48 bzw. 
0x30 als Byte-Wert.

Wenn du deinen Messwert von "3" nun nicht als ASCII-Zeichen 51 (0x33) 
überträgst, sondern als Byte-Wert von 3 (0x03), dann zeigt dein Terminal 
dir keine 3 an, sondern irgendeinen Indikator dafür, dass ein 
Steuerzeichen "End of Text" gesendet wurde. Denn das hat den Byte-Wert 
3.

Um aus dem Wert "54.3" nun einen ASCII-String mit den entsprechenden 
Zeichen zu machen, gibt es ein paar Funktionen (printf und solche 
Späßchen)

von STK500-Besitzer (Gast)


Lesenswert?

Sebastian R. schrieb:

Man kann auch in hTerm die Anzeige umstellen...

von Mario M. (thelonging)


Lesenswert?

Leonidas T. schrieb:
>         data[0] = 0xC2;
>         data[1] = 0x03;
>         data[2] = 0x00;
>
>         I2C1_WriteNBytes(0x61, data, 3);

Kann nicht klappen. In der PDF ist die komplette Übertragung auf dem Bus 
zu sehen. Die I²C-Adresse wird aber bei I2C1_WriteNBytes extra 
übergeben, daher  darf nicht noch mal 0xC2 gesendet werden. 0xC2 ist bei 
I²C Schreiben an Adresse 0x61.

von Leonidas T. (helpleo)


Lesenswert?

STK500-Besitzer schrieb:
> Sebastian R. schrieb:
>
> Man kann auch in hTerm die Anzeige umstellen...

Jap das weiss ich. Ich kann trotzdem nur Nuller sehen.

Danke für eure Antworten

: Bearbeitet durch User
von Leonidas T. (helpleo)


Lesenswert?

Mario M. schrieb:
> Leonidas T. schrieb:
>>         data[0] = 0xC2;
>>         data[1] = 0x03;
>>         data[2] = 0x00;
>>
>>         I2C1_WriteNBytes(0x61, data, 3);
>
> Kann nicht klappen. In der PDF ist die komplette Übertragung auf dem Bus
> zu sehen. Die I²C-Adresse wird aber bei I2C1_WriteNBytes extra
> übergeben, daher  darf nicht noch mal 0xC2 gesendet werden. 0xC2 ist bei
> I²C Schreiben an Adresse 0x61.

Also soll ich 0xC2 nicht schreiben und es probieren oder wie?
Verzeih ich habs nicht ganz verstanden

von Mario M. (thelonging)


Lesenswert?

Genau, schreib nur 2 Bytes, das 0xC2 wird automatisch voran gesendet. 
Zwischen Schreiben und Lesen müssen laut des PDFs mehr als 3ms Pause 
sein. Lege Dir so einen billigen Logikanalysator zu, dann kannst Du 
überprüfen, was über den Bus geht.

von Leonidas T. (helpleo)


Lesenswert?

Mario M. schrieb:
> Genau, schreib nur 2 Bytes, das 0xC2 wird automatisch voran gesendet.
> Zwischen Schreiben und Lesen müssen laut des PDFs mehr als 3ms Pause
> sein. Lege Dir so einen billigen Logikanalysator zu, dann kannst Du
> überprüfen, was über den Bus geht.

Das hat geholfen danke dir, jetzt bekomm ich nur Trash values.

von Leonidas T. (helpleo)


Lesenswert?

Also am ende vom Datenblatt finde ich wie ich die werte in physik. Werte 
umwandel. Nur denk ich es ist am ende eine variable und ich kann die 
nicht über UART schicken.
Über UART kann ich nur Byte by Byte schicken. (Da spezielles format)
Gibts es eine Möglichkeit die variable in ein array aufzuteilen um es 
eben in bytes zu unterteilen?

Ich danke euch

von STK500-Besitzer (Gast)


Lesenswert?

Leonidas T. schrieb:
> Gibts es eine Möglichkeit die variable in ein array aufzuteilen um es
> eben in bytes zu unterteilen?

man verschiebt die einzelnen Bytes der größeren Variablen um die 
entsprechende Anzahl von Bits:
1
uint16_t word = 0xAABB;
2
uint8_t bytes[2] = {0};
3
bytes[0] = word >> 8;     // MSB
4
bytes[1] = word & 0x00FF; // LSB
Man könnte den "Berechnungen" noch ein Cast verpassen. Sollte aber nicht 
notwendig sein.

Solche Bitschubsereien sind Grundlagen...

von Mario M. (thelonging)


Lesenswert?

Leonidas T. schrieb:
> I2C1_ReadNBytes(0x61, i2c_payload, 19);
>
>         UART5_Write(0x02);
>         UART5_Write(0x00);
>         UART5_Write(0x0C);
>
>         UART5_Write(i2c_payload[1]);
>         UART5_Write(i2c_payload[2]);
>         UART5_Write(i2c_payload[4]);

Die Zahl der gelesenen Bytes sollte durch 3 teilbar sein (also 18 statt 
19), weil immer MSB, LSB, CRC gesendet werden. Außerdem beginnt 
i2c_payload bei Null, die Messwerte liegen also bei 0, 1 und 3, 4 usw.

von Leonidas T. (helpleo)


Lesenswert?

STK500-Besitzer schrieb:

> man verschiebt die einzelnen Bytes der größeren Variablen um die
> entsprechende Anzahl von Bits:
>
>
1
> uint16_t word = 0xAABB;
2
> uint8_t bytes[2] = {0};
3
> bytes[0] = word >> 8;     // MSB
4
> bytes[1] = word & 0x00FF; // LSB
5
>
> Man könnte den "Berechnungen" noch ein Cast verpassen. Sollte aber nicht
> notwendig sein.
>
> Solche Bitschubsereien sind Grundlagen...

Dankeschön das war sehr hilfreich, ich probiers aus und sag euch 
bescheid :)

: Bearbeitet durch User
von Leonidas T. (helpleo)


Lesenswert?

Mario M. schrieb:

Danke dir auch :)

von Leonidas T. (helpleo)


Lesenswert?

Ich komm leider nicht weiter, also im datenblatt steht folgendes:

float co2Concentration;
unsigned int tempU32;

unsigned char buffer[4];
buffer[0] = 0x43; // MMSB CO2
buffer[1] = 0xDB; // MLSB CO2
buffer[2] = 0x8C; // LMSB CO2
buffer[3] = 0x2E; // LLSB CO2

tempU32 = (unsigned int)((((unsigned int)buffer[0]) << 24) |
 (((unsigned int)buffer[1]) << 16) |
 (((unsigned int)buffer[2]) << 8) |
 ((unsigned int)buffer[3]));

co2Concentration = *(float*)&tempU32; // co2Concentration = 439.09f

Die sache ist nur, ich weiss nicht wie ich co2Concentration über UART 
verschicken soll, da ich nur byte by byte verschicken kann. ICh würde es 
gerne in ein array abspeichern. Was denkt ihr??

von Thomas W. (Gast)


Lesenswert?

Leonidas T. schrieb:
> Ich komm leider nicht weiter, also im datenblatt steht folgendes:
>
> co2Concentration = *(float*)&tempU32; // co2Concentration = 439.09f
>
> Die sache ist nur, ich weiss nicht wie ich co2Concentration über UART
> verschicken soll, da ich nur byte by byte verschicken kann. ICh würde es
> gerne in ein array abspeichern. Was denkt ihr??

Bitte sprintf() (Library-Funktion, oder fprintf()) nachschlagen. 
Eventuell ein Buch benutzen (bei solchen Fragen reicht Kernighan & 
Ritchie aus).

Gruesse

Th.

von Mario M. (thelonging)



Lesenswert?

Der Sensor gibt drei Messwerte zurück: CO2-Gehalt, Feuchtigkeit und 
Temperatur. Diese werden als  Float-Werte mit einer Länge von jeweils 4 
Bytes übermittelt. Das Programmbeispiel zeigt, wie die 4 Bytes in eine 
Float-Variable kopiert werden.

von Peter D. (peda)


Lesenswert?

Leonidas T. schrieb:
> Die sache ist nur, ich weiss nicht wie ich co2Concentration über UART
> verschicken soll, da ich nur byte by byte verschicken kann.

Will man mehr als ein Byte übertragen, benötigt man ein Protokoll. Die 
UART kann nicht unterscheiden, welches Byte in einem Datenstrom welche 
Bedeutung hat.

Ein einfaches Protokoll ist eine Textzeile, die mit CR/LF abgeschlossen 
wird und nur Textzeichen enthält. Werte lassen sich leicht als Text mit 
printf ausgeben, bzw. mit scanf einlesen.

Binärprotokolle sind zwar kompakter, aber auch deutlich komplexer und 
nicht direkt lesbar.

von Leonidas T. (helpleo)


Lesenswert?

Mario M. schrieb:
> Der Sensor gibt drei Messwerte zurück: CO2-Gehalt, Feuchtigkeit und
> Temperatur. Diese werden als  Float-Werte mit einer Länge von jeweils 4
> Bytes übermittelt. Das Programmbeispiel zeigt, wie die 4 Bytes in eine
> Float-Variable kopiert werden.

Das ist sehr hilfreich, ich danke dir.
Kann dich das programmieren, also das es von alleine passiert.

von W.S. (Gast)


Lesenswert?

Mario M. schrieb:
> Der Sensor gibt drei Messwerte zurück: CO2-Gehalt, Feuchtigkeit und
> Temperatur. Diese werden als  Float-Werte mit einer Länge von jeweils 4
> Bytes übermittelt. Das Programmbeispiel zeigt, wie die 4 Bytes in eine
> Float-Variable kopiert werden.

Sowas ist einigermaßen ungewöhnlich, denn Gleitkommaformate können 
unterschiedlich sein. Sowohl vom schieren Format her als auch in den 
dargestellten Wertigkeiten. Muß aber nicht. Auf alle Fälle ist es 
hilfreich, im PIC all das, was da vom Sensor kommt, zunächst in ein 
Format zu wandeln, mit dem die GK-Routinen des verwendeten Compilers 
zurecht kommen und dann zur Übertragung diese in Text zu konvertieren. 
Und das dann senden.

Ob das, was da in deinem Datenblatt als funktionale Konvertierroutine 
angesehen werden kann, ist deshalb fraglich. Nach meiner Erfahrung sind 
Audrücke, wo extensiv gecastet wird, recht fehleranfällig.

Versuche doch erstmal, die vom Sensor kommenden Bytes als Hexzahlen zu 
senden, etwa so:
1
 String_Out("CO2: ",toUART1);
2
 HexB_Out(Buffer[0],toUART1); Char_Out(',',toUART1);
3
 HexB_Out(Buffer[1],toUART1); Char_Out(',',toUART1);
4
 HexB_Out(Buffer[2],toUART1); Char_Out(',',toUART1);
5
 HexB_Out(Buffer[3],toUART1); Crlf_Out(toUART1);

W.S.

von Profibewunderer (Gast)


Lesenswert?

1
 String_Out("CO2: ",toUART1);
2
 HexB_Out(Buffer[0],toUART1); Char_Out(',',toUART1);
3
 HexB_Out(Buffer[1],toUART1); Char_Out(',',toUART1);
4
 HexB_Out(Buffer[2],toUART1); Char_Out(',',toUART1);
5
 HexB_Out(Buffer[3],toUART1); Crlf_Out(toUART1);

Daran erkennt man den Könner, der unbegabte Laie würde viel 
umständlicher
1
 printf("CO2: %02x,%02x,%02x,%02x\r\n", Buffer[0], Buffer[1], Buffer[2], Buffer[3]);
schreiben.

Da sieht man förmlich, wie viel eleganter die Nutzung eigener 
Ausgabefunktionen ist.

Schön, dass hier ein Fachmann und Könner zeigt, wie es richtig gemacht 
wird. Auch die Quelltextformatierung ist mit mehreren Statements in 
einer Zeile viel überschaubarer. Wie lange man wohl braucht, um diesen 
Level an Exzellenz zu erlangen?

von Falk B. (falk)


Lesenswert?

Profibewunderer schrieb:
> Wie lange man wohl braucht, um diesen
> Level an Exzellenz zu erlangen?

Naja, es sind halt die bekannten Koniferen des Forums . . .

von baumschulengärtner (Gast)


Lesenswert?

Falk B. schrieb:
> Naja, es sind halt die bekannten Koniferen des Forums . . .

Diese Koniferen möchten halt dem Compiler noch etwas
Optimierungsarbeit überlassen.

von W.S. (Gast)


Lesenswert?

Profibewunderer schrieb:
> Daran erkennt man den Könner,...

Nö, sondern man erkennt das Prinzip. Das ist alles.

Aber mal im Detail: Wenn jemand eine Ausgabefunktion benutzt, die neben 
den Zeigern auf 4 Bytes obendrein auch noch einen Formatstring benötigt 
und dieser von einem in der Firmware befindlichen Textinterpreter 
auseinandergenommen werden muß, um dann dort viermal die eigentlichen 
Konvertier- und Ausgabefunktionen aufzurufen, dann ist das für dich eine 
bessere Lösung? Und das in einem PIC (allerdings ohne detaillierte 
Bezeichnung) mit vermutlich nur wenig Programmspeicher?

Ich habe da so den Eindruck, daß deine Vorstellungskraft nicht über 
einen C-Quelltext hinausreicht.

W.S.

von Profibewunderer (Gast)


Lesenswert?

Das ist es ja, was ich an Profis wie Dir bewundere. Die rufen neun 
Funktionen nacheinander auf, und schwabulieren immer was davon, wie 
unendlich kompliziert das doch alles ist, was printf veranstaltet.
Bekommen die Geld für nicht genutzes Flash-ROM ihrer Controller zurück?

von Falk B. (falk)


Lesenswert?

Profibewunderer schrieb:
> Bekommen die Geld für nicht genutzes Flash-ROM ihrer Controller zurück?

Sie retten das Weltklima!!!

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.