Dieser Sketch ist angepasst für die Anwendung Mittns ECU Key Calculator.
Ist ein Ausschnitt von meinem anderen Projekt, daher sind nur die notwendigsten Funktionen im Sketch enthalten.
Anleitung zur Verdrahtung des Arduino's mit dem MCP2515 Modul, findet ihr hier.
Benötigte Library's:
- Thread.h (Download via Arduino IDE)
- ThreadController.h (Download via Arduino IDE)
- mcp_can.h
- SPI.h
Benötigtes Material:
Changelog:
- v1.0.1 - Typo Zeile 131
Arduino: Mittns_ECU_Key_Calculator.ino
/*
Copyright ©2022-2024 by Mittns <http://www.mittns.de>
Program Version: 1.0.1
Last modified: 2024-02-28
EN
### Mittns ECU Key Calculator ###
Use this Sketch for Mittns ECU Key Calculator
DE
### Mittns ECU Key Calculator ###
Verwende diesen Sketch für Mittns ECU Key Calculator
*/
//------------------------------------
// .: Librarys :. //
//------------------------------------
#include <Thread.h>
#include <ThreadController.h>
#include <mcp_can.h>
#include <SPI.h>
//------------------------------------
// .: Sketch Informationen :. //
//------------------------------------
#define Sketch_Autor "Mittns"
#define Sketch_Version "1.0.1 beta"
#define Sketch_Build "BUILD28102024"
#define Sketch_Webseite "https://www.mittns.de/"
//------------------------------------
// .: MCP2515 :. //
//------------------------------------
#define Max_Chars 512 //Maximale Zeichen über Serielle Schnittstelle
#define CAN0_INT 2 // MCP INT PIN (2)
MCP_CAN CAN0(10); // MCP CS PIN (10)
int TX_ID = 0x752; // Senden an ECU (Platzhalter)
int RX_ID = 0x652; // Empfang vom ECU (Platzhalter)
//------------------------------------
// .: Multithreading :. //
//------------------------------------
ThreadController Multithread_Controller = ThreadController();
Thread Thread_Serial_RECV = Thread();
Thread Thread_Serial_WORK = Thread();
Thread Thread_Can_Read = Thread();
//------------------------------------
// .: SKETCH SETUP :. //
//------------------------------------
uint8_t Setup_MCP_Bitrate = 2; // 0=125kbps, 1= 250kbps, 2 = 500kbps
uint8_t Setup_MCP_Frequenz = 0; // 0=8Mhz, 1=16Mhz
uint8_t Setup_MCP_Modus = 4; // Nicht verändern!
bool MCP_Configured = true; // true = MCP automatisch einrichten // false = Anwendung zum einstellen nutzen
void setup() {
Serial.begin(115200);
Serial.println(F("Starte Sketch..."));
while (MCP_Configured == false) {
if (Serial.available()) {
Setup_Funktion(Serial.readStringUntil('\n'));
}
}
if (MCP_Configured == true) {
if (CAN0.begin(MCP_ANY, MCP_SETUP_SET_BITRATE(), MCP_SETUP_SET_SPEED()) == CAN_OK) {
CAN0.setMode(MCP_NORMAL);
pinMode(CAN0_INT, INPUT);
MCP_Configured = true;
Serial.println(F("MCP2515 erfolgreich initiiert!"));
} else {
Serial.println(F("Fehler MCP2515 Modul. Überprüfe Deine Verdrahtung und/oder das Modul."));
MCP_Configured = false;
}
}
Setup_Set_MultiThreads();
}
void loop() {
Multithread_Controller.run();
}
char Serial_Daten[Max_Chars];
boolean Serial_Daten_empfangen = false;
void Serial_Daten_Empfang() {
static int C_Index = 0;
char RC;
while (Serial.available() > 0 && Serial_Daten_empfangen == false) {
RC = Serial.read();
if (RC != '\n') {
Serial_Daten[C_Index] = RC;
C_Index++;
if (C_Index >= Max_Chars) {
C_Index = Max_Chars - 1;
}
} else {
Serial_Daten[C_Index] = '\0'; // Abschluss Terminierung !Wichtig!
C_Index = 0;
Serial_Daten_empfangen = true;
}
}
}
bool Multiframe_aktiv = false;
void Serial_Daten_Auswertung() {
if (Serial_Daten_empfangen == true) {
int Datenlaenge = strlen(Serial_Daten);
if (strstr_P(Serial_Daten, PSTR("SETUP"))) {
Setup_Funktion(Serial_Daten);
} else {
switch (Datenlaenge) {
case 0:
Serial.println(F("000"));
break;
case 1: //Frei für Setup und weiteres.
if (Serial_Daten[0] == '?') {
char buffer[40];
Serial.print(F("Sketch: "));
sprintf(buffer, "%s;%s;%s;%s;", Sketch_Autor, Sketch_Version, Sketch_Build, Sketch_Webseite);
Serial.println(buffer);
} else {
Serial.println(F("???"));
}
break;
case 2 ... 14: //Mindestens 1 Byte (2 Zeichen) bis maximal 7 bytes (14 Zeichen)
if (Serial_Daten[0] == '>' && sizeof(Serial_Daten) == 8) {
uint8_t Index = 0;
char * N_ID = strtok(Serial_Daten + 1, ":");
while (N_ID != NULL) {
if (Index == 0) {
TX_ID = strtoul(N_ID, NULL, 16);
} else if (Index == 1) {
RX_ID = strtoul(N_ID, NULL, 16);
}
Index++;
N_ID = strtok(NULL, ":");
}
Serial.print(F("TX/RX Set to: "));
Serial.print(TX_ID, HEX);
Serial.print(F(":"));
Serial.println(RX_ID, HEX);
} else {
Sende_SingleFrame(Serial_Daten);
}
break;
default:
Serial.println(F("*Daten unbekannt oder unzureichende Datenlänge"));
break;
}
}
memset(Serial_Daten, 0, sizeof(Serial_Daten));
Serial_Daten_empfangen = false;
}
}
int HexToInt(char a, char b) {
a = (a <= '9') ? a - '0' : (a & 0x7) + 9;
b = (b <= '9') ? b - '0' : (b & 0x7) + 9;
return (a << 4) + b;
}
long unsigned int Can_RX_ID;
unsigned char Can_RX_DLC = 0;
unsigned char Can_RX_DATA[8];
int i_MF_Index = 1;
void Can_Daten_lesen() {
char buffer[256]; // Can Buffer Array
if (!digitalRead(CAN0_INT)) {
CAN0.readMsgBuf(&Can_RX_ID, &Can_RX_DLC, Can_RX_DATA);
Serial.print("<");
for (byte i = 1; i < Can_RX_DLC; i++) { // 1. Byte (PSA DLC) überspringen
sprintf(buffer, "%.2X", Can_RX_DATA[i]);
Serial.print(buffer);
}
Serial.println();
}
}
void Sende_SingleFrame(char * Can_Daten) {
int Datenlaenge = strlen(Can_Daten);
int D_0 = Datenlaenge / 2;
if (Datenlaenge % 2 != 0) {
Serial.println(F("Can Frame Fehler: Unzureichende Datenlänge"));
return;
}
byte SingleFrame_Array[8]; // Temp. Frame erstellen
int Pos_Index_Array2 = 1; // Position [0] entfällt, da das 1. Byte für DLC belegt ist => PSA DLC
int iS_DL = 0;
char PSA_DLC = (strlen(Can_Daten) / 2);
SingleFrame_Array[0] = PSA_DLC;
for (iS_DL = 0; iS_DL < Datenlaenge; iS_DL += 2) {
if (isxdigit(Can_Daten[iS_DL]) && isxdigit(Can_Daten[iS_DL + 1])) {
SingleFrame_Array[Pos_Index_Array2] = HexToInt(Can_Daten[iS_DL], Can_Daten[(iS_DL + 1)]);
Pos_Index_Array2++;
} else {
Serial.print(F("Can Frame Fehler: Ungültiges Zeichen im Frame"));
return;
}
}
Serial.print(F(">"));
int i4;
for (i4 = 1; i4 < D_0 + 1; i4++) { // 1 = Ab dem 2. Byte ausgeben => PSA DLC Byte ausblenden
if (SingleFrame_Array[i4] <= 15) Serial.print(0); //Vorangestellte 0
Serial.print(SingleFrame_Array[i4], HEX);
}
Serial.println();
byte sndStat = CAN0.sendMsgBuf(TX_ID, 0, PSA_DLC+1, SingleFrame_Array); //PSA_DLC + DATA Länge
if (sndStat != CAN_OK) {
Serial.println(F("Fehler: Can Frame konnte nicht gesendet werden!"));
}
}
void Setup_Set_MultiThreads() {
Thread_Serial_RECV.onRun(Serial_Daten_Empfang); //Serielle Daten empfangen
Thread_Serial_RECV.setInterval(0);
Thread_Serial_WORK.onRun(Serial_Daten_Auswertung); //Serielle Daten auswerten, wenn welche empfangen wurden
Thread_Serial_WORK.setInterval(0);
Thread_Can_Read.onRun(Can_Daten_lesen);
Thread_Can_Read.setInterval(0);
Multithread_Controller.add(&Thread_Serial_RECV);
Multithread_Controller.add(&Thread_Serial_WORK);
Multithread_Controller.add(&Thread_Can_Read);
}
void Snd_OK() {
Serial.println(F("OK"));
}
void Setup_Funktion(String Befehl) {
const char *Trennzeichen = ";";
char Befehl_in_Char[64];
int Str_Laenge = Befehl.length() + 1;
Befehl.toCharArray(Befehl_in_Char, Str_Laenge);
if (Befehl.indexOf(Trennzeichen) > 0) {
if (strcmp(strtok(Befehl_in_Char, Trennzeichen), "SETUP_SET") == 0 ) {
Setup_MCP_Bitrate = atoi(strtok(NULL, Trennzeichen));
Setup_MCP_Frequenz = atoi(strtok(NULL, Trennzeichen));
Setup_MCP_Modus = atoi(strtok(NULL, Trennzeichen));
if (CAN0.begin(MCP_NORMAL, MCP_SETUP_SET_BITRATE(), MCP_SETUP_SET_SPEED()) == CAN_OK) {
CAN0.setMode(MCP_NORMAL);
MCP_Configured = true;
Snd_OK();
} else {
Serial.println(F("NOT OK"));
MCP_Configured = false;
}
} else if (strcmp(strtok(Befehl_in_Char, Trennzeichen), "SETUP_GET") == 0) {
char buffer[100];
sprintf(buffer, "SETUP;%s;%s;%s;%s;%d;%d;%d;%d;%i;%i;", Sketch_Autor, Sketch_Version, Sketch_Build, Sketch_Webseite, Setup_MCP_Bitrate, Setup_MCP_Frequenz, Setup_MCP_Modus, MCP_Configured, TX_ID, RX_ID);
Serial.println(buffer);
Snd_OK();
} else if (strcmp(strtok(Befehl_in_Char, Trennzeichen), "RX") == 0) {
RX_ID = atoi(strtok(NULL, Trennzeichen));
Snd_OK();
} else if (strcmp(strtok(Befehl_in_Char, Trennzeichen), "TX") == 0) {
TX_ID = atoi(strtok(NULL, Trennzeichen));
Snd_OK();
} else {
Serial.println(F("Strtok Fehler"));
Serial.println(strtok(Befehl_in_Char, Trennzeichen));
}
} else {
Serial.print(F("Fehler: Setup Befehl unbekannt"));
}
}
uint8_t MCP_SETUP_SET_BITRATE() {
switch (Setup_MCP_Bitrate) {
case 0:
return CAN_125KBPS;
case 1:
return CAN_250KBPS;
case 2:
return CAN_500KBPS;
default:
Serial.println(F("Fehler: MCP BITRATE"));
return 0;
}
}
uint8_t MCP_SETUP_SET_SPEED() {
switch (Setup_MCP_Frequenz) {
case 0:
return MCP_8MHZ;
case 1:
return MCP_16MHZ;
default:
Serial.println(F("Fehler: MCP SPEED"));
return 0;
}
}
uint8_t MCP_SETUP_SET_MODE() {
switch (Setup_MCP_Modus) {
case 0:
return MCP_STDEXT;
case 1:
return MCP_STD;
case 2:
return MCP_EXT;
case 3:
return MCP_ANY;
case 4:
return MCP_NORMAL;
default:
Serial.println(F("Fehler: MCP MODUS"));
return 0;
}
}
Alles anzeigen
Arduino: Mittns_ECU_Key_Calculator.ino
/*
Copyright ©2022-2023 by Mittns <http://www.mittns.de>
Program Version: 1.0.0
Last modified: 2023-01-03
EN
### Mittns ECU Key Calculator ###
Use this Sketch for Mittns ECU Key Calculator
DE
### Mittns ECU Key Calculator ###
Verwende diesen Sketch für Mittns ECU Key Calculator
*/
//------------------------------------
// .: Librarys :. //
//------------------------------------
#include <Thread.h>
#include <ThreadController.h>
#include <mcp_can.h>
#include <SPI.h>
//------------------------------------
// .: Sketch Informationen :. //
//------------------------------------
#define Sketch_Autor "Mittns"
#define Sketch_Version "1.0.0 beta"
#define Sketch_Build "BUILD27122022"
#define Sketch_Webseite "https://www.mittns.de/"
//------------------------------------
// .: MCP2515 :. //
//------------------------------------
#define Max_Chars 512 //Maximale Zeichen über Serielle Schnittstelle
#define CAN0_INT 2 // MCP INT PIN (2)
MCP_CAN CAN0(10); // MCP CS PIN (10)
int TX_ID = 0x752; // Senden an ECU (Platzhalter)
int RX_ID = 0x652; // Empfang vom ECU (Platzhalter)
//------------------------------------
// .: Multithreading :. //
//------------------------------------
ThreadController Multithread_Controller = ThreadController();
Thread Thread_Serial_RECV = Thread();
Thread Thread_Serial_WORK = Thread();
Thread Thread_Can_Read = Thread();
//------------------------------------
// .: SKETCH SETUP :. //
//------------------------------------
uint8_t Setup_MCP_Bitrate = 2; // 0=125kbps, 1= 250kbps, 2 = 500kbps
uint8_t Setup_MCP_Frequenz = 0; // 0=8Mhz, 1=16Mhz
uint8_t Setup_MCP_Modus = 4; // Nicht verändern!
bool MCP_Configured = true; // true = MCP automatisch einrichten // false = Anwendung zum einstellen nutzen
void setup() {
Serial.begin(115200);
Serial.println(F("Starte Sketch..."));
while (MCP_Configured == false) {
if (Serial.available()) {
Setup_Funktion(Serial.readStringUntil('\n'));
}
}
if (MCP_Configured == true) {
if (CAN0.begin(MCP_ANY, MCP_SETUP_SET_BITRATE(), MCP_SETUP_SET_SPEED()) == CAN_OK) {
CAN0.setMode(MCP_NORMAL);
pinMode(CAN0_INT, INPUT);
MCP_Configured = true;
Serial.println(F("MCP2515 erfolgreich initiiert!"));
} else {
Serial.println(F("Fehler MCP2515 Modul. Überprüfe Deine Verdrahtung und/oder das Modul."));
MCP_Configured = false;
}
}
Setup_Set_MultiThreads();
}
void loop() {
Multithread_Controller.run();
}
char Serial_Daten[Max_Chars];
boolean Serial_Daten_empfangen = false;
void Serial_Daten_Empfang() {
static int C_Index = 0;
char RC;
while (Serial.available() > 0 && Serial_Daten_empfangen == false) {
RC = Serial.read();
if (RC != '\n') {
Serial_Daten[C_Index] = RC;
C_Index++;
if (C_Index >= Max_Chars) {
C_Index = Max_Chars - 1;
}
} else {
Serial_Daten[C_Index] = '\0'; // Abschluss Terminierung !Wichtig!
C_Index = 0;
Serial_Daten_empfangen = true;
}
}
}
bool Multiframe_aktiv = false;
void Serial_Daten_Auswertung() {
if (Serial_Daten_empfangen == true) {
int Datenlaenge = strlen(Serial_Daten);
if (strstr_P(Serial_Daten, PSTR("SETUP"))) {
Setup_Funktion(Serial_Daten);
} else {
switch (Datenlaenge) {
case 0:
Serial.println(F("000"));
break;
case 1: //Frei für Setup und weiteres.
if (Serial_Daten[0] == '?') {
char buffer[40];
Serial.print(F("Sketch: "));
sprintf(buffer, "%s;%s;%s;%s;", Sketch_Autor, Sketch_Version, Sketch_Build, Sketch_Webseite);
Serial.println(buffer);
} else {
Serial.println(F("???"));
}
break;
case 2 ... 14: //Mindestens 1 Byte (2 Zeichen) bis maximal 7 bytes (14 Zeichen)
if (Serial_Daten[0] == '>' && sizeof(Serial_Daten == 8)) {
uint8_t Index = 0;
char * N_ID = strtok(Serial_Daten + 1, ":");
while (N_ID != NULL) {
if (Index == 0) {
TX_ID = strtoul(N_ID, NULL, 16);
} else if (Index == 1) {
RX_ID = strtoul(N_ID, NULL, 16);
}
Index++;
N_ID = strtok(NULL, ":");
}
Serial.print(F("TX/RX Set to: "));
Serial.print(TX_ID, HEX);
Serial.print(F(":"));
Serial.println(RX_ID, HEX);
} else {
Sende_SingleFrame(Serial_Daten);
}
break;
default:
Serial.println(F("*Daten unbekannt oder unzureichende Datenlänge"));
break;
}
}
memset(Serial_Daten, 0, sizeof(Serial_Daten));
Serial_Daten_empfangen = false;
}
}
int HexToInt(char a, char b) {
a = (a <= '9') ? a - '0' : (a & 0x7) + 9;
b = (b <= '9') ? b - '0' : (b & 0x7) + 9;
return (a << 4) + b;
}
long unsigned int Can_RX_ID;
unsigned char Can_RX_DLC = 0;
unsigned char Can_RX_DATA[8];
int i_MF_Index = 1;
void Can_Daten_lesen() {
char buffer[256]; // Can Buffer Array
if (!digitalRead(CAN0_INT)) {
CAN0.readMsgBuf(&Can_RX_ID, &Can_RX_DLC, Can_RX_DATA);
Serial.print("<");
for (byte i = 1; i < Can_RX_DLC; i++) { // 1. Byte (PSA DLC) überspringen
sprintf(buffer, "%.2X", Can_RX_DATA[i]);
Serial.print(buffer);
}
Serial.println();
}
}
void Sende_SingleFrame(char * Can_Daten) {
int Datenlaenge = strlen(Can_Daten);
int D_0 = Datenlaenge / 2;
if (Datenlaenge % 2 != 0) {
Serial.println(F("Can Frame Fehler: Unzureichende Datenlänge"));
return;
}
byte SingleFrame_Array[8]; // Temp. Frame erstellen
int Pos_Index_Array2 = 1; // Position [0] entfällt, da das 1. Byte für DLC belegt ist => PSA DLC
int iS_DL = 0;
char PSA_DLC = (strlen(Can_Daten) / 2);
SingleFrame_Array[0] = PSA_DLC;
for (iS_DL = 0; iS_DL < Datenlaenge; iS_DL += 2) {
if (isxdigit(Can_Daten[iS_DL]) && isxdigit(Can_Daten[iS_DL + 1])) {
SingleFrame_Array[Pos_Index_Array2] = HexToInt(Can_Daten[iS_DL], Can_Daten[(iS_DL + 1)]);
Pos_Index_Array2++;
} else {
Serial.print(F("Can Frame Fehler: Ungültiges Zeichen im Frame"));
return;
}
}
Serial.print(F(">"));
int i4;
for (i4 = 1; i4 < D_0 + 1; i4++) { // 1 = Ab dem 2. Byte ausgeben => PSA DLC Byte ausblenden
if (SingleFrame_Array[i4] <= 15) Serial.print(0); //Vorangestellte 0
Serial.print(SingleFrame_Array[i4], HEX);
}
Serial.println();
byte sndStat = CAN0.sendMsgBuf(TX_ID, 0, PSA_DLC+1, SingleFrame_Array); //PSA_DLC + DATA Länge
if (sndStat != CAN_OK) {
Serial.println(F("Fehler: Can Frame konnte nicht gesendet werden!"));
}
}
void Setup_Set_MultiThreads() {
Thread_Serial_RECV.onRun(Serial_Daten_Empfang); //Serielle Daten empfangen
Thread_Serial_RECV.setInterval(0);
Thread_Serial_WORK.onRun(Serial_Daten_Auswertung); //Serielle Daten auswerten, wenn welche empfangen wurden
Thread_Serial_WORK.setInterval(0);
Thread_Can_Read.onRun(Can_Daten_lesen);
Thread_Can_Read.setInterval(0);
Multithread_Controller.add(&Thread_Serial_RECV);
Multithread_Controller.add(&Thread_Serial_WORK);
Multithread_Controller.add(&Thread_Can_Read);
}
void Snd_OK() {
Serial.println(F("OK"));
}
void Setup_Funktion(String Befehl) {
const char *Trennzeichen = ";";
char Befehl_in_Char[64];
int Str_Laenge = Befehl.length() + 1;
Befehl.toCharArray(Befehl_in_Char, Str_Laenge);
if (Befehl.indexOf(Trennzeichen) > 0) {
if (strcmp(strtok(Befehl_in_Char, Trennzeichen), "SETUP_SET") == 0 ) {
Setup_MCP_Bitrate = atoi(strtok(NULL, Trennzeichen));
Setup_MCP_Frequenz = atoi(strtok(NULL, Trennzeichen));
Setup_MCP_Modus = atoi(strtok(NULL, Trennzeichen));
if (CAN0.begin(MCP_NORMAL, MCP_SETUP_SET_BITRATE(), MCP_SETUP_SET_SPEED()) == CAN_OK) {
CAN0.setMode(MCP_NORMAL);
MCP_Configured = true;
Snd_OK();
} else {
Serial.println(F("NOT OK"));
MCP_Configured = false;
}
} else if (strcmp(strtok(Befehl_in_Char, Trennzeichen), "SETUP_GET") == 0) {
char buffer[100];
sprintf(buffer, "SETUP;%s;%s;%s;%s;%d;%d;%d;%d;%i;%i;", Sketch_Autor, Sketch_Version, Sketch_Build, Sketch_Webseite, Setup_MCP_Bitrate, Setup_MCP_Frequenz, Setup_MCP_Modus, MCP_Configured, TX_ID, RX_ID);
Serial.println(buffer);
Snd_OK();
} else if (strcmp(strtok(Befehl_in_Char, Trennzeichen), "RX") == 0) {
RX_ID = atoi(strtok(NULL, Trennzeichen));
Snd_OK();
} else if (strcmp(strtok(Befehl_in_Char, Trennzeichen), "TX") == 0) {
TX_ID = atoi(strtok(NULL, Trennzeichen));
Snd_OK();
} else {
Serial.println(F("Strtok Fehler"));
Serial.println(strtok(Befehl_in_Char, Trennzeichen));
}
} else {
Serial.print(F("Fehler: Setup Befehl unbekannt"));
}
}
uint8_t MCP_SETUP_SET_BITRATE() {
switch (Setup_MCP_Bitrate) {
case 0:
return CAN_125KBPS;
case 1:
return CAN_250KBPS;
case 2:
return CAN_500KBPS;
default:
Serial.println(F("Fehler: MCP BITRATE"));
return 0;
}
}
uint8_t MCP_SETUP_SET_SPEED() {
switch (Setup_MCP_Frequenz) {
case 0:
return MCP_8MHZ;
case 1:
return MCP_16MHZ;
default:
Serial.println(F("Fehler: MCP SPEED"));
return 0;
}
}
uint8_t MCP_SETUP_SET_MODE() {
switch (Setup_MCP_Modus) {
case 0:
return MCP_STDEXT;
case 1:
return MCP_STD;
case 2:
return MCP_EXT;
case 3:
return MCP_ANY;
case 4:
return MCP_NORMAL;
default:
Serial.println(F("Fehler: MCP MODUS"));
return 0;
}
}
Alles anzeigen