Software-Entprellen eines FRM_IN Eingangs

Begonnen von limats, 12 Januar 2014, 12:19:29

Vorheriges Thema - Nächstes Thema

pula

Hallo,

falls es jemanden interessieren sollte (bzw. mal irgendwann jemand das gleiche Problem wie ich haben sollte).
Da mit der Lösung aus dem letzten Posting leider die "Phantom-Auslösungen" noch immer nicht behoben waren (mit der bounce2 aber schon), bin ich gemeinsam mit einem Freund der Sache auf den Grund gegangen und wir haben herausgefunden, warum ein Arduino überfordert war.

Durch den Code
Bounce bouncePIN[TOTAL_PORTS] in DigitalInputFirmata.h
wird für jeden Pin des Arduino ein Bounce-Objekt instanziert, was das Ding offenbar überfordert (mit einem Mega hingegen funktioniert die Sache).

Wie haben den Code nun folgendermaßen angepasst:
Bounce bouncePIN[8]

Und in der DigitalFirmata.cpp entsprechend:
DigitalInputFirmata::DigitalInputFirmata()
{

  DigitalInputFirmataInstance = this;
  Firmata.attach(REPORT_DIGITAL, reportDigitalInputCallback);
  for (byte i=0; i < 8 /*TOTAL_PORTS*/; i++) {
    if (i >= 2 && i <= 7) {
      //bouncePIN[i] = Bounce();
      bouncePIN[i].attach(i);
      bouncePIN[i].interval(100);
      bouncePIN[i].update();
    }
  }
}
void DigitalInputFirmata::report(void)
{
  /* Using non-looping code allows constants to be given to readPort().
   * The compiler will apply substantial optimizations if the inputs
   * to readPort() are compile-time constants. */
  if (TOTAL_PORTS > 0 && reportPINs[0]) {
byte bitmask = portConfigInputs[0];
unsigned char out=0;
if (IS_PIN_DIGITAL(0) && (bitmask & 0x01) && digitalRead(PIN_TO_DIGITAL(0))) out |= 0x01;
if (IS_PIN_DIGITAL(1) && (bitmask & 0x02) && digitalRead(PIN_TO_DIGITAL(1))) out |= 0x02;
        if (IS_PIN_DIGITAL(3)) {
          bouncePIN[3].update();
  if (bouncePIN[3].update() && (bouncePIN[3].read() == HIGH)) bitSet(out,3);
          if (bouncePIN[3].read()) bitSet(out,3);
        }
        if (IS_PIN_DIGITAL(2)) {
          bouncePIN[2].update();
          if (bouncePIN[2].read()) bitSet(out,2);
        }
if (IS_PIN_DIGITAL(5)) {
          bouncePIN[5].update();
          if (bouncePIN[5].read()) bitSet(out,5);
        }
if (IS_PIN_DIGITAL(6)) {
          bouncePIN[6].update();
          if (bouncePIN[6].read()) bitSet(out,6);
        }
if (IS_PIN_DIGITAL(7)) {
          bouncePIN[7].update();
          if (bouncePIN[7].read()) bitSet(out,7);
        }
outputPort(0, out, false);
  }
  if (TOTAL_PORTS > 1 && reportPINs[1]) outputPort(1, readPort(1, portConfigInputs[1]), false);
  if (TOTAL_PORTS > 2 && reportPINs[2]) outputPort(2, readPort(3, portConfigInputs[3]), false);
  if (TOTAL_PORTS > 3 && reportPINs[3]) outputPort(3, readPort(3, portConfigInputs[3]), false);
  if (TOTAL_PORTS > 4 && reportPINs[4]) outputPort(4, readPort(4, portConfigInputs[4]), false);
  if (TOTAL_PORTS > 5 && reportPINs[5]) outputPort(5, readPort(5, portConfigInputs[5]), false);
  if (TOTAL_PORTS > 6 && reportPINs[6]) outputPort(6, readPort(6, portConfigInputs[6]), false);
  if (TOTAL_PORTS > 7 && reportPINs[7]) outputPort(7, readPort(7, portConfigInputs[7]), false);
  if (TOTAL_PORTS > 8 && reportPINs[8]) outputPort(8, readPort(8, portConfigInputs[8]), false);
  if (TOTAL_PORTS > 9 && reportPINs[9]) outputPort(9, readPort(9, portConfigInputs[9]), false);
  if (TOTAL_PORTS > 10 && reportPINs[10]) outputPort(10, readPort(10, portConfigInputs[10]), false);
  if (TOTAL_PORTS > 11 && reportPINs[11]) outputPort(11, readPort(11, portConfigInputs[11]), false);
  if (TOTAL_PORTS > 12 && reportPINs[12]) outputPort(12, readPort(12, portConfigInputs[12]), false);
  if (TOTAL_PORTS > 13 && reportPINs[13]) outputPort(13, readPort(13, portConfigInputs[13]), false);
  if (TOTAL_PORTS > 14 && reportPINs[14]) outputPort(14, readPort(14, portConfigInputs[14]), false);
  if (TOTAL_PORTS > 15 && reportPINs[15]) outputPort(15, readPort(15, portConfigInputs[15]), false);
}


Damit ist seit gestern Ruhe, ich hatte an momentan zwei angeschlossenen Tastern keine einzige "Phantom-Auslösung" und die Taster sind sauber entprellt. War mir lieber als das in Hardware zu machen ;-)

Cheers,

Pula
fhem (debian auf proxmox), HM-LAN und wired, MySensors, FritzBoxes, Kodi, vdr, Onkyo, squeezeplayers, nanoCUL, wifilight (Ethernet-Bridge), Heizungssteuerung (python/vncdotool), doorpi, ESP/Arduinos/MQTT, Alexa, HomeConnect, Sonoff/Tasmota, espRGBWW, esphome, Telegram

tresa

Hallo,
ich würde deinen Code gerne verwenden aber leider funktioniert das bei mir nicht so richtig. Ich habe die Eingänge an einem Arduino Mega an den PINs 22 bis 32 angeschlossen. Muss ich da an deinem Code noch was anpassen? Hier?


  for (byte i=0; i < 8 /*TOTAL_PORTS*/; i++) {
    if (i >= 2 && i <= 7) {


Danke für deine Hilfe.
Grüße

ckreuzer

Hallo,
ich habe einen Arduino Mega als reines Input Device, d.h. sämmtliche Ports von 2 bis 69 sollen als DigitalInput verwendet werden.
Derzeit behelfe ich mir mit attr <TASTER> event-min-interval reading:0.1
Das funktioniert eigentlich relativ gut.
Allerdings ist man da von "Geistereffekten" nicht gefeilt.
Mit der Bounc2 Library habe ich nun versucht sämmtliche Ports mittels Bounce zu entprellen.
void DigitalInputFirmata::report(void)
{
  /* Using non-looping code allows constants to be given to readPort().
   * The compiler will apply substantial optimizations if the inputs
   * to readPort() are compile-time constants. */
  if (TOTAL_PORTS > 0 && reportPINs[0])
  {
byte bitmask = portConfigInputs[0];
unsigned char out=0;
if (IS_PIN_DIGITAL(0) && (bitmask & 0x01) && digitalRead(PIN_TO_DIGITAL(0))) out |= 0x01;
if (IS_PIN_DIGITAL(1) && (bitmask & 0x02) && digitalRead(PIN_TO_DIGITAL(1))) out |= 0x02;
    for (byte i=2; i < TOTAL_PORTS; i++)
{
      bouncePINs[i].update();
      if (bouncePINs[i].read()) bitSet(out,i);
}
outputPort(0, out, false);
  }
  if (TOTAL_PORTS > 1 && reportPINs[1]) outputPort(1, readPort(1, portConfigInputs[1]), false);
  if (TOTAL_PORTS > 2 && reportPINs[2]) outputPort(2, readPort(3, portConfigInputs[3]), false);
  if (TOTAL_PORTS > 3 && reportPINs[3]) outputPort(3, readPort(3, portConfigInputs[3]), false);
  if (TOTAL_PORTS > 4 && reportPINs[4]) outputPort(4, readPort(4, portConfigInputs[4]), false);
  if (TOTAL_PORTS > 5 && reportPINs[5]) outputPort(5, readPort(5, portConfigInputs[5]), false);
  if (TOTAL_PORTS > 6 && reportPINs[6]) outputPort(6, readPort(6, portConfigInputs[6]), false);
  if (TOTAL_PORTS > 7 && reportPINs[7]) outputPort(7, readPort(7, portConfigInputs[7]), false);
  if (TOTAL_PORTS > 8 && reportPINs[8]) outputPort(8, readPort(8, portConfigInputs[8]), false);
  if (TOTAL_PORTS > 9 && reportPINs[9]) outputPort(9, readPort(9, portConfigInputs[9]), false);
  if (TOTAL_PORTS > 10 && reportPINs[10]) outputPort(10, readPort(10, portConfigInputs[10]), false);
  if (TOTAL_PORTS > 11 && reportPINs[11]) outputPort(11, readPort(11, portConfigInputs[11]), false);
  if (TOTAL_PORTS > 12 && reportPINs[12]) outputPort(12, readPort(12, portConfigInputs[12]), false);
  if (TOTAL_PORTS > 13 && reportPINs[13]) outputPort(13, readPort(13, portConfigInputs[13]), false);
  if (TOTAL_PORTS > 14 && reportPINs[14]) outputPort(14, readPort(14, portConfigInputs[14]), false);
  if (TOTAL_PORTS > 15 && reportPINs[15]) outputPort(15, readPort(15, portConfigInputs[15]), false);
}

Das funktioniert allerdings anscheinend nur für die ersten Pins.
Andere Pins werden nicht entprellt bzw. derDigitalInput funktioniert gar nicht mehr (z.B. Pin 16-19)
Ich würde hier dringend Hilfe benötigen, da meine Programmierkenntnisse nicht wirklich die besten sind und ich da nicht mehr weiterkomme.
(Ich verstehe die Funktionsweise des Arduino auch zu wenig)

Danke &lg
Christian

ckreuzer

 HAllo,
ein kurzes Update:
Zum Glück habe ich eine kleine Schwester die programmieren kann.
Bei mir sind die Geistereffekte nun schon ein paar Tage weg.
(ca. 60 Taster wurden auf einem Arduino Mega entprellt)
Die dazugehörigen Änderungen (falls es jemand brauchen kann):
/*
  DigitalInputFirmata.h - Firmata library
  Copyright (C) 2006-2008 Hans-Christoph Steiner.  All rights reserved.
  Copyright (C) 2010-2011 Paul Stoffregen.  All rights reserved.
  Copyright (C) 2009 Shigeru Kobayashi.  All rights reserved.
  Copyright (C) 2009-2011 Jeff Hoefs.  All rights reserved.
  Copyright (C) 2013 Norbert Truchsess. All rights reserved.

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  See file LICENSE.txt for further informations on licensing terms.
*/

#ifndef DigitalInputFirmata_h
#define DigitalInputFirmata_h
#define TIMES_TO_WAIT 5
#include <Firmata.h>
#include "FirmataFeature.h"

void reportDigitalInputCallback(byte port, int value);

class DigitalInputFirmata:public FirmataFeature
{
public:
  DigitalInputFirmata();
  void reportDigital(byte port, int value);
  void report(void);
  void handleCapability(byte pin);
  boolean handleSysex(byte command, byte argc, byte* argv);
  boolean handlePinMode(byte pin, int mode);
  void reset();

private:
  /* digital input ports */
  byte reportPINs[TOTAL_PORTS];       // 1 = report this port, 0 = silence
  byte previousPINs[TOTAL_PORTS];     // previous 8 bits sent
  byte timePINs[TOTAL_PORTS];     // Timing Pins

  /* pins configuration */
  byte portConfigInputs[TOTAL_PORTS]; // each bit: 1 = pin in INPUT, 0 = anything else
  void outputPort(byte portNumber, byte portValue, byte forceSend);
};

#endif

Und:
/*
  DigitalInputFirmata.cpp - Firmata library
  Copyright (C) 2006-2008 Hans-Christoph Steiner.  All rights reserved.
  Copyright (C) 2010-2011 Paul Stoffregen.  All rights reserved.
  Copyright (C) 2009 Shigeru Kobayashi.  All rights reserved.
  Copyright (C) 2009-2011 Jeff Hoefs.  All rights reserved.
  Copyright (C) 2013 Norbert Truchsess. All rights reserved.

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  See file LICENSE.txt for further informations on licensing terms.
*/

#include <Firmata.h>
#include "DigitalInputFirmata.h"

DigitalInputFirmata *DigitalInputFirmataInstance;

void reportDigitalInputCallback(byte port, int value)
{
  DigitalInputFirmataInstance->reportDigital(port,value);
}

DigitalInputFirmata::DigitalInputFirmata()
{
  DigitalInputFirmataInstance = this;
  Firmata.attach(REPORT_DIGITAL, reportDigitalInputCallback);
}

boolean DigitalInputFirmata::handleSysex(byte command, byte argc, byte* argv)
{
  return false;
}

void DigitalInputFirmata::outputPort(byte portNumber, byte portValue, byte forceSend)
{
  // pins not configured as INPUT are cleared to zeros
  portValue = portValue & portConfigInputs[portNumber];
 
  if(!forceSend)
  {
  if(previousPINs[portNumber] != portValue)
  {
//Änderung des Signals

if(timePINs[portNumber] == (TIMES_TO_WAIT + 1))
{
//vorheriges Signal wurde gesendet -->
//dieses Signal eventuell auch senden
timePINs[portNumber] = 1;
}
else
{
//vorheriges Signal wurde nicht gesendet -->
//dieses Signal als gesendet setzen
timePINs[portNumber] = TIMES_TO_WAIT + 1;
}
previousPINs[portNumber] = portValue;
  }
  else
  {
if (timePINs[portNumber] < TIMES_TO_WAIT)
timePINs[portNumber] = timePINs[portNumber] + 1;
  }
  }
 
  if(forceSend || timePINs[portNumber] == TIMES_TO_WAIT)
  {
    //Signal senden
    Firmata.sendDigitalPort(portNumber, portValue);
    //Zeichen, dass Signal gesendet wurde
    timePINs[portNumber] = TIMES_TO_WAIT +1;
  }
}

/* -----------------------------------------------------------------------------
* check all the active digital inputs for change of state, then add any events
* to the Serial output queue using Serial.print() */
void DigitalInputFirmata::report(void)
{
  /* Using non-looping code allows constants to be given to readPort().
   * The compiler will apply substantial optimizations if the inputs
   * to readPort() are compile-time constants. */
   /*for (byte i=0; i < TOTAL_PORTS; i++) {
   if (reportPINs[i]) outputPort(i, readPort(i, portConfigInputs[i]), false);
   }*/
  if (TOTAL_PORTS > 0 && reportPINs[0]) outputPort(0, readPort(0, portConfigInputs[0]), false);
  if (TOTAL_PORTS > 1 && reportPINs[1]) outputPort(1, readPort(1, portConfigInputs[1]), false);
  if (TOTAL_PORTS > 2 && reportPINs[2]) outputPort(2, readPort(2, portConfigInputs[2]), false);
  if (TOTAL_PORTS > 3 && reportPINs[3]) outputPort(3, readPort(3, portConfigInputs[3]), false);
  if (TOTAL_PORTS > 4 && reportPINs[4]) outputPort(4, readPort(4, portConfigInputs[4]), false);
  if (TOTAL_PORTS > 5 && reportPINs[5]) outputPort(5, readPort(5, portConfigInputs[5]), false);
  if (TOTAL_PORTS > 6 && reportPINs[6]) outputPort(6, readPort(6, portConfigInputs[6]), false);
  if (TOTAL_PORTS > 7 && reportPINs[7]) outputPort(7, readPort(7, portConfigInputs[7]), false);
  if (TOTAL_PORTS > 8 && reportPINs[8]) outputPort(8, readPort(8, portConfigInputs[8]), false);
  if (TOTAL_PORTS > 9 && reportPINs[9]) outputPort(9, readPort(9, portConfigInputs[9]), false);
  if (TOTAL_PORTS > 10 && reportPINs[10]) outputPort(10, readPort(10, portConfigInputs[10]), false);
  if (TOTAL_PORTS > 11 && reportPINs[11]) outputPort(11, readPort(11, portConfigInputs[11]), false);
  if (TOTAL_PORTS > 12 && reportPINs[12]) outputPort(12, readPort(12, portConfigInputs[12]), false);
  if (TOTAL_PORTS > 13 && reportPINs[13]) outputPort(13, readPort(13, portConfigInputs[13]), false);
  if (TOTAL_PORTS > 14 && reportPINs[14]) outputPort(14, readPort(14, portConfigInputs[14]), false);
  if (TOTAL_PORTS > 15 && reportPINs[15]) outputPort(15, readPort(15, portConfigInputs[15]), false);
}

void DigitalInputFirmata::reportDigital(byte port, int value)
{
  if (port < TOTAL_PORTS) {
    reportPINs[port] = (byte)value;
    if (value) outputPort(port, readPort(port, portConfigInputs[port]), true);
  }
  // do not disable analog reporting on these 8 pins, to allow some
  // pins used for digital, others analog.  Instead, allow both types
  // of reporting to be enabled, but check if the pin is configured
  // as analog when sampling the analog inputs.  Likewise, while
  // scanning digital pins, portConfigInputs will mask off values from any
  // pins configured as analog
}

boolean DigitalInputFirmata::handlePinMode(byte pin, int mode)
{
  if (IS_PIN_DIGITAL(pin)) {
    if (mode == INPUT) {
      portConfigInputs[pin/8] |= (1 << (pin & 7));
      pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver
      digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups
      return true;
    } else {
      portConfigInputs[pin/8] &= ~(1 << (pin & 7));
    }
  }
  return false;
}

void DigitalInputFirmata::handleCapability(byte pin)
{
  if (IS_PIN_DIGITAL(pin)) {
    Firmata.write((byte)INPUT);
    Firmata.write(1);
  }
}

void DigitalInputFirmata::reset()
{
  for (byte i=0; i < TOTAL_PORTS; i++) {
    reportPINs[i] = false;      // by default, reporting off
    portConfigInputs[i] = 0;    // until activated
    previousPINs[i] = 0;
timePINs[i] = TIMES_TO_WAIT + 1;
  }
}



Viele Grüße

Christian