Arduino Blue Pill & CAN mit SN65HVD230

OP #7342109
Lesenswert?

Hallo und guten Tag zusammen,

ich hoffe Ihr könnt mir helfen, nachdem das in diversen Arduino Foren nicht wirklich funktioniert hat. Ich bin auf der Suche nach entweder jemandem, der ein Arduino Blue Pill (STM32F103) und SN65HVD230 für CAN Bus mittels in der Arduino IDE programmiert hat, oder ein (wenn möglich deutschsprachiges) Tutorial dazu. Gefunden dazu hab ich ein Video eines nuschelnden Spaniers der versucht englisch zu sprechen.. ;-)

ich bin auf der Suche nach Hilfe zur Selbsthilfe es soll mir keiner einen Sketch schreiben. Wenn jemand etwas fertiges lauffähiges zu dem Thema hat, was vernünftig kommentiert ist, würde mir das als Grundlage auf der ich aufbauen kann weiterhelfen.

Mein Projekt ist die Steuerung einer analogen Modelleisenbahn. Teile der Steuerung (wie zB die Steuerung des Schattenbahnhofes) habe ich fertig. Ich möchte nur den Zustand von ein paar Variablen via CAN von einem Arduino zum anderen schicken. ZB (Lichtschranke 1 = High)

Gruß

Kay

OP #7342730
Lesenswert?

Es hakt überall :-)

Das ist ja das Problem. Die absoluten Basics des CAN sind mir so halbwegs klar, aber in dem beispielsketch den ich bei Github gefunden habe: https://github.com/nopnop2002/Arduino-STM32-CAN/blob/master/stm32f103/stm32f103.ino

Komme ich keinen schritt weiter, da steige ich nicht durch. Das mag auch am Englisch oder der für einen Laien nicht ausreichenden kommentierung liegen.

Zu meinem Hintergrund ich programiere erst seit 2 Jahren, komme aber aus der Elektronic... Wohl noch analog :-)

Zu meinen Programierkenntnissen: Umgesetzt habe ich bis dato:

  1. Steuerung des Schattenbahnhofes mit 5 Gleisen (Suche freies Gleis, fahren des Zuges bis zum Haltepunkt, schalten der Weichen usw.
  2. Geschwindigkeits mess und Regelung (mit LCD)
  3. Totman box, die Verhindert das die Bahn tagelang im Keller unter strom steht (mit LCD)
  4. Schweisslicht
  5. Gleisstatusanzeige mit LCD und ein paar andere Kleinigkeiten Alles als State Maschine mit Übergang also mit aktualState und nextState.

Habe mir das alles selber bei gebracht, aber für den CAN Bus fehlen mir wohl noch jede Menge Basics. Deshalb wäre ein Tutorial wie dieses: https://www.fh-bielefeld.de/medienportal/video/13B1-Aufzugtuer-als-endlicher-Automat-in-C/36538450aeaa04af71bc17b2ae9617d0 (damit hab ich die State Maschine verstanden) nur halt für CAN äusserst hilfreich. Alternativ würde auch ein sehr gut kommentierter Code reichen der eine Variable übergibt. Denn könnte ich mir dann mittels try and error erklären. Dafür ist der Code von Github aber zu komplex

Gruß

Kay

Gast #7342841
Lesenswert?

Kay L. schrieb:

Komme ich keinen schritt weiter, da steige ich nicht durch. Das mag auch am Englisch oder der für einen Laien nicht ausreichenden kommentierung liegen.

In dem Github-Code ist Treiber und Beispiel alles in einem Sourcefile verwurstet. Das ist für das erste Verständnis auch maximal ungünstig. Besser wäre eine abgekapselte Lib, die einfach nur den can_write, can_read und die grundlegende CAN-Struktur mit Id, Len und Data[8] zur Verfügung stellt.

Wichtig ist auch, dass man nicht unbedingt nur seine beiden CAN-Teilnehmer vor sich liegen hat, dessen Code man selber erstellt hat. Besser man hat ein CAN-Analyzer mit angeschlossen, dem man vertraut und einem anzeigt, was gerade auf dem Bus vor sich geht. So ein CAN-Analyzer kann etwas von Peak sein (evtl. etwas teuer für Hobby), etwas von fischl.de oder auch einfach nur ein Logik-Analyzer von Amazon für <10€. Der LA hat den Nachteil, dass er keine Live-View bietet. Gibt auch noch weitere CAN-Werkzeuge für kleines Geld, einfach mal stöbern.

Bleibe dran, es lohnt sich! CAN ist zwar schon uralt, aber eine schöne Methode, damit sich verschiedene Teilnehmer Botschaften zuschieben können, ohne an Bustimings gebunden zu sein.

#7342938
Lesenswert?

Kay L. schrieb:

ich hoffe Ihr könnt mir helfen, nachdem das in diversen Arduino Foren nicht wirklich funktioniert hat. Ich bin auf der Suche nach entweder jemandem, der ein Arduino Blue Pill (STM32F103) und SN65HVD230 für CAN Bus mittels in der Arduino IDE programmiert hat, oder ein (wenn möglich deutschsprachiges) Tutorial dazu.

Bei Deinem STM32F103 kannst Du entweder USB oder CAN verwendet, nicht beides zusammen. Erstens liegen die Signale auf den gleichen Pins, und zweitens verwenden beide Peripherieeinheiten das gleiche Dual-Port-RAM.

Erste Empfehlung: keinen F103 nehmen, sondern einen F302 oder F303. Die haben das Problem nicht. Zweite Empfehlung, wenn das Kind schon ganz tief im Brunnen steckt: Schauen, ob Du für Dein konkretes Board einen Schaltplan bekommst. Wenn da USB drauf ist, dann alles, was damit zu tut hat, runternehmen. Überprüfen, ob PA11/PA12 tatsächlich mit der Stiftleiste verbunden sind. In der Software alles, was mit USB zu tun hat, rauswerfen.

Dann könnte es gehen.

Es ist halt blöd, dass noch so altes Zeugs verkauft und verwendet wird. Blöde Anfängerfalle.

fchk

OP #7342998
Lesenswert?

Frank K. schrieb:

Kay L. schrieb:

ich hoffe Ihr könnt mir helfen, nachdem das in diversen Arduino Foren nicht wirklich funktioniert hat. Ich bin auf der Suche nach entweder jemandem, der ein Arduino Blue Pill (STM32F103) und SN65HVD230 für CAN Bus mittels in der Arduino IDE programmiert hat, oder ein (wenn möglich deutschsprachiges) Tutorial dazu.

Bei Deinem STM32F103 kannst Du entweder USB oder CAN verwendet, nicht beides zusammen. Erstens liegen die Signale auf den gleichen Pins, und zweitens verwenden beide Peripherieeinheiten das gleiche Dual-Port-RAM.

Erste Empfehlung: keinen F103 nehmen, sondern einen F302 oder F303. Die haben das Problem nicht. Zweite Empfehlung, wenn das Kind schon ganz tief im Brunnen steckt: Schauen, ob Du für Dein konkretes Board einen Schaltplan bekommst. Wenn da USB drauf ist, dann alles, was damit zu tut hat, runternehmen. Überprüfen, ob PA11/PA12 tatsächlich mit der Stiftleiste verbunden sind. In der Software alles, was mit USB zu tun hat, rauswerfen.

Dann könnte es gehen.

Es ist halt blöd, dass noch so altes Zeugs verkauft und verwendet wird. Blöde Anfängerfalle.

fchk

Hallo Frank,

ich verstehe gerade deinen Post nicht, ich möchte USB gar nicht nutzen. Selbst das programieren des Arduinos mache ich direkt, also über STLink utility.

Gruß

Kay

#7343014
Lesenswert?

Kay L. schrieb:

ich verstehe gerade deinen Post nicht, ich möchte USB gar nicht nutzen.

Ist auf Deinem Bluepill Board denn ein USB-Anschluss drauf? Auch wenn der nicht benutzt wird. Wenn ja, dann wird der die gleichen Pins (PA11/PA12) benutzen, die der CAN verwendet. Genau diese Doppelbeschaltung kann zu Problemen führen.

Was mir noch einfallt: Ist das denn wirklich ein originaler Chip von ST? Die STM32F103 sind mit die am häufigsten gecloneten Chips überhaupt - da gibt es wesentlich mehr Kopien als Originale. Auch der Aufdruck ist of gefälscht.

Die STM32F30x sind von der Clonerei noch nicht so betroffen, obwohl es auch da Nachbauten gibt. Und die Nachbauten sind nicht immer überall 1:1 kompatibel.

fchk

OP #7343018
Lesenswert?

Pieter schrieb:

moin,

in Zusammenfassung: CAN ist einfacher als I2C! Was verwirrend ist, sind die Filter und Masken. Meist braucht man die aber gar nicht. Was ist an dem code unklar?

https://github.com/nopnop2002/Arduino-STM32-CAN/blob/master/stm32f103/stm32f103.ino

VG Pieter

So ziemlich alles ;-) vor allem der ist ziemlich lang. Wir ist auch nicht klar warum der verschiedene Bitraten zulässt, fehlermeldung für eine falsche Bitrate auswirft usw. Das dies für die saubere Programierung und den sauberen stabilen Betrieb notwendig ist, ist mir natürlich klar, für den Einstieg aber nur maximal verwirrend

Eine Sketch zB der Via CAN einfach nur den Zustand einer Variable mit festgelegter Bitrate an einen anderen übermittelt, ohne hätte, sollte, könnte, vielleicht wäre für mich der ideale Einstieg.
Da könnte ich dann sehen, ah es läuft, dann ändere ich den Zustand der Variable die ich sende und sehe "ach da und in der Form wird der Zustand übertragen" dann "ach da wird der Name in der Form der variablen übertragen" ach da syncronisiere ich die Bitrate" usw usw. Oder halt ein Video die CAN für Dummies erklärt ;-)

Ich muß auch nicht so tief gehen wenn es eine einfache Libery wie zB für die Character LCD´s gibt wäre mir das noch lieber. ich mache ja keine Raketentechnik nur eine Modelleisenbahn, da ist es nicht schlimm wenn mal was schief läuft.

Gruß

Kay

#7343034
Lesenswert?

Kay L. schrieb:

Eine Sketch zB der Via CAN einfach nur den Zustand einer Variable mit festgelegter Bitrate an einen anderen übermittelt

Du musst ja auch nicht den kompletten Code verstehen. Wenn er funktioniert - ich habe es nicht getestet - reicht der Teil ab Zeile 522. Als erstes muss man natürlich den CAN mal einschalten:

1
void setup() {
2
  Serial.begin(115200);
3
  bool ret = CANInit(CAN_500KBPS, 2);  // CAN_RX to PB8, CAN_TX to PB9
4
  if (!ret) while(true);
5
}

Und dann ein einfaches Senden:

1
void loop() {
2
  CAN_msg_t CAN_TX_msg;
3

4
  CAN_TX_msg.data[0] = 0x00;
5
  CAN_TX_msg.data[1] = 0x01;
6
  CAN_TX_msg.data[2] = 0x02;
7
  CAN_TX_msg.len = 3;  // Länge der Botschaft: 3 Bytes
8

9
  CAN_TX_msg.type = DATA_FRAME;
10
  CAN_TX_msg.id = 0x123;
11

12
  CANSend(&CAN_TX_msg);
13

14
  Delay(1000);
15
  }

Wie gesagt: ungetestet, aber in etwa so läufts.

OP #7343123
Lesenswert?

Thomas F. schrieb:

Kay L. schrieb:

Eine Sketch zB der Via CAN einfach nur den Zustand einer Variable mit festgelegter Bitrate an einen anderen übermittelt

Du musst ja auch nicht den kompletten Code verstehen. Wenn er funktioniert - ich habe es nicht getestet - reicht der Teil ab Zeile 522. Als erstes muss man natürlich den CAN mal einschalten:

1
> void setup() {
2
>   Serial.begin(115200);
3
>   bool ret = CANInit(CAN_500KBPS, 2);  // CAN_RX to PB8, CAN_TX to PB9
4
>   if (!ret) while(true);
5
> }
6
>

Und dann ein einfaches Senden:

1
> void loop() {
2
>   CAN_msg_t CAN_TX_msg;
3
> 
4
>   CAN_TX_msg.data[0] = 0x00;
5
>   CAN_TX_msg.data[1] = 0x01;
6
>   CAN_TX_msg.data[2] = 0x02;
7
>   CAN_TX_msg.len = 3;  // Länge der Botschaft: 3 Bytes
8
> 
9
>   CAN_TX_msg.type = DATA_FRAME;
10
>   CAN_TX_msg.id = 0x123;
11
> 
12
>   CANSend(&CAN_TX_msg);
13
> 
14
>   Delay(1000);
15
>   }
16
>

Wie gesagt: ungetestet, aber in etwa so läufts.

Erstmal vielen lieben Dank!! ich suche schon seit Monaten in den Arduino Foren....

Mal sehen ob ich das bis dato gelesene auch richtig Verstanden habe.

Auf der Empängerseite mus ich das auch so einfügen nur anstelle von TX (Transiver) RX (Receiver) einsetzten?

Zum Sketch

1
CAN_msg_t CAN_TX_msg;  
2
// Beutet für den STM ab hier startet eine CAN Message als Sender
3

4
CAN_TX_msg.data[0] = 0x00;
5
// Bedeutet Datenbits 1 -3  aber was bedeutet "0x00"? 
6
 CAN_TX_msg.len = 3;  
7
// Länge der Botschaft: 3 Bytes (selbsterklärend)
8
 CAN_TX_msg.type = DATA_FRAME;  
9
// Hier weis ich nicht so genau was das ist?
10
CAN_TX_msg.id = 0x123; 
11
// Der "Name" der Botschaft, damit der Empfänger die für Ihn bestimme Botschaft auch findet. aber was ist 0x123 (sind die 0x123 usw ev nur Platzhalter?
12
CANSend(&CAN_TX_msg); 
13
// "Sendebefehl das die Mitteilung jetzt gesendet wird

Ich hoffe das stimmt so halbwegs? und meine Fragen sind nicht komplett doof

Gruß

Kay

#7343140
Lesenswert?

Kay L. schrieb:

1
CAN_TX_msg.data[0] = 0x00;
2
// Bedeutet Datenbits 1 -3  aber was bedeutet "0x00"?

Dir ist der Ausdruck "0x00" unbekannt? Das sind jetzt aber absolute Anfänger-Grundlagen: 0x steht für die Hex-Schreibweise einer Zahl. 0x00 ist einfach 0. 0x0A ist 10.

1
CAN_TX_msg.id = 0x123; 
2
// Der "Name" der Botschaft, damit der Empfänger die für Ihn bestimme Botschaft auch findet. aber was ist 0x123 (sind die 0x123 usw ev nur Platzhalter?

Siehe oben: Hexadezimale Schreibweise. Ich fürchte du solltest dich erst noch mal mit den Grundlagen befassen.

Gast #7343175
Lesenswert?

Frank K. schrieb:

Wenn ja, dann wird der die gleichen Pins (PA11/PA12) benutzen, die der CAN verwendet. Genau diese Doppelbeschaltung kann zu Problemen führen.

Was wird denn hier wieder für Käse-Information verbreitet?

Ein F103 kann das CAN Interface entweder auf PA11/PA12 oder auf PB8/PB9 konfiguriert haben.

Einfach mal ins Datenblatt schauen oder CubeMX über sich ergehen lassen .....

OP #7343178
Lesenswert?

Frank K. schrieb:

Kay L. schrieb:

ich verstehe gerade deinen Post nicht, ich möchte USB gar nicht nutzen.

Ist auf Deinem Bluepill Board denn ein USB-Anschluss drauf? Auch wenn der nicht benutzt wird. Wenn ja, dann wird der die gleichen Pins (PA11/PA12) benutzen, die der CAN verwendet. Genau diese Doppelbeschaltung kann zu Problemen führen.

Was mir noch einfallt: Ist das denn wirklich ein originaler Chip von ST? Die STM32F103 sind mit die am häufigsten gecloneten Chips überhaupt - da gibt es wesentlich mehr Kopien als Originale. Auch der Aufdruck ist of gefälscht.

Die STM32F30x sind von der Clonerei noch nicht so betroffen, obwohl es auch da Nachbauten gibt. Und die Nachbauten sind nicht immer überall 1:1 kompatibel.

fchk

Sorry hatte deine Post übersehen. Ja USB ist drauf, um den USB zur Programierung zu nutzen muss man vorher mittels eines FTDI Adapters einen Bootloader aufspielen. Da ich ja über STLink Programiere, spiele ich keinen Bootloader auf und in der Arduino IDE nutze ich auch kein USB. Eine doppelnutzung kann also nicht vorkommen. Mir ist auch bewusst das die 103er oft gefaked werden. Ich hatte sogar schon mal welche, da hab ich mich tot gesucht, warum die sich nicht programieren lassen. Irgendwann bin ich dann mal darauf gekommen mir die Chips genauer anzusehen und siehe da, kein ST Logo drauf.

Das ist der Arduino Blue Pill: https://www.az-delivery.de/products/stm32f103c8t6

ich weiß jetzt auch nicht ob es einen anderen ST32 als "Arduino" gibt.

Ich hab mal die Scematics von dem teil angehangen. Ich hoffe, das ist OK?

OP #7343198
Lesenswert?

erklehr behr schrieb:

Kay L. schrieb:

Sorry hatte deine Post übersehen.

Meinen Beitrag hast du auch wohl auch übersehen.

Kay L. schrieb:

Ich hab mal die Scematics von dem teil angehangen.

Nein, du hast ihn angehängt. Oder sagst du auch du hast etwas eingekaufen, du hast etwas aufgemalen, du hast etwas eingelöten?

Trägt dieser Post etwas zur Lösung meiner Fragestellung bei?

Gast #7343223
Lesenswert?

Kay L. schrieb:

Das ist der Arduino Blue Pill: https://www.az-delivery.de/products/stm32f103c8t6

AZ-Delivery verkauft schon lange keine BluePills mehr mit einem Originalen STM32. Sind immer nur mehr oder weniger kompatible Nachbauten. Meist von CKS oder GD

Schau doch mal genau, was für eine Bezeichnung auf dem Chip steht.

Schau dir mal die Referenz Bilder an.

Die Klone fangen vorne nicht mit

"STM" https://www.richis-lab.de/STM32_02.htm

sondern z.B. mit

"CKS" https://www.richis-lab.de/STM32_03.htm

"APM" https://www.richis-lab.de/STM32_05.htm

"GD" https://www.richis-lab.de/STM32_06.htm / https://www.richis-lab.de/STM32_10.htm

"MM" https://www.richis-lab.de/STM32_07.htm

"BLM" https://www.richis-lab.de/STM32_08.htm

"HK" https://www.richis-lab.de/STM32_09.htm

an.

Oder es können Fakes sein, wo zwar STM drauf steht, aber kein STM drin ist https://www.richis-lab.de/STM32_01.htm / https://www.richis-lab.de/STM32_04.htm

Gast #7343230
Lesenswert?

Kay L. schrieb:

Das ist der Arduino Blue Pill... ich weiß jetzt auch nicht ob es einen anderen ST32 als "Arduino" gibt.

Es hat noch nie ein echtes "Arduino Blue Pill" Board gegeben. Das LeafLabs Maple Mini Board kommt dem noch am nächsten, aber auch das war nie ein originales Arduino Board. Beide Boards wurden nicht von Arduino designt und die zugehörige Software kommt auch nicht von Arduino.

Wenn du etwas besseres mit ähnlichem Format haben willst, dann nimm ein Nucleo32 Board von ST. Das kannst du auch mit der Arduino IDE programmieren und die entsprechende Software (https://github.com/stm32duino/Arduino_Core_STM32) kommt direkt vom Chiphersteller ST.

#7343245
Lesenswert?

Thomas F. schrieb:

1
CAN_TX_msg.type = DATA_FRAME;
2
CAN_TX_msg.id = 0x123;
3
CANSend(&CAN_TX_msg);

Ich glaube, da sollte besser noch ein

1
CAN_TX_msg.format = STANDARD_FORMAT;

vor das CANSend().

Kay L. schrieb:

Auf der Empängerseite mus ich das auch so einfügen nur anstelle von TX (Transiver) RX (Receiver) einsetzten?

TX steht für Transmitter. Und nein, du solltest vor dem Aufruf von CANReceive(&CAN_RX_msg) mit CANMsgAvail() prüfen, ob überhaupt eine CAN-Nachricht empfangen wurde.

In der loop()-Routine des stm32f103.ino werden regelmäßig zwei verschiedene CAN-Nachrichten gesendet, und dann werden auch alle CAN-Nachrichten empfangen und ausgegeben. Nimm das doch als ersten Versuch.

LG, Sebastian

OP #7343668
Lesenswert?

Sebastian W. schrieb:

Thomas F. schrieb:

1
> CAN_TX_msg.type = DATA_FRAME;
2
> CAN_TX_msg.id = 0x123;
3
> CANSend(&CAN_TX_msg);
4
>

Ich glaube, da sollte besser noch ein

1
> CAN_TX_msg.format = STANDARD_FORMAT;
2
>

vor das CANSend().

Kay L. schrieb:

Auf der Empängerseite mus ich das auch so einfügen nur anstelle von TX (Transiver) RX (Receiver) einsetzten?

TX steht für Transmitter. Und nein, du solltest vor dem Aufruf von CANReceive(&CAN_RX_msg) mit CANMsgAvail() prüfen, ob überhaupt eine CAN-Nachricht empfangen wurde.

In der loop()-Routine des stm32f103.ino werden regelmäßig zwei verschiedene CAN-Nachrichten gesendet, und dann werden auch alle CAN-Nachrichten empfangen und ausgegeben. Nimm das doch als ersten Versuch.

LG, Sebastian

Vielen lieben Dank dafür, damit kann ich etwas anfangen. Verstehe ich das richtig, das ich die info die ich übertragen will (zB StatusLS1 = true)

in die canTX.msg umwandeln muß?

1
 void loop() {
2
>   CAN_msg_t CAN_TX_msg;
3
>  if (StatusLS1 = true)
4

5
{
6
>   CAN_TX_msg.data[0] = 0x00; // Status LS1 = true
7
>   CAN_TX_msg.data[1] = 0x01;
8
>   CAN_TX_msg.data[2] = 0x02;
9
>   CAN_TX_msg.len = 3;  // Länge der Botschaft: 3 Bytes
10
> }
11
> else 
12

13
{
14
>  CAN_TX_msg.data[0] = 0x01; // Status LS1 = false
15
>   CAN_TX_msg.data[1] = 0x01;
16
>   CAN_TX_msg.data[2] = 0x02;
17
>   CAN_TX_msg.len = 3;  // Länge der Botschaft: 3 Bytes
18

19
}
20
>
21
>   CAN_TX_msg.type = DATA_FRAME;
22
>   CAN_TX_msg.id = 0x123;
23
> 
24
>   CANSend(&CAN_TX_msg);
25
> 
26
>   Delay(1000);
27
>   }
Gast #7343687
Lesenswert?

Hallo,

vielleicht habe den Sinn nicht verstanden, aber warum nimmst Du nicht einfach eine fertige Can-Bus Platine mit Controller 2515?

Oder soll es eine persönliche Herausforderung sein, nicht den normalen Weg über gute Programme wie schon erwähnt ACAN2515, MCP_Can usw.... zu gehen?

OP #7343721
Lesenswert?

Peter* schrieb:

Hallo,

vielleicht habe den Sinn nicht verstanden, aber warum nimmst Du nicht einfach eine fertige Can-Bus Platine mit Controller 2515?

Oder soll es eine persönliche Herausforderung sein, nicht den normalen Weg über gute Programme wie schon erwähnt ACAN2515, MCP_Can usw.... zu gehen?

Hallo Peter, Der STM32F1 stellt ja den CAN BUS zur verfügung, also warum den Umweg über Umwandeln gehen? Der 2525 Wandelt ja das CAN in ein SPI Signal um.

Nun ja der "normale Weg" ist wohl eher das vorhandene CAN ohne Umwandler zu nutzen. Nur weil es viele anders machen muß es ja nicht der normale sein :-)

Die Herausforderung dabei ist meine Konstellation:

  1. ich bin blutiger Anfänger
  2. Den Blue Pill mit STM32F1 nutzen nicht viele (wie man auch hier im Fred ja schon sieht ist der eher verpöhnt)
  3. Den CAN Bus darauf noch entsprechend weniger.

Auch habe ich meine Baseboards für die Nutzung von CAN vorgesehen.

Zu guter letzt, ja mittlerweile ist es etwas persönliches zwischen mir und dem CAN Bus :-)

Gruß

Kay

OP #7343723
Lesenswert?

Sebastian schrieb:

Kay L. schrieb:

das ich die info die ich übertragen will (zB StatusLS1 = true) in die canTX.msg umwandeln muß

Ja. Vielleicht besser nicht so umständlich, aber ja.

LG, Sebastian

Hallo Sebastian,

vielen lieben Dank! Jetzt weiß ich wo ich ansetzten muß!

Auch an alle anderen die etwas zur Lösung und damit das ich einen Ansatz habe beigetragen haben

Gruß

Kay

Gast #7343735
Lesenswert?

Kay L. schrieb:

Auch an alle anderen die etwas zur Lösung und damit das ich einen Ansatz habe beigetragen haben

Ein Oszilloskop und ein Logikanalysator könnten im weiteren Verlauf hilfreich sein. Tip: Schließe einen SN65HVD230 am CAN-Bus an, versorge ihn, und häng den Logikanalysator an seinen RX-Pin. So kannst du passiv den Bus beobachten

LG, Sebastian

OP #7343772
Lesenswert?

Sebastian schrieb:

Kay L. schrieb:

Auch an alle anderen die etwas zur Lösung und damit das ich einen Ansatz habe beigetragen haben

Ein Oszilloskop und ein Logikanalysator könnten im weiteren Verlauf hilfreich sein. Tip: Schließe einen SN65HVD230 am CAN-Bus an, versorge ihn, und häng den Logikanalysator an seinen RX-Pin. So kannst du passiv den Bus beobachten

LG, Sebastian

Ja mache ich Dankeschön.

#7343882
Lesenswert?

Kay L. schrieb:

Vielen lieben Dank dafür, damit kann ich etwas anfangen. Verstehe ich das richtig, das ich die info die ich übertragen will (zB StatusLS1 = true)

in die canTX.msg umwandeln muß?

canTX_msg ist ein struct. Das struct beinhaltet unter anderem die Datenbytes der zu sendenden Botschaft. Eine CAN-Botschaft kann zwischen 0 und 8 Datenbytes enthalten. Willst du lediglich ein Statusbit übertragen dann musst du min. 1 Datenbyte senden:

1
  CAN_TX_msg.data[0] = StatusLS1;
2
  CAN_TX_msg.len = 1;  // Länge der Botschaft: 1 Bytes
3
  CAN_TX_msg.id = 0x123; // Identifier der Botschaft
4

5
  // und nun ab damit...
6
  CANSend(&CAN_TX_msg);
Gast #7344004
Lesenswert?

Hallo,

Kay L. schrieb:

Nun ja der "normale Weg" ist wohl eher das vorhandene CAN ohne Umwandler zu nutzen. Nur weil es viele anders machen muß es ja nicht der normale sein :-)

Über "normal" kann man sich streiten, aber es hängt doch meistens vom dem Faktor der Anzahl ab, die es so nutzen!!

Der Can_Controller MCp2515 ist kein Umwandler er nutz SPI und übernimmt die ganze Abwicklung des CanBus's und befreit den Prozessor von dieser Aufgabe, der sonst gebunden ist!! und evtl. so zusätzlich Speicherplatz belegt.

  1. Den CAN Bus darauf noch entsprechend weniger.... dein handeln ist wohl so unlogisch oder :-)

Habe noch vor wenigen Jahren im Automotiv_bereich den CAN_Restbus (500k) mit dem BlusPill mit MCP2515 simuliert, selbst ein Arduino UNO reicht so aus.

verpönt ist dumm, aber ist inzwischen zu teuer geworden 2Euro hat er gekostet.

PI Pico W (6,99) mit ACAN

OP #7347078
Lesenswert?

Hallo Zusammen,

ich habe nun den Code in einen Sketch geschrieben. Für den CAN also nur das einschalten mappen des CANBusses

1
// --------------------------------------  Umbenenen der STM Pins
2
// Library
3

4

5
// Eingänge
6

7
// Taster
8

9
const int Taster = PB9;
10
int TasterState = 0;
11

12

13
// Ausgänge
14

15
const int LED = PA0;
16
void setup()
17
{
18
  pinMode(LED_BUILTIN, OUTPUT);  //LED auf Arduino auf HIGH
19
  // --------------------------------------  pinMode
20
  pinMode(Taster, INPUT);
21
  pinMode(LED, OUTPUT);
22

23
  // CAN aktivieren
24

25
  { 
26
Serial.begin(115200);
27
    bool ret = CANInit(CAN_500KBPS, 2);  // CAN_RX to PB8, CAN_TX to PB9
28
    if (!ret) while (true);
29
  }
30
}
31
void loop()
32
{
33
  TasterState = digitalRead(Taster);    // Taster abfragen
34

35
  if (TasterState == LOW)
36
  {
37
    digitalWrite(LED, HIGH);
38
  }
39
  else
40
  {
41
    digitalWrite(LED, LOW);
42
  }
43

44
}

Leider bekomme ich folgende Fehlermeldung: C:\Users\Büro\privat\Eisenbahn\MCU_Program\Sketches\Testprogramme\CAN\CAN1_0\CAN1_0.ino: In function 'void setup()': CAN1_0:52:24: error: 'CAN_500KBPS' was not declared in this scope CAN1_0:52:38: error: 'CANInit' was not declared in this scope exit status 1 'CAN_500KBPS' was not declared in this scope

Er sieht CANinit usw anscheinend als undefinierte Variable....

Was hab ich vergessen?

Gruß

Kay

#7347223
Lesenswert?

Kay L. schrieb:

Was hab ich vergessen?

Du hast den ganzen Kram aus https://github.com/nopnop2002/Arduino-STM32-CAN/blob/master/stm32f103/stm32f103.ino vergessen.

Du musst diese stm32f103.ino in eine stm32f103.h und eine stm32f103.cpp zerlegen, in dein Sketch-Verzeichnis kopieren, und in deinem Sketch

1
#include "stm32f103.h"

dazufügen.

Die Datei stm32f103.h sollte so aussehen:

1
typedef enum {CAN_50KBPS, CAN_100KBPS, CAN_125KBPS, CAN_125KBPS32MHZ, CAN_125P1KBPS31P9MHZ,CAN_250KBPS, CAN_500KBPS, CAN_1000KBPS} BITRATE;
2
typedef enum {STANDARD_FORMAT = 0, EXTENDED_FORMAT} CAN_FORMAT;
3
typedef enum {DATA_FRAME = 0, REMOTE_FRAME}         CAN_FRAME;
4

5
typedef struct
6
{
7
  uint32_t id;        /* 29 bit identifier                               */
8
  uint8_t  data[8];   /* Data field                                      */
9
  uint8_t  len;       /* Length of data field in bytes                   */
10
  uint8_t  ch;        /* Object channel(Not use)                         */
11
  uint8_t  format;    /* 0 - STANDARD, 1- EXTENDED IDENTIFIER            */
12
  uint8_t  type;      /* 0 - DATA FRAME, 1 - REMOTE FRAME                */
13
} CAN_msg_t;
14

15
bool CANInit(BITRATE bitrate, int remap);
16
void CANReceive(CAN_msg_t* CAN_rx_msg);
17
void CANSend(CAN_msg_t* CAN_tx_msg);
18
uint8_t CANMsgAvail(void);

Die Datei stm32f103.cpp solle alles aus stm32f103.ino bis einschliesslich Zeile 502 enthalten. Allerdings solle der Anfang danach noch leicht abgeändert werden: [code] #include <Arduino.h> #include "stm32f103.h" [code]

Außerdem solltest du die Typdefinitionen, die schon in stm32f103.h sind, in stm32f103.cpp am Anfang noch löschen (also die enums BITRATE, CAN_FORMAT, CAN_FRAME und die struct CAN_msg_t).

Dann sollte dein Sketch übersetzen.

LG, Sebastian

#7347435
Lesenswert?

Kay L. schrieb:

ok, dann hatte ich Frank s Post (09.02.2023 14:30) komplett falsch verstanden. Ich dachte ich bräuchte nur den kleinen Teil...

Meinst du den Beitrag von Thomas? Thomas F. schrieb:

Du musst ja auch nicht den kompletten Code verstehen. Wenn er funktioniert - ich habe es nicht getestet - reicht der Teil ab Zeile 522.

Er meinte wohl dass du den Code ausserhalb von loop() nicht verstehen musst, und dass es reicht den loop()-Teil für deine Zwecke anzupassen. Er meinte damit aber nicht dass du den Code vor setup () und loop() gar nicht brauchst.

Zumindest meine ich dass er das meinte.

Kay L. schrieb:

Auf ein neues.

Ich habe mir, angeregt durch deine Experimente, kurzfristig ein Nucleo-F303K8-Board zugelegt. Alles was ich heute mittag geschrieben habe hatte ich vorher mit https://github.com/nopnop2002/Arduino-STM32-CAN/tree/master/stm32f303 nachvollzogen. Bei mir läuft der CAN-Empfang auf dem STM32F303K8T6. Ich benutze allerdings einen TJA1050-Transceiver an PA11 und PA12 (die beiden Pins sind hoffentlich 5V-tolerant):

1
Standard ID: 0x206      DLC: 8 Data: 0x14 0x18 0x15 0x0 0xA 0x0 0x0 0x0
2
Standard ID: 0x249      DLC: 8 Data: 0x7B 0x22 0x74 0x6F 0x70 0x69 0x63 0x22
3
Standard ID: 0x249      DLC: 8 Data: 0x3A 0x22 0x77 0x61 0x74 0x74 0x22 0x2C
4
Standard ID: 0x249      DLC: 8 Data: 0x22 0x69 0x64 0x22 0x3A 0x31 0x32 0x38
5
Standard ID: 0x249      DLC: 8 Data: 0x30 0x39 0x2C 0x22 0x6E 0x6F 0x22 0x3A
6
Standard ID: 0x249      DLC: 7 Data: 0x9 0x0 0x25 0x41 0x46 0x0 0x1

Insofern: Nur Mut!

LG, Sebastian

Angehängte Dateien:
#7347481
Lesenswert?

Sebastian W. schrieb:

Meinst du den Beitrag von Thomas? Thomas F. schrieb:

Du musst ja auch nicht den kompletten Code verstehen. Wenn er funktioniert - ich habe es nicht getestet - reicht der Teil ab Zeile 522.

Er meinte wohl dass du den Code ausserhalb von loop() nicht verstehen musst, und dass es reicht den loop()-Teil für deine Zwecke anzupassen. Er meinte damit aber nicht dass du den Code vor setup () und loop() gar nicht brauchst.

Zumindest meine ich dass er das meinte.

Genau das habe ich gemeint. :-)

Natürlich muss man die benötigten Code-Teile vor Zeile 522 auch mit in das Projekt übernehmen. Wie das geht hat ja Sebastian dankenswerter Weise beschrieben.

Ab Zeile 522 kannst du dann mit deinen eigenen Code herumwerkeln.

OP #7350249
Lesenswert?

Hab ich auskommentiert,

ich bekomme weiterhin die Fehlermeldung beim Kompelieren: 'CAN1' was not declared in this scope

1
//------------------------------------------------------------------------------------------------------------Testweise auskommentiert    #include <assert.h>
2
#include <Arduino.h>
3
#include "stm32f103.h"
4

5
#define DEBUG 0
6

7

8

9

10

11

12
typedef struct
13
{
14
    uint16_t baud_rate_prescaler;                /// [1 to 1024]
15
    uint8_t time_segment_1;                      /// [1 to 16]
16
    uint8_t time_segment_2;                      /// [1 to 8]
17
    uint8_t resynchronization_jump_width;        /// [1 to 4] (recommended value is 1)
18
} CAN_bit_timing_config_t;
19

20
#define CAN_STM32_ERROR_UNSUPPORTED_BIT_RATE     1000
21
#define CAN_STM32_ERROR_MSR_INAK_NOT_SET         1001
22
#define CAN_STM32_ERROR_MSR_INAK_NOT_CLEARED     1002
23
#define CAN_STM32_ERROR_UNSUPPORTED_FRAME_FORMAT 1003
24

25
/*
26
 * Calculation of bit timing dependent on peripheral clock rate
27
 */
28
int16_t ComputeCANTimings(const uint32_t peripheral_clock_rate,
29
                          const uint32_t target_bitrate,
30
                          CAN_bit_timing_config_t* const out_timings)
31
{
32
    if (target_bitrate < 1000)
33
    {
34
        return -CAN_STM32_ERROR_UNSUPPORTED_BIT_RATE;
35
    }
36

37
    //------------------------------------------------------------------------------------------------------------Testweise auskommentiert    assert(out_timings != NULL);  // NOLINT
38
    memset(out_timings, 0, sizeof(*out_timings));
39

40
    /*
41
     * Hardware configuration
42
     */
43
    static const uint8_t MaxBS1 = 16;
44
    static const uint8_t MaxBS2 = 8;
45

46
    /*
47
     * Ref. "Automatic Baudrate Detection in CANopen Networks", U. Koppe, MicroControl GmbH & Co. KG
48
     *      CAN in Automation, 2003
49
     *
50
     * According to the source, optimal quanta per bit are:
51
     *   Bitrate        Optimal Maximum
52
     *   1000 kbps      8       10
53
     *   500  kbps      16      17
54
     *   250  kbps      16      17
55
     *   125  kbps      16      17
56
     */
57
    const uint8_t max_quanta_per_bit = (uint8_t)((target_bitrate >= 1000000) ? 10 : 17);    // NOLINT
58
    //------------------------------------------------------------------------------------------------------------Testweise auskommentiert     assert(max_quanta_per_bit <= (MaxBS1 + MaxBS2));
59

60
    static const uint16_t MaxSamplePointLocationPermill = 900;
61

62
    /*
63
     * Computing (prescaler * BS):
64
     *   BITRATE = 1 / (PRESCALER * (1 / PCLK) * (1 + BS1 + BS2))       -- See the Reference Manual
65
     *   BITRATE = PCLK / (PRESCALER * (1 + BS1 + BS2))                 -- Simplified
66
     * let:
67
     *   BS = 1 + BS1 + BS2                                             -- Number of time quanta per bit
68
     *   PRESCALER_BS = PRESCALER * BS
69
     * ==>
70
     *   PRESCALER_BS = PCLK / BITRATE
71
     */
72
    const uint32_t prescaler_bs = peripheral_clock_rate / target_bitrate;
73

74
    /*
75
     * Searching for such prescaler value so that the number of quanta per bit is highest.
76
     */
77
    uint8_t bs1_bs2_sum = (uint8_t)(max_quanta_per_bit - 1);    // NOLINT
78

79
    while ((prescaler_bs % (1U + bs1_bs2_sum)) != 0)
80
    {
81
        if (bs1_bs2_sum <= 2)
82
        {
83
            return -CAN_STM32_ERROR_UNSUPPORTED_BIT_RATE;          // No solution
84
        }
85
        bs1_bs2_sum--;
86
    }
87

88
    const uint32_t prescaler = prescaler_bs / (1U + bs1_bs2_sum);
89
    if ((prescaler < 1U) || (prescaler > 1024U))
90
    {
91
        return -CAN_STM32_ERROR_UNSUPPORTED_BIT_RATE;              // No solution
92
    }
93

94
    /*
95
     * Now we have a constraint: (BS1 + BS2) == bs1_bs2_sum.
96
     * We need to find such values so that the sample point is as close as possible to the optimal value,
97
     * which is 87.5%, which is 7/8.
98
     *
99
     *   Solve[(1 + bs1)/(1 + bs1 + bs2) == 7/8, bs2]  (* Where 7/8 is 0.875, the recommended sample point location *)
100
     *   {{bs2 -> (1 + bs1)/7}}
101
     *
102
     * Hence:
103
     *   bs2 = (1 + bs1) / 7
104
     *   bs1 = (7 * bs1_bs2_sum - 1) / 8
105
     *
106
     * Sample point location can be computed as follows:
107
     *   Sample point location = (1 + bs1) / (1 + bs1 + bs2)
108
     *
109
     * Since the optimal solution is so close to the maximum, we prepare two solutions, and then pick the best one:
110
     *   - With rounding to nearest
111
     *   - With rounding to zero
112
     */
113
    uint8_t bs1 = (uint8_t)(((7 * bs1_bs2_sum - 1) + 4) / 8);       // Trying rounding to nearest first  // NOLINT
114
    uint8_t bs2 = (uint8_t)(bs1_bs2_sum - bs1);  // NOLINT
115
   //------------------------------------------------------------------------------------------------------------Testweise auskommentiert     assert(bs1_bs2_sum > bs1);
116

117
    {
118
        const uint16_t sample_point_permill = (uint16_t)(1000U * (1U + bs1) / (1U + bs1 + bs2));  // NOLINT
119

120
        if (sample_point_permill > MaxSamplePointLocationPermill)   // Strictly more!
121
        {
122
            bs1 = (uint8_t)((7 * bs1_bs2_sum - 1) / 8);             // Nope, too far; now rounding to zero
123
            bs2 = (uint8_t)(bs1_bs2_sum - bs1);
124
        }
125
    }
126

127
    const bool valid = (bs1 >= 1) && (bs1 <= MaxBS1) && (bs2 >= 1) && (bs2 <= MaxBS2);
128

129
    /*
130
     * Final validation
131
     * Helpful Python:
132
     * def sample_point_from_btr(x):
133
     *     assert 0b0011110010000000111111000000000 & x == 0
134
     *     ts2,ts1,brp = (x>>20)&7, (x>>16)&15, x&511
135
     *     return (1+ts1+1)/(1+ts1+1+ts2+1)
136
     */
137
    if ((target_bitrate != (peripheral_clock_rate / (prescaler * (1U + bs1 + bs2)))) ||
138
        !valid)
139
    {
140
        // This actually means that the algorithm has a logic error, hence assert(0).
141
      //------------------------------------------------------------------------------------------------------------Testweise auskommentiert      assert(0);  // NOLINT
142
        return -CAN_STM32_ERROR_UNSUPPORTED_BIT_RATE;
143
    }
144

145
    out_timings->baud_rate_prescaler = (uint16_t) prescaler;
146
    out_timings->resynchronization_jump_width = 1;      // One is recommended by UAVCAN, CANOpen, and DeviceNet
147
    out_timings->time_segment_1 = bs1;
148
    out_timings->time_segment_2 = bs2;
149

150
    if (DEBUG) {
151
      Serial.print("target_bitrate=");
152
      Serial.println(target_bitrate);
153
      Serial.print("peripheral_clock_rate=");
154
      Serial.println(peripheral_clock_rate);
155
  
156
      Serial.print("timings.baud_rate_prescaler=");
157
      Serial.println(out_timings->baud_rate_prescaler);
158
      Serial.print("timings.time_segment_1=");
159
      Serial.println(out_timings->time_segment_1);
160
      Serial.print("timings.time_segment_2=");
161
      Serial.println(out_timings->time_segment_2);
162
      Serial.print("timings.resynchronization_jump_width=");
163
      Serial.println(out_timings->resynchronization_jump_width);
164
    }
165
    return 0;
166
}
167
 
168
/**
169
 * Print registers.
170
*/ 
171
void printRegister(const char * buf, uint32_t reg) {
172
  if (DEBUG == 0) return;
173
  Serial.print(buf);
174
  Serial.print(reg, HEX);
175
  Serial.println();
176
}
177

178
/**
179
 * Initializes the CAN filter registers.
180
 *
181
 * @preconditions   - This register can be written only when the filter initialization mode is set (FINIT=1) in the CAN_FMR register.
182
 * @params: index   - Specified filter index. index 27:14 are available in connectivity line devices only.
183
 * @params: scale   - Select filter scale.
184
 *                    0: Dual 16-bit scale configuration
185
 *                    1: Single 32-bit scale configuration
186
 * @params: mode    - Select filter mode.
187
 *                    0: Two 32-bit registers of filter bank x are in Identifier Mask mode
188
 *                    1: Two 32-bit registers of filter bank x are in Identifier List mode
189
 * @params: fifo    - Select filter assigned.
190
 *                    0: Filter assigned to FIFO 0
191
 *                    1: Filter assigned to FIFO 1
192
 * @params: bank1   - Filter bank register 1
193
 * @params: bank2   - Filter bank register 2
194
 *
195
 */
196
void CANSetFilter(uint8_t index, uint8_t scale, uint8_t mode, uint8_t fifo, uint32_t bank1, uint32_t bank2) {
197
  if (index > 27) return;
198

199
  CAN1->FA1R &= ~(0x1UL<<index);               // Deactivate filter
200

201
  if (scale == 0) {
202
    CAN1->FS1R &= ~(0x1UL<<index);             // Set filter to Dual 16-bit scale configuration
203
  } else {
204
    CAN1->FS1R |= (0x1UL<<index);              // Set filter to single 32 bit configuration
205
  }
206
    if (mode == 0) {
207
    CAN1->FM1R &= ~(0x1UL<<index);             // Set filter to Mask mode
208
  } else {
209
    CAN1->FM1R |= (0x1UL<<index);              // Set filter to List mode
210
  }
211

212
  if (fifo == 0) {
213
    CAN1->FFA1R &= ~(0x1UL<<index);            // Set filter assigned to FIFO 0
214
  } else {
215
    CAN1->FFA1R |= (0x1UL<<index);             // Set filter assigned to FIFO 1
216
  }
217

218
  CAN1->sFilterRegister[index].FR1 = bank1;    // Set filter bank registers1
219
  CAN1->sFilterRegister[index].FR2 = bank2;    // Set filter bank registers2
220

221
  CAN1->FA1R |= (0x1UL<<index);                // Activate filter
222

223
}
224

225
/**
226
 * Initializes the CAN controller with specified bit rate.
227
 *
228
 * @params: bitrate - Specified bitrate. If this value is not one of the defined constants, bit rate will be defaulted to 125KBS
229
 * @params: remap   - Select CAN port. 
230
 *                    =0:CAN_RX mapped to PA11, CAN_TX mapped to PA12
231
 *                    =1:Not used
232
 *                    =2:CAN_RX mapped to PB8, CAN_TX mapped to PB9 (not available on 36-pin package)
233
 *                    =3:CAN_RX mapped to PD0, CAN_TX mapped to PD1 (available on 100-pin and 144-pin package)
234
 *
235
 */
236
bool CANInit(BITRATE bitrate, int remap)
237
{
238
  // Reference manual
239
  // https://www.st.com/content/ccc/resource/technical/document/reference_manual/59/b9/ba/7f/11/af/43/d5/CD00171190.pdf/files/CD00171190.pdf/jcr:content/translations/en.CD00171190.pdf
240

241
  RCC->APB1ENR |= 0x2000000UL;       // Enable CAN clock 
242
  RCC->APB2ENR |= 0x1UL;             // Enable AFIO clock
243
  AFIO->MAPR   &= 0xFFFF9FFF;        // reset CAN remap
244
                                     // CAN_RX mapped to PA11, CAN_TX mapped to PA12
245

246
  if (remap == 0) {
247
    RCC->APB2ENR |= 0x4UL;           // Enable GPIOA clock
248
    GPIOA->CRH   &= ~(0xFF000UL);    // Configure PA12(0b0000) and PA11(0b0000)
249
                                     // 0b0000
250
                                     //   MODE=00(Input mode)
251
                                     //   CNF=00(Analog mode)
252

253
    GPIOA->CRH   |= 0xB8FFFUL;       // Configure PA12(0b1011) and PA11(0b1000)
254
                                     // 0b1011
255
                                     //   MODE=11(Output mode, max speed 50 MHz) 
256
                                     //   CNF=10(Alternate function output Push-pull
257
                                     // 0b1000
258
                                     //   MODE=00(Input mode)
259
                                     //   CNF=10(Input with pull-up / pull-down)
260
                                     
261
    GPIOA->ODR |= 0x1UL << 12;       // PA12 Upll-up
262
    
263
  }
264
                                
265
  if (remap == 2) {
266
    AFIO->MAPR   |= 0x00004000;      // set CAN remap
267
                                     // CAN_RX mapped to PB8, CAN_TX mapped to PB9 (not available on 36-pin package)
268

269
    RCC->APB2ENR |= 0x8UL;           // Enable GPIOB clock
270
    GPIOB->CRH   &= ~(0xFFUL);       // Configure PB9(0b0000) and PB8(0b0000)
271
                                     // 0b0000
272
                                     //   MODE=00(Input mode)
273
                                     //   CNF=00(Analog mode)
274

275
    GPIOB->CRH   |= 0xB8UL;          // Configure PB9(0b1011) and PB8(0b1000)
276
                                     // 0b1011
277
                                     //   MODE=11(Output mode, max speed 50 MHz) 
278
                                     //   CNF=10(Alternate function output Push-pull
279
                                     // 0b1000
280
                                     //   MODE=00(Input mode)
281
                                     //   CNF=10(Input with pull-up / pull-down)
282
                                     
283
    GPIOB->ODR |= 0x1UL << 8;        // PB8 Upll-up
284
  }
285
  
286
  if (remap == 3) {
287
    AFIO->MAPR   |= 0x00005000;      // set CAN remap
288
                                     // CAN_RX mapped to PD0, CAN_TX mapped to PD1 (available on 100-pin and 144-pin package)
289

290
    RCC->APB2ENR |= 0x20UL;          // Enable GPIOD clock
291
    GPIOD->CRL   &= ~(0xFFUL);       // Configure PD1(0b0000) and PD0(0b0000)
292
                                     // 0b0000
293
                                     //   MODE=00(Input mode)
294
                                     //   CNF=00(Analog mode)
295

296
    GPIOD->CRH   |= 0xB8UL;          // Configure PD1(0b1011) and PD0(0b1000)
297
                                     // 0b1000
298
                                     //   MODE=00(Input mode)
299
                                     //   CNF=10(Input with pull-up / pull-down)
300
                                     // 0b1011
301
                                     //   MODE=11(Output mode, max speed 50 MHz) 
302
                                     //   CNF=10(Alternate function output Push-pull
303
                                     
304
    GPIOD->ODR |= 0x1UL << 0;        // PD0 Upll-up
305
  }
306

307
  CAN1->MCR |= 0x1UL;                   // Require CAN1 to Initialization mode 
308
  while (!(CAN1->MSR & 0x1UL));         // Wait for Initialization mode
309

310
  //CAN1->MCR = 0x51UL;                 // Hardware initialization(No automatic retransmission)
311
  CAN1->MCR = 0x41UL;                   // Hardware initialization(With automatic retransmission)
312
   
313
  // Set bit timing register 
314
  CAN_bit_timing_config_t timings;
315
  Serial.print("bitrate=");
316
  Serial.println(bitrate);
317
  uint32_t target_bitrate = SPEED[bitrate];
318
  Serial.print("target_bitrate=");
319
  Serial.println(target_bitrate);
320
  int result = ComputeCANTimings(HAL_RCC_GetPCLK1Freq(), target_bitrate, &timings);
321
  Serial.print("ComputeCANTimings result=");
322
  Serial.println(result);
323
  if (result) while(true);  
324
  CAN1->BTR = (((timings.resynchronization_jump_width - 1U) &    3U) << 24U) |
325
              (((timings.time_segment_1 - 1U)               &   15U) << 16U) |
326
              (((timings.time_segment_2 - 1U)               &    7U) << 20U) |
327
              ((timings.baud_rate_prescaler - 1U)           & 1023U);
328

329
  // Configure Filters to default values
330
  CAN1->FMR  |=   0x1UL;                // Set to filter initialization mode
331
  CAN1->FMR  &= 0xFFFFC0FF;             // Clear CAN2 start bank
332

333
  // bxCAN has 28 filters.
334
  // These filters are shared by both CAN1 and CAN2.
335
  // STM32F103 has only CAN1, so all 28 are used for CAN1
336
  CAN1->FMR  |= 0x1C << 8;              // Assign all filters to CAN1
337

338
  // Set fileter 0
339
  // Single 32-bit scale configuration 
340
  // Two 32-bit registers of filter bank x are in Identifier Mask mode
341
  // Filter assigned to FIFO 0 
342
  // Filter bank register to all 0
343
  CANSetFilter(0, 1, 0, 0, 0x0UL, 0x0UL); 
344
  
345
  CAN1->FMR   &= ~(0x1UL);              // Deactivate initialization mode
346

347
  uint16_t TimeoutMilliseconds = 1000;
348
  bool can1 = false;
349
  CAN1->MCR   &= ~(0x1UL);              // Require CAN1 to normal mode 
350

351
  // Wait for normal mode
352
  // If the connection is not correct, it will not return to normal mode.
353
  for (uint16_t wait_ack = 0; wait_ack < TimeoutMilliseconds; wait_ack++) {
354
    if ((CAN1->MSR & 0x1UL) == 0) {
355
      can1 = true;
356
      break;
357
    }
358
    delayMicroseconds(1000);
359
  }
360
  //Serial.print("can1=");
361
  //Serial.println(can1);
362
  if (can1) {
363
    Serial.println("CAN1 initialize ok");
364
  } else {
365
    Serial.println("CAN1 initialize fail!!");
366
    return false;
367
  }
368
  return true; 
369
}
370

371

372
#define STM32_CAN_TIR_TXRQ              (1U << 0U)  // Bit 0: Transmit Mailbox Request
373
#define STM32_CAN_RIR_RTR               (1U << 1U)  // Bit 1: Remote Transmission Request
374
#define STM32_CAN_RIR_IDE               (1U << 2U)  // Bit 2: Identifier Extension
375
#define STM32_CAN_TIR_RTR               (1U << 1U)  // Bit 1: Remote Transmission Request
376
#define STM32_CAN_TIR_IDE               (1U << 2U)  // Bit 2: Identifier Extension
377

378
#define CAN_EXT_ID_MASK                 0x1FFFFFFFU
379
#define CAN_STD_ID_MASK                 0x000007FFU
380
 
381
/**
382
 * Decodes CAN messages from the data registers and populates a 
383
 * CAN message struct with the data fields.
384
 * 
385
 * @preconditions A valid CAN message is received
386
 * @params CAN_rx_msg - CAN message structure for reception
387
 * 
388
 */
389
void CANReceive(CAN_msg_t* CAN_rx_msg)
390
{
391
  uint32_t id = CAN1->sFIFOMailBox[0].RIR;
392
  if ((id & STM32_CAN_RIR_IDE) == 0) { // Standard frame format
393
      CAN_rx_msg->format = STANDARD_FORMAT;;
394
      CAN_rx_msg->id = (CAN_STD_ID_MASK & (id >> 21U));
395
  } 
396
  else {                               // Extended frame format
397
      CAN_rx_msg->format = EXTENDED_FORMAT;;
398
      CAN_rx_msg->id = (CAN_EXT_ID_MASK & (id >> 3U));
399
  }
400

401
  if ((id & STM32_CAN_RIR_RTR) == 0) { // Data frame
402
      CAN_rx_msg->type = DATA_FRAME;
403
  }
404
  else {                               // Remote frame
405
      CAN_rx_msg->type = REMOTE_FRAME;
406
  }
407

408
  
409
  CAN_rx_msg->len = (CAN1->sFIFOMailBox[0].RDTR) & 0xFUL;
410
  
411
  CAN_rx_msg->data[0] = 0xFFUL &  CAN1->sFIFOMailBox[0].RDLR;
412
  CAN_rx_msg->data[1] = 0xFFUL & (CAN1->sFIFOMailBox[0].RDLR >> 8);
413
  CAN_rx_msg->data[2] = 0xFFUL & (CAN1->sFIFOMailBox[0].RDLR >> 16);
414
  CAN_rx_msg->data[3] = 0xFFUL & (CAN1->sFIFOMailBox[0].RDLR >> 24);
415
  CAN_rx_msg->data[4] = 0xFFUL &  CAN1->sFIFOMailBox[0].RDHR;
416
  CAN_rx_msg->data[5] = 0xFFUL & (CAN1->sFIFOMailBox[0].RDHR >> 8);
417
  CAN_rx_msg->data[6] = 0xFFUL & (CAN1->sFIFOMailBox[0].RDHR >> 16);
418
  CAN_rx_msg->data[7] = 0xFFUL & (CAN1->sFIFOMailBox[0].RDHR >> 24);
419

420
  // Release FIFO 0 output mailbox.
421
  // Make the next incoming message available.
422
  CAN1->RF0R |= 0x20UL;
423
}
424
 
425
/**
426
 * Encodes CAN messages using the CAN message struct and populates the 
427
 * data registers with the sent.
428
 * 
429
 * @params CAN_tx_msg - CAN message structure for transmission
430
 * 
431
 */
432
void CANSend(CAN_msg_t* CAN_tx_msg)
433
{
434
  volatile int count = 0;
435

436
  uint32_t out = 0;
437
  if (CAN_tx_msg->format == EXTENDED_FORMAT) { // Extended frame format
438
      out = ((CAN_tx_msg->id & CAN_EXT_ID_MASK) << 3U) | STM32_CAN_TIR_IDE;
439
  }
440
  else {                                       // Standard frame format
441
      out = ((CAN_tx_msg->id & CAN_STD_ID_MASK) << 21U);
442
  }
443

444
  // Remote frame
445
  if (CAN_tx_msg->type == REMOTE_FRAME) {
446
      out |= STM32_CAN_TIR_RTR;
447
  }
448

449
  CAN1->sTxMailBox[0].TDTR &= ~(0xF);
450
  CAN1->sTxMailBox[0].TDTR |= CAN_tx_msg->len & 0xFUL;
451
  
452
  CAN1->sTxMailBox[0].TDLR  = (((uint32_t) CAN_tx_msg->data[3] << 24) |
453
                               ((uint32_t) CAN_tx_msg->data[2] << 16) |
454
                               ((uint32_t) CAN_tx_msg->data[1] <<  8) |
455
                               ((uint32_t) CAN_tx_msg->data[0]      ));
456
  CAN1->sTxMailBox[0].TDHR  = (((uint32_t) CAN_tx_msg->data[7] << 24) |
457
                               ((uint32_t) CAN_tx_msg->data[6] << 16) |
458
                               ((uint32_t) CAN_tx_msg->data[5] <<  8) |
459
                               ((uint32_t) CAN_tx_msg->data[4]      ));
460

461
  // Send Go
462
  CAN1->sTxMailBox[0].TIR = out | STM32_CAN_TIR_TXRQ;
463

464
  // Wait until the mailbox is empty
465
  while(CAN1->sTxMailBox[0].TIR & 0x1UL && count++ < 1000000);
466

467
  // The mailbox don't becomes empty while loop
468
  if (CAN1->sTxMailBox[0].TIR & 0x1UL) {
469
    Serial.println("Send Fail");
470
    Serial.println(CAN1->ESR);
471
    Serial.println(CAN1->MSR);
472
    Serial.println(CAN1->TSR);
473
  }
474
}
475

476
 /**
477
 * Returns whether there are CAN messages available.
478
 *
479
 * @returns If pending CAN messages are in the CAN controller
480
 *
481
 */
482
uint8_t CANMsgAvail(void)
483
{
484
  // Check for pending FIFO 0 messages
485
  return CAN1->RF0R & 0x3UL;
486
}
OP #7350518
Lesenswert?

fuck schrieb:

Fuck!

Lese den Anhang, verstehe ihn, verinnerliche ihn und handle danach. Kann man so blöd sein nicht zu verstehen wie dein Posting die anderen sehen?

"Längerer Sourcecode" ist es wenn man dauernd scrollen muss um alles zu sehen. Dein Sourcecode ist länger!

Hallo Fuck,

das ist eine Definitionsfrage ;-)

Danke für den Hinweis, werde mich in Zukunft daran halten. Wenn ich nicht zu blöd bin....

OP #7356696
Lesenswert?

Hallo Jens,

ja hatte ich gesehen. Das ist selbstverständlich weg wenn ich das erste typedef struct aus der Datei lösche. Die frage die ich mir stelle ist: muss das struct in der .h oder der . ccp Datei sein? Egal in welcher Datei ich das auskommentiere der "conflicting declaration" Fehler ist weg, was aber bleibt ist der Hauptfehler "CAN1 was not declared in this scope"

Gruß

Kay

#7356774
Lesenswert?

Kay L. schrieb:

muss das struct in der .h oder der . ccp Datei sein?

Du willst diesen Typ auch im Hauptprogramm zur Verfügung haben, damit du CAN-Nachrichten überhaupt senden und empfangen kannst. Also in die .h-Datei.

Kay L. schrieb:

was aber bleibt ist der Hauptfehler "CAN1 was not declared in this scope"

Das passiert auf meinem Rechner nicht, wenn ich für BluePill F103C6 (32K) oder Generic F103C6Tx übersetze. Welche Version der Arduino-IDE und des STM32-Support für die Arduino-IDE hast du installiert? Bei mir sind es Arduino 1.8.19 und darin STM32 2.4.0 ...

LG, Sebastian

#7356779
Lesenswert?

Ok. Der Fehler wird in der ersten Zeile erzeugt, welche irgend etwas CAN spezifisches beinhaltet. Es hat also nichts explizit mit dem "CAN1" zu tun sondern vermutlich mit grundsätzlichen.

Arbeitest du in der Arduino Umgebung oder nutzt du einen anderen Editor?

Weil es jetzt Sinn machen würde sich durch die "Arduino.h" zu hangeln und zu schauen welchen Controller und damit welche Definitionen dazu wirklich verlinkt werden. Die ganzen CAN Registernamen welche in deinem Code auftauchen sind jedenfalls nicht jene, wie sie in der STM HAL genutzt werden. Wobei der Arduino STM32 Core eigentlich die HAL nutzt.

Hast du als "Controller" auch einen ausgewählt der CAN hat?

Sorry, wenn es da tiefer in den Arduino-Core bin ich wieder raus. Dein Beispiel von weiter oben müsste ich mir mal anschauen, wo der die CAN Definitionen her holt.

Beitrag #7357116 wurde von einem Moderator gelöscht.
OP #7357150
Lesenswert?

Sebastian W. schrieb:

Das passiert auf meinem Rechner nicht, wenn ich für BluePill F103C6 (32K) oder Generic F103C6Tx übersetze. Welche Version der Arduino-IDE und des STM32-Support für die Arduino-IDE hast du installiert? Bei mir sind es Arduino 1.8.19 und darin STM32 2.4.0 ...

meine IDE ist auch 1.8.19. Meinst Du mit STM32 2.4.0 den Boardverwalter? Da hab ich den STM32F1xx/GD32F1xx boards Version 2021.5.31

Jens R. schrieb:

Arbeitest du in der Arduino Umgebung oder nutzt du einen anderen Editor?

ich arbeite in der Arduino IDE

Zusatz von meiner Seite, ich vermute fast ich hab irgend etwas nicht installiert. ich habe die original Arduino-STM32-CAN in eine IDE auf einem anderen Rechner kopiert. Exakt die selbe Fehlermeldung. Dort ist wohl eine neuere IDE installiert 2.0.0

Angehängte Dateien:
#7357209
Lesenswert?

Kay L. schrieb:

Meinst Du mit STM32 2.4.0 den Boardverwalter? Da hab ich den STM32F1xx/GD32F1xx boards Version 2021.5.31

Ok, ich glaube ich verstehe jetzt warum bei dir die Übersetzung fehlschlägt.

Ich muss allerdings vorausschicken, dass ich erst vor zwei Wochen angefangen habe mich mit den STM32-Prozessoren und deren Programmierung zu beschäftigen.

Es scheint so, dass es zwei Arduino-IDE-Erweiterungen für die Programmierung der STM32-Prozessoren gibt.

Zum einen ist da (A) https://github.com/rogerclarkmelbourne/Arduino_STM32. Diese Umgebung kann über die Boardverwalter-URL http://dan.drown.org/stm32duino/package_STM32duino_index.json der Arduino-IDE hinzugefügt werden, und ergänzt den Boardverwalter dann um "STM32F1xx/GD32F1xx boards by stm32duino" und um "STM32F4xx boards by stm32duino".

Zum anderen gibt es (B) https://github.com/stm32duino/Arduino_Core_STM32. Diese Umgebung kann über die Boardverwalter-URL https://github.com/stm32duino/BoardManagerFiles/raw/main/package_stmicroelectronics_index.json der Arduino-IDE hinzugefügt werden, und ergänzt den Boardverwalter dann um "STM32 MCU based boards by STMicroelectronics".

Stefan hat die Geschichte dahinter unter http://stefanfrings.de/stm32/stm32f1.html ein wenig erläutert.

Du hast (A) installiert. (A) unterstützt aber allem Anschein nach nicht die Programmierung des CAN-Busses, und ist auch generell die ältere und inzwischen weniger gepflegte Version. Ich habe (B) installiert. (B) wird von ST Microelectronics selbst gepflegt, scheint umfassender und aktueller zu sein, und enthält die für dein Projekt nötige Unterstützung von CAN1.

Wie gesagt, ich bin diesbezüglich nicht der Experte, aber aus meiner Perspektive solltest du überlegen, grundsätzlich auf (B) umzusteigen. Dabei könnte es eventuell natürlich nötig werden, einige deiner älteren Projekte entsprechend anzupassen. Vielleicht benutzt du auch in diesen anderen Projekten aber auch Zusatzbibliotheken die (A) voraussetzen? Das ist von hier aus schwierig zu beurteilen.

LG, Sebastian

OP #7357332
Lesenswert?

Hallo Sebastian,

Top klasse! Wo kann ich "gefällt mir" drücken ;-)

Es funktioniert!!!! Da wäre ich nie drauf gekommen.

Jetzt kompeliert er alles einwandfrei. Da kann ich endlich versuchen ne LED auf dem zweiten Board VIA CAN zum Leuchten zu bringen!

Vielen lieben Dank an dich und alle anderen die mir geholfen haben!

Das ich dann ggf alle Projekte anpassen ist ist nicht das Problem. Da hätte ich sowieso früher oder später nochmal ran gemusst, da ich heute vieles anders lösen würde als noch vor 2 Jahren! LG

Kay

OP #7357409
Lesenswert?

Ja gerne....

aber leider schlechte Nachrichten....

ein kleiner sketch:

1
#include "stm32f103.h"  // 
2
const int Taster = PB6;
3
int TasterState = 0;
4

5
const int LED = PA0;
6
const int LED2 = PA3;
7
void setup()
8
{
9
  pinMode(LED_BUILTIN, OUTPUT);  //LED auf Arduino auf HIGH
10
  // --------------------------------------  pinMode
11
  pinMode(Taster, INPUT);
12
  pinMode(LED, OUTPUT);
13
  pinMode(LED2, OUTPUT);
14
  // CAN aktivieren
15
 {
16
 Serial.begin(115200);
17
  bool ret = CANInit(CAN_500KBPS, 2);  // CAN_RX to PB8, CAN_TX to PB9
18
  if (!ret) while (true);
19
 }
20
}
21
void loop()
22
{
23
  digitalWrite(LED2, HIGH);
24
  TasterState = digitalRead(Taster);    // Taster abfragen
25
  if (TasterState == LOW)
26
  {
27
    digitalWrite(LED, LOW);
28
  }
29
  else
30
  {
31
    digitalWrite(LED, HIGH);
32
  }
33
}

der nur funktionier, wenn ich von "Seriel.begin" bis "while (true);" auskommentiere. Dann Leuchtet LED 2 und LED1 lässt sich über den schalter ein und ausmachen. Auch LED_BUILDIN leuchtet so wie es sein soll

Bleiben die Zeilen aktiv, leuchtet nur die LED_Buildin, die im void setup angeschaltet wird, die anderen beiden nicht. alles was im Sketch nach Seriel.begin kommt wird ignoriert

#7358129
Lesenswert?

Kay L. schrieb:

aber leider schlechte Nachrichten....

Hast du denn den Tranceiver schon angeschlossen? Ansonsten kann es gut sein, dass CANInit fehlschlägt, und dann führst du ja eine Endlosschleife in setup() aus und loop() wird überhaupt nicht betreten. Setze in stm32f103.cpp mal DEBUG auf 1, dann sollte während CANInit auf Serial einiges an Informationen erscheinen.

Mir kommen auch die Bezeichner PB6, PA0, PA3 im Zusammenhang mit pinMode, digitalWrite und digitalRead sehr komisch vor. An der Stelle sollten eigentlich Bezeichner der Art D5 verwendet werden. Wie sieht dein Aufbau genau aus? Wie sind die digitalen Ein- und Ausgänge bezeichnet?

LG, Sebastian

#7358267
Lesenswert?

Sebastian W. schrieb:

Hast du denn den Tranceiver schon angeschlossen? Ansonsten kann es gut sein, dass CANInit fehlschlägt, und dann führst du ja eine Endlosschleife in setup() aus und loop() wird überhaupt nicht betreten.

Ich hab das hier mal mit meinem STM32F303 nachvollzogen. CANInit() funktioniert auch ohne angeschlossenen Transceiver. Da ist bei dir doch irgendwo ziemlich grundsätzlich noch der Wurm drin.

LG, Sebastian

OP #7358626
Lesenswert?

Sebastian W. schrieb:

Mir kommen auch die Bezeichner PB6, PA0, PA3 im Zusammenhang mit pinMode, digitalWrite und digitalRead sehr komisch vor. An der Stelle sollten eigentlich Bezeichner der Art D5 verwendet werden. Wie sieht dein Aufbau genau aus? Wie sind die digitalen Ein- und Ausgänge bezeichnet?

PB6, PA8, PA3 kommen aus dem STM Datenblatt: https://www.alldatasheet.com/datasheet-pdf/pdf/201596/STMICROELECTRONICS/STM32F103C8T6.html

Ab Seite 18 in der Tabelle. Ich hab ja auch schon mehrere Programme exakt so geschrieben nur beim CAN hab ich diese Probleme.

ich habs mit und ohne Transiver versucht, ebenso mit einem anderen Bluepill Board. Mit einem Logiganalyser habe ich RX dauerhaft High und TX dauerhaft 0. (gemessen direkt am Arduino vor dem Transiver.

Das "Problem" hab ich auch mal unserem Entwicklungsleiter geschrieben (er hat mich auf STM und CAN gebracht) vielleicht hat er eine Idee.

Dir trotzdem vielen Dank für die Mühe. Sobald sich irgendwas ergibt melde ich mich

Gruß

Kay

#7359160
Lesenswert?

Sebastian W. schrieb:

Sebastian W. schrieb:

Hast du denn den Tranceiver schon angeschlossen? Ansonsten kann es gut sein, dass CANInit fehlschlägt, und dann führst du ja eine Endlosschleife in setup() aus und loop() wird überhaupt nicht betreten.

Ich hab das hier mal mit meinem STM32F303 nachvollzogen. CANInit() funktioniert auch ohne angeschlossenen Transceiver. Da ist bei dir doch irgendwo ziemlich grundsätzlich noch der Wurm drin.

Mmh. Ohne Transceiver liefert bei meinem STM32F303 mit angeschlossenem Logikanalysator an PA11 und PA12 CANInit() plötzlich "CAN1 initialize fail!!" und false zurück. Ziehe ich den Logikanalysator ab erhalte ich "CAN1 initialize ok" und true.

Eine der zwei möglichen Meldungen solltest du aber in jedem Fall erhalten. Lösch auch mal die Zeile "if (!ret) while (true);". Dann sollte nach der Medung "CAN1 initialize fail!!" zumindest trotzdem deine loop()-Funktion mit Taster und LED betreten werden.

Kay L. schrieb:

ich habs mit und ohne Transiver versucht, ebenso mit einem anderen Bluepill Board. Mit einem Logiganalyser habe ich RX dauerhaft High und TX dauerhaft 0. (gemessen direkt am Arduino vor dem Transiver.

Mmh. CAN_RX ist ja ein Eingang und also ohne angeschlossenen Transceiver undefiniert. Aber bei geht ohne angeschlossenen Transceiver CAN_TX nach der Initialisierung auf dauerhaft High. CAN_TX ist bei dir PB9, und dort ist der D-Pin des SN65HVD230 angeschlossen?

Es besteht ja auch immer noch die Möglichkeit, dass dein F103 kein original STM32 ist. Bei den Nachbauten scheint ja oft gerade die CAN-Unterstützung zu fehlen oder fehlerhaft zu sein ...

LG, Sebastian

OP #7359827
Lesenswert?

Hallo Sebastian,

das es sich ggf nicht um STM32 original handelt hatte ich auch schon in Betracht gezogen und hab mir die am Samstag abend genauer angesehen, das ST Micro Logo ist drauf also kein Nachbau sondern, wenn, dann eine Fälschung. Mir ist dabei aber eine andere Abweichung aufgefallen. Drauf sein sollte der STM32F103C8xx verbaut ist aber STM32F103C6xx ob das der Grund sein kann kann ich so erstmal nicht sagen, ich habe mir aber zumindest bei AZ Delivery einen neuen Blue Pill mit C8 bestellt. Mal sehen ob es damit funktioniert

Danke und Gruß

Kay

OP #7362275
Lesenswert?

Soderle,

der C8 ist angekommen und getestet, selbes Ergebnis. Es liegt also nicht an der Chip version.

lösche ich "if (!ret) while (true);" bleibt der Code ebenfalls stehen, lösche ich " bool ret = CANInit(CAN_500KBPS, 0); " dabei ist egal ob ",0" oder ",2" läuft der Code weiter und die LED´s gehen wie gewünscht an.

Ein anderer Gedanke kam mir, ich programmiere mit den ST LinkV2 und nicht über die Arduino IDE, könnte das damit zusammen hängen?

Gruß

Kay

#7362378
Lesenswert?

Kay L. schrieb:

lösche ich " bool ret = CANInit(CAN_500KBPS, 0); " dabei ist egal ob ",0" oder ",2" läuft der Code weiter und die LED´s gehen wie gewünscht an.

Dann schlägt die CANInit fehl. Höchstwahrscheinlich hier:

1
  bool can1 = false;
2
  CAN1->MCR   &= ~(0x1UL);        // Require CAN1 to normal mode 
3
  // Wait for normal mode
4
  // If the connection is not correct, it will not return to normal mode.
5
  for (uint16_t wait_ack = 0; wait_ack < TimeoutMilliseconds; wait_ack++) {
6
    if ((CAN1->MSR & 0x1UL) == 0) {
7
      can1 = true;
8
      break;
9
    }

Das Datenblatt sagt dazu:

The request to enter Normal mode is issued by clearing the INRQ bit in the CAN_MCR register (-> Zeile 2). The bxCAN enters Normal mode and is ready to take part in bus activities when it has synchronized with the data transfer on the CAN bus. This is done by waiting for the occurrence of a sequence of 11 consecutive recessive bits (Bus Idle state). The switch to Normal mode is confirmed by the hardware by clearing the INAK bit in the CAN_MSR register.

Evtl. ist dein Bus nicht im Idle-State und der CAN-Controller verweigert deshalb den Normal Mode? Hast du einen zweiten Teilnehmer am Bus der auch funktioniert?

#7362469
Lesenswert?

Hallo Kay,

ich empfehle die systematisch vorzugehen:

  1. Setze in stm32f103.cpp mal DEBUG auf 1, dann sollte während CANInit auf Serial einiges an Informationen erscheinen.

  2. Zeig mal ein Foto von deinem Testaufbau mit Anschluß des Transceivers.

  3. Mach auch noch ein Foto der STM32, möglichst mit Licht von der Seite so dass man den Aufdruck gut erkennen kann.

Ich meine in der stm32f103.cpp auch noch einen Fehler entdeckt zu haben. In

1
bool CANInit(BITRATE bitrate, int remap)

wird für

1
remap==0

folgende Zeile ausgeführt:

1
    GPIOA->ODR |= 0x1UL << 12;       // PA12 Upll-up

PA12 ist aber der CAN_TX Ausgang, da macht ein Pull-up gar keinen Sinn. Ich meine daher, dort müsste stattdessen folgendes hin:

1
    GPIOA->ODR |= 0x1UL << 11;       // PA11 Pull-up

Dieses kleine Problem gilt nur für PA11, nicht für PB8, dort ist der Code korrekt. Das Problem spielt auch gar keine Rolle mehr sobald ein Transceiver angeschlossen ist, weil der seinen "R"-Ausgang treibt und damit den Pegel an PA11 definiert.

LG, Sebastian

OP #7365767
Lesenswert?

Soderle, ich glaube ich komme dem Übeltäter immer näher.

ich habe die Datei von Github komplett in meinen Sketch integriert, also nicht als geteilete .h. und .cpp Datei.

Dabei bleibt der Code nicht stehen. Die LED´s mach was sie sollen. Also muß ich beim "zerteilen" einen Bock eingebaut haben. Ich hab das jetzt zig mal kontrolliert finde aber keinen. Kann mal jemand schauen?

STM32_ino.txt ist die original Datei von Github. Die hab ich dann zerlegt und wie oben beschrieben geändert: stm32f103.cpp und stm32f103.h

Meine .ino Date: CAN2_1.txt

Ich hab die Ino dateien nur als txt hier hochgeladen, damit die jeder einsehen kann

LG Kay

Angehängte Dateien:
#7365865
Lesenswert?

Kay L. schrieb:

Also muß ich beim "zerteilen" einen Bock eingebaut haben. Ich hab das jetzt zig mal kontrolliert finde aber keinen. Kann mal jemand schauen?

In stm32f103.h ist ein Fehler. Die Deklaration von BITRATE muss so lauten:

1
typedef enum {CAN_50KBPS, CAN_100KBPS, CAN_125KBPS, CAN_250KBPS, CAN_500KBPS, CAN_1000KBPS} BITRATE;

In dem Vorschlag von mir oben waren noch zusätzliche Bitraten enthalten, sorry.

Ich habe auch noch eine erste Zeile #pragma once dazugefügt.

LG, Sebastian

Angehängte Dateien:
OP #7365878
Lesenswert?

Hallo Sebastian,

nun blockiert der Code nicht mehr. Top Danke. Und Du brauchst dich nicht entschuldigen. Du hilfst mir sehr weiter. Fehlersuche bildet :-) Hab ich wieder was gelernt.

Jetzt brauch ich nur noch kommentierungen was in welcher Zeile der VOID LOOP passiert dann sollte ich der Sache langsam aber stetig auf den Grund kommen.

Nochmals vielen leiben Dank!

LG

kay

#7365886
Lesenswert?

Kay L. schrieb:

vielleicht kann jemand mir die Zeilen in der VOID_loop_CAN.txt kommentieren, damit ich verstehe, was in den einzelnen Zeilen geschieht

Ich mach das mal mit CAN2_1.txt, weil VOID_loop_CAN.txt nicht vollständig ist.

Zeile 13: counter zählt bei jedem Versand einer Nachricht hoch.

Zeile 14: Es werden später CAN-Nachrichten verschiedener Länge versandt. In frameLength steht wie lang die nächste Nachricht sein soll.

Zeilen 41-52: CAN_TX_msg wird initial partiell befüllt.

Zeilen 54-56: Es wird alle interval Millisekunden etwas getan.

Zeilen 57-67: Der Rest der CAN_TX_msg wird befüllt. Wenn counter eine gerade Zahl ist, wird das EXTENDED_FORMAT und die ID 0x32F103 gewählt, sonst das STANDARD_FORMAT in die ID 0x103. Ausserdem wird bei CAN_TX_msg.len 0 ein REMOTE_FRAME gesendet, ansonsten ein DATA_FRAME. Es sollen hier halt einfach nur verschiedene Arten von CAN-Nachrichten mal testweise erzeugt werden. Für die Details kuck bei https://de.wikipedia.org/wiki/Controller_Area_Network.

Zeile 68: Die vorbereitete Nachricht wird an die Sende-Hardware zum Senden übergeben.

Zeilen 69-71: Die Zähler werden erhöht.

Zeile 74: Es wird geprüft ob eine empfangene Nachricht bereitliegt.

Zeile 75: Die Nachricht wird aus Empfangshardware abgeholt.

Zeilen 77-108: Die empfangene Nachricht wird auf Serial ausgegeben.

HTH.

LG, Sebastian

#7365899
Lesenswert?

Kay L. schrieb:

Fehlersuche bildet :-) Hab ich wieder was gelernt.

Durch die zusätzlichen Einträge ist dein gewählter CAN_500KBPS Wert nach hinten verschoben worden und hat den Wert 6 bekommen. CANInit holt sich die target_bitrate unter diesem index aus dem SPEED-Array, und der hat nur 6 Einträge. SPEED[6] liegt also hinter dem Array, und der Wert dort im Speicher ist irgend etwas. ComputeCANTimings schlägt dann wahrscheinlich fehl, gibt eine Fehlermeldung aus, und läuft in diese "if (result) while(true)" Endlosschleife in stm32f103.cpp Zeile 340.

LG, Sebastian

OP #7374845
Lesenswert?

Hallo Sebastian,

erstmal sorry das ich mich nicht gemeldet habe, aber ich musste mir einen neuen Rechner zulegen und es war nicht ganz so einfach alles wieder neu aufzusetzen.

ich habe noch ein paar Fragen:

Ich möchte zunächst nur den Zustand einer Variable übertragen. Kann ich das so senden:

1
CAN_msg_t CAN_TX_msg;                 //  CAN_TX_msg wird initial partiell befüllt. Daten die versendet werden sollen Begin Nachricht
2
    CAN_msg_t CAN_RX_msg;
3
    if (LEDAN == false)CAN_TX_msg.data[0] = 0x00;
4
    if (LEDAN == true) CAN_TX_msg.data[0] = 0x01;
5
    CAN_TX_msg.len = frameLength;         // Daten die versendet werden sollen ende / Ende Nachricht

Mir ist die Empfangsseite nicht ganz klar da im Beispiel die Nachricht mit der ID "0x32F103" versehen wird muss am Empfänger ja nach eben dieser gefragt (bzw verglichen werden) reicht eventuell:

1
if   (CAN_RX_msg.id == 0x32F103)

könnte ich da die Daten wieder in die Variable zurückwandeln? zB

1
if (CAN_RX_msg.type == DATA_FRAME)
2
{
3
if (CAN_TX_msg.data[0] == 0x00) LEDAN = false;
4
if (CAN_TX_msg.data[0] == 0x01) LEDAN = true;
5
}

LG

Kay

#7374883
Lesenswert?

Kay L. schrieb:

Kann ich das so senden:

1
     CAN_msg_t CAN_TX_msg; 
2
     CAN_msg_t CAN_RX_msg;
3

4
     if (LEDAN == false)CAN_TX_msg.data[0] = 0x00;
5
     if (LEDAN == true) CAN_TX_msg.data[0] = 0x01;
6
     CAN_TX_msg.len = frameLength;  // wird das auch befüllt?
7

8
// Da fehlt noch mindestens:
9

10
     CAN_TX_msg.id = 0x[irgendwas];
11
     CANSend(&CAN_TX_msg);
1
 if (CAN_RX_msg.type == DATA_FRAME)
2

3
 if (CAN_TX_msg.data[0] == 0x00) LEDAN = false;
4
        ^^^ Da sollte schon auch RX stehen...
#7374945
Lesenswert?

Kay L. schrieb:

Kann ich das so senden:

Im Prinzip ja. CAN_TX_msg.len, also die Länge des Datenbereichs der CAN-Nachricht, ist bei dir immer genau 1 und sollte also auch mit 1 intialisiert werden. CAN_TX_msg.id, CAN_TX_msg.type und CAN_TX_msg.format sollten auch noch gesetzt werden. Und CAN_TX_msg.data[0] kann man auch weniger umständlich füllen :)

Kay L. schrieb:

könnte ich da die Daten wieder in die Variable zurückwandeln?

Im Prinzip ja. Auch das Auslesen von CAN_RX_msg.data[0] geht etwas weniger umständlich. Ich würde auch wenigstens noch prüfen dass CAN_RX_msg.len zumindest >=1 ist, aber dass sind eher schon Details deines zu erstellenden Detailkonzepts von CAN-Nachrichten.

LG, Sebastian

OP #7375267
Lesenswert?

Hallo zusammen,

vielen Dank an alle die mir bis hierhin geholfen haben.

ich habe es geschafft der Zustand der ersten Variablen zu übertragen. Ich fühle mich wie Marconi :-)

Jetzt kann ich Schritt für Schritt weitermachen und verstehen, was passiert, wenn man dies ändert.

Ich halte euch auf dem laufenden bzw komme bei Fragen nochmal auf euch zu.

GLG

Kay

OP #7377259
Lesenswert?

Hallo zusammen, Soderle da ist doch noch eine allgemeine Frage zu CAN aufgetaucht.

Da nicht ständig gesendet werden muß (und auch soll) sondern nur wenn eine Änderung des Zustandes eingetreten ist, reicht es wenn ich im Sketch einmal sende? z.B.:

1
 if (next_state_Lichtschranke1 != akt_state_Lichtschranke1)  // ---------------vergleich ob sich der Status der Lichtschranke1 geändert hat
2
{
3
// Hier dann senden der CAN nachricht
4
}

Sprich wird die Rückmeldung, ob die Nachricht angekommen ist über die Hardware (Transiver) geregelt?

Gruß

Kay

#7377496
Lesenswert?

Kay L. schrieb:

Da nicht ständig gesendet werden muß (und auch soll) sondern nur wenn eine Änderung des Zustandes eingetreten ist

Bei CAN macht man es üblicherweise genau anders: Der Sender sendet zyklisch, z.B alle 100ms, immer wieder seine aktuellen Daten. Der oder die Empfänger lesen die Daten, entscheiden ob sich für sie etwas geändert hat und ob deshalb etwas zu tun ist. Das hat den Vorteil dass Empfänger die mal eine Nachricht verpasst haben dann beim nächsten Sendezyklus die aktuellen Daten auch noch bekommen.

Sprich wird die Rückmeldung, ob die Nachricht angekommen ist über die Hardware (Transiver) geregelt?

Ein CAN-Empfänger sendet am Ende der gerade empfangenen Botschaft das ACK-Bit an den Empfänger zurück. Der Empfänger weiß somit dass mindestens ein Empfänger seine Botschaft "quittiert" hat. Der Transceiver hat damit wenig zu tun, der leitet ja nur die Bits weiter.

OP #7377549
Lesenswert?

Thomas F. schrieb:

Kay L. schrieb:

Da nicht ständig gesendet werden muß (und auch soll) sondern nur wenn eine Änderung des Zustandes eingetreten ist

Bei CAN macht man es üblicherweise genau anders: Der Sender sendet zyklisch, z.B alle 100ms, immer wieder seine aktuellen Daten. Der oder die Empfänger lesen die Daten, entscheiden ob sich für sie etwas geändert hat und ob deshalb etwas zu tun ist. Das hat den Vorteil dass Empfänger die mal eine Nachricht verpasst haben dann beim nächsten Sendezyklus die aktuellen Daten auch noch bekommen.

Erstmal danke, aber dann kann es doch passieren, das der Bus permanent belegt ist, wenn ich zB 100 Nachrichten mit oberster Priorität alle 100ms sende. Oder nicht?

#7377594
Lesenswert?

Kay L. schrieb:

Erstmal danke, aber dann kann es doch passieren, das der Bus permanent belegt ist, wenn ich zB 100 Nachrichten mit oberster Priorität alle 100ms sende. Oder nicht?

kann passieren, kommt natürlich auf die Bus-Geschwindigkeit an. Der "Architekt" des Busses überlegt sich das im Vorfeld und prüft ob die gewählte Baudrate das auch hergibt. Bei CAN heißt das dann "Bus-Last" und winrd in Prozent-Auslastung angegeben.

Ein 500kBit Bus langweilt sich mit 100 Botschaften im 0,1s Zyklus zu Tode.

OP #7377623
Lesenswert?

Thomas F. schrieb:

Kay L. schrieb:

Erstmal danke, aber dann kann es doch passieren, das der Bus permanent belegt ist, wenn ich zB 100 Nachrichten mit oberster Priorität alle 100ms sende. Oder nicht?

kann passieren, kommt natürlich auf die Bus-Geschwindigkeit an. Der "Architekt" des Busses überlegt sich das im Vorfeld und prüft ob die gewählte Baudrate das auch hergibt. Bei CAN heißt das dann "Bus-Last" und winrd in Prozent-Auslastung angegeben.

Ein 500kBit Bus langweilt sich mit 100 Botschaften im 0,1s Zyklus zu Tode.

OK Danke für den "Kernsatz" am Schluß ;-)

#7377705
Lesenswert?

Beim CAN-Bus kann man ziemlich sicher sein dass eine Nachricht entweder zugestellt wird oder sie nicht zustellbar ist. Der Fall "nicht zustellbar" lässt sich evtl. auf Senderseite durch das Auslesen von speziellen Registern erkennen.

Aber "ziemlich sicher" ist nicht "ganz sicher". Wenn du ganz sicher sein möchtest, dann könnte z.B. der Empfänger nach Erhalt einer Nachricht eine Quittung an den Sender zurücksenden.

Ich mach es bei meinem Haus- und Gartenbus so, dass ich jede Statusänderung sofort melde, und dann noch jede Minute den vollen Status versende. Ausnahme ist das Aufspielen neuer Software über den CAN-Bus, dabei quittiere ich dem Sender jede einzelne Nachricht. Auch damit der Sender nicht zu schnell wird, denn das Beschreiben des Flash dauert ein wenig.

LG, Sebastian

OP #7377744
Lesenswert?

hallo Zusammen,

ich steuere damit meine Modellbahnalage. Zur Zeit gehe ich von 4 Prios aus:

  1. Sensoren die belegte oder Einfahrt eines Zuges melden (um Kollisionen zu vermeiden) also Fahrstreckenüberwachung
  2. Manuelle steuerung der Fahrstrecken (Geschwindigkeitsregelung oder Weichenschaltung sowie Daten für die Anzeigemodule
  3. Sensoren in der Landschaft , Häuserbeleuchtung knopfdruckaktionen usw.

Ich befürchte das bei ständigem senden von Prio 1 und Prio 2 Nachrichten kein "Platz" mehr für Prio drei ist.

#7377939
Lesenswert?

Kay L. schrieb:

Ich befürchte das bei ständigem senden von Prio 1 und Prio 2 Nachrichten kein "Platz" mehr für Prio drei ist.

Nicht fürchten, ausrechnen. Wenn du den CAN-Bus mit 500kHz fährst, passen pro Sekunde theoretisch 5000 Nachrichten a 100 Bit drauf. Die Nachrichten mit numerisch kleineren Ids bekommen auf dem Bus Priorität vor Nachrichten mit höheren Ids.

LG, Sebastian

OP #7378227
Lesenswert?

Hallo Sebastian,

dann passt das wenn ich "nur" alle 500mS sende. Es ist nicht schlimm wenn eine info um die Zeit verzögert ankommt.

Noch etwas, ich habe zwei Dinge gelesen:

  1. In den Datenbits werden nur 8 Zustande (0-7) akzeptiert? also 8-F wird ignoriert?

  2. mit dem 11 Bit Identifier sind nur 2048 Nachrichten eindeutig zu identifizieren? Müssten das nicht viel mehr sein?

Gruß

Kay

#7378235
Lesenswert?

Kay L. schrieb:

  1. In den Datenbits werden nur 8 Zustande (0-7) akzeptiert? also 8-F wird ignoriert?

Wo hast du denn das gelesen? Ein Datenbit kennt nur 2 Zustände, 0 und 1. Das Data-Segment einer CAN-Botschaft kann maximal 8 Daten-Bytes innerhalb einer CAN-Botschaft transportieren. Ausnahme:CAN-FD, aber lassen wir das vorerst.

  1. mit dem 11 Bit Identifier sind nur 2048 Nachrichten eindeutig zu identifizieren? Müssten das nicht viel mehr sein?

Warum, reicht doch? Die Kommunikation in modernen Autos kommt mit 11-Bit Identifiern aus.

#7378245
Lesenswert?

Kay L. schrieb:

In den Datenbits werden nur 8 Zustande (0-7) akzeptiert? also 8-F wird ignoriert?

Nein, das stimmt nicht. Höchstwahrscheinlich hast du da etwas missverstanden. Das Datenfeld besteht aus 0 bis 8 Bytes aus 8 Bits. Jedes Datenbyte kann jeden Wert zwischen 0 und 255 annehmen. Das Datenlängenfeld bestimmt die Anzahl der Datenbytes. Es ist zwar 4 Bit lang, darf aber nur Werte zwischen 0 und 8 annehmen, 9-15 sind nicht erlaubt.

Kay L. schrieb:

mit dem 11 Bit Identifier sind nur 2048 Nachrichten eindeutig zu identifizieren? Müssten das nicht viel mehr sein?

Wenn man Nachrichten numerieren möchte, dann sollte so eine Nummer wohl besser Teil der Datenbytes sein. Die Id wird meist für den Typ der Daten verwendet, auch weil man per Hardware auf Ids filtern kann. Aber wenn du lustig bist kannst du auch einen Teil der Id-Bits für Daten verwenden, die CAN-Bus-Spezifikation selbst hindert dich nicht daran ...

LG, Sebastian

OP #7380474
Lesenswert?

Hallo Zusammen,

ich habe nun ein wenig rumexperimentiert und steige so halbwegs durch.

bis jetzt übertrage ich nur zwei Zustände pro Datenbyte in etwa so:

Variable A = false dann CAN_TX_msg.data[0] = 0x00

Variable A = true dann CAN_TX_msg.data[0] = 0x01

Das klappt einwandfrei

Das bedeutet aber wiederum das ich nur 2 Variablen in data[0]übertragen kann.

Wenn ich das richtig versteh können aber die eigentlich daten digits (also die letzten beiden) 0 bis F annehmen (0x00 bis 0xFF) dann könnte ich den Zustand (0 oder 1) von 4 verschiedenen Lichtschranken pro Ziffer übertragen. für die letzte Ziffer in etwa so:

LS1 - LS2 - LS3 - LS4 0 - 0 - 0 - 1

würde 1 als letzte Ziffer ergeben

LS1 - LS2 - LS3 - LS4 1 - 1 - 1 - 1 würde F als letzte Ziffer ergeben.

Ich bekomme nur gerade nicht wirklich hin die 4 Zustände in eine Hex umzuwandeln, die ich übertragen kann.

Gruß

Kay

#7380556
Lesenswert?

Kay L. schrieb:

Ich bekomme nur gerade nicht wirklich hin die 4 Zustände in eine Hex umzuwandeln, die ich übertragen kann.

Du musst die vier Zustände in eine Zahl umwandeln. Hexadezimal oder Dezimal sind nur Darstellungsformen von Zahlen, die aber mit der Übertragung nichts zu tun haben.

Dazu muss man ein wenig Binärarithmetik veranstalten.

Also z.B zum Senden:

1
bool ls1 = true;
2
bool ls2 = false;
3
bool ls3 = false;
4
bool ls4 = true;
5
bool ls5 = false;
6

7
uint8_t val = (ls1<<0)|(ls2<<1)|(ls3<<2)|(ls4<<3)|(ls5<<4);
8

9
msg.data[0] = val;
10
CANSend ...

Und beim Empfang wieder auseinandergedröselt:

1
CANReceive ... msg
2
uint8_t val = msg.data[0];
3

4
bool ls1 = val&1;
5
bool ls2 = val&2;
6
bool ls3 = val&4;
7
bool ls4 = val&8;
8
bool ls5 = val&16;

LG, Sebastian

OP #7380961
Lesenswert?

Hallo Sebastian,

ich hab deinen Vorschlag auf meine Gegebenheiten abgeändert und dabei zunächst nur einen Wert in die val geschrieben.

Sender:

1
    CAN_msg_t CAN_TX_msg;                 //  CAN_TX_msg wird initialisiert
2
    CAN_msg_t CAN_RX_msg;                 //  CAN_RX_msg wird initialisiert
3
    LEDAN = true;
4
    uint8_t val =(LEDAN<<0);
5
    CAN_TX_msg.data[0] = val;
6
    CAN_TX_msg.len = frameLength;         // Daten die versendet werden sollen ende / Ende Nachricht
7
    unsigned long currentMillis = millis();    // alle intervall Millisekunden senden
8
    if (currentMillis - previousMillis >= interval)
9
    {
10
      previousMillis = currentMillis;
11
      if ( ( counter % 2) == 0)
12
      { // Der Rest der CAN_TX_msg wird befüllt
13
        CAN_TX_msg.type = DATA_FRAME;
14
        if (CAN_TX_msg.len == 0) CAN_TX_msg.type = REMOTE_FRAME;
15
        CAN_TX_msg.format = EXTENDED_FORMAT;
16
        CAN_TX_msg.id = 0x32F103;
17
      }
18
    
19
      CANSend(&CAN_TX_msg);           // Die vorbereitete Nachricht wird an die Sende-Hardware zum Senden übergeben.
20
      frameLength++;                  // Die Zähler werden erhöht.
21
      if (frameLength == 9) frameLength = 0;
22
      counter++;
23
    }

Empfänger:

1
    CAN_msg_t CAN_TX_msg;                //  CAN_TX_msg wird initialisiert
2
    CAN_msg_t CAN_RX_msg;               //  CAN_RX_msg wird initialisiert
3
    if (CANMsgAvail())
4
    { 
5
// Es wird geprüft ob eine empfangene Nachricht bereitliegt.
6
      CANReceive(&CAN_RX_msg);        // Die Nachricht wird aus Empfangshardware abgeholt.
7

8
      if (CAN_RX_msg.format == EXTENDED_FORMAT)
9
      {
10
        if (CAN_RX_msg.id == 0x32F103)
11
        {
12
          uint8_t val = CAN_RX_msg.data[0];
13
          bool LEDAN = val & 1;
14
        }
15

16
      }
17
    }

Es wird aber nichts übertragen..

#7381090
Lesenswert?

Du verwendest immer noch frameLength als Länge der gesendeten Daten? Und der Code bastelt auch immer noch mit REMOTE_FRAME rum? Und warum EXTENDED_FRAME und so hohe Id (0x32F103)? Da würde ich erst einmal alle Überbleibsel der Testanwendung rausräumen die du (noch) nicht brauchst.

LG, Sebastian

OP #7381121
Lesenswert?

Da ich mir nicht sicher war was ich davon ggf noch brauche hab ich es noch nicht rausgeworfen. Das wollte ich machen nachdem die Übertragung in Hex auch funktioniert. EXTENDED_FRAME bedeutet doch nur das ich eine höhere ID Zahl habe. Ich ändere das aber heute Abend ab. Auch die ID setze ich dann auf den kleinsten Wert zum Test. Ich melde mich dann wieder

Gruß

Kay

OP #7381887
Lesenswert?

Soderle, ich hab mal etwas zusammengestrichen und nur das nötigste drin gelassen (hoffe ich)Senderseite:

1
    CAN_msg_t CAN_TX_msg;                 //  CAN_TX_msg wird initial partiell befüllt. Daten die versendet werden sollen Begin Nachricht
2
    CAN_msg_t CAN_RX_msg;
3
    if (LEDAN == false)CAN_TX_msg.data[0] = 0x00;
4
    if (LEDAN == true) CAN_TX_msg.data[0] = 0x01;
5
    CAN_TX_msg.len = 1;         // Daten die versendet werden sollen ende / Ende Nachricht
6

7
    unsigned long currentMillis = millis();    // alle intervall Millisekunden senden
8
    if (currentMillis - previousMillis >= interval)
9
    {
10
      previousMillis = currentMillis;
11
      // Der Rest der CAN_TX_msg wird befüllt
12
      CAN_TX_msg.type = DATA_FRAME;
13
      CAN_TX_msg.format = STANDARD_FORMAT;
14
      CAN_TX_msg.id = 0x000001;
15
      CANSend(&CAN_TX_msg);           // Die vorbereitete Nachricht wird an die Sende-Hardware zum Senden übergeben.
16
     }

Empfängerseite:

1
    CAN_msg_t CAN_TX_msg;                 //  CAN_TX_msg wird initial partiell befüllt. Daten die versendet werden sollen Begin Nachricht
2
    CAN_msg_t CAN_RX_msg;
3
    if (CANMsgAvail())
4
    { // Es wird geprüft ob eine empfangene Nachricht bereitliegt.
5
      CANReceive(&CAN_RX_msg);        // Die Nachricht wird aus Empfangshardware abgeholt.
6
      if (CAN_RX_msg.id == 0x000001)
7
      {
8
        if (CAN_RX_msg.data[0] == 0x00) LEDAN = false;
9
        if (CAN_RX_msg.data[0] == 0x01) LEDAN = true;
10
      }
11
    }

leider funktioniert das nicht, die ID wird nicht erkannt. Erst wenn ich:

1
      else
2
      {
3
        if (CAN_RX_msg.data[0] == 0x00) LEDAN = false;
4
        if (CAN_RX_msg.data[0] == 0x01) LEDAN = true;
5
      }

im Empfänger zur if Abfrage einfüge wird die Info übertragen. Er erkennt also die ID 0x000001 nicht. Ich sehe aber gerade nicht, warum...

Gruß

Kay

OP #7382690
Lesenswert?

Hallo Sebastian,

wie meinst du das ? Es gibt nur eine Nachricht und die hat die ID 0x000001 . Es sind auch nur die zwei Telnehmer am Bus. Ich kann auch eine andere ID nehmen. Die Übertragung funktioniert immer nur wenn im Empfänger die else Schleife drin ist.

Oder meinst Du wie die Daten vom Logiganalyser aussehen?

einen Screenshot findets Du im Anhang

Gruß

Kay

Angehängte Dateien:
#7382693
Lesenswert?

Kay L. schrieb:

Die Übertragung funktioniert immer nur wenn im Empfänger die else Schleife drin ist.

Ich meine: Warum wird der else-Zweig betreten? Doch anscheinend weil im Empfänger die Id nicht 0x000001 ist. Was ist sie denn? Gib die Id mal auf die serielle Schnittstelle aus. Oder besser: Schreib dir eine Prozedur die generell eine CAN_msg_t komplett auf die serielle Schnittstelle ausgibt, und ruf die Prozedur direkt vor dem Senden und direkt nach dem Empfang auf.

LG, Sebastian

PS: Du benutzt die Saleae-Software? Die hat einen Analysator für CAN ...

OP #7382700
Lesenswert?

Ok Nun verstanden.

Da muß ich mal sehen ob das mit der seriellen Schnittstellenausgabe bei mir überhaupt geht, da ich nicht mit der Arduino Software das Board beschreibe sondern eine kompilierte Binärdatei exportiere und dann mit ST - LinkV2 auf den STM32 programmiere. Ich hab das noch nicht ausprobiert.

ja ich nutze Logic2 von saleae, wohl die Freewareversion. Bis Dato hab ich noch keinen CAN Analysator gefunden.

Gruß

Kay

OP #7382722
Lesenswert?

So CAN Analyser gefunden.

Screenshot anbei Ch1 ist TX am Sender. ist Async Serial die ID? dann ist die 0xFF und nicht 0x000001 was das verhalten erklären würde. Ich aber (noch) keinen blassen Schimmer habe warum die ID falsch ist.

Ausserdem zeigt er mir zweimal Error an.

ich muß jetzt leider weg. Ich werde morgen die funktionierenden Sketche in die STMs einprogramieren und erneut messen. Mal sehen ob die Fehler dann weg sind.

Und wieder mal, vielen Dank Sebastian.

Gruß

Kay

Angehängte Dateien:
#7382729
Lesenswert?

Kay L. schrieb:

Bis Dato hab ich noch keinen CAN Analysator gefunden.

Siehe Bild.

Kay L. schrieb:

einen Screenshot findets Du im Anhang

Ich hab das mal händisch dekodiert. Das ist eine saubere STANDARD DATA CAN-Nachricht mit id 0x0001, len 0x01 und data[0] 0x00. Die Prüfsumme stimmt, und der Empfänger hat den korrekten Empfang mit ACK quittiert.

Kay L. schrieb:

Da muß ich mal sehen ob das mit der seriellen Schnittstellenausgabe bei mir überhaupt geht.

Alternativ kuck es dir im Debugger an. Aber irgendeine Möglichkeit, deine Software im laufenden Betrieb zu untersuchen, wirst du brauchen ...

LG, Sebastian

Angehängte Dateien:
#7382736
Lesenswert?

Kay L. schrieb:

creenshot anbei Ch1 ist TX am Sender. ist Async Serial die ID? dann ist die 0xFF und nicht 0x000001 was das verhalten erklären würde.

Erstens hast du nicht die ganze CAN-Nachricht erwischt, die ersten zwei Bits oder so fehlen.

Zweitens ist Async Serial der Analysator für eine serielle Schnittstelle. Den solltest du mal deaktivieren oder entfernen, der hilft hier nicht.

[[[ Wenn du Debug-Meldungen auf einen seriellen Port ausgibst, dann kannst du an diesen Port auch noch den Logik-Analysator anschließen, und die Ausgaben mit Async Serial als Text darstellen lassen. So sieht man manchmal ganz gut die Programmreaktionen auf eingehende Nachrichten und so. ]]]

Drittens musst du dem CAN-Analysator mitteilen, welchen Kanal er dekodieren soll. Nimm am besten Empfänger-RX. Sender-RX ginge aber auch, es geht nur darum dass der Analysator auch das ACK-Bit sieht.

LG, Sebastian

OP #7382746
Lesenswert?

Sebastian W. schrieb:

Ich hab das mal händisch dekodiert. Das ist eine saubere STANDARD DATA CAN-Nachricht mit id 0x0001, len 0x01 und data[0] 0x00. Die Prüfsumme stimmt, und der Empfänger hat den korrekten Empfang mit ACK quittiert.

Dann ist ja alles wie es sein sollte. Trotzdem empängt der nur wenn ich zu

die else funktion nach der if ID = 0x0001 einfüge. Da mus da doch irgendwo ein Bock sein. Blöde Frage; Spaces werden ignoriert? Nicht das ich etwas suche, was man nicht sieht.

PS: zum "händisch dekodoert, hast du ev einen Link wo ich nachschauen kann wie man das macht?

GRuß

Kay PPS: Mit mir hast Du dir ja ganz schön einen ans Bein gebunden..... ;-)

OP #7399046
Lesenswert?

Hallo zusammen,

sorry das ich mich jetzt erst melde aber ich hatte irgendwo einen Bock reingebaut somit hab ich nochmal von vorne mit CAN begonnen und leider in letzter Zeit wenig Zeit gehabt mich darum zu kümmern. ich bin jetzt wieder soweit das ich die Zustände meiner Lichtschranken getrennt übertragen kann.

Dies aber nur sehr umständlich:

1
  if (LEDan == 0)CAN_TX_msg.data[0] = 0x00;
2
      if (LEDan == 1)CAN_TX_msg.data[0] = 0x01;
3
      if (LED1an == 0)CAN_TX_msg.data[1] = 0x00;
4
      if (LED1an == 1)CAN_TX_msg.data[1] = 0x01;
5
      CAN_TX_msg.len = 2;

da ich, wenn ich das richtig verstehe, in data[0] (0x00 oder 0xff usw) 256 verschiedene Zustände übertragen kann, macht das so ja gar keinen Sinn, das so wie oben zu machen Ich müsste doch bis zu 8 verschiedene Lichtschranken a 2 Zuständen in Data[0] übertragen können?

Nur wie bekomme ich die Zustände der Lichtschranken, insgesamt 5 in das data0 byte geschrieben?

Gruß

Kay

#7399056
Lesenswert?

Kay L. schrieb:

Nur wie bekomme ich die Zustände der Lichtschranken, insgesamt 5 in das data0 byte geschrieben?

Indem du für jede der fünf Lichtschranken ein Bit in einem Byte reservierst.

1
uint8_t state_ls0 = 1;  // willkürlich gewählte 0/1
2
uint8_t state_ls1 = 0;
3
uint8_t state_ls2 = 1;
4
uint8_t state_ls3 = 0;
5
uint8_t state_ls4 = 1;
6

7
CAN_TX_msg.data[0] = (  (state_ls4 << 4) | (state_ls3 << 3) 
8
                      | (state_ls2 << 2) | (state_ls1 << 1)
9
                      | (state_ls0 << 0)  );

Oh mann war das schwierig.

OP #7399501
Lesenswert?

Hallo zusammen,

soweit hab ich es jetzt. Es funktioniert. Ich habe aber die Zuweisung über den Befehl bitWrite bzw bitRead gemacht. Ich weiß nicht ob das ein Arduino spezifischer Befehl ist.

Es funktioniert mit 2 Arduinos In beide Richtungen mit verschiedenen Nachrichten!

Vielen vielen dank, nur durch eure Hilfe (und Geduld) hab ich das hin bekommen!

nächster Versuch ist dann einen dritten Arduino mit einzubinden!

LG

Kay

#7399630
Lesenswert?

Kay L. schrieb:

soweit hab ich es jetzt. Es funktioniert. Ich habe aber die Zuweisung über den Befehl bitWrite bzw bitRead gemacht. Ich weiß nicht ob das ein Arduino spezifischer Befehl ist.

Ja, die (Makro-)Definition von bitWrite und bitRead finden sich in C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino\Arduino.h. Es macht sowieso viel Sinn anzufangen im Quellcode von Arduino und den Bibliotheken zu stöbern, denn viele wichtige Details sind halt nicht dokumentiert.

LG, Sebastian

OP #7407901
Lesenswert?

Hallo nochmal, ich bins wieder und der Verzweiflung nahe...

Wie ich oben schrieb funktionierte es. Ich konnte nachrichten zwischen zwei Arduinos via CAN hin und her senden.

Dann beim versuch den Dritten einzubinden, ging plötzlich nichts mehr. Das Programm blieb stehen und zwar an dieser Stelle:

1
 {
2
    Serial.begin(115200);
3
    bool ret = CANInit(CAN_500KBPS, 0);  // CAN_RX mapped to PA11, CAN_TX mapped to PA12
4
    if (!ret) while (true);
5
  }

Alles was vorher im Sketch steht wird ausgeführt, was danach steht nicht mehr. Da ich keinen Fehler finden konnte, hab ich alles neu gemacht von ganz vorne. Also ab dem Punkt wo ich die Ursprungsdatei von Github in die .ccp und .h Datei zerlegen musste. Das funktionierte dann auch wieder mit zwei Arduinos. Dann aber plötzlich das gleiche, ab o.g. Zeile bleibt der Sketch stehen.
Um auszuschließen das es an der HW liegt habe ich 3 verschiedenen Arduinos versucht, den ST - Link V2 Programieradapter durcht einen FTDI adapter ersetzt und letztendlich über einen anderen Rechner versucht, alles mit dem selben Ergebnis. Sketch bleibt stehen.

Kurzer Nachtrag : Ändere ich die:

1
  bool ret = CANInit(CAN_500KBPS, 0);  // CAN_RX mapped to PA11, CAN_TX mapped to PA12

auf

1
  bool ret = CANInit(CAN_500KBPS, 2);  // CAN_RX to PB8, CAN_TX to PB9

funktioniert es. Bleibt der Sketch nicht stehen.

der Aufbau der Auswahl CANInit 0 in der .ccp unterscheidet sich auch zur Version 2. Ich hatte versucht das anzupassen. Also Zeile 246 in d r.ccp an Stelle 250 (also hinter if(remap ==0)) zu legen. das hat aber keine Änderung gebracht. Ich habe mal meine Dateien angehängt, hat jemand eine Idee?

Dank im voraus

Gruß

Kay

Angehängte Dateien:
#7408307
Lesenswert?

Sebastian W. schrieb:

Oder schau dir im Debugger an, an welcher Stelle CANInit scheitert ...

Gute Witz, denn: Kay L. schrieb im Beitrag #7407939:

da ich eine kompelierte Datei exportiere und dann mit ST-Link den Arduino programmiere.

Aber eigentlich sollte man mit jedem x-beliebigen Terminlaprogramm die serielle Ausgabe sehrn können. Das wäre der einfachste Weg des Debuggings.

OP #7409397
Lesenswert?

Hallo Sebastian und interessierte,

es scheint der Fehler gefunden, der Fehler war in der Bibliothek.

Beim Remap auf PB8 und 9 wird der Pullup in PB8 aktiviert (Zeile 288). PB8 ist der RX Pin

Beim remap auf PA11 und 12 wird der Pullup in PB12 aktiviert (Zeile 266) PB12 ist aber der TX Pin. Schalte ich den Pullup in PA11 (TX PIN) an scheint es zu funktionieren (zumindest läuft der Code weiter)

Gruß

Kay

OP #7409524
Lesenswert?

Kay L. schrieb:

Hallo Sebastian und interessierte,

es scheint der Fehler gefunden, der Fehler war in der Bibliothek.

Beim Remap auf PB8 und 9 wird der Pullup in PB8 aktiviert (Zeile 288). PB8 ist der RX Pin

Beim remap auf PA11 und 12 wird der Pullup in PB12 aktiviert (Zeile 266) PB12 ist aber der TX Pin. Schalte ich den Pullup in PA11 (TX PIN) an scheint es zu funktionieren (zumindest läuft der Code weiter)

Gruß

Kay

Sorry ich meinte natürlich:PA11 ist der RX Pin. Sorry

OP #7420799
Lesenswert?

Hallo zusammen,

Ich bin mittlerweile so weit das ich den ersten "größeren" Bus mit 9 Teilnehmern, 8 Slave und 1 Master(Zentrale), aufgebaut habe und dieser Funktioniert auch einwandfrei. Ich weiß man kann mehrere Empfänger einer Nachricht zuordnen, aber ist das sinnvoll? Bei meinem Beispiel senden die Slaves jeder eine Nachricht mit verschiedenen Daten an die Zentrale. Die Zentrale könnte alle Infos in einer Nachricht an alle Arduinos senden. Macht das Sinn oder ist es besser, jedem einzelnen Slave eine Nachricht von der Zentrale zu senden?

Gruß

Kay

#7420967
Lesenswert?

Kay L. schrieb:

Bus mit 9 Teilnehmern, 8 Slave und 1 Master(Zentrale)

Das Konzept CAN-Bus ist eigentlich nicht als Master-Slave gedacht. Vielmehr sind alle Busteilnehmer gleichberechtigt im Senden und Empfangen. Sie haben nur unterschiedliche Aufgaben.

Die Zentrale könnte alle Infos in einer Nachricht an alle Arduinos senden.

Man sendet bei CAN nicht an gezielte Busknoten. Informationen bündelt man thematisch zu einer Botschaft mit einer ID. Die anderen Busknoten empfangen die Botschaft und entscheiden dann (in ihrer Software) ob sie diese Informationen auch benutzen wollen.

jedem einzelnen Slave eine Nachricht von der Zentrale zu senden.

Man spricht den entsprechenden Busknoten nicht direkt an und sagt ihm was er tun soll, sondern man schickt das Ziel welches man erreichen will über den Bus.

Beispiel aus dem Auto: Man sagt nicht: "Türsteuergerät Beifahrerseite: Entriegel mal das Türschloss." Sondern: "Türschloss Beifahrerseite bitte entriegeln." Das Türsteuergerät BF weiß dass dies seine Aufgabe ist und führt den Befehl aus. Die anderen Steuergeräte ignorieren die Botschaft weil sie andere Aufgaben haben.

OP #7420977
Lesenswert?

Hallo Thomas,

sorry da habe ich die falschen Begriffe gewählt.

Zur Beschreibung: Ein Arduino fungiert als Zentrale in dem das eigentliche Programm abläuft. Jedes Modul hat einen Arduino, der nur die Eingänge abfragt, via CAN zur Zentrale sendet und die Ausgänge steuert, so wie die Zentrale es vorgibt.

Sorry das ich das als Master Slave bezeichnet habe.

Mir ist auch klar das ich nicht die Knoten anspreche.

Als Beispiel:

an den 8 Arduinos der einzelnen Module hängen in Summe 28 Eingänge. Durch die 8 Arduinos werden natürlich 8 Nachrichten an die Zentrale versendet.

Die Zentrale soll nun mittels variablen via CAN die Ausgänge an den Arduinos in den einzelnen modulen steuern. Insgesammt hab ich 35 Ausgänge auf den verschiedenen Arduinos.

Ich könnte jetzt: A) 8 Nachrichten in denn nur die Variablen für die Ausgänge der jeweiligen Arduinos übertragen werden oder B) ein nachricht in der alle Variablen für die Ausgänge übertragen werden versenden.

bei B würde nur eine Nachricht gesendet, die von allen 8 Adiunos auf den Modulen empfangen wird. Die suchen sich dann jeweils die Variable raus, die auf diesem Arduino gebraucht wird.

Gruß

Kay

#7421006
Lesenswert?

Tja, das sind so Designfragen. Meiner Erfahrung nach sollte man die einfachste Lösung wählen, die für genau das aktuelle Problem funktioniert. Man kann vielleicht schon fest vorgesehene Erweiterungen berücksichtigen. Aber wer für Eventualitäten designt, der hat Angst vor späterer Änderung!

LG, Sebastian

#7421018
Lesenswert?

Kay L. schrieb:

A) 8 Nachrichten in denn nur die Variablen für die Ausgänge der jeweiligen Arduinos übertragen werden

Ich würde es wohl so machen. 8 CAN-IDs (Botschaften) mit den jeweiligen Kommando. Auch wenn jede Botschaft dann nur aus 1 oder 2 Byte besteht so ist das am Ende doch übersichtlicher und später einfach erweiterbar.

bei B würde nur eine Nachricht gesendet, die von allen 8 Adiunos auf den Modulen empfangen wird.

Geht auch. Aber man hat ja bei CAN genügend IDs zur Verfügung, da muss man nicht mit Botschaften geizen.

Letztendlich bist du dein eigener Busarchitekt und musst auch die Software dafür schreiben.

OP #7421025
Lesenswert?

Ok verstehe,

meine "Sorge" ist halt (vielleicht habe ich da auch etwas nicht verstanden) das, wenn mehrere Empfänger eine Nachricht nutzen, dann sendet einer doch ein Bit "Übertragung Fehlerfrei" damit hört der Sender (bis zum nächsten Intervall) auf diese Nachricht zu senden. Könnte es nicht sein, das ein Empfänger dann die Nachricht gar nicht bekommen hat? Oder ist das "graue Theorie"?

Eigentlich würde ich die Variableren gerne "Abschnittsweise" bei den Nachrichten zusammen fassen. Im Beispiel mit den 8 Arduinos gibt es 3 Abschnitte: Abschnitt SBH1 (bestehend aus 4 Modulen mit jeweils einem Arduino), Abschnitt Kreuzung (1 Arduino) und Abschnitt SBH2 (2 Arduinos). Die Zentrale würde also alle Variablen für SBH1 in einer Nachricht übertragen, ebenso für den Abschnitt Kreuzung und dann noch SBH 2. Die untere Ebene würde dann mit 3 Nachrichten aus der Zentrale gesteuert Somit hätte ich auf der ganzen Anlage (insgesmmt 32 Module und ca 9 "Abschnitte") immer alle Daten zu einem Abschnitt in einer Nachricht parat.

Gruß

Kay

OP #7421566
Lesenswert?

Hallo Zusammen,

bei mir klemmt es gerade wieder.....

Ich kann nur eine Nachricht versenden. Die zweite erscheint auf dem Bus erst gar nicht. Die Nachricht ID 0x100010 erscheint nicht. Kommentiere ich aber Nachricht 0x00009 aus wird Nachricht 0x00010 versendet.

1
    // begin CAN senden
2
    {
3
      {CAN_msg_t CAN_TX_msg;                 // Initialisierung Senden
4
        // ----------------------------  Begin CAN Nachricht 0x10009 senden
5
        // eigentliche Daten werden eingefüllt
6
        // mit bitwrite lassen sich einzelne bits innerhalb eines Bytes beschreiben.  Hier Zustand TasterState in Erstes (ganz rechtes) Bit von Data0 schreiben
7
        bitWrite (CAN_TX_msg.data[0], 0, WeicheEinfahrtSBHSudGeradeausState);   // Data 00 Steuerung der Ausgaenge Modul2 Einfahrt SBH Sued
8
        bitWrite (CAN_TX_msg.data[0], 1, WeicheEinfahrtSBHSudAbbiegenState);
9
        bitWrite (CAN_TX_msg.data[1], 0, WeicheSBHSudGleis1geradeausState);     // Data 01 Steuerung der Ausgaenge Modul3 SBH Sued Rechts
10
        bitWrite (CAN_TX_msg.data[1], 1, WeicheSBHSudGleis1abbiegenState);
11
        bitWrite (CAN_TX_msg.data[1], 2, WeicheSBHSudGleis1geradeausState);
12
        bitWrite (CAN_TX_msg.data[1], 3, WeicheSBHSudGleis1abbiegenState);
13
        bitWrite (CAN_TX_msg.data[1], 4, WeicheSBHSudGleis1geradeausState);
14
        bitWrite (CAN_TX_msg.data[1], 5, WeicheSBHSudGleis1abbiegenState);
15
        bitWrite (CAN_TX_msg.data[1], 6, WeicheSBHSudGleis1geradeausState);
16
        bitWrite (CAN_TX_msg.data[1], 7, WeicheSBHSudGleis1abbiegenState);     // Data 02 Steuerung der Ausgänge Modul3 SBH Sued Rechts
17
        CAN_TX_msg.len = 2;                             // Länge der Nachricht
18
        unsigned long currentMillis = millis();         // Senden alle x millisekunden
19
        if (currentMillis - previousMillis >= interval)
20
        {
21
          previousMillis = currentMillis;
22
          if ( ( counter % 2) == 0)
23
          { // Rest der Nachricht wird befüllt
24
            CAN_TX_msg.type = DATA_FRAME;
25
            if (CAN_TX_msg.len == 0) CAN_TX_msg.type = REMOTE_FRAME;
26
            CAN_TX_msg.format = EXTENDED_FORMAT;
27
            CAN_TX_msg.id = 0x100009;                   // nachrichten ID
28
          }
29
          CANSend(&CAN_TX_msg);                         // Übergabe der Nachricht an die Hardware
30
        }
31

32
        //// ----------------------------  Ende CAN Nachricht 0x10009 senden an Modul 2
33
      }
34
      {CAN_msg_t CAN_TX_msg;                 // Initialisierung Senden
35
        // ----------------------------  Begin CAN Nachricht 0x10010 senden  fahrspannungen für SBH Sud
36
        // eigentliche Daten werden eingefüllt
37
        // mit bitwrite lassen sich einzelne bits innerhalb eines Bytes beschreiben.  Hier Zustand TasterState in Erstes (ganz rechtes) Bit von Data0 schreiben
38
        bitWrite (CAN_TX_msg.data[0], 0, FahrstromSBHSudGleis1State);
39
        CAN_TX_msg.len = 1;                             // Länge der Nachricht
40
        unsigned long currentMillis = millis();         // Senden alle x millisekunden
41
        if (currentMillis - previousMillis >= interval1)
42
        {
43
          previousMillis = currentMillis;
44
          if ( ( counter % 2) == 0)
45
          { // Rest der Nachricht wird befüllt
46
            CAN_TX_msg.type = DATA_FRAME;
47
            if (CAN_TX_msg.len == 0) CAN_TX_msg.type = REMOTE_FRAME;
48
            CAN_TX_msg.format = EXTENDED_FORMAT;
49
            CAN_TX_msg.id = 0x100010;                   // nachrichten ID
50
          }
51
          CANSend(&CAN_TX_msg);                         // Übergabe der Nachricht an die Hardware
52
        }

Ich habe schon mit 2 Sende Intervallen für die beiden Nachrichten (100ms und 122ms) versucht, damit die nicht gleichzeitig versendet werden. hat aber nichts gebracht

Könnt Ihr mir helfen?

Nachtrag: ich habe mit dem Logic Analyse am Rx Pin geschaut, ID 100009 ist vorhanden, ID 100010 nicht.

Gruß

Kay

#7421605
Lesenswert?

Kay L. schrieb:

Ich habe schon mit 2 Sende Intervallen für die beiden Nachrichten (100ms und 122ms) versucht, damit die nicht gleichzeitig versendet werden. hat aber nichts gebracht

Ich glaube du hast previousMillis nur einmal. Wenn du die zwei Nachrichten unabhängig voneinander in bestimmten Intervallen verschicken möchtest, musst du dir aber für jede der Nachrichten separat merken wann du die vorherige verschickt hast.

LG, Sebastian

PS: Wofür ist diese ((counter % 2) == 0) Abfrage gut?

OP #7423459
Lesenswert?

Hallo Sebastian,

vielen dank das war es. Wenn man nicht zu Ende überlegt.

Counter ist der Zähler, wie oft eine Nachricht versendet wurde und die Zeile stellt sicher, das nur einmal versendet wird. Da müsste ich dann auch für jede Nachricht mit einem eigen counter arbeiten, richtig?

Gruß

Kay

Gast #7423989
Lesenswert?

Kay L. schrieb:

meine "Sorge" ist halt (vielleicht habe ich da auch etwas nicht verstanden) das, wenn mehrere Empfänger eine Nachricht nutzen, dann sendet einer doch ein Bit "Übertragung Fehlerfrei" damit hört der Sender (bis zum nächsten Intervall) auf diese Nachricht zu senden

Das Acknowledge-Bit sendet jeder Teilnehmer, egal ob er die Botschaft nutzt oder nicht.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren