Forum: Mikrocontroller und Digitale Elektronik signed int (16 bit) über CAN verschicken


von Sebastian (Gast)


Lesenswert?

Guten morgen,

ich soll für ein Projekt Debug-Nachrichten über CAN verschicken.
Das funktioniert auch schon (Die Funktion zum senden ist ja schon 
vorgegeben).
Diese werwartet die Adresse (an wem ich verschicke, uint8 array (mit den 
Daten) und die Anzahl der Daten.


Aber wie kann ich Jetzt habe ich hier aber werte, welche sint16 sind. 
Wie kann man diese denn am besten verschicken? Für die Anderen 
Nachrichten habe ich ein Array welches uint16 Werte erwartet (das sind 
nämlich die meisten werte), welches ich dann beim Funktionsaufruf auf 
uint8* caste.

von Thomas F. (igel)


Lesenswert?

Sebastian schrieb:
> Diese werwartet die Adresse ... und die Anzahl der Daten.

> Aber wie kann ich Jetzt habe ich hier aber werte, welche sint16 sind.

Wie soll man das verstehen?

> Wie kann man diese denn am besten verschicken?

Indem man die Bits auf mehrere Datenbytes verteilt:

https://images3.programmersought.com/555/31/311da57148fbf07dcf259f58cfdb17fb.JPEG

Sender und Empfänger müssen sich nur über die Reihenfolge einig sein: 
Lo-Byte oder High-Byte zuerst. In fertiger CAN-Software wird das Intel- 
und Motorola-Byte-Order genannt.

von Udo (Gast)


Lesenswert?

Du schreibst deinen sint16 Wert in das Array. Wenn ich deinen Text 
richtig
interpretiere, müsste das Schreiben ausserhalb der Sendefunktion 
erfolgen.

Du müsstest allerdings folgendes wissen:
An welche Stelle im uint8 Array soll der Wert geschrieben werden?
In welcher Byteoder (LSB oder MSB) wird auf dem Bus gesendet?

Mal ein Beispiel:

uint8 txData[8] = {0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA};
sint16 dbgValue;

txData[0] = uint8((dbgValue&0xFF00)>>8);
txData[1] = uint8(dbgValue&0x00FF);

SendeCAN(txData, 8);

Dieses Beispiel geht von Byteorder MSB aus und legt den dbg-Wert auf 
Byte 0 und 1 im CAN Frame.

von Martin (Gast)


Lesenswert?

Sebastian schrieb:
> Nachrichten habe ich ein Array welches uint16 Werte erwartet (das sind
> nämlich die meisten werte), welches ich dann beim Funktionsaufruf auf
> uint8* caste.

dann nimm halt ein sint16 Array und caste es auf uint8*

von Sebastian (Gast)


Lesenswert?

Martin schrieb:
> dann nimm halt ein sint16 Array und caste es auf uint8*

Das habe ich jetzt auch mal getestet und den zu sendenden wert 
festgelegt
1
tmp_16 = -200;
2
debug_au16[0] = tmp_16;
3
debug_au16[1] = 200;
4
debug_au16[2] = 0xFF;
5
debug_au16[3] = 0xFF;
6
canSend(0x111, (uint8*)debug_au16[0], 8);

jetzt sehe ich im CAN-Trace, dass byte[0]=0x38, byte[1]=0xFF, 
byte[2]=C8, byte[3]=0x00, byte[4]-byte[7]=0xFF

wie kann ich denn von diesem Wert (0x38 und 0xFF) auf die -200 
schließen?

von Peter D. (peda)


Lesenswert?

Der Empfänger muß feststellen können, welches Byte im Paket welche 
Bedutung hat, d.h. Du brauchst ein Protokoll, was man parsen kann.
Man kann sich ein Protokoll selber ausdenken oder irgendein 
Standardprotokoll nehmen.

Gerne werden Strings genommen, da man die in einem Terminal direkt lesen 
kann. Da Stringnachrichten oft >8 Byte sind, braucht einen Pakettyp, der 
aus mehreren CAN-Nachrichten besteht.

von Achim M. (minifloat)


Lesenswert?

Peter D. schrieb:
> Gerne werden Strings genommen, da man die in einem Terminal direkt lesen
> kann. Da Stringnachrichten oft >8 Byte sind, braucht einen Pakettyp, der
> aus mehreren CAN-Nachrichten besteht.

Über ein Transportprotokoll?

Ich würde den einfacheren Weg gehen, die sint16 im CANdb-Tool in der 
gewollten CAN-Message zu definieren, damit das dann im CAN-Trace oder im 
CAN-Graphen korrekt skaliert angezeigt wird. Dann in der ECU bzw. PLC 
entsprechend dieser Definition befüllen. Den Rest erledigt 
INCA/CANoe/CANape/... dann von selbst.

Wenn der TO einen XCP-Server auf dem Steuergerät/Industriegerät zum 
laufen bringt, geht es mit einem XCP-client wie z.B. eben INCA oder 
CANape noch einfacher. Über ein generiertes A2L bzw. aus ELF generiertem 
A2L kann dann Wahlfrei jede Variable angesehen und ggf. Manipuliert 
werden. Wie ein Debugger eben :)

mfg mf

: Bearbeitet durch User
von Dirk B. (dirkb2)


Lesenswert?

Sebastian schrieb:
> canSend(0x111, (uint8*)debug_au16[0], 8);

Damit castest du den Inhalt vom Arrayeintag 0.
Wenn du die Adresse vom Array haben möchtest, nimmst du nur den Namen 
(oder den Adressoperator für Index 0)
1
canSend(0x111, (uint8*)debug_au16, 4 * sizeof(debug_au16[0]));

von Dirk B. (dirkb2)


Lesenswert?

Sebastian schrieb:
> wie kann ich denn von diesem Wert (0x38 und 0xFF) auf die -200
> schließen?

Gar nicht, sind ja die falschen Werte.

Mach dich mal über Zweierkomplement und Endianess schlau.
Dazu gibt es Wikipediabeiträge.

von Martin (Gast)


Lesenswert?

Sebastian schrieb:
> wie kann ich denn von diesem Wert (0x38 und 0xFF) auf die -200
> schließen?

Du könntest dich mal ein bissl bemühen, und dir aneignen wie Zahlen in 
der Digitalen Welt gespeichert werden. Stichwort Binärzahlen. Dazu gibt 
es viel in der Literatur und im Internet zu lesen.

http://www.scalingbits.com/book/export/html/46

0xff38 hex = -200 dec

0x0000 - 1 = 0xffff
0x0000 - 2 = 0xfffe

von Dirk B. (dirkb2)


Lesenswert?

Sebastian schrieb:
> wie kann ich denn von diesem Wert (0x38 und 0xFF) auf die -200
> schließen?

Mach dich mal über Zweierkomplement und Endianess schlau.
Dazu gibt es Wikipediabeiträge.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Serialisierung

Die dort vorgestellte µSer-Bibliothek kann signed Integer in 
verschiedenen Formaten kodieren/dekodieren.

Peter D. schrieb:
> Da Stringnachrichten oft >8 Byte sind, braucht einen Pakettyp, der
> aus mehreren CAN-Nachrichten besteht.

Zahlen als Strings über CAN verschicken ist nicht sehr zweckmäßig.

von Peter D. (peda)


Lesenswert?

Niklas G. schrieb:
> Zahlen als Strings über CAN verschicken ist nicht sehr zweckmäßig.

Es sind ja nicht nur reine Zahlen.
Meine Nachrichten sind so aufgebaut:
"Befehl Parametername Wert1 [Wert2] [...]\n"
Ich brauche also nur einen allgemeinen Sniffer, der CAN-Pakete zu einer 
Stringnachricht aneinander reiht und anzeigt.
Das Aneinanderreihen geht ganz einfach. Das erste Byte kennzeichnet den 
Stringtyp bzw. ist die fortlaufende Nummer der zu einer Nachricht 
gehörenden CAN-Pakete (max 16).

Ich kann dann Befehle beliebig hinzufügen oder ändern, ohne das ich 
jedesmal einen neuen Interpreter brauche.
Wir hatten früher auch binär benutzt, aber das war fürs Debuggen ein 
Graus. Alles nur kryptische Hex-Bytes.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Peter D. schrieb:
> Wir hatten früher auch binär benutzt, aber das war fürs Debuggen ein
> Graus. Alles nur kryptische Hex-Bytes.

Schon mal CANoe mit DBC-Daten benutzt? Das dekodiert alles automatisch 
und stellt es lesbar dar. Wenn man eine Nachricht ändert klickt man das 
in CANdb++ fix zusammen, da muss man keinen neuen Interpreter bauen. Im 
Idealfall generiert man sowieso den Code aus den DBC-Dateien, sodass man 
die Definition der Nachricht nur 1x machen muss.

CAN ist sowieso schon langsam, das dann noch mit String-Kodierung noch 
weiter auszubremsen... Dann auch noch die Fehlerbehandlung, wenn 
einzelne Nachrichten in der Folge fehlen...

Und wenn für CANoe das nötige Kleingeld fehlt: Einfach den selben Code 
für den Controller wie für die Analyse auf dem PC nutzen, z.B. eben in 
der Form der Deklarationen der µSer-Library. Dann schreibt man es 1x im 
Code hin und verwendet ihn für beide Seiten.

Peter D. schrieb:
> "Befehl Parametername Wert1 [Wert2] [...]\n"

Das riecht nach dem "Inner Platform Antipattern". CAN hat bereits eine 
Nachrichtenkennung ("Befehl"), die ID. Noch eine weitere ID zu 
übertragen, die von der Hardware dann auch nicht gefiltert werden kann, 
ist redundant. Parameter-Namen ständig erneut zu übertragen frisst 
unnötig Bandbreite. CAN ist sowieso nicht Plug-And-Play, man muss 
sowieso alle Teilnehmer explizit anpassen oder konfigurieren.

: Bearbeitet durch User
von Peter D. (peda)


Lesenswert?

Niklas G. schrieb:
> Wenn man eine Nachricht ändert klickt man das
> in CANdb++ fix zusammen, da muss man keinen neuen Interpreter bauen.

Das geht bei uns nicht. Der CAN-Bus geht nicht direkt auf den PC, 
sondern die Nachrichten werden per Ethernet an den PC übertragen. Daher 
ist das Stringformat sehr bequem.

Niklas G. schrieb:
> CAN ist sowieso schon langsam, das dann noch mit String-Kodierung noch
> weiter auszubremsen...

Das muß man schon dem Anwender überlassen, ob da was bremst. Wir haben 
natürlich vorher untersucht, ob das Stringformat für unsere Anwendungen 
schnell genug ist und das ist es.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Peter D. schrieb:
> Das geht bei uns nicht.

Warum? Dann baut halt einen Interpreter welcher mittels DBC-Dateien das 
Binärformat interpretiert, was zuvor per Ethernet verschickt wurde.

Peter D. schrieb:
> Wir haben
> natürlich vorher untersucht, ob das Stringformat für unsere Anwendungen
> schnell genug ist und das ist es.

Okay, aber das ist dann eine Lösung die nur in diesem Spezialfall 
funktioniert. Viele Fahrzeuge und Anlagen haben sogar mehrere 
CAN-Netzwerke, u.a. weil ein einzelnes nicht genug Bandbreite hat. 
CAN-FD wurde auch deshalb erfunden. Für diese Anwendungen sollte man 
also lieber eine Binärkodierung verwenden. Natürlich auch, weil 
praktisch alle CAN-basierten Systeme auf dem Markt das eben so machen.

von Martin (Gast)


Lesenswert?

Peter D. schrieb:
> Gerne werden Strings genommen, da man die in einem Terminal direkt lesen
> kann.

Dafür ist CAN aber nicht gedacht. Es kann ja auch passieren das ein 
anderer Client eine Nachricht dazwischen funkt und schon ist dein String 
futsch. In deinem speziellen Fall mag das evtl. nicht möglich sein aber 
das zu verallgemeinern ... hm? Ausserdem geht das ganz schön auf die 
Datenübertragungsrate, also bei Zeitkritischen Anwendungen auch eher 
nicht geeignet.

Die Jungend von heute ... tztztz. Früher konnten Programmierer noch 
programmieren und konnten noch mit Hex und Bin umgehen. ;-)

von Peter D. (peda)


Lesenswert?

Martin schrieb:
> Die Jungend von heute ...

Nö, im Alter (ü60) will man es schön bequem haben.

Ich schreibe auch keine Windows-Anwendungen. Ein Kollege hat mal das 
UDP-Terminal geschrieben und ich benutze es nur, um die CAN-Module 
anzusprechen. Ich kann damit an der eigentlichen Steuerung vorbei mit 
den Modulen sprechen, d.h. auch im Betrieb. Das funktioniert sogar im 
Homeoffice.

von Dirk (Gast)


Lesenswert?

>Sender und Empfänger müssen sich nur über die Reihenfolge einig sein:
>Lo-Byte oder High-Byte zuerst. In fertiger CAN-Software wird das Intel-
>und Motorola-Byte-Order genannt.

Auch das wird im DBC File festgelegt, genauso wie die ID Nachrichten, 
sowie die Zykluszeiten.

Ich bin der Meinung für dein anliegen empfiehlt es sich das TP-Protokoll 
aufzusetzen, falls du mit dem Payload von 8 Byte nicht auskommst.

https://de.wikipedia.org/wiki/ISO_15765-2

von Wolfgang (Gast)


Lesenswert?

Udo schrieb:
> Du müsstest allerdings folgendes wissen:
> ...
> In welcher Byteoder (LSB oder MSB) wird auf dem Bus gesendet?

Was spielt das für eine Rolle?
Hauptsache Sender und Empfänger machen es gleich ;-)

von Rolf M. (rmagnus)


Lesenswert?

Wolfgang schrieb:
> Udo schrieb:
>> Du müsstest allerdings folgendes wissen:
>> ...
>> In welcher Byteoder (LSB oder MSB) wird auf dem Bus gesendet?
>
> Was spielt das für eine Rolle?
> Hauptsache Sender und Empfänger machen es gleich ;-)

Naja, wenn man die beiden entwickelt, sollte man das schon wissen. Wie 
soll man sonst sicherstellen, dass sie es gleich machen?

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.