Go Down

Topic: Motorradtacho mit Arduino nano // Hilfe benötigt (Read 962 times) previous topic - next topic

BwieBertha

Aug 08, 2018, 04:48 pm Last Edit: Aug 08, 2018, 04:49 pm by BwieBertha
Hallo Kollegen,
ich hab ein komisches Problem mit einem Motorradtacho-Sketch, welches ich nicht recht inWorte fassen kann.. daher hab ich auch keinen aussagekräftigeren Titel gewählt (Falls jemand eine gute Idee hat - bitte melden ):

Also... Ich programmiere mir gerade einen kleinen Tacho für mein Motorrad. Vereinfacht gesagt wird per Reedschalter eine Interruptroutine ausgelöst, in der ich die Geschwindigkeit berechne. Das ganze wird dann  auf einem 0.96" oled dargestellt und der Kilometerstand (Gesamt & Trip) zyklisch ins Eeprom weggeschrieben.
Bis gestern funktionierte auch alles, dann bin ich aber über ein (für mich) unerklärliches Phänomen gestolpert.
Sobald ich in void setup() die drei zeilen ab //  if (GesamtMeter > 3000 ) ..... einkommentiere, gibt mir die RunningAverage Funktion (zur "Glättung" der Geschwindkeit) nur noch "nan" (not a number) aus und der Tacho funktioniert nicht mehr. Kommentiert man diese drei Zeilen wieder raus, klappt alles.

Ich konnte das Problem auf die Variable "Gesamtmeter" eingrenzen. Sobald man damit irgendwas in void-setup anstellt, funktinoiert RunningAverage nicht mehr... (Serial.println(GesamtMeter); führt zum selben Problem)


Wieso tangiert diese Variable die RunningAverage Funktion?
Für mich als Anfänger ist das sehr befremdlich :)

Unten findet ihr den aufs wesentliche gekürzten Code. Als Attachement habe ich die ungekürzte Version angehängt.

danke im Voraus

mfg
Basti


Code: [Select]


#include <EEPROM.h>
#include <RunningAverage.h>
#include <Wire.h>
#include "OneButton.h"
#include <U8g2lib.h>
#include "RTClib.h"

U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE, /* clock=*/ 16, /* data=*/ 17);   // ESP32 Thing, HW I2C with pin remapping
RTC_DS3231 rtc;


RunningAverage myRA(5);
volatile unsigned long dauer = 0;
volatile unsigned long last = 0;              // Zählerwert beim letzten Interrupt
short geschwindigkeit;                         
short VAnzeige;
const int buttonPin = 4;
const int reedPin = 3;
int screen = 0;
volatile int RotationCounter = 0;
OneButton button(buttonPin, true);
char Minute[3];
char Stunde[3];
const int RadUmfang = 1862;
char Uhrzeit[10];
char Temperatur[15];
char Speed[10];
float dummyInterval = (RadUmfang/1000.0 * 160.0);

unsigned long GesamtMeter;
unsigned long TripMillimeter;
int GesamtMeter_ADDR = 0;
int TripMillimeter_ADDR = GesamtMeter_ADDR + 4;
char TripKm[10];
char GesamtKm[10];
int testMeter = 0;
boolean reset = 0;


   
void setup()   {
  Serial.begin(9600);      // open the serial port at 9600 bps:

  if (reset) { resetEEPROM(); }     //alles auf 0 setzen
 
  pinMode(reedPin, INPUT_PULLUP); // Reed-Sensor an Pin 3
  pinMode(buttonPin, INPUT_PULLUP); // Taster an Pin 2
  attachInterrupt(digitalPinToInterrupt(reedPin), readmillis, RISING);
  GesamtMeter = eepromReadLong(GesamtMeter_ADDR);
  TripMillimeter = eepromReadLong(TripMillimeter_ADDR);

//  if (GesamtMeter > 3000 ) {
//    Serial.println("EEPROMschonen()");
//    }

  myRA.clear();
  button.attachClick(klick);
  button.attachLongPressStop(langDruck);
  u8g2.begin();
  delay(500);
 
}



void loop() { 

      if (RotationCounter >= 160) {    //ungefähr alle 300m Tachostand ins EEprom wegschreiben und GesamtMeter hochzählen
         RotationCounter = 0;
         GesamtMeter += dummyInterval;  //alle 160 Umdrehungen Radumfang (mm) auf Gesamtlaufleistung (Meter) addieren
         eepromWriteLong(GesamtMeter, GesamtMeter_ADDR);
         eepromWriteLong(TripMillimeter, TripMillimeter_ADDR);
       }

      button.tick();
           
      if (millis()-last >= 2000) {
        myRA.clear();                       //wenn keine Radumdrehung innerhalb von 2 Sek stattgefunden hat --> Geschwindigkeit nullen
      }
     
      VAnzeige = myRA.getAverage();        // Mittelwert errechnen
      u8g2.clearBuffer();
      draw();     
      u8g2.sendBuffer();
      delay(100);
}


void draw() {
  u8g2_prepare();
  DateTime now = rtc.now();
  sprintf(Uhrzeit, "%02d:%02d", now.hour(), now.minute());
  int hunderter = (TripMillimeter / 100000) % 10;
  int tausender = TripMillimeter / 1000000;
  sprintf(GesamtKm, "%6dkm", GesamtMeter/1000);
  sprintf(TripKm, "%5d.%dkm", tausender, hunderter);
  sprintf(Speed, "%3d", VAnzeige);
 
  switch (screen) {
    case 0:
      u8g2.setFont(u8g2_font_logisoso38_tn);
      u8g2.drawStr( 5, 15, Uhrzeit);   
    break;
    case 1:
      u8g2.drawXBMP( 80, 0, tachoSymbol_width, tachoSymbol_height, tachoSymbol); 
      u8g2.setFont(u8g2_font_logisoso38_tn);   
      u8g2.drawStr( 0, 15, Speed);   
      u8g2.setFont(u8g2_font_logisoso20_tr);
      u8g2.drawStr( 75, 32, "kmh");
    break; 
    case 2:
      u8g2.setFont(u8g2_font_logisoso20_tr);
      u8g2.drawStr( 0, 10, "Trip:");
      u8g2.drawStr( 0, 40, TripKm);
      u8g2.drawXBMP( 80, 0, route_width, route_height, route_bits); 
    break;
    case 3:
      u8g2.drawStr( 0, 40, TripKm);
      u8g2.drawStr( 5, 10, GesamtKm);
    break;
    case 4:
      u8g2.setFont(u8g2_font_logisoso38_tn);
      u8g2.setCursor(0, 15);
      u8g2.print(tempDS3231(), 1);
      u8g2.drawCircle(98, 20, 5, U8G2_DRAW_ALL);  //nicht besonders schön, aber speicher-optimalste Veriante ??
      u8g2.drawCircle(98, 20, 4, U8G2_DRAW_ALL);
      u8g2.drawXBMP( 105, 0, thermometer_width, thermometer_height, thermometer_Symbol); 
    break;               
    }
}


void u8g2_prepare(void) {
  u8g2.setFontRefHeightExtendedText();
  u8g2.setDrawColor(1);
  u8g2.setFontPosTop();
  u8g2.setFontDirection(0);
}


void readmillis() {                           // Interrupt-Routine
 
  unsigned long m = millis();                 // Microsekundenzähler auslesen
  unsigned long v = m - last;                 // Differenz zum letzten Durchlauf berechnen
  if (v > 20) {                               // ignorieren wenn <= 10ms (Kontaktpreller)
    dauer = v;                                // Dauer einer Radumdrehung in ms
    last = m;                                 // und wieder den neuen Wert merken
    geschwindigkeit = RadUmfang*3.6/dauer;             // Geschwindigkeit: 1 Interrupt alle 1861mm (Radumfang)
    myRA.addValue(geschwindigkeit);           // Wert zur Mittelwerberechnung hinzufügen
    TripMillimeter += RadUmfang;                    //pro Umdrehung 1861mm gefahren
    RotationCounter += 1;
    Serial.println(myRA.getAverage());
    }
}

void klick() {   //durchtoggeln der Screens
  screen++; 
  if (screen > 4) { screen= 0; }
 }

void langDruck() {   
  if (screen == 2)  {
    TripMillimeter = 0;   //Trip zurücksetzen
    eepromWriteLong(TripMillimeter, TripMillimeter_ADDR);
    }
}


float tempDS3231() {    // Die Temperatur des DS3231 auslesen 
  float temp;
  int msb, lsb;
  Wire.beginTransmission(0x68);
  Wire.write(0x11); // DS3231 Register zu 11h
  Wire.endTransmission();
  Wire.requestFrom(0x68, 2); // 2 Byte Daten vom DS3231 holen
  msb = Wire.read();
  lsb = Wire.read();
  temp=((msb << 2) + (lsb >> 6) ) /4.0;
  return temp;
}


void eepromWriteLong(long lo, int adr) {
    byte by;
    for(int i=0;i< 4;i++) {
      by = (lo >> ((3-i)*8)) & 0x000000ff;
      EEPROM.write(adr+i, by);
    }
}

long eepromReadLong(int adr) {
  long lo=0;
  for(int i=0;i< 3;i++){
    lo += EEPROM.read(adr+i);
    lo = lo << 8;
  }
  lo += EEPROM.read(adr+3);
  return lo;
}





agmue

Ich sehe einen Typkonflikt:

Code: [Select]
unsigned long GesamtMeter;
...
GesamtMeter = eepromReadLong(GesamtMeter_ADDR);
...
long eepromReadLong(int adr) {
...


Ob das mit Deinem Problem zu tun hat, weiß ich aber nicht.
Wahnsinn und Verstand trennt nur eine dünne Wand. (Daniel Düsentrieb)

BwieBertha

#2
Aug 08, 2018, 05:49 pm Last Edit: Aug 08, 2018, 06:03 pm by BwieBertha
Also das unsigned entfernen?

Edit:
mit "long GesamtMeter;" klappt es auch nicht (falls du das gemeint hast)...

mfg
basti

agmue

Also das unsigned entfernen?
Eher umgekehrt, weil der Wert nicht negativ werden kann.
Wahnsinn und Verstand trennt nur eine dünne Wand. (Daniel Düsentrieb)

BwieBertha

#4
Aug 08, 2018, 06:26 pm Last Edit: Aug 08, 2018, 06:27 pm by BwieBertha
Ok, aber ohne unsigned gibt es doch keinen Konflikt mehr... Sinnhaftigkeit hin oder her...

Somit dürfte mein Problem woanders liegen...

BwieBertha

Kleines Update:
Ich habe rausgefunden, dass das Problem verschwindet, sobald man diese Line auskommentiert (auch wenn sie viel später im code steht):

Code: [Select]
sprintf(Uhrzeit, "%02d:%02d", now.hour(), now.minute());

Mache ich da irgendwas falsch?


Bin gerade etwas angefressen O_o...

mfg
basti

gregorss

Ich habe rausgefunden, dass das Problem verschwindet, sobald man diese Line auskommentiert (auch wenn sie viel später im code steht):
Wo sich die Ursache für ein Fehlverhalten versteckt, ist eines der vielen großen und kleinen Adventures, die man im Leben spielt. Manchmal helfen nur gute Flüche und ein Backup. Glücklich ist, wer versioniert :-)

Gruß

Gregor
„Ich glaube, ich leg' mich noch mal hin", sagte das Bit.

BwieBertha

Danke......

Mittlerweile hab ich noch zwei weitere Ungereimtheiten gefunden, die sich jedoch alle in Luft auflösen, wenn ich sämtliche sprintf() Anweisungen rausnehme.

Kann mir jemand sagen ob ich da was falsch mache?
Oder ist diese Funktion generell mit Vorsicht zu genießen?

Hilfe...

HotSystems

Danke......

Mittlerweile hab ich noch zwei weitere Ungereimtheiten gefunden, die sich jedoch alle in Luft auflösen, wenn ich sämtliche sprintf() Anweisungen rausnehme.

Kann mir jemand sagen ob ich da was falsch mache?
Oder ist diese Funktion generell mit Vorsicht zu genießen?

Ja ist doch super.
Funktioniert dann dein Sketch noch ?

Im übrigen sind alle Funktionen und Anweisungen mit Vorsicht zu genießen, wenn man nicht damit umgehen kann.

Einfach mal die Dokumentation dazu lesen.
Gruß Dieter

I2C = weniger ist mehr: weniger Kabel, mehr Probleme. 8)

BwieBertha

Nein, mein sketch funktioniert nicht mehr ohne sprintf.
Des weiteren bin ich mir sicher, sprintf richtig zu verwenden.
Das Problem muss wo anders liegen.... Evtl ein Speicherschmierer?

anwofis

Hallo,

also dein Sketch kompiliert erfolgreich.

Wenn du NaN bekommst wirst du wahrscheinlich irgendwo Quatsch einlesen oder durch 0 teilen oder sowas.

MfG,

anwofis

BwieBertha

#11
Aug 09, 2018, 11:36 am Last Edit: Aug 09, 2018, 12:06 pm by BwieBertha
Das kann ich eigentlich ausschließen....

Es sei denn, die RunnigAverage Lib hat einen bug, aber das kann ich mir nicht vorstellen.

Edit: (Um das nochmal zu präzisieren:)
RunningAverage liest hier immer 5 (Geschwindigkeits-)Werte ein und bildet dann den Mittelwert.
Ich habe mir jeden dieser Werte vorher ausgeben lassen - alle waren ok (zwischen 0 und 210).
Allerdings bringt die Abfrage von RA.getElement(0) schon NaN (obwohl die Input-Größe wie besagt nachweislich ok war).

 

anwofis

Hab mal den RunningAverage getestet:

Code: [Select]
#include <RunningAverage.h>

const uint8_t ra_size = 5;

RunningAverage my_RA(ra_size);

void setup(void) {
  Serial.begin(115200);
  my_RA.clear();
  //my_RA.fillValue(0.0,ra_size);
  randomSeed(analogRead(0));
}

void loop(void) {
  my_RA.addValue(random(300) * 1.0);
  for (uint8_t ii = 0; ii < ra_size; ii++) {
    Serial.print(my_RA.getElement(ii));
    Serial.print(" ");
  }
  Serial.println(my_RA.getAverage());
  delay(2000);
}


Wenn du nur "clear()" verwendest wird der RA mit NaN initialisiert. Vllt. liegts daran?

BwieBertha

Ja, das weiß ich. Aber ich füge ja laufend neue Werte hinzu....

Wenn ich die sprintf auskommentiere funktioniert auch alles...

Mir ist einfach dieser Zusammenhang unklar.


anwofis

Hallo,

ich hab mir mal die Warnungen beim Kompilieren (kannst du unter Einstellungen alle anschalten) angesehen:

In deiner draw() steht:

Code: [Select]
sprintf(GesamtKm, "%6dkm", GesamtMeter/1000);

GesamtMeter ist aber unsigned long. Sollte also sowas sein wie:

Code: [Select]
sprintf(GesamtKm, "%6lukm", GesamtMeter/1000);

Vllt. hilft das ja.

Go Up