Instantie van bounce-bibliotheek in een klas

Ik probeer mijn hoofd rond te krijgen om objecten van bestaande bibliotheken in een klasseobject te instantiëren. Specifiek probeer ik de bounce2.h-debouncer aan het werk te krijgen.

Op dit moment compileert mijn code, maar ik denk dat de debounce-functie niet werkt, omdat de knop mijn array met veel willekeurige getallen vult (zelfs vanaf de setup), terwijl het prima werkt op een niet-klassige schets, dus ik denk dat ik waarschijnlijk het bounce-object niet op de juiste manier instantiëren. Als iemand kan helpen, zou ik erg dankbaar zijn!

Mijn kop:

#ifndef CandleRack_h
#define CandleRack_h

class CandleRack
{
  public:

    CandleRack(byte candleRackStatus);
    void begin();
    void pushButton();
    void selectRandomCandle();
    void turnOnCandle(byte candlePosition);
    void burnCandlesForMs();
    void fadeOutCandle(byte candlePosition);

  private:
    Bounce _debouncePushButton;
    byte _pushButtonPin; 
    byte _candleRackStatus;    
    byte _candlePosition;
    byte _candleStatus[];
    elapsedMillis _candleTimeElapsed;
    unsigned int _candleOnForMs;
};
#endif

Mijn cpp

#include "Arduino.h"
#include 
#include 
#include 
#include "CandleRack.h"

#define NUM_LEDS 50

CandleRack::CandleRack(byte candleRackStatus)
{
  _candleRackStatus = candleRackStatus;
}

void CandleRack::begin()
{
  randomSeed(analogRead(0));

  _debouncePushButton = Bounce();
  _pushButtonPin = 3;
  _candleOnForMs = 20000;
  pinMode(_pushButtonPin, INPUT_PULLUP);
  _debouncePushButton.attach(_pushButtonPin);
  _debouncePushButton.interval(10);

  for (byte b = 0; b < NUM_LEDS; b++)
  {
    _candleStatus[_candlePosition] = 0;
  }

  Serial.println("Candle Array: ");      //Debug ************************
  for (byte b = 0; b < NUM_LEDS; b++)    //Debug ************************
  {                                      //Debug ************************
    Serial.print(_candleStatus[b]);      //Debug ************************
    Serial.print(", ");                  //Debug ************************
  }                                      //Debug ************************
  Serial.println("");                    //Debug ************************
  Serial.println("Begin Complete");      //Debug ************************
}


void CandleRack::pushButton()
{
 //Look for a button push
  if (_debouncePushButton.update())
  {
    if (_debouncePushButton.fell())
    {
      selectRandomCandle();
    }
  }
}


void CandleRack::selectRandomCandle()
{
  byte randomCandlePosition;
  do
  {
    randomCandlePosition = random(0, NUM_LEDS);
  }
  while (_candleStatus[randomCandlePosition] != 0);

  turnOnCandle(randomCandlePosition);
}


void CandleRack::turnOnCandle(byte _candlePosition)
{
 //leds[_candlePosition] = CRGB::Red;
  _candleStatus[_candlePosition] = 1;

  Serial.println("Button Pushed: ");     //Debug ************************
  Serial.println(_candlePosition);       //Debug ************************
  Serial.println("Candle Array: ");      //Debug ************************
  for (byte b = 0; b < NUM_LEDS; b++)    //Debug ************************
  {                                      //Debug ************************
    Serial.print(_candleStatus[b]);      //Debug ************************
    Serial.print(", ");                  //Debug ************************
  }                                      //Debug ************************
  Serial.println("");                    //Debug ************************
}


void CandleRack::burnCandlesForMs()
{
 //See if it is time to turn the candle off
  for (byte b = 0; b < NUM_LEDS; b++)
  {
    if (_candleTimeElapsed > _candleOnForMs && _candleStatus[b] == 1)
    {
      CandleRack::fadeOutCandle(b);
      _candleTimeElapsed = 0;
    }
  }
}


void CandleRack::fadeOutCandle(byte _candlePosition)
{
  _candleStatus[_candlePosition] = 0;
}

Mijn schets:

#include "Arduino.h"
#include 
#include 
#include 
#include "CandleRack.h"

CandleRack MyCandleRack(0);

void setup() {
  delay(3000);//sanity delay

  Serial.begin(9600);
  while (!Serial); 

  Serial.println("Setup Starts"); //Debug ************************

  MyCandleRack.begin();

  Serial.println("Setup Complate"); //Debug ************************
}

void loop() {

  MyCandleRack.pushButton();
//MyCandleRack.burnCandlesForMs();

  FastLED.show();
}

bewerken - voeg de code uit het originele voorbeeld van de ontkenning toe voor een enkele schets

// Detect the falling edge

// Include the Bounce2 library found here :
// https://github.com/thomasfredericks/Bounce-Arduino-Wiring
#include 


#define BUTTON_PIN 2
#define LED_PIN 13

int ledState = LOW;


// Instantiate a Bounce object :
Bounce debouncer = Bounce(); 

void setup() {

 //Setup the button with an internal pull-up :
  pinMode(BUTTON_PIN,INPUT_PULLUP);

 //After setting up the button, setup the Bounce instance :
  debouncer.attach(BUTTON_PIN);
  debouncer.interval(500);

 //Setup the LED :
  pinMode(LED_PIN,OUTPUT);
  digitalWrite(LED_PIN,ledState);


}

void loop() {

 //Update the Bounce instance :
   debouncer.update();

  //Call code if Bounce fell (transition from HIGH to LOW) :
   if ( debouncer.fell() ) {

    //Toggle LED state :
     ledState = !ledState;
     digitalWrite(LED_PIN,ledState);

   }
}
0

1 antwoord

Uw belangrijkste probleem (de oorzaak van uw symptomen) is het feit dat u geen maat heeft voor uw array _candleStatus . Zonder een grootte op te geven, krijg je uiteindelijk geen geheugen toegewezen aan de array en dus geen geldige inhoud.

In je klassedefinitie staat de regel:

byte _candleStatus[];

moet worden gewijzigd om:

byte _candleStatus[NUM_LEDS];

en NUM_LEDS moet worden gedefinieerd in de kop, niet in het CPP-bestand. (Door het op te geven in het headerbestand, omdat het headerbestand deel uitmaakt van het CPP-bestand, komt de definitie in beide bestanden terecht).

Afgezien daarvan doet deze regel niet wat je denkt dat het doet:

_debouncePushButton = Bounce();

U kopieert de inhoud van een anoniem bounce-object dat speciaal voor de gelegenheid is gemaakt naar een reeds bestaand Bounce-object. U wilt niet dat die regel bestaat, omdat het Bounce-object al is geïnstantieerd door de constructie van uw CandleRack -object.

Er is echter iets waarvan u op de hoogte moet zijn dat bekend staat als de statische initialisatieorder Fiasco die u aan de achterkant kan bijten als u zich hiervan niet bewust bent. Dit is eigenlijk wanneer u objecten in andere objecten gebruikt en die objecten nog niet correct zijn gemaakt, omdat u de volgorde waarin objecten worden geïnitialiseerd niet kunt voorspellen. Dit kan al dan niet een probleem zijn in je systeem - het hangt allemaal af van hoe de andere klassen die je gebruikt zich gedragen.

Eén manier om dit probleem te omzeilen, als je merkt dat het een probleem wordt (of als je het probleem gewoon helemaal wilt vermijden), is om pointers te gebruiken en wat bekend staat als Construct op eerste gebruik . Dit is waar u geen objecten in uw constructor of de klassendefinitie instantieert - in plaats daarvan heeft u er alleen verwijzingen naar en gebruikt u het trefwoord new om het object te bouwen vanuit een lidfunctie (zoals < code> begin() ).

Hiervoor wijzigt u uw klassedefinitieobjectitems als aanwijzers, zoals:

Bounce *_debouncePushButton = NULL;

(Merk op dat niet alle versies van de compiler die toewijzing ondersteunen in de klassendefinitie.) Het is een moderne toevoeging aan C ++ en afhankelijk van je versie van de Arduino-software kan dit wel of niet werken. de toewijzing in de constructor door de = NULL uit de definitie te verwijderen en _debouncePushButton = NULL; toe te voegen aan de constructor.)

Bouw vervolgens een nieuw object in de functie begin() (als het nog niet is gemaakt):

if (_debouncePushButton == NULL) {
    _debouncePushButton = new Bounce();
}

Now you have to access the _debouncePushButton as a pointer to an object not an object, so change all your accesses to use the pointer dereference operator ->:

_debouncePushButton->attach(_pushButtonPin);
... etc ...

Als de klas ooit buiten het bereik zou moeten gaan of op een dynamische manier zou moeten worden gebruikt, zou u echt een destructor moeten maken om objecten te verwijderen die gemaakt:

CandleRack::~CandleRack() {
    if (_debouncePushButton != NULL) {
        delete _debouncePushButton;
    }
}

Merk op dat u alleen objecten moet proberen verwijderen die daadwerkelijk zijn gemaakt - vandaar de test om te zien of deze niet nul is.

Overmatig gebruik van nieuw en verwijderen wordt afgeraden, dus het is het beste om objecten zo mogelijk in een statische context te gebruiken. Te veel nieuw en verwijderen of malloc en gratis kan heap-fragmentatie veroorzaken die kan leiden tot een tekort aan geheugen en alle bijbehorende stabiliteitsproblemen die daarmee gepaard gaan.

Natuurlijk is dit allemaal optioneel en is de kans groot dat het niet nodig is als de andere klassen zich goed gedragen.

1
toegevoegd
Zie mijn bewerking. U hebt een tweede volledig onafhankelijk probleem met uw code.
toegevoegd de auteur Majenko, de bron
Als het in CandleRack.h is, dan is het ook in CandleRack.cpp aangezien CandleRack.h is opgenomen in CandleRack.cpp.
toegevoegd de auteur Majenko, de bron
Alleen als u ooit het CandleRack-object verwijdert en omdat u statisch maakt dat het nooit wordt verwijderd. Je kunt een destructor maken voor CandleRack als je het echt wilt en het Bounce-object verwijderen (als het is gemaakt) maar als je het altijd statisch gaat maken, is er niet echt behoefte aan.
toegevoegd de auteur Majenko, de bron
En het is niet het gebruik van nieuw dat slecht is - het is de herhaalde nieuwe en verwijderen die heap-fragmentatie veroorzaakt - en wanneer je maar een heel klein beetje hebt heap-fragmentatie is heel erg slecht. Het gebruik van nieuw op een statische manier (nooit delete gebruiken en nooit delete gebruiken) veroorzaakt nooit heap-fragmentatie.
toegevoegd de auteur Majenko, de bron
U kunt doen, ja. Het is mogelijk om het hele ding statisch te doen en helemaal geen gebruik te maken - keer gewoon terug naar hoe het was en verwijder de regel die een Bounce-object toewijst in de beginfunctie - er is echter een risico op statische initialisatiebestellingsproblemen dan als u niet wat de constructeurs van de andere objecten aan het doen zijn. Door pointers voor uw objecten te gebruiken, krijgt u van hen de zogenoemde "constructie bij eerste gebruik", wat betekent dat ze altijd worden opgebouwd nadat het systeem volledig is geïnitialiseerd.
toegevoegd de auteur Majenko, de bron
@ frarugi87 ja, ik schreef het vlak voor het slapengaan. Het is geen prachtig antwoord.
toegevoegd de auteur Majenko, de bron
Persoonlijk zou ik dit antwoord oplossen, omdat het misleidend is. Je moet zeker het aanwijzer (en nieuwe) deel verwijderen, omdat het niet gerelateerd is aan het daadwerkelijke probleem. Als je het daarentegen wilt behouden, de woorden wilt veranderen (het is niet verplicht om te doen, het is gewoon iets wat je suggereert) maar dan moet je 1) de aanwijzer initialiseren naar NULL 2) controleer of de aanwijzer null is (bescherming tegen meerdere beginoproepen of er zijn geheugenlekken) voordat u een nieuwe 3) expliciet verwijdert (anders zijn er geheugenlekken als het object in een kleiner bereik wordt gebruikt)
toegevoegd de auteur Tom Collins, de bron
@Majenko nu DIT is een goed antwoord .. +1
toegevoegd de auteur Tom Collins, de bron
Bedankt. Het geeft me echter nog steeds hetzelfde probleem, het voegt veel willekeurige getallen toe aan de array. Ik kan de code voor het gebruik van het debounce-object in een enkele schets plaatsen als dit helpt?
toegevoegd de auteur Slacker, de bron
Agh, OK. een probleem is dat #define NUM_LEDS uit mijn FastLED-array komt en ik heb dat nodig in de hoofdschets die ik denk. Ik weet niet zeker hoe te verwijzen/naar een #define verwijst (wat het moet zijn).
toegevoegd de auteur Slacker, de bron
Super goed. Gewoon geprobeerd en het heeft het probleem opgelost! Enorm bedankt :) Nu voor het lastige bit dat FastLED in het object gebruikt :)
toegevoegd de auteur Slacker, de bron
een vraag ... Ik had gelezen dat het niet goed was om nieuw te gebruiken in arduino-schetsen. Is dit oude adivce?
toegevoegd de auteur Slacker, de bron
Ik heb gelezen op nieuw en zou ik ergens delete moeten gebruiken, evenals per arduino.land/FAQ/content/4/24/en/mixing-malloc-and-new.html ?
toegevoegd de auteur Slacker, de bron
Moet ik ook pointers gebruiken voor mijn andere bibliotheekobject - elapsedMillis? werkt het op dit moment goed, maar denkend aan je laatste advies, kan het ook een voordeel zijn om een ​​aanwijzer daar ook te gebruiken?
toegevoegd de auteur Slacker, de bron
Klopt - ik begrijp nu dat de fout die ik had vanaf het begin van de thread was met het array array randomNumber - de rest is meer 'best practice'. Dus alles wat ik moet doen is veranderen (in de koptekst) elapsedMillis _candleTimeElapsed [NUM_LEDS]; in elapsedMillis * _candleTimeElapsed [NUM_LEDS]; ? omdat ik in dit geval de notatie -> niet kan gebruiken, omdat ik er nu beter naar kijk, het geeft in dit geval niet daadwerkelijk een elapsedMillis-object ter referentie. Is dat juist?
toegevoegd de auteur Slacker, de bron
Bedankt voor het bijgewerkte antwoord, het maakt een enorm verschil voor mijn begrip. Vooral omdat ik eerder veronderstelde dat het gebruik van new de voorkeursmanier zou zijn om een ​​object te instantiëren.
toegevoegd de auteur Slacker, de bron