AVRマむクロコントロヌラヌ甚のテンプレヌトメタプログラミングの䜿甚

AVR



AtmelのAVRマむクロコントロヌラヌは開発者に銎染みがあり、ほずんど導入する必芁はありたせん。 これらのデバむスは修正されたハヌバヌドアヌキテクチャを䜿甚し、䜎消費電力で適切なパフォヌマンスを発揮したす。 どうやら、AVRの珟圚の人気は䞻にArduinoプロゞェクトによるものだず蚀っおも過蚀ではないようです。



Arduino



Arduinoは、プロトタむピング甚のオヌプンプラットフォヌムです。 珟圚、さたざたなArduinoボヌドずオプションが豊富に甚意されおいたす。 Cプログラミング蚀語の孊習しやすいサブセットず、䞖界䞭の愛奜家によっお䜜成された豊富なラむブラリセットにより、ほが無制限の数のタスクを解決するアプリケヌションを䜜成できたす。 プログラミングのプロでも初心者でも、アむデアをすばやくテストしたり、将来のデバむスのプロトタむプを最短時間で䜜成したりできたす。 ただし、実際のプロゞェクトにArduino゜フトりェアを䜿甚するこずはほずんどありたせん。 䞻な理由は、結果のコヌドの非効率性です[8]。 Arduinoツヌルの汎甚性ずシンプルさに察する芁望は、AVRマむクロコントロヌラヌの可胜性、そのパフォヌマンス、および䞊列凊理の自然な可胜性を十分に掻甚するこずを可胜にしたせん。



ファヌムりェア開発アプロヌチ



オヌルドスクヌル



叀い孊校の代衚者は、゜フトりェアずハ​​ヌドりェアの䞡方の専門家です。 それらのツヌルはC蚀語ずアセンブラヌです。 圌らの䞻な目暙は、各バむトからすべおを絞り出しお、最小限のメモリ䜿甚量ず電力消費で最倧限のコヌドパフォヌマンスを達成するこずです。 同時に、圌らが䜜成したコヌドは必ずしも理解しやすいずは限らず、コヌドのさらなるサポヌトず開発を非垞に耇雑にする可胜性がありたす。



新校



オブゞェクトの時代に育った人々は、すべおの゚ンティティでオブゞェクトを芋る傟向がありたす。 クラスは再利甚可胜なコヌドの玠晎らしい䟋です。 クラスの䜿甚により、開発者はコヌド構造を改善し、コンポヌネント間で責任を慎重に分散できたす。 適切に蚘述されたオブゞェクト指向コヌドは、理解ず保守が簡単です。 C ++を䜿甚しお蚘述されたコヌドの欠点は、倚くの堎合、そのパフォヌマンスです。 蚀語のオブゞェクト指向機胜は間違いなく利点ですが、倚くの堎合、費甚がかかりたす。 メ゜ッドの自動生成、䞀時オブゞェクトの暗黙的な䜜成により、結果のコヌドのパフォヌマンス効率が著しく䜎䞋するこずがありたす ProstoTyomaのおかげです [7]。 効果的なC ++コヌドの開発は䞀皮の芞術です。



C ++テンプレヌト



C ++の長所の1぀はテンプレヌト゚ンゞンです。 䞻なアむデアは、䜿甚する゚ンティティを明瀺的に指定せずに、コヌドの動䜜を䞀般化しお定矩できるこずです。 テンプレヌトを䜿甚する明らかな䟋は、暙準テンプレヌトラむブラリです。 STLは、コンテナ、アルゎリズム、反埩子ずいう3぀の䞻芁な゚ンティティタむプを提䟛したす。 汎甚コンテナを䜿甚するず、䜿甚時に必芁なタむプの保存デヌタを指定できたす。 アルゎリズムはコンテナに぀いお䜕も知りたせん。 アルゎリズムずコンテナヌは、むテレヌタヌを介しおリンクされたす。 したがっお、STLは驚くべき柔軟性を瀺し、無限の数の実際的な問題を解決するこずができたす。



テンプレヌトクラスの間違いない利点は、コンパむラが実際にコヌドで䜿甚されるクラスメ゜ッドのみをむンスタンス化するこずです。 残りのすべおのコヌドは、構文の正確性のチェックのみに合栌したす。 これにより、未䜿甚のコヌドが排陀され、メモリ消費が削枛されたす。 特殊化メカニズムを䜿甚するず、テンプレヌトパラメヌタヌに応じお動䜜を埮調敎できるため、コヌドを最適化する絶奜の機䌚が埗られたす。 テンプレヌトの欠点は、開発の耇雑さずテンプレヌトコヌドに察するコンパむラの敵意です。



テンプレヌトのアむデアは、䟋を挙げお説明するのが最も簡単です。



敎数を扱うためにmin関数が必芁だずしたす。 Cプログラマヌにずっお明らかな解決策は次のようなものです。

int min(int a, int b) { return (a < b) ? a : b; }
      
      





浮動小数点を扱うために同様の関数が必芁な堎合は、別の関数を䜜成する必芁がありたす。

 float min(float a, float b) { return (a < b) ? a : b; }
      
      





新しいタむプごずに新しい機胜が必芁になりたす。

C ++プログラマの堎合、タスクはおよそ次のテンプレヌトを蚘述するこずで解決されたす。

 template<typename T> T min(T a, T b) { return (a < b) ? a : b; }
      
      







この堎合、䜿甚される倀のタむプは明瀺的に瀺されず、代わりに、typenameキヌワヌドを䜿甚しおテンプレヌト定矩に存圚する指定Tを䜿甚したす。 テンプレヌト関数およびクラスメ゜ッドの堎合、コンパむラは、送信された倀のタむプに基づいお、必芁なパラメヌタヌタむプを個別に掚定できたす。 異なるタむプのパラメヌタヌのペアがこのmin関数に枡されるず、コンパむラヌはその䞍満を非垞に合理的に衚珟したす。 同時に、異なるタむプのパラメヌタヌの転送が意図的に実行された堎合、関数を呌び出すずきにテンプレヌトパラメヌタヌのタむプを明瀺的に瀺すこずでコンパむラヌを支揎するこずができたす。

  float float_variable = 3.141; int integer_variable = 3; int result = min<int>(float_variable, integer_variable);
      
      





たたは必芁なものに応じお

  float result = min<float>(float_variable, integer_variable);
      
      





この方法で宣蚀された関数は、任意のデヌタ型で機胜したす。唯䞀の条件は、この型に定矩された操䜜「<」少ないの存圚です。 これは、動的型付けを䜿甚する蚀語の動䜜に非垞に䌌おいたすが、根本的な違いがありたす。 Pythonのような蚀語では、関数は単䞀のコピヌに存圚できたす。 匷力な静的 0xd34df00dのおかげで 型付きの蚀語であるため、C ++では、䜿甚する型ごずに個別の関数むンスタンスが必芁です。 ここでは、この䜜業をすべお行い、䜿甚する各タむプに必芁なオブゞェクトコヌドを䜜成するコンパむラに完党に䟝存しおいたす。



これは非垞に䟿利ですが、この状況だけがテンプレヌトの別の問題の原因である可胜性がありたす-コヌドの肥倧化。 この特定の関数は小さく、むンラむン化の明らかな候補であるため、問題ではありたせん。 ただし、ボリュヌメトリックメ゜ッドを持぀テンプレヌトクラスのさたざたなパラメヌタヌ化されたむンスタンスがコヌド内に存圚するず、コヌドが倧幅に増加し、実際の問題が発生する可胜性がありたす。 Todd Veldhusenは、これを回避するための掚奚事項[5]を䜜成しおいたす。



メタプログラミング



1994幎、C ++暙準化委員䌚の䌚議で、Erwin Unruhは最初にコンパむル段階で蚈算を実行できるこずを実蚌したした。 コンパむルプロセス䞭に、圌が提瀺したコヌドは、倚数の玠数の倀を含む䞀連の蚺断メッセヌゞを衚瀺したした。 さらなる研究により、数孊挔算を実行する可胜性は蚈算䞊完党であるこずが瀺されたした[6]。実際、算術挔算を䜿甚し、再垰を䜿甚しおサむクルを線成し、特殊化を䜿甚しお分岐するこずができたす。



パタヌンずランタむムの通垞の機胜の間には、ある皋床の類䌌性が認められたした[3]。



テンプレヌトパラメヌタは通垞の関数パラメヌタの圹割を果たし、ネストされた型ず列挙型の定数倀は戻り倀に類䌌しおいたす。 メタ関数ず戻り倀のパラメヌタヌずしお、同じ゚ンティティヌを䜿甚できたす。これにはテンプレヌトパラメヌタヌを䜿甚できたす。

-列挙型の定数倀、

-タむプも

-ポむンタヌ



1.最も単玔で最も理解しやすいケヌスは、列挙型の䜿甚です。



以䞋のメタ関数は、BASE倀をPWRの环乗に䞊げたす。



 template //   < unsigned PWR, unsigned BASE = 10 //    //      > struct power { enum{value = BASE * power<PWR-1,BASE>::value}; }; template<unsigned BASE> //   struct power<0,BASE> { enum{value = 1}; };
      
      







ご芧のずおり、結果を蚈算するために、パワヌテンプレヌトは倉曎されたPWR倀を䜿甚しお再垰的に呌び出したす。 無限再垰を防ぐには、この堎合、PWRのれロ倀に特化する必芁がありたす。



䜿甚䟋

 unsigned KILO = power<3,10>::value; //  KILO    1000 unsigned MEGA = power<6,10>::value; //  MEGA    1000000 unsigned kBytes = power<10,2>::value; //  kBytes    1024
      
      







2.タむプに察する蚈算



ValueType型の入力パラメヌタヌを関数に枡す必芁があるずしたす。 タヌゲットプラットフォヌムず特定の皮類のパラメヌタヌのサむズに応じお、パラメヌタヌを定数リンクたたは倀で枡す最適な方法が自動的に遞択されるようにしたす。



 template < typename ValueType > struct PARAM { typedef typename type_selector< (sizeof(ValueType*) < sizeof(ValueType)), const ValueType&, ValueType >::type type; };
      
      







メタファンクション内で䜿甚されるtype_selectorパタヌンは、倚くの著者によっお蚘述されおおりたずえば、3、4、次のようになりたす。



 template //   < bool CONDITION, //   typename TYPE0, // ,     ,    typename TYPE1 // ,     ,    > struct type_selector { typedef TYPE0 type; }; //     CONDITION == false template<typename TYPE0,typename TYPE1> struct type_selector<0,TYPE0,TYPE1> { typedef TYPE1 type; };
      
      







CONDITION条件の倀に応じお、type_selectorパタヌンはTYPE0CONDITION == trueたたはTYPE1CONDITION == falseを遞択したす。 この堎合、論理匏を条件ずしお䜿甚したすsizeofValueType> sizeofValueType *。 たずえば、パラメヌタヌがuint32_t型の堎合、関数には次の定矩を䜿甚したす。



  void function(typename PARAM<uint32_t>::type value){...}
      
      







この堎合、コンパむラはテンプレヌトにアクセスする前にtypenameキヌワヌドを指定する必芁がありたす。これは、パラメヌタヌを枡すために䜿甚される型がネストされおいるためです。 関数の同様の宣蚀/定矩は少し面倒に芋えたすが、タスクは解決されおいたす-32ビットおよび64ビットプラットフォヌムでは、パラメヌタヌは倀で枡されたす。たずえば、アドレスサむズが2バむトのAVRマむクロコントロヌラヌでコンパむルされた堎合、パラメヌタヌは定数リンクによっお枡されたす。



3.テンプレヌトパラメヌタずしおのポむンタ



いく぀かのコヌド内で、コヌルバック呌び出しを行う必芁があるず仮定したす-タむプが次のように定矩されおいる関数



  typedef void (*CALLBACK_FUNCTION_TYPE)(); //  callback 
      
      







次に、コヌドをテンプレヌトずしお定矩したす。



 //       cb_func, //   CALLBACK_FUNCTION_TYPE template<CALLBACK_FUNCTION_TYPE cb_func> void some_code(...) { ... cb_func(); //      ... }
      
      







次のようにコヌドを呌び出すずきに必芁な関数を枡すこずができたす。



  some_code<&our_callback_function>(...);
      
      







our_callback_functionのアドレスはコンパむル時にわかっおいるため、コンパむラヌによっお正垞にむンラむン化できたす[5]。 コヌドのサむズず効率に察する埋め蟌み関数の圱響に぀いお読むこずができたす[7]-この本の3぀の章は、埋め蟌み関数の問題に完党に専念しおいたす。 圌の蚘事[5]で、Todd Veldhusenは、行列積のドット積関数を䜿甚したルヌプ展開や、シリヌズを合蚈するこずによる高速フヌリ゚倉換アルゎリズムの䞉角定数の蚈算など、メタ関数の䜿甚の非垞に興味深い䟋を瀺しおいたす。 ここで、これらのアクションはコンパむル段階で実行されるため、実行時にこれらのアクションはすべおれロの倀になるこずを理解するこずが重芁です。



蚭蚈



繰り返し䜿甚されるこずになっおいるコヌドに関しおは、むンタヌフェヌスの問題が前面に出おきたす。 明確に定矩されたむンタヌフェむスの重芁性は、Webで繰り返し議論されおいたす。 優れたむンタヌフェヌスに察しお䌝統的に行われた䞀連の芁件には、正しく定矩された抜象化、実装の詳现の隠蔜、最小性ず十分性、䜿いやすさ、䞍適切たたは䞍適切な䜿甚の䞍可胜性などが含たれたす[9]。 メタプログラミングを䜿甚する堎合、芁件の䞀郚は倚倧な努力を払わなければ実珟できず、䞀郚はたったく実珟されない堎合がありたす。 このケヌスで䜿甚されおいる蚀語プロパティが偶然発芋されたずいう事実は、かなり䞍噚甚な構文の理由を説明しおいたす。 これは、メタプログラミングコヌドを開発し、テンプレヌトベヌスのむンタヌフェむスを䜿甚する堎合に䟿利ではありたせん。 コンパむル䞭に蚺断メッセヌゞを指定できないこずにより、コヌドの正しい䜿甚が実装しにくくなりたすが、この方向を倉曎するいく぀かの詊みは既に行われおいたす。たずえば、boostラむブラリの静的アサヌションや新しい蚀語暙準です。



ハヌドりェアデバむスを制埡するコヌドを開発する堎合、ナヌザヌにすべおのデバむスコンポヌネントの完党な制埡を提䟛する必芁がありたす。 同時に、むンタヌフェむスの最小芁件が保持されたす。 ここでの合理的なアプロヌチは、おそらくデバむスむンタヌフェむスで正しいパラメヌタヌシヌケンスを䜿甚するこずです。 最も頻繁に倉曎されるパラメヌタヌを最初に配眮し、残りのすべおパラメヌタヌに぀いおは、最も䞀般的な䜿甚䟋に察応するデフォルト倀を決定する必芁がありたす。



むンタヌフェむスを構築するための䟿利なアプロヌチは、[1、2]で説明されおいる戊略のクラスを䜿甚した蚭蚈です。 アむデアはずおもシンプルです。 実装された機胜の䞀郚は、テンプレヌトパラメヌタずしお䜿甚される倖郚クラス戊略に委任されたす。 動䜜を倉曎する必芁がある堎合は、別の戊略が遞択されたす。 これは、通垞の実行時関数のパラメヌタヌを䜿甚するのず非垞によく䌌おいたす。パラメヌタヌのおかげで、匕数のさたざたな倀を関数に枡すず、異なる結果を埗るこずができたす。 ハヌドコヌドされた匕数倀を持぀関数は垞に同じ結果を返したすが、これはあたり意味がありたせん。 テンプレヌトのパラメヌタヌ戊略ずしお、すべおの機胜を備えたタむプクラスを䜿甚できたす。 これにより、テンプレヌト匕数ずしお目的の動䜜を持぀戊略を指定するこずで、䜿甚時にアルゎリズムをパラメヌタヌ化できたす。 これにより、新しいレベルの柔軟性ず䞀般化が実珟したす。



兞型的なAVRコントロヌラヌの䞀郚であるUSARTデバむスむンタヌフェむスナニバヌサル同期-非同期トランシヌバヌの実装䟋を怜蚎しおください。



 enum USART_ID //   { USART0, USART1, USART2, USART3, }; enum BAUD_RATE //   { BR_2400 = 2400, ... BR_921600 = 921600, BR_CUSTOM = CUSTOM_BAUD_RATE }; //   -   ( ) template < BAUD_RATE baud = BR_9600, //    (enum) DATA_BITS data_bits = DATA_BITS_8, //      (enum) PARITY parity = NO_PARITY, //  (enum) STOP_BITS stop_bits = STOP_1, //   (enum) ... > struct FRAME_CONTROL;
      
      







C ++の厳密な型指定では、パラメヌタヌずしお、宣蚀されたデヌタ型ず完党に䞀臎する倀を指定する必芁がありたす。 たずえば、為替レヌトを瀺すために、BAUD_RATE列挙で宣蚀されおいる倀のみを遞択できたす。 特別な非暙準速床倀が必芁な堎合は、必芁なデヌタレヌトでマクロ定矩CUSTOM_BAUD_RATEを事前に宣蚀しおおくず、BR_CUSTOM倀を䜿甚できたす。



USARTクラスの定矩は次のずおりです。



 template < USART_ID id, //   (enum) class usart_ctrl = FRAME_CONTROL<>, //   - () -  FRAME_CONTROL class receiver = USART_RECEIVER<>, //   - () -  USART_RECEIVER class transmitter = USART_TRANSMITTER<> //   - () -  USART_TRANSMITTER > struct USART { static void inline init(){...} static size_type send(const uint8_t* data, size_type data_size){...} static size_type print(const char* fmt, ...){...} static size_type _vprintf(const char* fmt, va_list ap){...} ... static void USART_UDRE_handler(){...} };
      
      







ここでは、簡朔にするために、倚くの列挙ず構造の定矩は省略されおいたす。 実際のコヌドで䜿甚するために、includeディレクティブを䜿甚しおこれらすべおの構造の説明を含むヘッダヌファむルを含め、デバむスに必芁なパラメヌタヌを決定したす。



 #define SEND_BUFFER_SIZE 32 #define RECV_BUFFER_SIZE 16 typedef USART< USART0, FRAME_CONTROL<BR_921600>, RECEIVER_DISABLED, USART_TRANSMITTER<SEND_BUFFER_SIZE> > usart_0; //  USART0,  921600 , 8N1,   ,   32  typedef USART< USART1, FRAME_CONTROL<BR_9600, DATA_BITS_7, EVEN_PARITY, STOP_2> USART_RECEIVER<RECV_BUFFER_SIZE>, USART_TRANSMITTER<SEND_BUFFER_SIZE> > usart_1; //  USART1, 9600-7E2,   16 ,   32  typedef TWI<400000> I2C; // TWI -  400 kHz
      
      







そのため、USART構造は4぀のテンプレヌトパラメヌタを受け入れたす。

-デバむス識別子-4぀の利甚可胜なデバむスのいずれかを䜿甚できたすMega256のみ、若いチップにはUSART0を䜿甚する必芁がありたす

-単䞀実装のusart_ctrl戊略-FRAME_CONTROL-亀換パラメヌタヌの指定甚䞊蚘を参照。

-レシヌバヌ戊略-実装が2぀しかないレシヌバヌ-必芁なレシヌバヌパラメヌタヌの蚭定を可胜にするUSART_RECEIVERバッファヌサむズの指定ず割り蟌みの制埡およびRECEIVER_DISABLED必芁に応じおレシヌバヌの切断を可胜にする

-トランスミッタヌ戊略​​-USART_TRANSMITTER実装バッファヌサむズ、割り蟌み制埡およびTRANSMITTER_DISABLEDを䜿甚したトランスミッタヌパラメヌタヌ。トランスミッタヌおよび察応する割り蟌みを犁止したす。



この䞀連の戊略は、デバむスを完党に制埡し、デフォルト倀を䜿甚するこずにより、最も䞀般的なナヌスケヌスのクラスパラメヌタヌ化を簡玠化したす。



次に、デバむスを初期化したす。



  usart_0::init(); I2C::init();
      
      







ここでは、メ゜ッドを呌び出すための異垞な構文に泚意を払う必芁がありたす。 通垞の挔算子「。」の代わりに-構造䜓のメンバヌぞの参照構造䜓参照、ここでは挔算子「::」が䜿甚されたす-スコヌプの開瀺スコヌプ解決。 実際には、USARTクラスのすべおのメ゜ッドおよびTWIが静的ずしお定矩されおいるため、ここではオブゞェクトではなく型を䜿甚したす。 これにより、斜蚭の建蚭ず砎壊のオヌバヌヘッドが回避され、さらに、デバむスのシングルトンのような性質が明確に反映されたす。 これは、型ずその静的メンバヌの䜿甚を支持しお、通垞のオブゞェクトを完党に攟棄するこずを意味するものではありたせん。 ほずんどの堎合、コヌドには倚くの䜿い慣れたオブゞェクトが含たれたすが、ハヌドりェアコンポヌネントを管理するための構造に぀いお説明する堎合、このアプロヌチの方が理にかなっおいたす。



このために生成されたアセンブラヌMega256甚は次のようになりたす。



 000000ba <_Z10usart_initv>: ba: 10 92 c4 00 sts 0x00C4, r1 be: 10 92 c5 00 sts 0x00C5, r1 c2: 10 92 c0 00 sts 0x00C0, r1 c6: 88 e2 ldi r24, 0x28 ; 40 c8: 80 93 c1 00 sts 0x00C1, r24 cc: 86 e0 ldi r24, 0x06 ; 6 ce: 80 93 c2 00 sts 0x00C2, r24 d2: 10 92 26 01 sts 0x0126, r1 d6: 08 95 ret 000000d8 <_Z8twi_initv>: d8: 8c e0 ldi r24, 0x0C ; 12 da: 80 93 b8 00 sts 0x00B8, r24 de: 10 92 b9 00 sts 0x00B9, r1 e2: 85 e4 ldi r24, 0x45 ; 69 e4: 80 93 bc 00 sts 0x00BC, r24 e8: 10 92 03 01 sts 0x0103, r1 ec: 08 95 ret
      
      







リストから、デバむスの初期化に必芁なすべおの定数の蚈算がコンパむル段階で実行されるこずがわかりたす。



別の䟋



独自の亀換プロトコルを開発しおいる堎合、その発衚戊略を䜿甚は次のようになりたす。



 template < class transport, class params = PROTO_PARAMETERS<...> // -    ... > struct SUPER_DUPPER_EXCHANGE_PROTOCOL;
      
      







ここで興味深いのは、プロトコルのトランスポヌトがテンプレヌトパラメヌタヌずしお指定されおいるこずです。 これにより、䜿甚時にプロトコルを蚭定できたす。次に䟋を瀺したす。



 typedef SUPER_DUPPER_EXCHANGE_PROTOCOL<usart_0, PROTO_PARAMETERS<>, ...> PROTO_SERIAL;
      
      







必芁に応じお、SPIやTWIなどの別のデバむスで同じプロトコルを䜿甚できたす。



 typedef SUPER_DUPPER_EXCHANGE_PROTOCOL<TWI<200000>, PROTO_PARAMETERS<>, ...> PROTO_TWI;
      
      







戊略クラスには、たずえば、共通の祖先からの継承の芁件など、远加の制限はありたせん。 トランスポヌトずしお䜿甚されるタむプの唯䞀の芁件は、必芁な眲名を䜿甚したメ゜ッド送信や受信などの可甚性です。



必芁な数の戊略を定矩するこずができたす。それぞれの戊略は機胜の特定の偎面を担圓する必芁があり、そのためそれらの盎亀性が保蚌されたす[2]。



戊略ごずに、倚くの異なる実装が存圚する可胜性がありたす。 その結果、さたざたな動䜜戊略の倚くの可胜な組み合わせの数が非垞に倧きくなる可胜性がありたす。 これは、兞型的な継承パフォヌマンスの問題を匕き起こすこずなく、優れたコヌドの柔軟性を提䟛し、静的倚態性の優れた䟋です。



このようにしお必芁な型を定矩したら、次のようにコヌドで䜿甚したす。



 PROTO_SERIAL::send(data, size); //   data   usart_0 PROTO_TWI::send(data, size); //   data  TWI 
      
      







デバッグ



プログラムコヌドのデバッグは簡単な䜜業ではないこずを繰り返す必芁はありたせん。 ボむラヌプレヌトコヌドのデバッグは、コンパむラが䜿いにくいため、開発者にずっおさらに困難です。 テキスト内のタむプミスは、長い蚺断リストの結論に぀ながりたす。これは、コンパむラヌの2パスモヌドによりさらに倍増したす。 これらのリストは最初から読む必芁があり、次のコンパむルを詊みる前に最小限のコヌド倉曎を行いたす。 䞀郚のメッセヌゞは、誘導された゚ラヌによっお匕き起こされ、゚ラヌが修正されるず消えたす-根本原因。



テンプレヌトの特殊化は、芪族関係によっおプラむマリテンプレヌトずは関係ありたせん。 実際、特殊化は個別の独立したクラスず芋なすこずができ、特殊化されたパラメヌタヌが䞀臎した堎合にプラむマリテンプレヌトの代わりに䜿甚されたす。 したがっお、テンプレヌトコヌドの操䜜性を少なくずもある皋床確実にするには、テンプレヌトの各特殊化を少なくずも1回むンスタンス化する必芁がありたす。 これにより、ボむラヌプレヌトコヌドのデバッグプロセスはかなり長いプロセスになりたす。



埋め蟌たれたコヌドのデバッグは、特に特別な機噚がない堎合、開発者にずっお悪倢です。 この堎合、唯䞀の解決策はブルヌトフォヌス-デバッグメッセヌゞの挿入です。



次のむンタヌフェむスを持぀DEVICEクラスをデバッグするずしたす。



 template < class params = DEVICE_SETTINGS<...>, class dbg = NO_DEBUG > struct DEVICE { static uint8_t some_method(uint8_t parameter) { dbg::print("%s:%d\n", __FUNCTION__, parameter); .... dbg:: print("retval:%d\n", retval); return retval; } };
      
      







ここでは、デフォルトで倀NO_DEBUGで初期化されるdbgテンプレヌトパラメヌタに泚目したす。問題のメ゜ッド内で、dbg :: printを呌び出したす。

アプリケヌションコヌドでは、デバむスは次のように宣蚀できたす。



 typedef DEVICE_SETTINGS<...> DEV_SETTINGS; //  typedef   typedef DEVICE<DEV_SETTINGS, AVR_DEBUG<usart_0> > device; //    
      
      







dbgパラメヌタヌずしお、usart_0タむプでパラメヌタヌ化された特定のAVR_DEBUGテンプレヌトを䜿甚しおいるこずがわかりたす。AVR_DEBUGの定矩を芋るず、次のコヌドのようなものが衚瀺されたす。



 template < class SENDER > struct AVR_DEBUG { ... static void print(const char* fmt, ...) { va_list ap; va_start(ap, fmt); uint8_t retval = SENDER::_vprintf(fmt, ap); va_end(ap); } };
      
      







実際、これは、アプリケヌションの実行䞭にdbg :: printを呌び出すず、クラスAVR_DEBUG <usart_0>のprintメ゜ッドが呌び出され、それがクラスusart_0の_vprintfメ゜ッドを呌び出すこずを意味したす。したがっお、デバッグプロセス䞭に、usart_0パラメヌタヌで指定されたシリアルむンタヌフェむスに必芁なデバッグ情報を送信したす。



デバむスのコヌドのデバッグが完了したら、宣蚀行を次のように眮き換えたす。



  typedef DEVICE<DEV_SETTINGS, NO_DEBUG> device;
      
      







たたはより単玔な堎合、dbgパラメヌタにデフォルト倀NO_DEBUGを䜿甚したす。



  typedef DEVICE<DEV_SETTINGS> device;
      
      







NO_DEBUGクラスの印刷関数には空の本文があり、次のようになりたす。



 struct NO_DEBUG { ... static void inline print(const char* , ...){} };
      
      







ここでも、空の関数の本䜓のむンラむン化ず削陀を正垞に実行するコンパむラに䟝存しおいたす。コヌドのリリヌスバヌゞョンをビルドするず、未䜿甚のコヌドはすべお削陀されたす。

したがっお、デバッグ情報の出力を制埡できるメカニズムがありたす。



単䜓テスト



Atmelは、ドキュメントにデヌタを保存するための最小サむズのデヌタ​​型を䜿甚するこずをお勧めしたす。掚奚事項は、結果のコヌドのサむズの分析に䟝存し、アプリケヌションが䜿甚するメモリのコストを削枛し、サむズがプラットフォヌムに䟝存しないタむプの䜿甚を意味したす。そしおこれは、より良い移怍性を持぀コヌドの䜜成に貢献したす。理想的には、PC䞊でコヌドを実行する機䌚を埗お、開発䞭に単䜓テストを䜿甚できるようにしたす。マむクロコントロヌラヌ向けのコヌドのかなりの郚分は、コントロヌラヌにアップロヌドされるずっず前にテストでテストできたす。



䞊蚘のプロトコルの䟋に戻るず、特別に蚘述されたクラスモック/フェむクをトランスポヌトずしお䜿甚できたす。これにより、任意のコンテンツを持぀パケットの受信をシミュレヌトでき、開発䞭のプロトコルのデバッグが簡単になりたす。



このアむデアをさらに発展させるず、PC䞊のほずんどすべおのコヌドをデバッグする機䌚が埗られたす。

察凊する必芁がある倚くの呚蟺機噚は、倖郚むンタヌフェむスTWI、SPI ...を介しおコントロヌラヌによっお制埡され、特定のプラットフォヌムに盎接関連しおいたせん。さたざたな皮類のセンサヌ、リアルタむムクロック、LCDディスプレむなどに぀いお話しおいたす。このような呚蟺機噚を管理するためのコヌドは、理想的にはどのプラットフォヌムでも実行できるはずです。これにより、コヌドの移怍性移怍性の重芁性が決たりたす。



このようなコヌドをデバッグするには、デバむスを開発者のコ​​ンピュヌタヌに盎接接続するず非垞に䟿利です。残念ながら、デバむスに必芁なむンタヌフェむスはコンピュヌタヌ䞊で物理的に利甚できない堎合がありたす。この堎合、デバむスず暙準のシリアルむンタヌフェむスCOMたたはUSBの間のアダプタヌずしおマむクロコントロヌラヌを䜿甚できたす。これは、任意のコンピュヌタヌで䜿甚できたす。戊略を䜿甚した蚭蚈では、制埡フロヌを暙準のシリアルむンタヌフェむスにリダむレクトするような方法で、デバッグされたコヌドをパラメヌタヌ化できたす。シリアルむンタヌフェヌスずデバッグ察象デバむスに同時に接続されおいるマむクロコントロヌラヌは、デバッグ時間党䜓にわたっお䞀床プログラムされ、2぀のむンタヌフェヌス間のトランスレヌタヌずしお機胜したす。これにより、開発者のコ​​ンピュヌタヌでコヌドを盎接実行できたす。このコヌドを完党に制埡できたす。



デバッグが完了したら、完成したコヌドを必芁なプラットフォヌム向けにアセンブルし、適切なマむクロコントロヌラヌにダりンロヌドできたす。 SPIむンタヌフェヌスコントロヌラヌがSPIぞのアダプタヌのシリアルコヌドを実行を介しおSDカヌドを操䜜するためのコヌドをデバッグする際、およびTWIむンタヌフェヌスコントロヌラヌがTWIアダプタヌぞのシリアルずしお機胜したを䜿甚したリアルタむムクロックず慣性ナビゲヌションセンサヌのコヌドをデバッグするずきに、この手法が正垞に䜿甚されたした。



リンクをたどる[ avr_meta]実際に䜿甚されおいるコヌドの䟋をダりンロヌドできたす。 avr8-gnu-toolchain-3.4.5.15.15-linuxを䜿甚しお開発され、ナニットテストフレヌムワヌクずしおTUTC ++テンプレヌトナニットテストフレヌムワヌクが䜿甚されたした。コヌドは私たち自身のニヌズのために開発されたしたが、それでも倚くの䜜業が必芁です。しかし、誰かに圹立぀かもしれないずいう垌望を持っお、それを公開するこずが可胜であるこずがわかりたした。

 bin  ,    . avr_adc   AVR ADC – Analog to Digital Converter avr_debug  AVR_DEBUG avr_interrupt/ext_int_control      AVR avr_interrupt/pin_ch_int_control    Pin Change  AVR avr_misc   avr_pin     AVR avr_power_mgmt     AVR avr_spi    AVR SPI – Serial Peripheral Interface avr_twi    AVR 2-wire Serial Interface (  ) avr_usart    AVR USART (  ) container/bit_field   bit field container/circular_buffer   event_driven      meta   misc   state/led_blinker    () state/state_machine     state/switch_case  switch case
      
      







おわりに



C ++蚀語のオブゞェクト指向機胜を䜿甚するず、コヌドの構造、読みやすさ、わかりやすさを改善できたす。クラスは、コヌドの再利甚ずいう考え方の優れた実斜圢態です。



テンプレヌトに固有の柔軟性により、䞀般的であるず同時に非垞に効率的なコヌドを開発できたす。䜿甚するデヌタの皮類からコヌドが独立しおいるため、開発の最終段階で倚くの蚭蚈䞊の決定を䞋したり、゜ヌスコヌドを倧幅に倉曎するこずなくこれらの決定を倉曎したりできたす。



戊略を䜿甚するず、動的な倚態性に固有の継承や䞀般的なパフォヌマンスの問題を䜿甚せずに、コヌドの動䜜に倚くのオプションを提䟛できたす。テンプレヌトの専門化により、開発者はコヌドの動䜜を最適化および埮調敎するこずができたす。



1994幎に実蚌されたErwin Unruchが偶然発芋したC ++機胜は、蚀語の䜜成者の本来の意図の䞀郚ではありたせんでしたが、倚くの開発者から倧きな関心を呌び起こしたした。コンパむル段階で蚈算を実行する機胜は、開発者にコヌドの新しいレベルの䞀般化ずその実行の有効性を提䟛したす。珟圚、このメカニズムはC ++プログラマヌによく知られおおり、Blitz ++やboost :: MPLなどの倚くの有名なラむブラリヌに組み蟌たれおいたす。



実際、1぀のプログラミング蚀語のフレヌムワヌク内で、実行䞭のコヌドの動䜜ず、コンパむル段階で同じコヌドを生成するプロセスの䞡方を制埡できたす。動的バむンディング関数パラメヌタヌず静的バむンディングテンプレヌトパラメヌタヌを持぀゚ンティティは、1぀の蚀語構造テンプレヌト関数内に同時に存圚できたす。 Todd Veldhusenは、C ++を2レベル蚀語ず呌んでいたす。



メタプログラミングを䜿甚するず、実行の効率が倧幅に向䞊し、コンパむル䞭に決定を䞋すこずで生成されるコヌドの量を枛らすこずができたす。プロゞェクト内に、コヌド実行䞭に倉化しないコンパむル時定数であるパラメヌタヌが存圚するこずは、メタプログラミングを䜿甚しお最適化する良い機䌚です。コンパむル段階で蚈算できる倀、および定数パラメヌタヌによっお制埡される分岐は、すべお最適化の適切な候補です。぀たり、コンパむル時間を増やすこずで、プログラムの実行を高速化できるこずがよくありたす。蚘事[10]は、AVRで実行されるメタプログラムコヌドのパフォヌマンスを枬定した結果ず、Atmelラむブラリに基づいお埓来開発されたコヌドずの比范を瀺しおいたす。



メタプログラムコヌドの開発は、かなり時間がかかり、時間のかかるプロセスであり、1回限りのプロゞェクトにはお勧めできたせん。ただし、ラむブラリの開発に関しおは、そのような長期投資はすべおの再利甚に有益であるずいう期埅から努力が正圓化されたす[3]。



プログラムコヌドの優れた移怍性は、より少ない結果でより倚くの結果をもたらすこずを意味し、すべおの堎合においお利点です。プロトコルの䟋に戻るず、ここでは移怍性が重芁な条件です。盞互䜜甚の各偎に個別のプロトコル実装を開発するこずはほずんど意味がありたせん。デバむスを提䟛する堎合、クラむアントにプロトコルの定矩を察応するコヌドの圢匏で提䟛できるため、必芁なプラットフォヌム甚の制埡゜フトりェアの開発が倧幅に促進されたす。



少数の出版物から刀断するず、䞀般的なテンプレヌト、特にメタプログラミングは組み蟌み゜フトりェアの䞖界ではあたり人気がありたせんが、メタプログラミング機胜が倧きなメリットをもたらす堎合がありたす。オブゞェクト指向プログラミングに埓来の手法を䜿甚するず同時に、CおよびASMで手動で蚘述されたコヌドに固有の効率を確保できたす。



文孊



1.デビッドノァンデブヌルデずニコラむM.ゞョシュティス。 C ++テンプレヌト完党ガむド

2. Andrei Alexandrescu。 C ++デザむン汎甚プログラミングおよびデザむンパタヌン適甚

3. David Abrahams and Aleksey Gurtovoy、C ++テンプレヌトメタプログラミングBoost and Beyondのコンセプト、ツヌル、テクニック

4. Davide Di Gennaro。高床なC ++メタプログラミング

5. Todd Veldhuizen。 Scientific C ++のテクニック。むンディアナ倧孊コンピュヌタヌサむ゚ンステクニカルレポヌト542

6. Todd L. Veldhuizen。 C ++テンプレヌトはチュヌリング完党2003です。

7. Dov BulkaずDavid Mayhew。効率的なC ++。パフォヌマンスプログラミングテクニック。 Addison-Wesley2000。8.

Dale Wheat。 Arduino内郚。抌しお。

9.マヌティン・レディ。 C ++のAPIデザむン。 2011 Morgan Kaufmann Publishers

10.クリストフ・スチュヌプ、マむケル・シュルツェ、ペルグ・カむザヌ。高床に適応可胜なデバむスドラむバヌのためのテンプレヌトメタプログラミングの掻甚-AVR CANドラむバヌであるCANARYのケヌススタディ。マグデブルク倧孊分散システム孊郚

11.第24回CPSU議䌚の議事録。「経枈郚門の効率を改善するための察策を匷化するこずに぀いお。組み蟌み゜フトりェアの有効性のコンプラむアンスを監芖したす。」



All Articles