Hilfe bei Programmieren von Geigerzähler

Hallo, ich bin absoluter Anfänger und habe fast gar keine Ahnung von Arduino. Ich habe eine Geigerzähler Platine von Amazon gekauft und den VIN Anschluss des Zählers mit dem 3. Digitalport des Arduino verbunden. Ein SH1106 OLED-Display zeigt die Messwerte an. Es hat 4 Anschlüsse, 2 für Strom (VDD und GND) sowie einen SCK, der am A5 des Arduino hängt und einen SDA der am A4 hängt. Den Code hab ich aus dem Internet und hab ihn etwas modifiziert. Der Code misst für 10 Sekunden die Interrupt Impulse, und rechnet das Ergebnis mal 6. So erhalte ich die Counts per Minute (cpm) diese werden mal 0,0081 gerechnet um auf die Einheit uSv/h zu kommen. Angezeigt wird cpm und uSv/h. Der Code funktioniert, ich möchte aber noch eine Funktion hinzufügen. In der letzten Zeile sollen noch cpm und uSv/h von den tatsächlichen letzten 60 Sekunden gezeigt werden. Reicht aus wenn dieser Wert alle 60 Sekunden neu berechnet wird, schnelleres aktualisieren der Anzeige für die letzte Minute wär aber schöner. Ich hoffe ihr könnt mir helfen. Hier der Code:


#include <Wire.h>
#include <U8glib.h>

const int Interruptpin = 3;       // GPIO Anschluss des Zählrohrs
const int durchlaufzeit = 10000;  // 10 Sekunden
unsigned long treffer;            // Gezählte Treffer des Zählrohrs
unsigned long tpm;                // Treffer pro Minute

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
U8GLIB_SH1106_128X64 u8g(U8G_I2C_OPT_NONE);

void setup() {
  treffer = 0;
  tpm = 0;
  pinMode(Interruptpin, INPUT);
  u8g.begin();
  delay(2000);
  u8g.firstPage();
  do {
    u8g.setFont(u8g_font_6x10);
    u8g.drawStr(3, 10, "Geigerzähler");
    u8g.drawStr(5, 35, "Willkommen");
  } while (u8g.nextPage());
  
  // immer wenn fallendes Signal am Geigerzähler soll Funktion counter_hit Zähler um 1 erhöhen
  attachInterrupt(digitalPinToInterrupt(Interruptpin), counter_hit, FALLING);
}

void loop() {
  static unsigned long startzeit;
  unsigned long zeit = millis();  // Millisekunden seit Auslöser
  double uSv; // Microsievert Wert pro Stunde

  // Wert errechnen beim Ende der Durchlaufzeit
  if (zeit - startzeit > durchlaufzeit) {
    startzeit = zeit;
    if (treffer) {
      tpm = treffer * 6; // Treffer pro Durchlauf mal Wert um auf eine Minute zu kommen
      uSv = tpm * 0.0081; // Zählrohr Konversationsrate J305: 153,8 CPM = 1 uSv/h 
    } else {
      uSv = 0;
    }
    
    u8g.firstPage();
    do {
      u8g.setFont(u8g_font_6x10);
      u8g.drawStr(7, 10, "Messung aktiv");
      u8g.drawStr(7, 18, "Treffer:");
      u8g.setPrintPos(57, 18);
      u8g.print(treffer);
      u8g.drawStr(7, 30, "pro Minute cpm:");
      u8g.setPrintPos(100, 30);
      u8g.print(tpm);
      u8g.drawStr(7, 43, "uSv/h:");  // Mikrosievert/h
      u8g.setPrintPos(50, 43);
      u8g.print(uSv, 4);
    
      
    } while (u8g.nextPage());

    treffer = 0;
    tpm = 0;
  }
  delay(50);
}

void counter_hit() {
  treffer++;  // bei Treffer plus 1 pro Durchlaufzeit
}

Wirklich?
Was ist der 3. Digitalport?

Grüße Uwe

Hallo @paul_lorenz_32c

herzlich willkommen im Forum.
Sehr gut gemacht den Code als Code-Section zu posten und eine präzise Beschreibung zu posten.

Man braucht ja ein bisschen Zeit zum lesen. Also alle 10 Sekunden ablesen.
Du nimmst einen Array mit 13 Elementen (Index-Zählweise 0,1,2,3,4,5,6,7,8,9,10,11,12)
Wegen dem Start bei Index 0 sind es dann 13 Elemente

Das nullte Element wird dann gar nicht benutzt. Muss aber trotzdem da sein.
Der Indexzähler startet bei 1
nach 10 Sekunden Zählwert im Element 1 speichern
nach 20 Sekunden Zählwert im Element 2 speichern
...
nach 60 Sekunden Zählwert im Element 6 speichern
Damit ist der gleitende Summenspeicher zum ersten mal gefüllt
Jetzt kann man Elemente 1 bis 6 Zusammenzählen und hat den 60 Sekundenwert

nach 70 Sekunden Zählwert im Element 7 speichern
jetzt kann man die Elemente 2 bis 7 zusammenzählen und hat den nächsten Summenwert

nach 80 Sekunden Zählwert im Element 8 speichern
jetzt kann man die Elemente 3 bis 8 zusammenzählen und hat den nächsten Summenwert
....
nach 120 Sekunden Zählwert im Element 12 speichern
jetzt kann man die Elemente 7 bis 12 zusammenzählen und hat den nächsten Summenwert

Wenn man bei Index 12 angekommen ist wird der Index auf 1 zurückgesetzt
Und der nächste 10 Sekundenwert wird wieder in Element 1 gespeichert
dann kann man Elemente 1 bis 6 Zusammenzählen und hat den 60 Sekundenwert
usw. usw. so läuft das dann im Kreis

Wenn du noch kürzere Intervalle willst dann muss eben die Zeitkontstante kleiner werden
und der Array entsprechend mehr Elemente haben.

Kann sein. Das wirst du jetzt ändern indem du mal einen Programmierversuch machst
oder
in dem du spezifische Fragen stellst.
Was immer auch die Frage sein mag.

Dieser Forum funktioniert NICHT so, dass man hier seinen Funktionalitätswunsch postet und dann alles fertig programmiert bekommt.

vgs

Kann sein das er nicht so heißt. Ich mein den Anschluss 3~

Du kannst keinen digitalen Ausgang als Versorgungspin für eine Schaltung nehmen.
Grüße Uwe

Kurz gebastelt.

#include <Wire.h>
#include <U8glib.h>

const int Interruptpin = 3;       // GPIO Anschluss des Zählrohrs
const int durchlaufzeit = 10000;  // 10 Sekunden
const uint8_t maxIdx = 6;
uint32_t allTpm[maxIdx] = {0};
uint8_t idx;

unsigned long treffer;            // Gezählte Treffer des Zählrohrs
unsigned long tpm;                // Treffer pro Minute

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
U8GLIB_SH1106_128X64 u8g(U8G_I2C_OPT_NONE);

void setup()
{
  treffer = 0;
  tpm = 0;
  pinMode(Interruptpin, INPUT);
  u8g.begin();
  delay(2000);
  u8g.firstPage();
  do
  {
    u8g.setFont(u8g_font_6x10);
    u8g.drawStr(3, 10, "Geigerzähler");
    u8g.drawStr(5, 35, "Willkommen");
  } while (u8g.nextPage());
  // immer wenn fallendes Signal am Geigerzähler soll Funktion counter_hit Zähler um 1 erhöhen
  attachInterrupt(digitalPinToInterrupt(Interruptpin), counter_hit, FALLING);
}

void loop()
{
  static unsigned long startzeit = 0;
  unsigned long zeit = millis();  // Millisekunden seit Auslöser
  double uSv = 0; // Microsievert Wert pro Stunde
  // Wert errechnen beim Ende der Durchlaufzeit
  if (zeit - startzeit > durchlaufzeit)
  {
    startzeit = zeit;
    if (treffer)
    {
      tpm = treffer * 6; // Treffer pro Durchlauf mal Wert um auf eine Minute zu kommen
      uSv = tpm * 0.0081; // Zählrohr Konversationsrate J305: 153,8 CPM = 1 uSv/h
      allTpm[idx] = tpm;
      idx++;
      if (idx >= maxIdx)
      { idx = 0; }
    }
    u8g.firstPage();
    do
    {
      u8g.setFont(u8g_font_6x10);
      u8g.drawStr(7, 10, "Messung aktiv");
      u8g.drawStr(7, 18, "Treffer:");
      u8g.setPrintPos(57, 18);
      u8g.print(treffer);
      u8g.drawStr(7, 30, "pro Minute cpm:");
      u8g.setPrintPos(100, 30);
      u8g.print(tpm);
      u8g.drawStr(7, 43, "uSv/h:");  // Mikrosievert/h
      u8g.setPrintPos(50, 43);
      u8g.print(uSv, 4);
      // Ab hier neu: XX ersetzen!
      uint32_t minuteTpm = 0;
      for (byte b = 0; b < maxTmp; b++)
      { minuteTpm += allTpm[b]; }
      u8g.setPrintPos(XX, XX);
      u8g.print(minuteTpm);
      u8g.setPrintPos(XX, XX);
      u8g.print(minuteTpm * 0.0081);
      // Ende neu
    } while (u8g.nextPage());
    treffer = 0;
    tpm = 0;
  }
  delay(50);
}

void counter_hit()
{
  treffer++;  // bei Treffer plus 1 pro Durchlaufzeit
}

Dein Code hat eine Schwachstelle bei der Verarbeitung von treffer.

Danke für die Hilfe. Ich habe deinen Code aufgespielt. Beide neuen Werte werden zwar angezeigt, allerdings bewegt sich der minuteTpm immer zwischen 100 und 200, während der vorher schon existierende tpm auf Basis der 10 Sekunden bei 15 bis 40 liegt. Dementsprechend auch ein Unterschied zwischen uSv und minuteTpm+0,0081. Weißt du woran das liegen könnte. (Zählt man das Klicken des Geigerzählers pro Minute sind die 15-40 realistisch)
Und dann interessiert mich noch wo die Schwachstelle in der Verarbeitung der Treffer liegt.

Viele Grüße, Paul

Dann ist es doch richtig.
Du bekommst 6 mal den Wert, der im 10 Sekundentakt aufaddiert war.
Der muss also irgendwo zwischen 6*15 und 6*40 liegen. :slight_smile:

Das war doch die Ausgangssituation:

Wenn Du jetzt den Mittelwert der letzten 60 sekunden haben willst, dann
Alt:

Neu:

      // Ab hier neu: XX ersetzen!
      uint32_t minuteTpm = 0;
      for (byte b = 0; b < maxTmp; b++)
      { minuteTpm += allTpm[b]; }
      minuteTpm/=maxTmp;
      u8g.setPrintPos(XX, XX);
      u8g.print(minuteTpm);
      u8g.setPrintPos(XX, XX);
      u8g.print(minuteTpm * 0.0081);
      // Ende neu

Ja, Mist. Du hast Deinen Post gelöscht, während ich schreibe...

Danke dir, der Code funktioniert. Ich musste aber in folgendem Codeteil



      allTpm[idx] = tpm;
      idx++;

Das tpm durch Treffer ersetzen, um auf den Durchschnitt zu kommen. Könnte es sein dass es da ein Missverständnis über die Bedeutung von treffer und tpm gab oder meinst du was anders mit dem Problem in der Verarbeitung von treffer zu tpm?

Du meinst wohl maxIdx

vgs

Ja, das hab ich bei mir geändert.

Wenn du selbsterklärende Variablen-Namen verwenden würdest gäbe es weniger Mißverständnisse

Ja.
Eine Variable zu füttern, deren Inhalt zur Laufzeit errechnet werden kann, macht manchmal solche... :man_shrugging:
Aber hast ja gefunden, auf was es rausläuft. :wink:

Solltest Du noch Fragen zur Verarbeitung eines 32bit Wertes auf einem 8bit Controller haben, musst Du den Post wiederherstellen... :wink:
Erklär ich dann morgen.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.