Hallo, liebe Gemeinde.
Folgendes Setup: Arduino Uno, MCP2515 Can-Modul, SSD1306 OLED 164x32 und ein Drehregler, versorgt von einem StepDown-Wandler 12V->5V.
Eingebaut in meinem KFZ um CAN-Botschaften mitzulesen und einige davon im Display anzuzeigen.
Grundsätzlich funktioniert es, jedoch friert das Programm/der Uno in unregelmäßigen Abständen ein. Das Display zeigt weiterhin einen Wert an, reagiert aber nicht mehr.
Alles auch bei nicht laufendem Motor, nur Zündung. Das Display (I2C) sowie der Drehregler sind ca. 50cm vom Arduino entfernt.
Gibt es "übliche Verdächtige" um das Einfrieren zu unterbinden? Freue mich über jeden Hinweis.
Vielen Dank fürs Lesen.
Roland
Anbei noch mein Code:
#include <Arduino.h>
#include <U8g2lib.h>
#include <SPI.h>
#include <mcp_can.h>
//rotary
#define encoderPinA 2
#define encoderPinB 3
#define encoderSwitch 4
int encoderPos = 0; // a counter for the dial
unsigned int lastReportedPos = 1; // change management
static boolean rotating = false; // debounce management
unsigned long lastButtonPress = 0;
// interrupt service routine vars
boolean A_set = false;
boolean B_set = false;
//display
U8G2_SSD1306_128X32_UNIVISION_F_HW_I2C u8g2(U8G2_R0, /* reset=*/U8X8_PIN_NONE, /* clock=*/SCL, /* data=*/SDA);
char TempStr[20];
//menu
int Modus = 0;
int Abgasmodus = 0;
bool Abgas = false;
int MAXMENU = 8;
int MAXABGAS = 4;
//FahrzeugCAN
long unsigned int rxId;
unsigned char len = 0;
unsigned char rxBuf[8];
long unsigned int canId = 0x000;
MCP_CAN CAN0(10);
float Lambda;
float BoostPressure;
float IntakeTemp;
float CoolantTemp;
int RPM;
float OilPressure;
float TEMP;
float Volt;
float FuelPressure;
int Lambdabox;
int Lambdapeak;
int combined;
int EGT;
int EGT1;
int EGT2;
int EGT3;
int EGT4;
void setup() {
//rotary
pinMode(encoderPinA, INPUT);
pinMode(encoderPinB, INPUT);
pinMode(encoderSwitch, INPUT_PULLUP);
digitalWrite(encoderPinA, HIGH); // turn on pullup resistors
digitalWrite(encoderPinB, HIGH); // turn on pullup resistors
attachInterrupt(0, doEncoderA, CHANGE); // encoder pin on interrupt 0 (pin 2)
attachInterrupt(1, doEncoderB, CHANGE); // encoder pin on interrupt 1 (pin 3)
//can bus
CAN0.begin(MCP_ANY, CAN_500KBPS, MCP_8MHZ); // init can bus : baudrate = 500k
CAN0.setMode(MCP_NORMAL);
pinMode(5, INPUT); //(CAN)
//display
u8g2.begin();
u8g2.setFont(u8g2_font_10x20_tf); // choose a suitable font
u8g2.drawRFrame(0, 0, 128, 32, 5); //Rahmen außen
u8g2.sendBuffer();
//Serial.begin(9600); // output
}
void loop() {
// CAN auslesen
if (!digitalRead(5)) { // If pin 5 is low, read receive buffer
CAN0.readMsgBuf(&canId, &len, rxBuf); // Read data: len = data length, buf = data byte(s)
//Serial.println(canId);
if (canId == 1328) { //0x530
//Volt
combined = ((int)rxBuf[1] << 8) | rxBuf[0];
Volt = (float)combined / 100;
//BaroPress
combined = ((int)rxBuf[3] << 8) | rxBuf[2];
BoostPressure = (float)combined / 1000;
//IntakeTemp
combined = ((int)rxBuf[5] << 8) | rxBuf[4];
IntakeTemp = (float)combined / 10;
//CoolantTemp
combined = ((int)rxBuf[7] << 8) | rxBuf[6];
CoolantTemp = (float)combined / 10;
} else if (canId == 1329) {
//EGT1
EGT1 = ((int)rxBuf[7] << 8) | rxBuf[6];
} else if (canId == 1330) {
EGT2 = ((int)rxBuf[1] << 8) | rxBuf[0];
EGT3 = ((int)rxBuf[3] << 8) | rxBuf[2];
EGT4 = ((int)rxBuf[5] << 8) | rxBuf[4];
EGT = ((int)rxBuf[7] << 8) | rxBuf[6];
} else if (canId == 1335) {
combined = ((int)rxBuf[1] << 8) | rxBuf[0];
FuelPressure = (float)combined / 1000;
//combined = ((int)rxBuf[7] << 8) | rxBuf[6];
//BoostPressure = (float)combined / 10;
} else if (canId == 1312) {
combined = ((int)rxBuf[7] << 8) | rxBuf[6];
Lambda = (float)combined / 1000;
} else if (canId == 1312) {
RPM = ((int)rxBuf[1] << 8) | rxBuf[0];
}
}
//Rotary handling
rotating = true; // reset the debouncer
if (lastReportedPos != encoderPos) {
// Serial.print("Abgasmodus:");
// Serial.println(Abgasmodus);
// Serial.print("Modus:");
// Serial.println(Modus);
// Serial.println(encoderPos);
lastReportedPos = encoderPos;
}
if (Modus == 1) { //Abgasmodus aktiv und Knopf wird gedrückt
// Read the button state
int btnState = digitalRead(encoderSwitch);
//If we detect LOW signal, button is pressed
if (btnState == LOW) {
//if 50ms have passed since last LOW pulse, it means that the
//button has been pressed, released and pressed again
if (millis() - lastButtonPress > 50) {
if (Abgas == false) {
Abgas = true;
} else {
Abgas = false;
Abgasmodus = 0;
}
}
// Remember last button press event
lastButtonPress = millis();
}
}
switch (Modus) {
case 0: //Batteriespannung
//Volt = random(11, 14);
strcpy(TempStr, "Batt: ");
dtostrf(Volt, 5, 2, &TempStr[strlen(TempStr)]); //add to end of str
strcat(TempStr, "V");
draw(TempStr);
//Serial.println(TempStr);
break;
case 1: //Abgastemperatur
switch (Abgasmodus) {
case 0: //Fühler vor Turbo
strcpy(TempStr, "Abgas:");
dtostrf(EGT, 4, 0, &TempStr[strlen(TempStr)]); //add to end of str
strcat(TempStr, "\260C");
draw(TempStr);
//Serial.println(TempStr);
break;
case 1: //Zylinder1
strcpy(TempStr, "EGT1:");
dtostrf(EGT1, 5, 0, &TempStr[strlen(TempStr)]); //add to end of str
strcat(TempStr, "\260C");
draw(TempStr);
//Serial.println(TempStr);
break;
case 2: //Zylinder2
strcpy(TempStr, "EGT2:");
dtostrf(EGT2, 5, 0, &TempStr[strlen(TempStr)]); //add to end of str
strcat(TempStr, "\260C");
draw(TempStr);
//Serial.println(TempStr);
break;
case 3: //Zylinder2
strcpy(TempStr, "EGT3:");
dtostrf(EGT3, 5, 0, &TempStr[strlen(TempStr)]); //add to end of str
strcat(TempStr, "\260C");
draw(TempStr);
//Serial.println(TempStr);
break;
case 4: //Zylinder4
strcpy(TempStr, "EGT4:");
dtostrf(EGT4, 5, 0, &TempStr[strlen(TempStr)]); //add to end of str
strcat(TempStr, "\260C");
draw(TempStr);
//Serial.println(TempStr);
break;
}
break;
case 2: //Lambda
u8g2.clearBuffer(); // clear the internal memory
u8g2.drawRFrame(0, 0, 128, 32, 5); //Rahmen außen
u8g2.drawBox(63, 30, 2, 2); //Punkt 2x2 Pixel in der Mitte, der Lmabda 1 markiert
Lambdabox = map(Lambda * 1000, 650, 1455, 5, 119);
if (Lambdapeak < Lambdabox) { // if the peak is below the current bar size
Lambdapeak = Lambdabox; // move peak to the new max. position (i.e. size of the bar)
} else if (Lambdapeak > Lambdabox) { // if the bar is lower than the peak
Lambdapeak--; // slowly move the peak down, one pixel every frame
}
u8g2.drawBox(5, 28, Lambdabox, 2);
u8g2.drawBox(Lambdapeak, 28, 2, 2);
u8g2.setFont(u8g2_font_10x20_tf); // choose a suitable font
strcpy(TempStr, "Lambda:");
dtostrf(Lambda, 4, 2, &TempStr[strlen(TempStr)]); //add to end of str
u8g2.drawStr(5, 22, TempStr); // write something to the internal memory
u8g2.sendBuffer(); // transfer internal memory to the display
//Serial.println(TempStr);
break;
case 3: //BoostPressure
strcpy(TempStr, "Boost: ");
dtostrf(BoostPressure, 4, 2, &TempStr[strlen(TempStr)]); //add to end of str
// strcat(TempStr, "kpa");
draw(TempStr);
//Serial.println(TempStr);
break;
case 4: //IntakeTemp
strcpy(TempStr, "Luft: ");
dtostrf(IntakeTemp, 3, 0, &TempStr[strlen(TempStr)]); //add to end of str
strcat(TempStr, "\260C");
draw(TempStr);
//Serial.println(TempStr);
break;
case 5: //CoolantTemp
strcpy(TempStr, "Wasser:");
dtostrf(CoolantTemp, 3, 0, &TempStr[strlen(TempStr)]); //add to end of str
strcat(TempStr, "\260C");
draw(TempStr);
//Serial.println(TempStr);
break;
case 6: //RPM
strcpy(TempStr, "RPM:");
dtostrf(RPM, 4, 0, &TempStr[strlen(TempStr)]); //add to end of str
strcat(TempStr, " min");
draw(TempStr);
//Serial.println(TempStr);
break;
case 7: //OilPressure
strcpy(TempStr, "\326l: "); //Öl
dtostrf(OilPressure, 3, 2, &TempStr[strlen(TempStr)]); //add to end of str
strcat(TempStr, " bar");
draw(TempStr);
//Serial.println(TempStr);
break;
case 8: //FuelPressure
strcpy(TempStr, "Rail: ");
dtostrf(FuelPressure, 3, 1, &TempStr[strlen(TempStr)]); //add to end of str
strcat(TempStr, "bar");
draw(TempStr);
//Serial.println(TempStr);
break;
}
}
// Interrupt on A changing state
void doEncoderA() {
if (rotating) delay(1); // wait a little until the bouncing is done
if (digitalRead(encoderPinA) != A_set) { // debounce once more
A_set = !A_set;
// adjust counter + if A leads B
if (A_set && !B_set) {
if (Abgas == false) {
encoderPos -= 1;
Modus -= 1;
if (Modus < 0) Modus = MAXMENU;
} else {
encoderPos -= 1;
Abgasmodus -= 1;
if (Abgasmodus < 0) Abgasmodus = MAXABGAS;
}
}
rotating = false; // no more debouncing until loop() hits again
}
}
// Interrupt on B changing state, same as A above
void doEncoderB() {
if (rotating) delay(1);
if (digitalRead(encoderPinB) != B_set) {
B_set = !B_set;
// adjust counter - 1 if B leads A
if (B_set && !A_set) {
if (Abgas == false) {
encoderPos += 1;
Modus += 1;
if (Modus > MAXMENU) Modus = 0;
} else {
encoderPos += 1;
Abgasmodus += 1;
if (Abgasmodus > MAXABGAS) Abgasmodus = 0;
}
}
rotating = false;
}
}
void draw(char what[20]) {
u8g2.clearBuffer(); // clear the internal memory
u8g2.setFont(u8g2_font_10x20_tf); // choose a suitable font
u8g2.drawRFrame(0, 0, 128, 32, 5);
u8g2.drawStr(5, 22, what); // write something to the internal memory
u8g2.sendBuffer(); // transfer internal memory to the display
}