I / Oピンの抽象化のためのC ++クラス


13

ハードウェアI / OポイントまたはピンのC ++抽象化を探しています。in_pin、out_pin、inout_pin、open_collector_pinなどのようなもの。

私はきっとこのような抽象化のセットを自分で思いつくことができるので、私は「ねえ、あなたはこのようにするかもしれない」タイプの答えを探しているのではなく、「これとこれで使用されているこのライブラリを見て、このプロジェクト」。

他の人がこれをどのように呼ぶのかわからないので、Googleは何も表示しませんでした。

私の目的は、そのようなポイントに基づいているが、そのようなポイントも提供するI / Oライブラリを構築することです。そのため、たとえば、HD44780 LCdをチップのIOピンまたはI2C(またはSPI)のいずれかに簡単に接続できますI / Oエクステンダー、またはLCDクラスを変更せずに、何らかの方法で制御できるその他のポイント。

私はこれが電子機器/ソフトウェアの端にあることを知っています、それがここに属さない場合は申し訳ありません。

@leon:配線それはソフトウェアの大きな袋です。詳しく見る必要があります。しかし、彼らは私が望むようにピンの抽象化を使用していないようです。たとえば、キーパッドの実装では

digitalWrite(columnPins[c], LOW);   // Activate the current column.

これは、I / Oピンへの書き込み方法を知っている関数(digitalWrite)が1つあることを意味します。これにより、digitalWrite関数を書き換えずに、新しいタイプのI / Oピン(たとえば、MCP23017上にあるため、I2Cを介して書き込む必要がある)を追加できなくなります。

@Oli:Arduino IOの例をグーグルで検索しましたが、Wiringライブラリとほぼ同じアプローチを使用しているようです:

int ledPin = 13;                 // LED connected to digital pin 13
void setup(){
    pinMode(ledPin, OUTPUT);      // sets the digital pin as output
}

ここで話しているマイクロコントローラーは何ですか?
マジェンコ

それは無関係です。特定のマイクロコントローラの場合、そのuCのioピンは適切なインターフェイスを実装します。ただし、これはC ++向けであるため、ARM、Cortex、MIPSなどの32ビットチップを考えてください。
はWouterバンOoijen

1
使用したことはありませんが、Arduinoはこのようにすべてのピンを抽象化しませんか?あなたは彼らが物事をやった方法を見ていくつかの有用な情報を取得する場合があります(取得しない場合があります)。
オリグレイザー

1
また、digitalWrite関数の書き換えについては、C ++の「オーバーロード」をご覧ください。ほんの少し前に、ArduinoのIOエクスパンダーボード用のオーバーロードされたdigitalWrite関数を書きました。異なるパラメーターを使用している限り(最初の "int"を "struct"に置き換えました)、digitalWriteをデフォルトのパラメーターよりも優先して選択します。
マジェンコ

1
このテーマに関する私の仕事について、ベルリンでC ++に会うことについて講演しました。youtubeで見つけることができます:youtube.com/watch?v=k8sRQMx2qUwそれ以来、少し異なるアプローチに切り替えましたが、話はまだ面白いかもしれません。
ウーターヴァンOoijen

回答:


3

短い答え:悲しいことに、あなたがやりたいことをするライブラリはありません。私は何度もそれをやってきましたが、常に非オープンソースプロジェクトで行ってきました。私はgithubに何かを置くことを考えていますが、いつできるのかわかりません。

なぜC ++なのか?

  1. コンパイラは、動的なワードサイズの式評価を自由に使用できます。Cはintに伝播します。バイトマスク/シフトはより速く/より小さくできます。
  2. インライン化。
  3. テンプレート化操作を使用すると、タイプセーフでワードサイズやその他のプロパティを変更できます。

5

オープンソースプロジェクトhttps://Kvasir.ioを恥知らずにプラグインできるようにします。Kvasir :: Io部分は、ピン操作機能を提供します。まず、Kvasir :: Io :: PinLocationを使用してピンを定義する必要があります。

constexpr PinLocation<0,4> led1;    //port 0 pin 4
constexpr PinLOcation<0,8> led2;

これらはconstexpr変数であるため、実際にはRAMを使用しないことに注意してください。

コード全体で、makeOpenDrain、set、clear、makeOutputなどの「アクションファクトリ」関数でこれらのピン位置を使用できます。「アクションファクトリ」は実際にアクションを実行するのではなく、Kvasir :: Register :: apply()を使用して実行できるKvasir :: Register :: Actionを返します。これは、apply()が、同じレジスタで動作するときに渡されるアクションをマージするため、効率が向上するためです。

apply(makeOutput(led1),
    makeOutput(led2),
    makeOpenDrain(led1),
    makeOpenDrain(led2));

アクションの作成とマージはコンパイル時に行われるため、これにより、典型的なハンドコーディングされた同等のものと同じアセンブラーコードが生成されます。

PORT0DIR |= (1<<4) | (1<<8);
PORT0OD |= (1<<4) | (1<<8);


2

C ++では、I / Oポートを変数であるかのように使用できるようにクラスを書くことができます。例えば

  PORTB = 0x12; / * 8ビットポートへの書き込み* /
  if(RB3)LATB4 = 1; / * 1つのI / Oビットを読み取り、条件付きで別のビットを書き込みます* /

基礎となる実装に関係なく。たとえば、ビットレベルの操作をサポートしていないがバイトレベルのレジスタ操作をサポートしているハードウェアプラットフォームを使用している場合、(おそらくいくつかのマクロの助けを借りて)インライン読み取り/書き込みで静的クラスIO_PORTSを定義できます上記の最後のステートメントが次のようになるような、bbRB3およびbbLATB4と呼ばれるプロパティ

  if(IO_PORTS.bbRB3)IO_PORTS.bbLATB4 = 1;

次のように処理されます。

  if(!!(PORTB&8))(1?(PORTB | = 16):(PORTB&=〜16));

コンパイラは、?:演算子の定数式に気付き、単純に「true」部分を含める必要があります。マクロを次のように展開することにより、作成されるプロパティの数を減らすことができる場合があります。

  if(IO_PORTS.ppPORTB [3])IO_PORTS.ppPORTB [4] = 1;

または

  if(IO_PORTS.bb(addrPORTB、3))IO_PORTS.bbPORTB(addrPORTB、4)= 1;

しかし、コンパイラーがコードを適切にインライン化できるかどうかはわかりません。

I / Oポートを変数であるかのように使用することが必ずしも良いアイデアであることを意味するつもりはありませんが、C ++について言及しているので、知っておくと便利です。前述のスタイルを使用するコードとの互換性が必要でない場合、CまたはC ++での私自身の好みは、おそらく各I / Oビットにあるタイプのマクロを定義し、次に「readBit」、「writeBit」、 「setBit」および「clearBit」。ただし、これらのマクロに渡されるビット識別引数は、そのようなマクロで使用するためのI / Oポートの名前でなければなりません。たとえば、上記の例は次のように記述されます。

  if(readBit(RB3))setBit(LATB4);

と翻訳された

  if(!!(_ PORT_RB3&_BITMASK_RB3))_PORT_LATB4 | = _BITMASK_LATB4;

これは、C ++スタイルよりもプリプロセッサの作業が少し多くなりますが、コンパイラの作業は少なくなります。また、多くのI / O実装に対して最適なコード生成が可能になり、ほぼすべてに対して適切なコード実装が可能になります。


3
質問からの引用:「私は「ちょっと、あなたはこの方法でやる」タイプの答えを探していません」...
Wouter van Ooijen

私はあなたが何を探しているのかはっきりしていないと思います。確かに、I / Oピンの再構築のクラスに興味のある多くの人々は、プロパティを使用して、1つのスタイルのI / O用に記述されたコードを作成できることを知りたいと思うでしょう。プロパティを使用して、「LATB3 = 1;」のようなステートメントを作成しました。I / O要求をTCPストリームに送信します。
-supercat

私の質問で明確にしようとしました:IOピンを使用するコードを書き直すことなく、新しいタイプのIOピンに対応できるようにしたいのです。ユーザー定義の型変換と代入演算子について書いています。これらは確かに興味深いものです。私は常にそれらを使用していますが、私の問題の解決策ではありません。
ウーターヴァンOoijen

@Wouter van Ooijen:どんな「新しいタイプのI / Oピン」を期待していますか?ソースコードが「if(BUTTON_PRESSED)MOTOR_OUT = 1;」のような構文で記述されている場合、プロセッサがボタンコントロールまたはモーターを読み取る可能性のあるほぼすべてのメカニズムについて、上記のソースボタンを押すと、コードはモーターをオンにします。このようなライブラリは、モーターをオンにする最も効率的な方法ではないかもしれませんが、動作するはずです。
-supercat

@Wouter van Ooijen:入力を読み込む前にソースコードがUPDATE_IO()またはUPDATE_INPUTS()マクロを呼び出し、出力の後にUPDATE_IO()またはUPDATE_OUTPUTS()を実行する必要がある場合、おそらく効率を改善できます入力を読み取るコードで、または前回のUPDATE_INPUTS()/ UPDATE_IO()呼び出しで入力をサンプリングできるセマンティクス。同様に、出力はすぐに発生するか、遅延する可能性があります。I / Oがシフトレジスタなどを使用して実装されている場合、アクションを延期すると、複数の操作を統合できます。
-supercat

1

ハードウェアを抽象化するのに本当に素晴らしいものを探していて、C ++スキルに自信がある場合は、次のパターンを試してください。

https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern

Cortex-M0チップのハードウェアを抽象化する試みの1つで使用しました。私はこの経験についてはまだ何も書いていません(いつかやる予定です)が、その静的なポリモーフィックな性質のために非常に有用であると信じています:異なるチップに対して同じ方法で、無料で(動的なポリモーフィズムと比較して)。


この投稿以来、私はpin_in、pin_out、pin_oc、pin_in_outの個別の「クラス」に悩まされていました。最適なパフォーマンス(サイズと速度)のために、テンプレートパラメーターとして渡される静的クラスを使用します。私はベルリンでの会議C ++でこれについて話しました
はWouterバンOoijen
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.