6

led マトリックス (max7219) へのデータの送信を処理するクラスを作成しました。

これは、LedControl クラスのインスタンスを作成するために行っていたことです。

LedControl lc=LedControl(11, 13, 12);// data, clock, latch;

void setup() 
{
   ...
}

今、クラスにタイマー割り込みを追加しようとしています。しかし、初期化子 ( ) で適切なレジストリを設定できないことがわかりましたLedControl::LedControl()。このコードを に移動するとsetup、すべてが完全に機能します。私の推測ではtimer1、PWM を使用する Arduino ブートローダーは、呼び出しの直前でsetup()オブジェクトが初期化された後に、これらのレジストリを上書きします。

だから私の考えは、オブジェクトの作成をセットアップ機能に移動することでした

// FAIL
LedControl lc;

void setup() 
{
   lc=LedControl(11, 13, 12);// data, clock, latch;
   ...
}

しかし、その後、エラーが発生しますno matching function for call to 'LedControl::LedControl()'

ポインター ( LedControl *lc; lc=&LedControl(11, 13, 12);) を使用してみましたが、私が知る限り、これ(*lc).someFunction()lc.someFunction(). レジストリ設定コードを setup() に移動するよりも洗練されていません。

だから私の質問はです。関数内でオブジェクトを作成する方法はありますが、setup()それを指すグローバル変数はまだありますか?

4

2 に答える 2

12

最初のエラー「no matching ..」は、デフォルトのコンストラクターがないためです。そのアプローチを機能させることができます。

次のように、パラメーターなし、別名デフォルト コンストラクターをクラスに追加します。

class LedControl {
  LedControl();
  LedControl(uint8_t pin1, uint8_t pin2, uint8_t pin3);

private:
  uint8_t pin1;
  uint8_t pin2;
  uint8_t pin3;
};

LedControl::LedControl() : pin1(0), pin2(0), pin3(0) {
  // this constructor leaves the class unusable
}

LedControl::Ledcontrol(uint8_t p1, uint8_t p2, uint8_t p3) 
  : pin1(p1), pin2(p2), pin3(p3)
{
  // this object is ready to use    
}

このクラスでは、アプローチは機能しますが、最適な方法ではありません。この行はあまりにも多くの作業を行います:

void setup() {
  lc = LedControl(11, 13, 12);// data, clock, latch;
}

このコード行には、コンパイラがコードを作成することが含まれます。

  • 最初に、クラスの別のインスタンスが、パラメーター 11、13、12 を使用してスタック上に構築されます。
  • 次に、スタック オブジェクトからグローバル オブジェクトにデータをコピーする= 演算子を適用します。
  • setup() が終了すると、スタック オブジェクトがフラッシュされます。

一時オブジェクトがスタック上にあるため、プログラムはメモリをあまり使用しませんでしたが、一時オブジェクトを作成してから一時オブジェクトから永続オブジェクトにコピーするための余分な操作が必要になるため、コード サイズが大きくなります。

行の関数を埋めるために、コンパイラが= 演算子を作成していることに注意してください。

  lc = LedControl(11, 13, 12);

これは、コンストラクターの内容に応じて機能する場合と機能しない場合があります。コンパイラは、単純な= 演算子が必要であると推測することしかできません。基本的な代入演算子は、すべてのデータ メンバーを = の右側のインスタンスから左側のインスタンスにコピーするだけです。構築されたコンパイラ = にはコードが含まれません。

コンストラクターが重要なこと (パラメーターの保存以外) を行う場合、コンパイラーによって構築された (推測された) 割り当て演算子は、期待どおりに機能しない可能性があります。あなたの場合、コンストラクターはおそらく次のようなピンモードを設定します。

LedControl::LedControl(uint8_t p1, uint8_t p2, uint8_t p3) 
  : pin1(p1), pin2(p2), pin3(p3)
{
  pinMode(pin1, INPUT);
  pinMode(pin2, OUTPUT);
  pinMode(pin3, OUTPUT);
  return;
}

これはたまたま機能しますが、たまたまです。pinMode() 呼び出しは、一時オブジェクトが構築され、グローバルlcからではなく、そのオブジェクトから呼び出されるときに行われます。pinMode() はグローバルであるため、このケースは正しい目標を達成しますが、期待した方法ではない可能性があります。割り込みハンドラの登録などのより複雑な操作については、独自の代入演算子を作成する必要があります。

LedControl& operator= (const LedControl & other);

その方法では、グローバルlcの状態が必要なものであることを確認できます。より簡単で安全なアプローチは、それをまったく扱わないことです。

シンプルで効率的なアプローチは、他のライブラリで見たことがあるかもしれませんが、ピンを割り当てるクラスにメソッドを追加することです。

class LedControl {
  void attach(uint8_t pin1, uint8_t pin2, uint8_t pin3);
};

void LedControl::attach(uint8_t pin1, uint8_t pin2, uint8_t pin3) {
  this.pin1 = pin1;
  this.pin2 = pin2;
  this.pin3 = pin3;
  // do other setup type operations
  return;
}

これで、プログラムは空のオブジェクトを構築し、setup() 中にピンを割り当てます。

LedControl lc; // not ready to use until attach pins

void setup() {
  lc.attach(11, 13, 12);// data, clock, latch;
  ...
}

これには、一時オブジェクトの構築も代入演算子も含まれません。設計に関して、一部の人々は、ユーザーが attach() を呼び出すのを忘れて、グローバル lc オブジェクトを使用できないままにしておく可能性があるとかなりコメントするかもしれません。デスクトップ アプリケーションの場合は、その失敗を防ぐためにコードを追加することがあります。組み込みアプリケーションの場合、これは許容できるリスクであり、コード サイズの増加またはメモリの節約によってバランスが取れています。

于 2013-09-15T05:07:38.333 に答える
5

私はちょうど同じ問題に遭遇しました。グローバル デバッグ ポート オブジェクトを作成したかったのですが、 setup() が呼び出された後にポートが機能しないため、グローバル インスタンスとして作成できませんでした。私は、arduino コードが (グローバル オブジェクトの) コンストラクターの後、setup() の前にいくつかのセットアップを行うという同じ仮定を持っています。

オブジェクトをポインターとして宣言し、セットアップで初期化するのが最も簡単な解決策であることがわかりました。あなたの状況では、次のようになります。

LedControl* lc;

void setup() 
{ 
   lc = new LedControl(11, 13, 12);// data, clock, latch;
}

void loop()
{
   lc->doSomething();
}

したがって、コンストラクターや演算子を追加する必要はありません。オブジェクトは電源が切れるまで使用されるため、この場合は削除する必要はありません。

于 2017-12-27T10:26:02.613 に答える