Frequenzen messen

Hallo,

ich möchte 3 Frequenzen messen.
Es handelt sich dabei um 3 Lüfter, die ich optisch abtaste.
Ich habe also bereits 3 saubere Signale im Bereich von etwa 20-60Hz.
Soweit so gut.
Nun habe ich dies an einem ESP8266 dran.
Funktioniert auch schon.....
.....allerdings kommt es in völlig unregelmäßigen Abständen (manchmal 3x innerhalb von 2 Minuten, manchmal läuft es eine Stunde fehlerfrei) zu Warmboots.
Die Stromversorgung konnte ich bereits ausschließen, die ist absolut einwandfrei.
Ich vermute, es liegt daran, dass auf 3 Kanälen ständig Interrupts ausgelöst werden.
Irgendwann überlagern sich diese so sehr, dass der ESP8266 nicht mehr genug Zeit für seine Kernfunktionen bekommt und einen Warmstart ausführt.

Um das zu umgehen suche ich nun einen Baustein / Chip, der das Impulszählen übernimmt und dann die Daten an den ESP8266 sendet.

Ich stelle mir das so vor, dass der Chip 60 Sekunden lang die Impulse zählt, und dann z.B. über I2C den Wert an den ESP8266 sendet, und dann wieder von vorne beginnt zu zählen.
Die Hardware soll dabei gerne so einfach wie möglich sein.

Hat jemand eine Idee mit welchem Baustein man sowas möglichst einfach realisieren kann?

Lieben Dank und lieben Gruß,
Chris

Hi

Selbst 200 Ereignisse in der Sekunde sollten KEINEN µC aus der Ruhe bringen können.
Ich denke, Du hast ein Stack-Überlauf.
Ist in Deinem Code die Freigabe der/des Interrupt bereits in der ISR gegeben?

Es ist im Allgemeinen keine gute Idee, Probleme zu umgehen - zumindest sollte man Diese zuvor identifiziert haben, bevor man sich für ein work-around entscheidet.

Kann ja nicht angehen, daß ich meinen Hyper-Sportwagen alle drei Sekunden aus machen muß, da nach einer Minute kein Gas mehr angenommen wird und ich dann beim Ampelstart blöd aussehe ...

MfG

Müsste ein Stack Überlauf nicht in regelmäßigen Perioden auftreten?
Ich habe den Code leider nicht geschrieben. Der Code gehört zu ESPEasy. Dort im Forum schrieb man als Antwort, dass der Code für sehr niederfrequente Gas/Wasserzähler ausgelegt ist.
Hättest du ein Codebeispiel wie man einen Frequenzzähler idealer Weise programmiert?

Liebe Dank und liebe Grüße,
Chris

Hi

Du könntest die Startzeit merken (Startzeit=millis(); ) und die Eingänge der Sensoren pollen.

If (sensor1==high && sensor1old==low){
   spin1++;
   sensor1old=sensor1;
}

Das mit den drei Sensoren.
Unter die drei Abfragen schaust Du dann, ob Deine Messzeit abgelaufen ist

if (millis()-Startzeit>=Messzeit){
   //Messwerte ausgeben/verarbeiten
   //Messwerte auf Null zurück setzen
}

Weiter ist es etwas schwierig, Fehler/Unzulänglichkeiten in einem nicht vorliegendem Code zu suchen :wink:

MfG

Hallo postmaster-ino,

vielen Dank für die Antwort.

Der komplette Code von dem Plugin sieht folgendermaßen aus:

//#######
//### Plugin 003: Pulse  ###
//#######
#define PLUGIN_003
#define PLUGIN_ID_003         3
#define PLUGIN_NAME_003       "Pulse Counter"
#define PLUGIN_VALUENAME1_003 "Count"
#define PLUGIN_VALUENAME2_003 "Total"
#define PLUGIN_VALUENAME3_003 "Time"
void Plugin_003_pulse_interrupt1() ICACHE_RAM_ATTR;
void Plugin_003_pulse_interrupt2() ICACHE_RAM_ATTR;
void Plugin_003_pulse_interrupt3() ICACHE_RAM_ATTR;
void Plugin_003_pulse_interrupt4() ICACHE_RAM_ATTR;
//this takes 20 bytes of IRAM per handler
// void Plugin_003_pulse_interrupt5() ICACHE_RAM_ATTR;
// void Plugin_003_pulse_interrupt6() ICACHE_RAM_ATTR;
// void Plugin_003_pulse_interrupt7() ICACHE_RAM_ATTR;
// void Plugin_003_pulse_interrupt8() ICACHE_RAM_ATTR;
unsigned long Plugin_003_pulseCounter[TASKS_MAX];
unsigned long Plugin_003_pulseTotalCounter[TASKS_MAX];
unsigned long Plugin_003_pulseTime[TASKS_MAX];
unsigned long Plugin_003_pulseTimePrevious[TASKS_MAX];
boolean Plugin_003(byte function, struct EventStruct *event, String& string)
{
  boolean success = false;
  switch (function)
  {
    case PLUGIN_DEVICE_ADD:
      {
        Device[++deviceCount].Number = PLUGIN_ID_003;
        Device[deviceCount].Type = DEVICE_TYPE_SINGLE;
        Device[deviceCount].VType = SENSOR_TYPE_SINGLE;
        Device[deviceCount].Ports = 0;
        Device[deviceCount].PullUpOption = false;
        Device[deviceCount].InverseLogicOption = false;
        Device[deviceCount].FormulaOption = true;
        Device[deviceCount].ValueCount = 3;
        Device[deviceCount].SendDataOption = true;
        Device[deviceCount].TimerOption = true;
        Device[deviceCount].GlobalSyncOption = true;
        break;
      }
    case PLUGIN_GET_DEVICENAME:
      {
        string = F(PLUGIN_NAME_003);
        break;
      }
    case PLUGIN_GET_DEVICEVALUENAMES:
      {
        strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_003));
        strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[1], PSTR(PLUGIN_VALUENAME2_003));
        strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[2], PSTR(PLUGIN_VALUENAME3_003));
        break;
      }
    case PLUGIN_WEBFORM_LOAD:
      {
      	addFormNumericBox(string, F("Debounce Time (mSec)"), F("plugin_003")
      			, Settings.TaskDevicePluginConfig[event->TaskIndex][0]);

        byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][1];
        byte choice2 = Settings.TaskDevicePluginConfig[event->TaskIndex][2];
        String options[4] = { F("Delta"), F("Delta/Total/Time"), F("Total"), F("Delta/Total") };
        addFormSelector(string, F("Counter Type"), F("plugin_003_countertype"), 4, options, NULL, choice );

        if (choice !=0)
          string += F("<span style=\"color:red\">Total count is not persistent!</span>");

        String modeRaise[4];
        modeRaise[0] = F("LOW");
        modeRaise[1] = F("CHANGE");
        modeRaise[2] = F("RISING");
        modeRaise[3] = F("FALLING");
        int modeValues[4];
        modeValues[0] = LOW;
        modeValues[1] = CHANGE;
        modeValues[2] = RISING;
        modeValues[3] = FALLING;

        addFormSelector(string, F("Mode Type"), F("plugin_003_raisetype"), 4, modeRaise, modeValues, choice2 );

        success = true;
        break;
      }

    case PLUGIN_WEBFORM_SAVE:
      {
        Settings.TaskDevicePluginConfig[event->TaskIndex][0] = getFormItemInt(F("plugin_003"));
        Settings.TaskDevicePluginConfig[event->TaskIndex][1] = getFormItemInt(F("plugin_003_countertype"));
        Settings.TaskDevicePluginConfig[event->TaskIndex][2] = getFormItemInt(F("plugin_003_raisetype"));
        success = true;
        break;
      }
    case PLUGIN_WEBFORM_SHOW_VALUES:
      {
        string += F("<div class=\"div_l\">");
        string += ExtraTaskSettings.TaskDeviceValueNames[0];
        string += F(":</div><div class=\"div_r\">");
        string += Plugin_003_pulseCounter[event->TaskIndex];
        string += F("</div><div class=\"div_br\"></div><div class=\"div_l\">");
        string += ExtraTaskSettings.TaskDeviceValueNames[1];
        string += F(":</div><div class=\"div_r\">");
        string += Plugin_003_pulseTotalCounter[event->TaskIndex];
        string += F("</div><div class=\"div_br\"></div><div class=\"div_l\">");
        string += ExtraTaskSettings.TaskDeviceValueNames[2];
        string += F(":</div><div class=\"div_r\">");
        string += Plugin_003_pulseTime[event->TaskIndex];
        string += F("</div>");
        success = true;
        break;
      }

    case PLUGIN_INIT:
      {
        String log = F("INIT : Pulse ");
        log += Settings.TaskDevicePin1[event->TaskIndex];
        addLog(LOG_LEVEL_INFO,log);
        pinMode(Settings.TaskDevicePin1[event->TaskIndex], INPUT_PULLUP);
        success = Plugin_003_pulseinit(Settings.TaskDevicePin1[event->TaskIndex], event->TaskIndex,Settings.TaskDevicePluginConfig[event->TaskIndex][2]);
        break;
      }

    case PLUGIN_READ:
      {
        UserVar[event->BaseVarIndex] = Plugin_003_pulseCounter[event->TaskIndex];
        UserVar[event->BaseVarIndex+1] = Plugin_003_pulseTotalCounter[event->TaskIndex];
        UserVar[event->BaseVarIndex+2] = Plugin_003_pulseTime[event->TaskIndex];

        switch (Settings.TaskDevicePluginConfig[event->TaskIndex][1])
        {
          case 0:
          {
            event->sensorType = SENSOR_TYPE_SINGLE;
            UserVar[event->BaseVarIndex] = Plugin_003_pulseCounter[event->TaskIndex];
            break;
          }
          case 1:
          {
            event->sensorType = SENSOR_TYPE_TRIPLE;
            UserVar[event->BaseVarIndex] = Plugin_003_pulseCounter[event->TaskIndex];
            UserVar[event->BaseVarIndex+1] = Plugin_003_pulseTotalCounter[event->TaskIndex];
            UserVar[event->BaseVarIndex+2] = Plugin_003_pulseTime[event->TaskIndex];
            break;
          }
          case 2:
          {
            event->sensorType = SENSOR_TYPE_SINGLE;
            UserVar[event->BaseVarIndex] = Plugin_003_pulseTotalCounter[event->TaskIndex];
            break;
          }
          case 3:
          {
            event->sensorType = SENSOR_TYPE_DUAL;
            UserVar[event->BaseVarIndex] = Plugin_003_pulseCounter[event->TaskIndex];
            UserVar[event->BaseVarIndex+1] = Plugin_003_pulseTotalCounter[event->TaskIndex];
            break;
          }
        }
        Plugin_003_pulseCounter[event->TaskIndex] = 0;
        success = true;
        break;
      }
  }
  return success;
}
/********\
 * Check Pulse Counters (called from irq handler)
\********/
void Plugin_003_pulsecheck(byte Index)
{
  unsigned long PulseTime=millis() - Plugin_003_pulseTimePrevious[Index];
  if(PulseTime > (unsigned long)Settings.TaskDevicePluginConfig[Index][0]) // check with debounce time for this task
    {
      Plugin_003_pulseCounter[Index]++;
      Plugin_003_pulseTotalCounter[Index]++;
      Plugin_003_pulseTime[Index] = PulseTime;
      Plugin_003_pulseTimePrevious[Index]=millis();
    }
}
/*********\
 * Pulse Counter IRQ handlers
\*********/
void Plugin_003_pulse_interrupt1()
{
  Plugin_003_pulsecheck(0);
}
void Plugin_003_pulse_interrupt2()
{
  Plugin_003_pulsecheck(1);
}
void Plugin_003_pulse_interrupt3()
{
  Plugin_003_pulsecheck(2);
}
void Plugin_003_pulse_interrupt4()
{
  Plugin_003_pulsecheck(3);
}
void Plugin_003_pulse_interrupt5()
{
  Plugin_003_pulsecheck(4);
}
void Plugin_003_pulse_interrupt6()
{
  Plugin_003_pulsecheck(5);
}
void Plugin_003_pulse_interrupt7()
{
  Plugin_003_pulsecheck(6);
}
void Plugin_003_pulse_interrupt8()
{
  Plugin_003_pulsecheck(7);
}
/*****\
 * Init Pulse Counters
\*****/
bool Plugin_003_pulseinit(byte Par1, byte Index, byte Mode)
{
  switch (Index)
  {
    case 0:
      attachInterrupt(Par1, Plugin_003_pulse_interrupt1, Mode);
      break;
    case 1:
      attachInterrupt(Par1, Plugin_003_pulse_interrupt2, Mode);
      break;
    case 2:
      attachInterrupt(Par1, Plugin_003_pulse_interrupt3, Mode);
      break;
    case 3:
      attachInterrupt(Par1, Plugin_003_pulse_interrupt4, Mode);
      break;
    // case 4:
    //   attachInterrupt(Par1, Plugin_003_pulse_interrupt5, Mode);
    //   break;
    // case 5:
    //   attachInterrupt(Par1, Plugin_003_pulse_interrupt6, Mode);
    //   break;
    // case 6:
    //   attachInterrupt(Par1, Plugin_003_pulse_interrupt7, Mode);
    //   break;
    // case 7:
    //   attachInterrupt(Par1, Plugin_003_pulse_interrupt8, Mode);
    //   break;
    default:
      addLog(LOG_LEVEL_ERROR,F("PULSE: Error, only the first 4 tasks can be pulse counters."));
      return(false);
  }
  return(true);
}