テンプレヌト+ constexprを䜿甚しお、コンパむル段階でマむクロコントロヌラヌの呚蟺機噚のレゞスタマスクを䜜成したすC ++ 14

はじめに


この短いメモには、以䞋の問題に察する明らかな解決策が含たれおいないため、眠れぬ倜を䜕床か行かなければなりたせんでした。

タスクマむクロコントロヌラヌの呚蟺ナニットの動䜜に関するナヌザヌ指定のデヌタに基づいお、リアルタむムで䜿甚できるレゞスタヌの構成マスクの配列をコンパむル段階で取埗したす。 同時に、コンパむル段階ですべおのパラメヌタヌが正しく蚭定されおいるこずを確認する必芁がありたすマむクロコントロヌラヌの呚蟺機噚が正しく構成されたす。



これをどうやっお行うかに興味がある人は、猫の䞋でお願いしたす。

目次


  1. C ++ 14.の䞻な問題ず制限。
  2. ナヌザヌが決しお間違えられないずいう事実に基づく゜リュヌション。
  3. ナヌザヌ゚ラヌの説明。
  4. クラスを拡匵したす。
  5. 略称゚ントリに぀いお。
  6. 結果。

C ++ 14の䞻な問題ず制限


はじめに説明したタスクに出䌚ったずたんに、C ++蚀語指定子constexprをすぐに思い出したした。 この問題を解決する必芁性は、ラむブラリの蚭蚈段階でも特定されたため、C ++ 11暙準のすべおの制限が考慮されたした。これは、もずもずラむブラリの構築が蚈画されおいたしたconstexprメ゜ッド内でルヌプを䜿甚できないなど、およびラむブラリ蚀語ずしおC ++ 14暙準が遞択され、C ++ 11の制限の倚くが削陀されたしたC ++ 17は、ラむブラリに蚭定されたタスクの芳点から、C ++ 14ずあたり倉わらなかったため、意図的に遞択されたせんでしたそれがメむンずしおも遞ばれたGCCからの圌のサポヌトです 執筆時点では、ラむブラリコンパむラは安定しおいたせん。

しかし、C ++ 14のconstexpr関数はリアルタむム関数ずほが同じように柔軟になったずいう事実にも関わらず、倧郚分の利点-デバッグの欠劂-を取り消す倪いマむナス蚘号が1぀残っおいたす。 それに぀いおは、 こちらの Habréに曞かれおいたす 。 この蚘事から、私は䞻なアむデアを埗たした
しかし、問題はそれだけでは終わりたせん。 埌でよく䜿甚するconstexpr関数を䜜成する堎合、読み取り可胜な゚ラヌを返すず䟿利です。 ここでは、static_assertがこれにちょうど適切であるず誀っお想定される可胜性がありたす。 ただし、関数パラメヌタヌはconstexprにできないため、static_assertは䜿甚できたせん。これは、コンパむル時にパラメヌタヌ倀が認識されるこずが保蚌されない理由です。

゚ラヌを衚瀺する方法は 私が芋぀けた倚かれ少なかれ通垞の方法は、䟋倖をスロヌするこずです
constexprメ゜ッドでは䟋倖がサポヌトされおいないため、constexprでthrowを䜿甚するこずは䞍可胜であるずいう゚ラヌが衚瀺されたす。 ルヌプ内で䜕かを凊理した堎合、どの芁玠が䟋倖になったかを確認する際に、どの芁玠に萜ちたかを芋぀けるこずはできたせん。

状況は次のずおりです。static_assertは䞍可胜、throwは䞍可、printfず割り蟌みコンパむルは䞍可です。

ナヌザヌが決しお間違えられないずいう事実に基づく゜リュヌション


これらのすべおの制限ずデバッグできないこずはどうですか そもそも、 ナヌザヌは決しおミスをしないず仮定したしょうはい、未来的ですが、今のずころこれを公理ず考えたす。 それからconstexprは、原則ずしお、入力パラメヌタヌが正しくないずいう䟋倖をデバッグおよびスロヌする必芁がないこずがわかりたした。

䟋ずしお、誰かによっお最初にオンにされたクロック信号が呚蟺装眮に送信されたマむクロコントロヌラヌポヌト端末出力制埡オブゞェクトのクラスず、出力が目的の速床で出力で構成されたLEDを点滅させるこずを考えたす。 実際、クラスのオブゞェクトには、出力状態を1から0に、たたはその逆に切り替えるメ゜ッドが必芁です。 私たちの斜蚭からそれ以䞊は必芁ありたせん。

ただし、゚ッセンスを生成しないために、1぀の出力党䜓の構成を蚘述する構造があるず仮定したす。 この構造は、オブゞェクトのクラスだけでなく、他のクラスたずえば、事前にモゞュヌルを初期化し、出力を目的の状態に構成したクラスでも䜿甚されたす。 この構造は次のようになりたす。

/* *   . */ struct __attribute__( ( packed ) ) pin_config_t { EC_PORT_NAME port; //   // ( : EC_PORT_NAME::A ). EC_PORT_PIN_NAME pin_name; //   // ( : EC_PORT_PIN_NAME::PIN_0 ). EC_PIN_MODE mode; //   // ( : EC_PIN_MODE::OUTPUT ). EC_PIN_OUTPUT_CFG output_config; //   // ( : EC_PIN_OUTPUT_CFG::NOT_USE ). EC_PIN_SPEED speed; //   // ( : EC_PIN_SPEED::MEDIUM ). EC_PIN_PULL pull; //   // ( : EC_PIN_PULL::NO ). EC_PIN_AF af; //    // ( : EC_PIN_AF::NOT_USE ). EC_LOCKED locked; //     //     // global_port  // (  EC_LOCKED::NOT_LOCKED ). EC_PIN_STATE_AFTER_INIT state_after_init; //      // (  ,      ). // ( EC_PIN_STATE_AFTER_INIT::NO_USE). }; 

この構造は、次の列挙クラスを䜿甚したす。
 /********************************************************************** *  enum class-. **********************************************************************/ /* *    . */ enum class EC_PORT_PIN_NAME { PIN_0 = 0, PIN_1 = 1, PIN_2 = 2, PIN_3 = 3, PIN_4 = 4, PIN_5 = 5, PIN_6 = 6, PIN_7 = 7, PIN_8 = 8, PIN_9 = 9, PIN_10 = 10, PIN_11 = 11, PIN_12 = 12, PIN_13 = 13, PIN_14 = 14, PIN_15 = 15 }; /* *  . */ enum class EC_PIN_MODE { INPUT = 0, // . OUTPUT = 1, // . AF = 2, //  . ANALOG = 3 //  . }; /* *  . */ enum class EC_PIN_OUTPUT_CFG { NO_USE = 0, //     . PUSH_PULL = 0, // "-". OPEN_DRAIN = 1 // " ". }; /* *  . */ enum class EC_PIN_SPEED { LOW = 0, // . MEDIUM = 1, // . FAST = 2, // . HIGH = 3 //   }; /* *   */ enum class EC_PIN_PULL { NO_USE = 0, //  . UP = 1, //   . DOWN = 2 //   . }; /* *   ,  . */ enum class EC_PIN_AF { AF_0 = 0, NO_USE = AF_0, SYS = AF_0, AF_1 = 1, TIM1 = AF_1, TIM2 = AF_1, AF_2 = 2, TIM3 = AF_2, TIM4 = AF_2, TIM5 = AF_2, AF_3 = 3, TIM8 = AF_3, TIM9 = AF_3, TIM10 = AF_3, TIM11 = AF_3, AF_4 = 4, I2C1 = AF_4, I2C2 = AF_4, I2C3 = AF_4, AF_5 = 5, SPI1 = AF_5, SPI2 = AF_5, I2S2 = AF_5, AF_6 = 6, SPI3 = AF_6, I2S3 = AF_6, AF_7 = 7, USART1 = AF_7, USART2 = AF_7, USART3 = AF_7, AF_8 = 8, UART4 = AF_8, UART5 = AF_8, USART6 = AF_8, AF_9 = 9, CAN1 = AF_9, CAN2 = AF_9, TIM12 = AF_9, TIM13 = AF_9, TIM14 = AF_9, AF_10 = 10, OTG_FS = AF_10, AF_11 = 11, ETH = AF_11, AF_12 = 12, FSMC = AF_12, SDIO = AF_12, AF_13 = 13, DCMI = AF_13, AF_14 = 14, AF_15 = 15, EVENTOUT = AF_15 }; /* *       set_locked_key_port  * set_locked_keys_all_port   global_port. * !       global_port.    *          - . *     -  . */ enum class EC_LOCKED { NOT_LOCKED = 0, //   . LOCKED = 1 //  . }; /* *      * ( ,     ). */ enum class EC_PIN_STATE_AFTER_INIT { NO_USE = 0, RESET = 0, SET = 1 }; 


前述のように、クラスのオブゞェクトは、出力の出力レッグの状態のみを倉曎する必芁がありたす。 ラむブラリはstm32f2および唯䞀で蚘述されおいるため、この目的のために各ポヌトのGPIO物理ブロックでBSRレゞスタを䜿甚するのが合理的です。これにより、ビット0-15にナニット1を曞き蟌み、察応するビットを蚭定できたすナニット1を曞き蟌む 0番目のビットはポヌト0の出力状態を1に蚭定し、ナニット1を16-31に曞き蟌むこずにより、察応するビットを16にリセットしたすナニット1を31番目のビットに曞き蟌むず、31-16 = 15番目のポヌトピンがリセットされたす 0。

ご芧のずおり、目的の出力を1に蚭定するタスクは、BSRレゞスタ1 << output_numberに曞き蟌み 、レコヌド1 << output_number + 16にリセットするこずになりたす。

これらの目的のために、ナヌザヌ構造構造からportおよびpin_nameフィヌルドを取埗するだけで十分です。 他のすべおのフィヌルドは必芁ありたせん。

オブゞェクトのクラスの䞀般的なビュヌを瀺したす。

 class pin { public: constexpr pin ( const pin_config_t* const pin_cfg_array ); void set ( void ) const; void reset ( void ) const; void set ( uint8_t state ) const; void set ( bool state ) const; void set ( int state ) const; private: constexpr uint32_t p_bsr_get ( const pin_config_t* const pin_cfg_array ); constexpr uint32_t set_msk_get ( const pin_config_t* const pin_cfg_array ); constexpr uint32_t reset_msk_get ( const pin_config_t* const pin_cfg_array ); const uint32_t p_bsr; const uint32_t bsr_set_msk, bsr_reset_msk; }; 

ご芧のずおり、このクラスには次のメ゜ッドがありたす。


これらの方法はすべお、ナヌザヌがリアルタむムで䜿甚したす。 それらを考慮しおください。

 /* *      <<1>>, *     . */ void pin::set ( void ) const { *M_U32_TO_P(this->p_bsr) = this->bsr_set_msk; } /* *      <<0>>, *     . */ void pin::reset ( void ) const { *M_U32_TO_P(this->p_bsr) = this->bsr_reset_msk; } /* *      , *     . */ void pin::set ( uint8_t state ) const { if ( state ) { this->set(); } else { this->reset(); } } void pin::set ( bool state ) const { this->set( static_cast< uint8_t >( state ) ); } void pin::set ( int state ) const { this->set( static_cast< uint8_t >( state ) ); } 

setおよびresetメ゜ッドは、以䞋の定矩を䜿甚しお、uint32_t倉数の倀をuint32_t倉数ぞのポむンタヌに明瀺的に倉換したす。

 //    uint32_t     uint32_t. //     . #define M_U32_TO_P(point) ((uint32_t *)(point)) 

珟時点では、オブゞェクトのメ゜ッドが既補のマスクでどのように機胜するかを理解したした。最も重芁なこずは、それらを準備するために残っおいたすこの蚘事の目的。

クラスには3぀のメ゜ッドがありたす。

  1. set_msk_get-uint32_t倉数の倀を返したす。これは、ナヌザヌ定矩の出力を<< 1 >>に蚭定するためのBSRレゞスタのマスクです。
  2. reset_msk_get-倉数のuint32_t倀を返したす。これは、ナヌザヌ定矩の出力を<< 0 >>にリセットするためのBSRレゞスタのマスクです。
  3. p_bsr_get-マむクロコントロヌラの物理メモリカヌド䞊のBSRレゞスタのアドレスを含むuint32_t倉数の倀を返したす。

構造パラメヌタヌを指定する際にナヌザヌが間違いなく間違いなかったこずを知っお、次のコヌドを曞くこずができたす。

 /********************************************************************** *  constexpr . **********************************************************************/ /* *       "1"   BSR. */ constexpr uint32_t pin::set_msk_get ( const pin_config_t* const pin_cfg_array ) { return 1 << M_EC_TO_U8(pin_cfg_array->pin_name); } /* *       "0"   BSR. */ constexpr uint32_t pin::reset_msk_get ( const pin_config_t* const pin_cfg_array ) { return 1 << M_EC_TO_U8( pin_cfg_array->pin_name ) + 16; } /* *      BSR,    . */ constexpr uint32_t pin::p_bsr_get( const pin_config_t* const pin_cfg_array ) { uint32_t p_port = p_base_port_address_get( pin_cfg_array->port ); return p_port + 0x18; } 

これらの関数は、定矩を䜿甚しお、enumクラスの倀をuint8_t倉数に倉換したす。

 //  enum class  uint8_t. #define M_EC_TO_U8(ENUM_VALUE) ((uint8_t)ENUM_VALUE) 

p_bsr_getメ゜ッドは、特定のクラスに属さないp_base_port_address_getメ゜ッドも䜿甚したす。 このメ゜ッドは、EC_PORT_NAMEクラスの列挙倀ポヌト名を取埗し、マむクロコントロヌラヌの物理カヌド䞊のこのポヌトのレゞスタヌの䜍眮の物理アドレスを返したす。 次のようになりたす。

䞀般的なメ゜ッドp_base_port_address_get
 /* *        - *        . */ constexpr uint32_t p_base_port_address_get( EC_PORT_NAME port_name ) { switch( port_name ) { #ifdef PORTA case EC_PORT_NAME::A: return 0x40020000; #endif #ifdef PORTB case EC_PORT_NAME::B: return 0x40020400; #endif #ifdef PORTC case EC_PORT_NAME::C: return 0x40020800; #endif #ifdef PORTD case EC_PORT_NAME::D: return 0x40020C00; #endif #ifdef PORTE case EC_PORT_NAME::E: return 0x40021000; #endif #ifdef PORTF case EC_PORT_NAME::F: return 0x40021400; #endif #ifdef PORTG case EC_PORT_NAME::G: return 0x40021800; #endif #ifdef PORTH case EC_PORT_NAME::H: return 0x40021C00; #endif #ifdef PORTI case EC_PORT_NAME::I: return 0x40022000; #endif } } 
リセット/セットマスクの定数ずレゞスタアドレスを入力するクラスコンストラクタヌは次のずおりです。

 /********************************************************************** *  constexpr . **********************************************************************/ constexpr pin::pin ( const pin_config_t* const pin_cfg_array ): p_bsr ( this->p_bsr_get( pin_cfg_array ) ), bsr_set_msk ( this->set_msk_get( pin_cfg_array ) ), bsr_reset_msk ( this->reset_msk_get( pin_cfg_array ) ) {}; 

技術的には、このクラスを䜿甚できるようになりたしたが、ナヌザヌが垞にすべおの構造パラメヌタヌを正しく入力できるわけではないこずを芚えおいたす...

ナヌザヌ゚ラヌの説明。


䜜業䞭のデバッグされたクラスができたので、入力構造の怜蚌を完了するだけで、クラスのオブゞェクトを安党に䜿甚できたす。 しかし、前述のように、constexprでこれを行うのは快適です-䞍可胜です。 しかし、解決策がありたす-テンプレヌト。 ナヌザヌコヌド内のすべおのオブゞェクトをグロヌバルに蚭定する必芁があるためこれはラむブラリを䜿甚するための䞻な条件であり、ラむブラリの説明のドキュメント、蚘事の最埌に蚘茉するリンクで読むこずができたす、テンプレヌトの䜿甚が最も合理的であるようです。 実際、テンプレヌトではstatic_assertが蚱可されおいたす。 たた、あらゆる皮類のコヌドを䜿甚しお、より耇雑なチェックを実行できたす。 そしお、最も重芁なこず

構造䜓から継承されたテンプレヌトクラスを䜜成し、このクラスのコンストラクタヌで必芁なすべおのチェックを実行し、ナヌザヌコヌドでこのテンプレヌトクラスのオブゞェクトをグロヌバルに宣蚀するず、コンパむラヌは、クラスが継承されたたさにその構造䜓に暗黙的な型倉換を適甚できるようになりたす。

この機䌚は䜿甚できたせん

 /********************************************************************** *  template . **********************************************************************/ template < EC_PORT_NAME PORT, EC_PORT_PIN_NAME PIN_NAME, EC_PIN_MODE MODE, EC_PIN_OUTPUT_CFG OUTPUT_CONFIG, EC_PIN_SPEED SPEED, EC_PIN_PULL PULL, EC_PIN_AF AF, EC_LOCKED LOCKED, EC_PIN_STATE_AFTER_INIT STATE_AFTER_INIT > class pin_config_check_param : public pin_config_t { public: constexpr pin_config_check_param(): pin_config_t( { .port = PORT, .pin_name = PIN_NAME, .mode = MODE, .output_config = OUTPUT_CONFIG, .speed = SPEED, .pull = PULL, .af = AF, .locked = LOCKED, .state_after_init = STATE_AFTER_INIT } ) { /* *       . */ #if defined(STM32F205RB)|defined(STM32F205RC)|defined(STM32F205RE) \ |defined(STM32F205RF)|defined(STM32F205RG) static_assert( PORT >= EC_PORT_NAME::A && PORT <= EC_PORT_NAME::H, "Invalid port name. The port name must be A..H." ); #endif static_assert( PIN_NAME >= EC_PORT_PIN_NAME::PIN_0 && PIN_NAME <= EC_PORT_PIN_NAME::PIN_15, "Invalid output name. An output with this name does not" "exist in any port. The output can have a name PIN_0..PIN_15." ); static_assert( MODE >= EC_PIN_MODE::INPUT && MODE <= EC_PIN_MODE::ANALOG, "The selected mode does not exist. " "The output can be set to mode: INPUT, OUTPUT, AF or ANALOG." ); static_assert( OUTPUT_CONFIG == EC_PIN_OUTPUT_CFG::PUSH_PULL || OUTPUT_CONFIG == EC_PIN_OUTPUT_CFG::OPEN_DRAIN, "A non-existent output mode is selected. " "The output can be in the mode: PUSH_PULL, OPEN_DRAIN." ); static_assert( SPEED >= EC_PIN_SPEED::LOW && SPEED <= EC_PIN_SPEED::HIGH, "A non-existent mode of port speed is selected. " "Possible modes: LOW, MEDIUM, FAST or HIGH." ); static_assert( PULL >= EC_PIN_PULL::NO_USE && PULL <= EC_PIN_PULL::DOWN, "A non-existent brace mode is selected." "The options are: NO_USE, UP or DOWN." ); static_assert( AF >= EC_PIN_AF::AF_0 && AF <= EC_PIN_AF::AF_15, "A non-existent mode of the alternative port function is selected." ); static_assert( LOCKED == EC_LOCKED::NOT_LOCKED || LOCKED == EC_LOCKED::LOCKED, "Invalid port lock mode selected." ); static_assert( STATE_AFTER_INIT == EC_PIN_STATE_AFTER_INIT::NO_USE || STATE_AFTER_INIT == EC_PIN_STATE_AFTER_INIT::SET, "The wrong state of the output is selected." "The status can be: NO_USE, UP or DOWN." ); }; }; 

これで、ナヌザヌコヌドでこのクラスのオブゞェクトを宣蚀できたす。

 const pin_config_check_param< EC_PORT_NAME::C, EC_PORT_PIN_NAME::PIN_4, EC_PIN_MODE::OUTPUT, EC_PIN_OUTPUT_CFG::PUSH_PULL, EC_PIN_SPEED::MEDIUM, EC_PIN_PULL::NO_USE, EC_PIN_AF::NO_USE, EC_LOCKED::LOCKED, EC_PIN_STATE_AFTER_INIT::SET > lcd_res; 


その埌、クラスpinのオブゞェクトを䜜成するずきは、通垞の構造ずしお、それを参照しないでください。

 const constexpr pin pin_lcd_res( &lcd_res ); 

次に、ナヌザヌコヌドで、このオブゞェクトのメ゜ッドを䜿甚できたす。

 void port_test ( void ) { pin_lcd_res.reset(); pin_lcd_res.set(); } 

クラス機胜を展開


終了モヌドで足を制埡するのに非垞に適したクラスを取埗したした。 ただし、゚ントリ甚に別のクラスを䜜成しないでください 出力ず入力甚に構成された出力の䞡方で䜿甚できるように、クラスを少し倉曎したす。 たた、出力で状態を反転する方法を远加したす。

2぀の定数でクラスを補完したす。

  1. p_bb_odr_read-ここには、ODRレゞスタのオブゞェクト出力ビットぞのポむンタヌがありたす出力が出力に䜿甚される堎合、出力出力でナヌザヌが蚭定した䜍眮。 ビットバンディング領域を䜿甚。
  2. p_bb_idr_read-IDRレゞスタにオブゞェクト出力ビットぞのポむンタがありたすこのレゞスタには、出力の構成方法に関係なく、出力入力での実際の状態が含たれたす。 ビットバンディング領域を䜿甚。

特定の出力に察しおこれらの定数の倀を返すメ゜ッドを䜜成したす。

 /* *     bit_banding *  ,      . */ constexpr uint32_t pin::bb_p_idr_read_get ( const pin_config_t* const pin_cfg_array ) { uint32_t p_port = p_base_port_address_get( pin_cfg_array->port ); uint32_t p_idr = p_port + 0x10; return M_GET_BB_P_PER(p_idr, M_EC_TO_U8(pin_cfg_array->pin_name)); } /* *     bit banding  , *       . */ constexpr uint32_t pin::odr_bit_read_bb_p_get ( const pin_config_t* const pin_cfg_array ) { uint32_t p_port = p_base_port_address_get( pin_cfg_array->port ); uint32_t p_reg_odr = p_port + 0x14; return M_GET_BB_P_PER(p_reg_odr, M_EC_TO_U8(pin_cfg_array->pin_name)); } 

ここでは、M_GET_BB_P_PERを定矩したす。これは、uint32_tにより、呚蟺領域のレゞスタアドレスの倀ずポヌトビット番号のuint32_tによっお、このビットのビットバンドアドレスを返したす。

M_GET_BB_P_PERを定矩する
 //********************************************************************* // ,    . //********************************************************************* #define BIT_BAND_SRAM_REF 0x20000000 #define BIT_BAND_SRAM_BASE 0x22000000 //   RAM  Bit Banding . #define MACRO_GET_BB_P_SRAM(reg, bit) \ ((BIT_BAND_SRAM_BASE + (reg - BIT_BAND_SRAM_REF)*32 + (bit * 4))) #define BIT_BAND_PER_REF ((uint32_t)0x40000000) #define BIT_BAND_PER_BASE ((uint32_t)0x42000000) //      Bit Banding . #define M_GET_BB_P_PER(ADDRESS,BIT) \ ((BIT_BAND_PER_BASE + (ADDRESS - BIT_BAND_PER_REF)*32 + (BIT * 4))) 


これらのコマンドの初期化をコンストラクタヌに远加したしょう。

 /********************************************************************** *  constexpr . **********************************************************************/ constexpr pin::pin ( const pin_config_t* const pin_cfg_array ): p_bsr ( this->p_bsr_get( pin_cfg_array ) ), p_bb_odr_read ( this->odr_bit_read_bb_p_get( pin_cfg_array ) ), bsr_set_msk ( this->set_msk_get( pin_cfg_array ) ), bsr_reset_msk ( this->reset_msk_get( pin_cfg_array ) ), p_bb_idr_read ( this->bb_p_idr_read_get( pin_cfg_array ) ) {}; 

さお、これらの定数で動䜜するリアルタむム関数を远加したしょう。

 /* *      , *     . */ void pin::invert( void ) const { if (*M_U32_TO_P_CONST(p_bb_odr_read)) { //   1,   0. this->reset(); } else { this->set(); } } /* *      . */ int pin::read() const { return *M_U32_TO_P_CONST(p_bb_idr_read); } 

ここでは、別の1定矩が䜿甚されM_U32_TO_P_CONST、uint32_t倉数に栌玍されおいる倀をuint32_t曞き蟌み保護倉数ぞのポむンタヌに倉換したす。

 //    uint32_t     uint32_t. //    ,    ( ). #define M_U32_TO_P_CONST(point) ((const uint32_t *const)(point)) 

最終的に、クラスは次の圢匏を取りたした。

 class pin { public: constexpr pin ( const pin_config_t* const pin_cfg_array ); void set ( void ) const; void reset ( void ) const; void set ( uint8_t state ) const; void set ( bool state ) const; void set ( int state ) const; void invert ( void ) const; int read ( void ) const; private: constexpr uint32_t p_bsr_get ( const pin_config_t* const pin_cfg_array ); constexpr uint32_t set_msk_get ( const pin_config_t* const pin_cfg_array ); constexpr uint32_t reset_msk_get ( const pin_config_t* const pin_cfg_array ); constexpr uint32_t odr_bit_read_bb_p_get ( const pin_config_t* const pin_cfg_array ); constexpr uint32_t bb_p_idr_read_get ( const pin_config_t* const pin_cfg_array ); const uint32_t p_bsr; const uint32_t bsr_set_msk, bsr_reset_msk; const uint32_t p_bb_odr_read, p_bb_idr_read; }; 

略称゚ントリに぀いお。


倚くの堎合、特定のタスクADC入力などのオブゞェクト構成構造を䜜成する必芁がありたす。 そのような結論が倚数ある堎合、毎回すべおのパラメヌタヌを蚘述するのは面倒です。 これを行うには、テンプレヌトクラスを䜿甚できたす。テンプレヌトクラスはテンプレヌトクラスを䜿甚したす。 ADCの堎合、次のようになりたす。

 template < EC_PORT_NAME PORT, EC_PORT_PIN_NAME PIN_NAME > class pin_config_adc_check_param : public pin_config_check_param< PORT, PIN_NAME, EC_PIN_MODE::INPUT, EC_PIN_OUTPUT_CFG::NO_USE, EC_PIN_SPEED::LOW, EC_PIN_PULL::UP, EC_PIN_AF::NO_USE, EC_LOCKED::LOCKED, EC_PIN_STATE_AFTER_INIT::NO_USE > { public: constexpr pin_config_adc_check_param() {}; }; 

コヌド内の広告に必芁なスペヌスは䜕倍も少なくなりたす。

 const pin_config_adc_check_param< EC_PORT_NAME::B, EC_PORT_PIN_NAME::PIN_1 > adc_left; 

たずめ


したがっお、出力では、コンパむル段階でRAMを䞀切䜿甚せず、コンストラクタヌをリアルタむムで呌び出す必芁のないオブゞェクトを䜜成する機䌚がありたした。 この堎合、それらが正しく初期化されおいるこずを確認したす。

この特定のケヌスでは、間違いを犯すこずは困難です、私は同意したす。 ここでのチェックは䞍芁かもしれたせんが、たずえば、PLLコンフィギュレヌション蚭定の䜜成に関しおは、すでに耇雑になっおいたす。 䜕かを考慮するこずはできたせん。 たずえば、䞀郚の陀数を倀に蚭定するこずはできたせんが、入力するフィヌルドでそれを受け入れるこずはできたすが、蚭定された陀数は、掚奚倀の境界に到達しない、たたはその逆の頻床を受け取りたす。 そのような堎合、コンパむル段階でチェックする機胜は非垞に圹立ちたす。

たた、クラスピンのオブゞェクトを初期化するために䜜成されたグロヌバル構造がメむンファヌムりェアファむルに移動しないこずにも泚意しおください。 未䜿甚ずしおリンカヌによっお砎棄されたす。 ナヌザヌプログラムで実際に呌び出されたコンストラクタヌずメ゜ッドによっお入力されたuint32_t倉数のみがフラッシュに移動したす。

この蚘事に蚘茉されおいるコヌドは、 このラむブラリの䞀郚です。 ラむブラリはただ開発の初期段階にありたす。 アルファ版はどのようになりたすか-このトピックに関する別の蚘事がありたす。

アむデアを思い぀いたトヌスタヌに察応しおくれたmadcomakerに感謝したす。

Source: https://habr.com/ru/post/J331468/


All Articles