Arduino Forum

International => Deutsch => Topic started by: BwieBertha on Aug 08, 2018, 04:48 pm

Title: Motorradtacho mit Arduino nano // Hilfe benötigt
Post by: BwieBertha on Aug 08, 2018, 04:48 pm
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;
}




Title: Re: Motorradtacho mit Arduino nano // Hilfe benötigt
Post by: agmue on Aug 08, 2018, 05:21 pm
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.
Title: Re: Motorradtacho mit Arduino nano // Hilfe benötigt
Post by: BwieBertha on Aug 08, 2018, 05:49 pm
Also das unsigned entfernen?

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

mfg
basti
Title: Re: Motorradtacho mit Arduino nano // Hilfe benötigt
Post by: agmue on Aug 08, 2018, 06:17 pm
Also das unsigned entfernen?
Eher umgekehrt, weil der Wert nicht negativ werden kann.
Title: Re: Motorradtacho mit Arduino nano // Hilfe benötigt
Post by: BwieBertha on Aug 08, 2018, 06:26 pm
Ok, aber ohne unsigned gibt es doch keinen Konflikt mehr... Sinnhaftigkeit hin oder her...

Somit dürfte mein Problem woanders liegen...
Title: Re: Motorradtacho mit Arduino nano // Hilfe benötigt
Post by: BwieBertha on Aug 09, 2018, 12:26 am
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
Title: Re: Motorradtacho mit Arduino nano // Hilfe benötigt
Post by: gregorss on Aug 09, 2018, 12:46 am
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
Title: Re: Motorradtacho mit Arduino nano // Hilfe benötigt
Post by: BwieBertha on Aug 09, 2018, 01:56 am
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...
Title: Re: Motorradtacho mit Arduino nano // Hilfe benötigt
Post by: HotSystems on Aug 09, 2018, 08:36 am
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.
Title: Re: Motorradtacho mit Arduino nano // Hilfe benötigt
Post by: BwieBertha on Aug 09, 2018, 10:59 am
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?
Title: Re: Motorradtacho mit Arduino nano // Hilfe benötigt
Post by: anwofis on Aug 09, 2018, 11:32 am
Hallo,

also dein Sketch kompiliert erfolgreich.

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

MfG,

anwofis
Title: Re: Motorradtacho mit Arduino nano // Hilfe benötigt
Post by: BwieBertha on Aug 09, 2018, 11:36 am
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).

 
Title: Re: Motorradtacho mit Arduino nano // Hilfe benötigt
Post by: anwofis on Aug 09, 2018, 01:15 pm
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?
Title: Re: Motorradtacho mit Arduino nano // Hilfe benötigt
Post by: BwieBertha on Aug 09, 2018, 01:25 pm
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.

Title: Re: Motorradtacho mit Arduino nano // Hilfe benötigt
Post by: anwofis on Aug 09, 2018, 03:33 pm
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.
Title: Re: Motorradtacho mit Arduino nano // Hilfe benötigt
Post by: BwieBertha on Aug 09, 2018, 11:56 pm
Habs eben probiert - bringt leider keine Änderung meines Problems ....

Danke dennoch!
Title: Re: Motorradtacho mit Arduino nano // Hilfe benötigt
Post by: BwieBertha on Aug 11, 2018, 09:37 pm
Hallo Kollegen,
sorry aber ich muss den Thread nochmal aufwärmen, da ich hier einfach nicht weiterkomme.
Ich habe meinen Sketch auf ein (kompilierendes) Minimum runtergestrickt; den Fehler "provoziere" ich in der Setup() Routine.
Hier übergebe ich 5 Werte an Runningaverage und lese anschließend den Mittelwert aus. Nach wievor bekomme ich "nan" als Rückgabewert.
Allerdings wird das Problem gelöst, wenn ich:

Eine dieser Aktionen reicht!!! Das macht doch alles keinen Sinn.
Wie kann eine Funktion in void setup() von später aufgerufenen Funktionen beeinflusst werden? Zumal diese Funktionen nichts mit RunningAverage zu tun haben?

ARGH!!!!  :o

Code: [Select]

#include <EEPROM.h>
#include <RunningAverage.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);
short VAnzeige;
const int buttonPin = 4;
OneButton button(buttonPin, true);
char Speed[10];

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

void setup()   {
  Serial.begin(9600);      // open the serial port at 9600 bps:
   
  myRA.clear();
  Serial.println("5 Werte werden übergeben");
  myRA.addValue(5);
  myRA.addValue(100);
  myRA.addValue(20);
  myRA.addValue(30);
  myRA.addValue(77);
  Serial.println(myRA.getAverage()); 

  getKilometerstand();                                   //gespeicherten Tachostand abrufen (eeprom-adresse mit höchstem Zählerstand suchen)

}

void loop() {                   
  u8g2.clearBuffer();
  draw();     
  u8g2.sendBuffer();
}


void draw() { 
  DateTime now = rtc.now();
  int hunderter = (TripMillimeter / 100000) % 10;
  int tausender = TripMillimeter / 1000000;
  sprintf(GesamtKm, "%6ldkm", GesamtMeter/1000);
  sprintf(TripKm, "%5d.%dkm", tausender, hunderter);
  sprintf(Speed, "%3d", VAnzeige);
  }

void getKilometerstand(){     
  EEPROM.get(GesamtMeter_ADDR, GesamtMeter);   
  EEPROM.get(TripMillimeter_ADDR, TripMillimeter);
  Serial.println("########");
  Serial.println("gefundener Kilometerstand:");     
  Serial.println(GesamtMeter);
}


Title: Re: Motorradtacho mit Arduino nano // Hilfe benötigt
Post by: anwofis on Aug 11, 2018, 10:35 pm
Hallo,

ich bekomme beim Kompilieren für den Nano folgende Meldung und auch dein Problem:

Quote
Der Sketch verwendet 12748 Bytes (41%) des Programmspeicherplatzes. Das Maximum sind 30720 Bytes.
Globale Variablen verwenden 1859 Bytes (90%) des dynamischen Speichers, 189 Bytes für lokale Variablen verbleiben. Das Maximum sind 2048 Bytes.
Wenig Arbeitsspeicher verfügbar, es können Stabilitätsprobleme auftreten.
Am Mega läufts einwandfrei.
Title: Re: Motorradtacho mit Arduino nano // Hilfe benötigt
Post by: BwieBertha on Aug 11, 2018, 10:37 pm
öh.. ist das Verhalten also "geräteabhängig"?????

Es beruhigt mich aber _ungemein_, dass du das Problem nachstellen kannst.
Title: Re: Motorradtacho mit Arduino nano // Hilfe benötigt
Post by: postmaster-ino on Aug 11, 2018, 10:45 pm
Hi

Hast Du einen Link zur RunningAverage?
Die fehlt mir und in der Arduino-eigenen-Bibliotheks-Auswahl ist Diese nicht enthalten.
-> bei mir kompiliert der Sketch so nicht (bisher das Einzige, was Er anmeckert)

MfG

PS:
Wenig Arbeitsspeicher verfügbar, es können Stabilitätsprobleme auftreten.
Das soll Dir sagen, daß beim Anlegen diverser lokalen Variablen der Speicher ausgehen wird und der Arduino Mist baut.
Du hast sehr sehr viele globale Variablen - überdenke, Welche Du davon wirklich global  brauchst und Welche Du nur innerhalb irgend welcher Abläufe benötigst.
Wobei in diesem Sketch DEINE Variablen echt übersichtlich sind - die ganzen eingebundenen Libs werden sich dort großzügig bedient haben - aber z.B. das Display wird den Puffer wohl brauchen.
Title: Re: Motorradtacho mit Arduino nano // Hilfe benötigt
Post by: anwofis on Aug 11, 2018, 10:46 pm
In der Wanung steht, dass schon 90% des RAM belegt sind. Ich kenne mich jetzt auch nicht so aus - ich glaub', dass dann für lokale Variablen kein Platz mehr da sein könnte. Ich vermute die u8g2lib ist einfach zu groß.

Dieser Sketch brauch schon 74%:

Code: [Select]
#include <U8g2lib.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

void setup() {}

void loop() {}


Title: Re: Motorradtacho mit Arduino nano // Hilfe benötigt
Post by: BwieBertha on Aug 11, 2018, 10:53 pm
Danke für eure Hinweise - ich wäre nie drauf gekommen, dass zuwenig Arbeitsspeicher schon zu Problemen in der Setup-Routine führen kann.

Der Speicherhunger von u8g2 stellt mich jetzt natürlich vor ein konzeptionelles Problem, da ich da nicht drauf verzichten kann.
Wieviel Arbeitsspeicher darf ich denn belegen, um auf der sicheren Seite zu sein?

@ino-postmaster:
Ich hab dir die RunningAverage angehängt..
Alternative hier zu finden: https://github.com/RobTillaart/Arduino/tree/master/libraries/RunningAverage

mfg

Basti
Title: Re: Motorradtacho mit Arduino nano // Hilfe benötigt
Post by: anwofis on Aug 12, 2018, 11:07 am
Gibt's da keine kompaktere Bibliothek für dein Display? Ist das so ein kleines OLED-Ding? Sonst fällt mir nur ein einen Mega oder so zu nehmen.