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)
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:
Steuerung des Schattenbahnhofes mit 5 Gleisen (Suche freies Gleis, fahren des Zuges bis zum Haltepunkt, schalten der Weichen usw.
Geschwindigkeits mess und Regelung (mit LCD)
Totman box, die Verhindert das die Bahn tagelang im Keller unter strom steht (mit LCD)
Schweisslicht
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
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?
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.
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.
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.
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.
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?
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.
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
voidsetup(){
2
Serial.begin(115200);
3
boolret=CANInit(CAN_500KBPS,2);// CAN_RX to PB8, CAN_TX to PB9
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
>voidsetup(){
2
>Serial.begin(115200);
3
>boolret=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
>voidloop(){
2
>CAN_msg_tCAN_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_tCAN_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
// 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.
Sorry da stand ich auf dem Schlauch.. Ich war schon bei Hexadezimal, nur hatte ich die zweistellig vor Augen... Das 0x vorne als Bescheibung für die Hexadezimalzahl hatte ich nicht mehr auf dem Schirm...
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.
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.
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.
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.
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)
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:
ich bin blutiger Anfänger
Den Blue Pill mit STM32F1 nutzen nicht viele (wie man auch hier im Fred ja schon sieht ist der eher verpöhnt)
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 :-)
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
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
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:
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.
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.
Von Natur aus nicht, aber jemand hat es hinbekommen, mit dem PIO CAN-Bus zu emulieren:
https://github.com/KevinOConnor/can2040
´
Das habe ich allerdings bisher nicht selbst ausprobiert.
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....
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).
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.
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):
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.
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"
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 ...
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.
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
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.
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.
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
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
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?
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.
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?
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
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.
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 ...
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
Drauf sein sollte der STM32F103C8xx verbaut ist aber STM32F103C6xx
Dann würde ich versuchen den Sketch noch einmal zu übersetzen und hochzuladen, und dabei vorher im Menü "Werkzeuge" unter "Board" "Generic STM32F1 series" als "Board part number" anstatt "BluePill F103C8" besser "BluePill F103C6 (32K)" auszuwählen.
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?
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?
Setze in stm32f103.cpp mal DEBUG auf 1, dann sollte während CANInit auf
Serial einiges an Informationen erscheinen.
Zeig mal ein Foto von deinem Testaufbau mit Anschluß des Transceivers.
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
boolCANInit(BITRATEbitrate,intremap)
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.
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
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.
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.
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.
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_tCAN_TX_msg;// CAN_TX_msg wird initial partiell befüllt. Daten die versendet werden sollen Begin Nachricht
2
CAN_msg_tCAN_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
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 :)
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.
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?
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.
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?
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.
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.
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.
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.
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.
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.
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.
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 ...
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.
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.
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.
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
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?
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 ...
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.
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.
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.
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.
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..... ;-)
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?
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!
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.
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
boolret=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
boolret=CANInit(CAN_500KBPS,0);// CAN_RX mapped to PA11, CAN_TX mapped to PA12
auf
1
boolret=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?
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)
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
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?
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.
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.
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!
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.
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.
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_tCAN_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
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.
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?
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?
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.