Инстанцирование бібліятэкі якая адлюстроўвае ўнутры класа

Я спрабую атрымаць маю галаву вакол, як ствараць аб'екты з існуючых ўнутры знайсці бібліятэкі аб'екта класа. У прыватнасці, я спрабую атрымаць bounce2.h debouncer працу.

На дадзены момант мой код кампілюецца, але я думаю, што функцыя бразгату не працуе як кнопка запаўнення майго масіва з вялікай колькасцю выпадковых лікаў (нават ад устаноўкі) у той час як ён працуе выдатна на аснове эскіза някласавую, так што я думаю, што я верагодна, не инстанцирование аб'екта адлюстроўвае правільна. Калі хто-небудзь можа дапамагчы я быў бы вельмі ўдзячны!

Мой загаловак:

#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

мой кастаў

#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;
}

Мой эскіз:

#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();
}

рэдагаваць - дадаў код з зыходнага прыкладу бразгату для аднаго эскіза

// 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 адказы

Ваша галоўная праблема (прычына вашых сімптомаў) з'яўляецца той факт, што ў вас няма памеру для _candleStatus масіва. Без указання памеру вы ў канчатковым выніку без памяці, выдзеленай для масіва, і, такім чынам, не сапраўднага зместу.

У вашым вызначэнні класа радкі:

byte _candleStatus[];

павінен быць зменены:

byte _candleStatus[NUM_LEDS];

і NUM_LEDS павінен быць вызначаны ў загалоўку, а не ў файле СРР. (Задаючы яго ў файле загалоўка, так як загалоўкавыя файл уключаны ў файл CPP, вызначэнне заканчваецца ў абодвух файлах).

Акрамя таго гэтая лінія не робіць тое, што вы думаеце, ён робіць:

_debouncePushButton = Bounce();

Вы капіруеце ўтрыманне ананімнага аб'екта рыкашэту, створаны толькі для выпадку ў папярэдне існуючы аб'ект адмоў. Вы не хочаце, што лінія існуе, так як аб'ект Адмоў ўжо инстанцирован будаўніцтвам вашага CandleRack аб'екта.

Аднак ёсць тое, што вам трэба, каб быць у курсе, вядомы як <�ет> Static Initialization Order Fiasco , які можа ўкусіць вас на заднім канцы, калі вы не ведаеце пра гэта. Гэта ў асноўным пры выкарыстанні аб'ектаў у іншых аб'ектах і тыя аб'екты, якія яшчэ не былі належным чынам створаны, так як вы не можаце прадказаць, парадак, у якім ініцыялізуецца аб'екты. Гэта можа ці не можа быць праблемай у вашай сістэме - усё гэта залежыць ад таго, як іншыя класы, якія вы выкарыстоўваеце, паводзяць сябе.

Адзін са спосабаў абыйсці гэтую праблему, калі вы знойдзеце гэта становіцца праблемай (або калі вы проста хочаце, каб пазбегнуць гэтай праблемы ў цэлым) з'яўляецца выкарыстанне паказальнікаў і тое, што вядома як Construct пры першым выкарыстанні . Тут вы не ствараеце асобнік якіх-небудзь аб'ектаў у канструктару або вызначэння класа - замест таго, каб проста мець паказальнікі на іх і выкарыстоўваць новы ключавое слова, каб пабудаваць аб'ект з функцыі-члена (напрыклад, < код> пачаць() ).

Для гэтага зменіце запісу аб'екта вызначэння класа як паказальнікі, такія як:

Bounce *_debouncePushButton = NULL;

(Звярніце ўвагу, што не ўсе версіі кампілятара будуць падтрымліваць гэтае прызначэнне ў вызначэнні класа. Гэта сучаснае дадатак да C ++, і ў залежнасці ад версіі праграмнага забеспячэння Arduino можа ці не можа працаваць. Калі гэта не вы можаце перамясціць прысваенне ў канструктар шляхам выдалення = NULL з вызначэння і дадання _debouncePushButton = NULL ;. у канструктар)

Затым пабудаваць новы аб'ект у пачаць() <�код /> функцыі (калі яна яшчэ не створана):

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 ...

У выпадку, калі клас павінен калі-небудзь з вобласці бачнасці або выкарыстоўвацца ў дынамічны , як вы сапраўды павінны стварыць деструктор , каб выдаліць усе аб'екты, якія маюць было створана:

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

Звярніце ўвагу, што вы павінны заўсёды спрабаваць выдаляць аб'екты, якія на самай справе былі створаны - значыць, тэст, каб убачыць, калі гэта не нуль.

Празмернае выкарыстанне новы і Выдаліць хоць не рэкамендуецца, так што лепш за ўсё выкарыстоўваць аб'екты ў статычным кантэксце, калі гэта магчыма. Занадта шмат новы і выдаліць або Таноса і бясплатна можа прывесці да фрагментацыі кучы , які можа прывесці да бяжыш з памяці і ўсе звязаныя з ім праблемы са стабільнасцю, якія прыходзяць з ёй.

Вядома, усё гэта не з'яўляецца абавязковым, і хутчэй за ўсё, ён не будзе патрэбен, калі іншыя класы вядуць сябе добра.

1
дададзена
Глядзіце маё рэдагаванне. У вас ёсць другая цалкам не звязаная праблема з вашым кодам.
дададзена аўтар Majenko, крыніца
Калі ён знаходзіцца ў CandleRack.h, то гэта таксама ў CandleRack.cpp паколькі CandleRack.h ўваходзіць у CandleRack.cpp.
дададзена аўтар Majenko, крыніца
Толькі калі вы калі-небудзь выдаліць аб'ект CandleRack, і так як вы статычна стварыць што ён ніколі не будзе выдалены. Вы можаце зрабіць деструктор CandleRack, калі вы сапраўды хочаце, і выдаліць аб'ект бразгату (калі ён быў створаны), але калі вы заўсёды будзеце статычны стварыць яго там не зусім ніякай неабходнасці.
дададзена аўтар Majenko, крыніца
І гэта не выкарыстанне новы , што дрэнна - гэта неаднаразовае новы і Выдаліць , што прыводзіць да фрагментацыі кучы - і калі ў вас ёсць толькі малюсенькае куча фрагментацыі вельмі і вельмі дрэнна. Выкарыстанне новы статычна (ніколі не выкарыстоўваючы выдаліць і ніколі не хоча выкарыстоўваць Выдаліць ) не прыводзіць да фрагментацыі кучы.
дададзена аўтар Majenko, крыніца
Вы можаце зрабіць, так. Можна зрабіць усё гэта статычна і не выкарыстоўваць новыя наогул - проста вярнуцца да таго, як гэта было і выдаліць радок, якая прысвойвае аб'ект бразгату ў функцыі пачынаюцца - аднак ёсьць рызыка статычных задач парадку ініцыялізацыі, то калі вы не «т ведаю, што канструктары іншых аб'ектаў робяць. Выкарыстоўваючы паказальнікі для вашых аб'ектаў, вы атрымліваеце тое, што называецца «пабудаваць на першым выкарыстанні» з іх, што азначае, што яны заўсёды будуць пабудаваны пасля таго, як сістэма цалкам ініцыялізаваны.
дададзена аўтар Majenko, крыніца
@ Frarugi87 так, я напісаў яе перад сном. Гэта не выдатны адказ.
дададзена аўтар Majenko, крыніца
Асабіста я б выправіць гэты адказ, бо гэта ўводзіць у зман. Вы абавязкова павінны выдаліць паказальнік (і новы) частка, бо яна не звязаная з рэальнай праблемай. Калі, па-іншаму, вы хочаце захаваць яго, змяніць словы вакол (гэта не з'яўляецца абавязковым, што трэба зрабіць, гэта проста тое, што вы прапануеце), але, то, вам трэба: 1) ініцыялізаваць паказальнік на NULL 2) праверыць, калі паказальнік з'яўляецца несапраўдным (абараняе ад некалькіх пачынаюць тэлефанаваць, або будзе ўцечка памяці), перш чым зрабіць новы 3) відавочна выдаліць яго (у адваротным выпадку ўцечкі памяці, калі аб'ект выкарыстоўваецца ў паменшаным аб'ёме)
дададзена аўтар Tom Collins, крыніца
@Majenko Зараз гэта добры адказ .. +1
дададзена аўтар Tom Collins, крыніца
Дзякуючы. Ён па-ранейшаму дае мне тое ж пытанне, хоць, гэта дадае шмат выпадковых лікаў у масіў. Я магу размясціць код для выкарыстання аб'екта бразгату ў адным эскізе, калі гэта дапамагае?
дададзена аўтар Slacker, крыніца
Agh, OK. адна праблема ў тым, што #define NUM_LEDS зыходзіць з майго FastLED масіва, і мне трэба, што ў галоўным эскізе я думаю. Я не ўпэўнены, як спасылацца/кропку да #define, хоць (што ён павінен быць).
дададзена аўтар Slacker, крыніца
Выдатна. Проста паспрабаваў і гэта адсартаваныя праблему! Вялікі дзякуй :) Цяпер каверзны біт, які выкарыстоўвае FastLED у аб'екце :)
дададзена аўтар Slacker, крыніца
адно пытанне ... Я чытаў, што гэта не было добра выкарыстоўваць новы у Arduino эскізаў. Гэта стары adivce?
дададзена аўтар Slacker, крыніца
Я чытаў на новы і я павінен выкарыстоўваць Выдаліць дзесьці, а таксама за arduino.land/FAQ/content/4/24/en/mixing-malloc-and-new.html ?
дададзена аўтар Slacker, крыніца
Ці павінен я быць таксама выкарыстанне паказальнікаў для майго іншага аб'екта бібліятэкі - elapsedMillis? яна выдатна працуе на дадзены момант, але думаць аб сваім апошнім радзе, можа быць перавага ў выкарыстанні паказальніка там, а?
дададзена аўтар Slacker, крыніца
Мае сэнс - зараз я разумею, што памылка ў мяне быў з самага пачатку разьбы было з пытаннем масіва randomNumber - астатняе больш «лепшая практыка». Так што ўсё, што мне трэба зрабіць, гэта змяніць (у загалоўку) elapsedMillis _candleTimeElapsed [NUM_LEDS]; у elapsedMillis * _candleTimeElapsed [NUM_LEDS]; ? як я не магу выкарыстоўваць -> абазначэння ў гэтым выпадку, як цяпер я больш уважліва не на самай справе асобнік аб'екта elapsedMillis для спасылкі ў гэтым выпадку. Ці з'яўляецца гэта правільна?
дададзена аўтар Slacker, крыніца
Дзякуй за абноўлены адказ, ён мае вялікае значэнне для майго разумення. Тым больш, што я выказаў здагадку, да гэтага з дапамогай <�коды> новага будзе пераважным спосабам для стварэння асобніка аб'екта.
дададзена аўтар Slacker, крыніца