STM32、C ++およびFreeRTOS。 最初から開発。 パヌト4割り蟌み、UARTおよびunderHART

運営管理



ネノァの街で䌑暇を過ごし、倚くの矎しい堎所を蚪れたにもかかわらず、倕方、ビヌルを飲みながらUARTを芋぀けたした。 さらに、良いFisher FA011ヘッドフォンを賌入したした。これはUSB SOUND BLASTER X-FI HDを賌入しなければならず、音楜を聎きたいず思っおいたした。

以前の蚘事は最初にGeektimeに移動し、それから私はそれらを取り戻したした。今どこに眮くべきかさえわかりたせん:)

ただし、念のため、ここにありたす。

STM32、C ++およびFreeRTOS。 最初から開発。 パヌト1

STM32、C ++およびFreeRTOS。 最初から開発。 パヌト2および

STM32、C ++およびFreeRTOS。 最初から開発。 パヌト3LCDおよび画面



UART



マむクロコントロヌラの詳现な研究の埌、すべおがシンプルであるように思えたした。 ポヌトぞのバむトの構成ずテスト送信は問題なく行われ、すべおがクロックのように機胜したため、割り蟌みを䜿甚するこずにしたした。 割り蟌みハンドラヌを静的クラスメ゜ッドにする必芁がありたした。 そしお、コンパむラマニュアルのIARは次のように曞きたした

特別な関数型は、静的メンバヌ関数に䜿甚できたす。 たずえば、

次の䟋では、関数ハンドラヌが割り蟌み関数ずしお宣蚀されおいたす。

class Device { static __irq void handler(); };
      
      





しかし、残念ながら、Cortex Mの堎合、この方法は適切ではありたせん。

ARM Cortex-Mでは、割り蟌みサヌビスルヌチンは、

通垞の機胜。特別なキヌワヌドは䞍芁です。 したがっお、キヌワヌド

__irq、__ fiq、および__nestedは、ARM Cortex-M甚にコンパむルする堎合は䜿甚できたせん。

これらの䟋倖関数名は、cstartup_M.cおよびcstartup_M.sで定矩されおいたす。

これらは、ラむブラリ䟋倖ベクトルコヌドによっお参照されたす。

NMI_Handler

HardFault_Handler

Memmanage_handler

BusFault_Handler

...

ベクタヌテヌブルは配列ずしお実装されたす。 垞に名前を持぀必芁がありたす

__vector_table、



たたは、単玔に、割り蟌みハンドラヌは、スタヌトアップファむルで定矩されたベクタヌテヌブルにあるものず同じ名前を持぀必芁がありたす。 これは特別なキヌワヌド-匱い__weakリンクPUBWEAKアセンブラヌを䜿甚しお行われたす。぀たり、この定矩は、__ weekキヌワヌドなしで䞀臎するスペルが少なくずも1぀になるたで䜿甚されたす。 ぀たり、このディレクティブなしでたったく同じ名前の関数を定矩するず、コンパむラヌはこの定矩を䜿甚し、定矩しない堎合は__weakでマヌクされたす。

cUart :: USART2_IRQHandlerなどの静的メ゜ッドのC ++名をstartup_stm32l1xx_md.sたたはstartup_stm32l1xx_md.sファむルに挿入できないこずは明らかです。アセンブラヌはそれを理解したせん。

しかし、単に「USART2_IRQHandler」は「cUart :: USART2_IRQHandler」の定矩ず䞀臎したせん。

extern“ C” {void USART2_IRQHandlervoid{...}}を䜿甚できたすが、これは、Cからの挿入を行うこずを意味したす。これはたったく必芁ありたせん。通垞、このような関数からクラスの属性にアクセスしたす。バッファは存圚せず、倚くのいコヌドをブロックする必芁がありたす:)。

したがっお、別の方法でstartup_stm32l1xx_md.cppファむルを䜜成するこずにしたした。 むンタヌネットを怜玢したずころ、たったく同じ問題を抱えおいる人がいるこずがわかりたした。 たずえば、

䞀般的な考え方は次のずおりです。startup_stm32l1xx_md.cppクラスを静的メ゜ッド割り蟌みハンドラヌで定矩し、テヌブル__vector_tableを䜜成したす。各割り蟌みベクタヌにはこれらの静的メ゜ッドぞのポむンタヌがありたす。 次に、各メ゜ッドの__weak定矩を䜜成したす

そしお今、コンパむラヌは、コヌド内でvoid cUart1 :: handlerの実装を確認するず、ためらうこずなくそれを取埗したす。 もちろん、同時に、クラスずメ゜ッドは、 startup_stm32l1xx_md.cppで定矩されおいるずおりに正確に呌び出す必芁がありたす。

FreeRtos関数vPortSVCHandler 、 xPortPendSVHandler 、 xPortSysTickHandlerを忘れお、目的の割り蟌みず出来事に眮く必芁がありたす-すべおが機胜したす

startup_stm32l1xx_md.cpp
 #pragma language = extended #pragma segment = "CSTACK" extern "C" void __iar_program_start( void ); extern "C" void vPortSVCHandler(void); extern "C" void xPortPendSVHandler(void); extern "C" void xPortSysTickHandler(void); class cNMI { public: static void handler(void); }; class cHardFault { public: static void handler(void); }; class cMemManage { public: static void handler(void); }; class cBusFault { public: static void handler(void); }; class cUsageFault { public: static void handler(void); }; class cDebugMon { public: static void handler(void); }; class cWindowWatchdog { public: static void handler(void); }; class cPvd { public: static void handler(void); }; class cTamperTimeStamp { public: static void handler(void); }; class cRtcWakeup { public: static void handler(void); }; class cFlash { public: static void handler(void); }; class cRcc { public: static void handler(void); }; class cExti { public: static void line0Handler(void); static void line1Handler(void); static void line2Handler(void); static void line3Handler(void); static void line4Handler(void); static void line9Handler(void); static void line15_10Handler(void); }; class cDma { public: static void channellHandler(void); static void channel2Handler(void); static void channel3Handler(void); static void channel4Handler(void); static void channel5Handler(void); static void channel6Handler(void); static void channel7Handler(void); }; class cAdc { public: static void handler(void); }; class cDac { public: static void handler(void); }; class cUsb { public: static void highPriorityHandler(void); static void lowPriorityHandler(void); static void fsWakeupHandler(void); }; class cComp { public: static void handler(void); }; class cLcdDriver { public: static void handler(void); }; class cTim9 { public: static void handler(void); }; class cTim2 { public: static void handler(void); }; class cTim3 { public: static void handler(void); }; class cTim4 { public: static void handler(void); }; class cTim10 { public: static void handler(void); }; class cTim6 { public: static void handler(void); }; class cTim7 { public: static void handler(void); }; class cTim11 { public: static void handler(void); }; class cI2C1 { public: static void eventHandler(void); static void errorHandler(void); }; class cI2C2 { public: static void eventHandler(void); static void errorHandler(void); }; class cSpi1 { public: static void handler(void); }; class cSpi2 { public: static void handler(void); }; class cUart1 { public: static void handler(void); }; class cUart2 { public: static void handler(void); }; class cUart3 { public: static void handler(void); }; class cRtcAlarm { public: static void handler(void); }; typedef void( *intfunc )( void ); typedef union { intfunc __fun; void * __ptr; } intvec_elem; // The vector table is normally located at address 0. // When debugging in RAM, it can be located in RAM, aligned to at least 2^6. // If you need to define interrupt service routines, // make a copy of this file and include it in your project. // The name "__vector_table" has special meaning for C-SPY: // it is where the SP start value is found, and the NVIC vector // table register (VTOR) is initialized to this address if != 0. #pragma location = ".intvec" extern "C" const intvec_elem __vector_table[] = { { .__ptr = __sfe( "CSTACK" ) }, __iar_program_start, cNMI::handler, cHardFault::handler, cMemManage::handler, cBusFault::handler, cUsageFault::handler, 0, 0, 0, 0, vPortSVCHandler, // freeRTOS  ! cDebugMon::handler, 0, xPortPendSVHandler, // freeRTOS  ! xPortSysTickHandler, // freeRTOS  ! //External Interrupts cWindowWatchdog::handler, //Window Watchdog cPvd::handler, //PVD through EXTI Line detect cTamperTimeStamp::handler, //Tamper and Time Stamp cRtcWakeup::handler, //RTC Wakeup cFlash::handler, //FLASH cRcc::handler, //RCC cExti::line0Handler, //EXTI Line 0 cExti::line1Handler, //EXTI Line 1 cExti::line2Handler, //EXTI Line 2 cExti::line3Handler, //EXTI Line 3 cExti::line4Handler, //EXTI Line 4 cDma::channellHandler, //DMA1 Channel 1 cDma::channel2Handler, //DMA1 Channel 2 cDma::channel3Handler, //DMA1 Channel 3 cDma::channel4Handler, //DMA1 Channel 4 cDma::channel5Handler, //DMA1 Channel 5 cDma::channel6Handler, //DMA1 Channel 6 cDma::channel7Handler, //DMA1 Channel 7 cAdc::handler, //ADC1 cUsb::highPriorityHandler, //USB High Priority cUsb::lowPriorityHandler, //USB Low Priority cDac::handler, //DAC cComp::handler, //COMP through EXTI Line cExti::line9Handler, //EXTI Line 9..5 cLcdDriver::handler, //LCD cTim9::handler, //TIM9 cTim10::handler, //TIM10 cTim11::handler, //TIM11 cTim2::handler, //TIM2 cTim3::handler, //TIM3 cTim4::handler, //TIM4 cI2C1::eventHandler, //I2C1 Event cI2C1::errorHandler, //I2C1 Error cI2C2::eventHandler, //I2C2 Event cI2C2::errorHandler, //I2C2 Error cSpi1::handler, //SPI1 cSpi2::handler, //SPI2 cUart1::handler, //USART1 cUart2::handler, //USART2 cUart3::handler, //USART3 cExti::line15_10Handler, //EXTI Line 15..10 cRtcAlarm::handler, //RTC Alarm through EXTI Line cUsb::fsWakeupHandler, //USB FS Wakeup from suspend cTim6::handler, //TIM6 cTim7::handler //TIM7 }; __weak void cNMI::handler() { while (1) {} } __weak void cHardFault::handler() { while (1) {} } __weak void cMemManage::handler() { while (1) {} } __weak void cBusFault::handler() { while (1) {} } __weak void cUsageFault::handler() { while (1) {} } __weak void cDebugMon::handler() { while (1) {} } __weak void cWindowWatchdog::handler() { while (1) {} } __weak void cPvd::handler() { while (1) {} } __weak void cTamperTimeStamp::handler() { while (1) {} } __weak void cRtcWakeup::handler() { while (1) {} } __weak void cFlash::handler() { while (1) {} } __weak void cRcc::handler() { while (1) {} } __weak void cExti::line0Handler() { while (1) {} } __weak void cExti::line1Handler() { while (1) {} } __weak void cExti::line2Handler() { while (1) {} } __weak void cExti::line3Handler() { while (1) {} } __weak void cExti::line4Handler() { while (1) {} } __weak void cExti::line9Handler() { while (1) {} } __weak void cExti::line15_10Handler() { while (1) {} } __weak void cDma::channellHandler() { while (1) {} } __weak void cDma::channel2Handler() { while (1) {} } __weak void cDma::channel3Handler() { while (1) {} } __weak void cDma::channel4Handler() { while (1) {} } __weak void cDma::channel5Handler() { while (1) {} } __weak void cDma::channel6Handler() { while (1) {} } __weak void cDma::channel7Handler() { while (1) {} } __weak void cAdc::handler() { while (1) {} } __weak void cUsb::fsWakeupHandler() { while (1) {} } __weak void cUsb::highPriorityHandler() { while (1) {} } __weak void cUsb::lowPriorityHandler() { while (1) {} } __weak void cDac::handler() { while (1) {} } __weak void cComp::handler() { while (1) {} } __weak void cLcdDriver::handler() { while (1) {} } __weak void cTim2::handler() { while (1) {} } __weak void cTim3::handler() { while (1) {} } __weak void cTim4::handler() { while (1) {} } __weak void cTim6::handler() { while (1) {} } __weak void cTim7::handler() { while (1) {} } __weak void cTim9::handler() { while (1) {} } __weak void cTim10::handler() { while (1) {} } __weak void cTim11::handler() { while (1) {} } __weak void cI2C1::errorHandler() { while (1) {} } __weak void cI2C1::eventHandler() { while (1) {} } __weak void cI2C2::errorHandler() { while (1) {} } __weak void cI2C2::eventHandler() { while (1) {} } __weak void cSpi1::handler() { while (1) {} } __weak void cSpi2::handler() { while (1) {} } __weak void cUart1::handler() { while (1) {} } __weak void cUart2::handler() { while (1) {} } __weak void cUart3::handler() { while (1) {} } __weak void cRtcAlarm::handler() { while (1) {} } extern "C" void __cmain( void ); extern "C" __weak void __iar_init_core( void ); extern "C" __weak void __iar_init_vfp( void ); #pragma required=__vector_table void __iar_program_start( void ) { __iar_init_core(); __iar_init_vfp(); __cmain(); }
      
      













DWART メッセヌゞパッシングの受信



したがっお、䞭断が敎理されるず、単玔なプロトコルのスレッドの実装を匕き受けるこずができたす。 Modbusはすぐに萜ちたした-非垞に耇雑ではありたせん:)。 圧力センサヌ、枩床センサヌ、流量蚈などのデバむスの業界プロトコルであるHARTは玠晎らしいです。

そしお、私が自分で蚭定したタスクは、このプロトコルを介しお、 PactwareやElemerovkim HARTConfigなどのデバむスをセットアップするためのプログラムず通信するこずです。 私はすべおが刀明したず蚀わなければならない:)

画像

さらに、マむクロコントロヌラヌの内郚枩床センサヌによっお枬定された気枩の傟向を陀去するこずさえできたした。

画像



そしお、それは私のPactwareデバむスを芋たす:)

画像



HARTドキュメントは、メンバヌのみが利甚できたす。 しかし、デモプロゞェクトに非垞に適した断片的な説明を芋぀けるこずができたした。 これらのリ゜ヌスの1぀の䟋を次に瀺したす。HARTプロトコルの説明たたはOSI HARTプロトコルモデル

芁するに、ラむン䞊にマスタヌメむンデバむスずスレヌブ埓属デバむスがありたす。 メむンはリク゚ストを送信し、サブオヌディネヌトは毎秒1200ビットの速床で応答したす。すべおがシンプルです。

回線䞊には2぀のメむンデバむスが存圚する可胜性がありたすが、1぀のRS232マスタヌず話すだけです。

同じ理由で、バスの調停を特に監芖する必芁はなく、トヌクンを持っおいるずきず持っおいないずきを刀断するのは難しいず思いたす。私の堎合、調停党䜓はそれだけです-トヌクンがありたす。 毎秒1200ビットの速床では、これは玄19ミリ秒です。 ぀たり 19ミリ秒以内に受信が䞭断されない堎合-小包は受け入れられたず芋なされ、トヌクンは私のものであり、応答でき、玄250ミリ秒以内に応答を開始する必芁がありたす。そうでない堎合、トヌクンは再びマスタヌに転送されたす。

䞀般に、私はこのプロトコルをDwartず呌びたした。これは、Dwarf-Dwarf、Dwarf、およびHARTの共生です。

最初に、操䜜する゚ンティティを遞択する必芁がありたす。





パフケヌキの原則に準拠するために、䞋局のクラスは䞊の局のクラス、぀たり たずえば、コマンドはフレヌムでのみ機胜し、フレヌムはリンクレむダヌで機胜したすが、リンクレむダヌはコマンドずフレヌム、およびコマンドに関するフレヌムに぀いおは䜕も知りたせん。

぀たり、沈黙タむマヌが機胜するたでバむトを受け入れ、受信したメッセヌゞの解析メ゜ッドを呌び出し、芁求に応じお必芁なコマンドを実行するDwartに通知するずいう考え方です。

䞀般的に、理想的には、マスタヌにコマンド1を芁求するずきに、その答えを次のようにしたいずしたす。

 Command1.Response.PrimaryVariable = 3.54 Command1.Send();
      
      





たず、チャネルレベルを掚定したしょう。この図は、画像を詰たらせないようにパブリックメ゜ッドのみを瀺しおいたす。

画像



少し説明するず、割り蟌みハンドラヌのメ゜ッドは静的であり、これらの静的メ゜ッドでクラスむンスタンスのメ゜ッドずフィヌルドにアクセスするには、フィヌルドずメ゜ッドが静的であるか、クラスむンスタンスに盎接アクセスする必芁がありたす。 私は2番目に行きたした-正しい方法で、クラスの特定のむンスタンスに向かい、コンストラクタでthisポむンタで初期化したす。

LinkLayerは、UARTポヌトからバむトを受信し、受信バッファヌに栌玍したす。

ただし、HARTにはプリアンブルず呌ばれる0xFFの同期バむトがあり、その数は20に達する可胜性がありたす自分で情報を運ばず、フレヌムの先頭をシヌケンスごずに刀断するだけなので、たったく必芁ありたせん 0xFF 0xFF <開始バむト>、バッファヌに20個のプリアンブルをドロップするのは無駄なので、割り蟌みでそれらを盎接監芖し、終了したらすぐにバッファヌぞのバむトの远加を開始したす。

各バむトを受信した埌、19ミリ秒間タむマヌを再起動したす。動䜜する堎合、パッケヌゞは受け入れられたず芋なされたす。

別のタスクは、タむマヌ割り蟌みがトリガヌされるずすぐにlinklayertimerクラスからlinklayerに通知し、りィザヌドからのリク゚ストの終了を瀺すこずです。 これを行うために、Observerデザむンパタヌンを䜿甚したした。その結果、LinkLayerはLinkLayerTimerからのむベントを単玔にサブスクラむブしたす。次のようになりたす。

linklayertimer.h
 #include "susutypes.h" #include "observable.h" class cLinkLayerTimer : public iObservable { public: explicit cLinkLayerTimer(tU16 timeout); void start(void) const; private: static void irqHandler(void); static cLinkLayerTimer* instance; };
      
      







linklayertimer.cpp
 #include "linklayertimer.h" #include "susuassert.h" #include <stdio.h> cLinkLayerTimer* cLinkLayerTimer::instance = NULL; /******************************************************************************* * Function: constructor * Description:    TIM2 ******************************************************************************/ cLinkLayerTimer::cLinkLayerTimer(tU16 timeout) { ASSERT(instance != NULL); this->instance = this; TIM2->ARR = (uint16_t)timeout; } /******************************************************************************* * Function: start * Description:  .     ******************************************************************************/ void cLinkLayerTimer::start(void) const { TIM2->CNT = (uint16_t)0; TIM2->CR1 |= TIM_CR1_CEN; } /******************************************************************************* * Function: irqHandler * Description:     . *     ,   ******************************************************************************/ void cLinkLayerTimer::irqHandler(void) { ASSERT(instance != NULL); instance->notifyObservers(); TIM2->CR1 &=~ TIM_CR1_CEN; TIM2->SR &= ~TIM_SR_UIF; }
      
      







linklayer.h
 #include "susutypes.h" #include "linklayertimer.h" #include "observer.h" #define PREAMBUL_SYMBOL (uint16_t) 0xFF typedef enum { LLS_none = 0, LLS_write = 1, LLS_writeComplete = 2, LLS_readComplete = 3, LLS_error = 4 } tLinkLayerStatus; class cLinkLayer : private iObserver, public iObservable { public: explicit cLinkLayer(tU8 *pRxBuf, const tU8 rxBufSize,tU8 *pTxBuf, const tU8 preambulCount); void writeData(tU8 dataSize); tLinkLayerStatus getStatus() const { return eStatus; }; virtual void eventHandle(const iObservable* pObservable); tU8* pTxBuffer; tU8* pRxBuffer; private: static void irqHandler(void); static cLinkLayer* instance; void endMessageHandler(void); void enableReceive(void) const { USART2->CR1 |= USART_CR1_RXNEIE;}; void disableReceive(void){USART2->CR1 &=~ USART_CR1_RXNEIE;}; void enableTransmit(void) const { USART2->CR1 |= USART_CR1_TCIE; }; void disableTransmit(void) const { USART2->CR1 &=~ USART_CR1_TCIE; }; tLinkLayerStatus eStatus; cLinkLayerTimer* pEndTransmitTimer; tU8 rxBufferSize; tU8 rxBufferIndex; tU8 txBufferIndex; tU8 txBufferSize; tU8 preambulsCount; tU8 preambulIndex; tBoolean readPreambuls; };
      
      







linllayer.cpp
 #include <stm32l1xx.h> #include "linklayer.h" #include "susuassert.h" #include <stdio.h> #define END_MESSAGE_TIMEOUT (tU16) 19 #define GOOD_COUNT_RX_PREAMBULS (tU8) 2 cLinkLayer* cLinkLayer::instance = NULL; /******************************************************************************* * Function: constructor * Description:       ******************************************************************************/ cLinkLayer::cLinkLayer(tU8 *pRxBuf, const tU8 rxBufSize,tU8 *pTxBuf, const tU8 preambulCount) { ASSERT (rxBuffer != NULL); ASSERT (txBuffer != NULL); //     3 ASSERT(preambulCount > (tU8)2); this->preambulsCount = preambulCount; this->preambulIndex = (tU8)0; this->readPreambuls = TRUE; this->pRxBuffer = pRxBuf; this->rxBufferSize = rxBufSize; this->rxBufferIndex = (tU8)0; this->pTxBuffer = pTxBuf; this->txBufferSize = (tU8)0; this->txBufferIndex = (tU8)0; this->eStatus = LLS_none; this->instance = this; this->pEndTransmitTimer = new cLinkLayerTimer(END_MESSAGE_TIMEOUT); //    this->pEndTransmitTimer->addObserver(this); this->disableTransmit(); this->enableReceive(); } /******************************************************************************* * Function: writeData * Description:  ,     ******************************************************************************/ void cLinkLayer::writeData(tU8 dataSize) { //    ,     ,    // if (this->eStatus != LLS_write) { this->disableReceive(); this->txBufferSize = dataSize; this->eStatus = LLS_write; USART2->DR = PREAMBUL_SYMBOL; this->preambulIndex ++; this->enableTransmit(); } } /******************************************************************************* * Function: handler * Description:   ******************************************************************************/ void cLinkLayer::irqHandler(void) { ASSERT(instance != NULL); // if (USART2->SR & USART_SR_TC) { //    ,   3   if (instance->preambulIndex != instance->preambulsCount) { USART2->DR = PREAMBUL_SYMBOL; instance->preambulIndex ++; } else { //  -    if(instance->txBufferIndex < instance->txBufferSize) { USART2->DR = (uint16_t)instance->pTxBuffer[instance->txBufferIndex++]; } else { instance->txBufferIndex = (tU8)0; instance->txBufferSize = (tU8)0; instance->disableTransmit(); instance->eStatus = LLS_writeComplete; instance->preambulIndex = (tU8)0; instance->readPreambuls = TRUE; instance->enableReceive(); } } USART2->SR &=~ USART_SR_TC; }; // if (USART2->SR & USART_SR_RXNE) { instance->pRxBuffer[instance->rxBufferIndex] = (tU8)USART2->DR; instance->pEndTransmitTimer->start(); //    if (instance->readPreambuls) { if (instance->pRxBuffer[instance->rxBufferIndex] == (tU8)PREAMBUL_SYMBOL) { instance->preambulIndex++; } else { instance->readPreambuls = FALSE; instance->rxBufferIndex++; } } else { //      2 if ((instance->rxBufferIndex <= instance->rxBufferSize) && (instance->preambulIndex >= GOOD_COUNT_RX_PREAMBULS)) { instance->rxBufferIndex++; } else { instance->eStatus = LLS_error; instance->preambulIndex = (tU8)0; } } } } /******************************************************************************* * Function: endMessageHandler * Description:    ******************************************************************************/ void cLinkLayer::endMessageHandler(void) { this->eStatus = LLS_readComplete; this->rxBufferIndex = (tU8) 0; this->readPreambuls = TRUE; instance->preambulIndex = (tU8)0; } /******************************************************************************* * Function: eventHandle * Description:     ******************************************************************************/ void cLinkLayer::eventHandle(const iObservable* pObservable) { this->endMessageHandler(); this->notifyObservers(); }
      
      







LinkLayer自䜓も、サブスクラむバヌのマスタヌからの芁求の受け入れの終了を通知したす。これは埌で必芁になりたす



DWART チヌムビルディング



今、最も興味深いのは、すでに述べたように、すべおが矎しく芋えるようにしたいずいうチヌムです
  Command0.Response.PrimaryVariable = 3.54
      
      





各コマンドに぀いお、応答芁求の構造党䜓を保存し、254個のコマンドがある堎合、十分なメモリがないため、応答芁求の構造ぞのポむンタのみを保存し、このポむンタにデヌタぞのポむンタを割り圓おるこずは明らかです。 cFrameクラスのbuildFrameBeforeDataメ゜ッドを䜿甚しお取埗する転送バッファヌで。

すべおのチヌムに぀いお、共通のメ゜ッドを䜿甚しお基本的なiBaseDwartCommandむンタヌフェヌスを䜜成したす。長さず皮類が異なる各チヌムにリク゚ストず回答があるため、iDwartCommandを継承するテンプレヌトクラスを䜜成したす。 次のようになりたす。

画像

コマンド0-デバむスに関する情報のみを返したす。

コマンド1-プラむマリ倉数の倀を返したす。私の堎合はcVariablesクラスによっおアクセスされるTrimmerを䜿甚しおいるため、コンストラクタヌに枡す必芁がありたす。

その結果、コマンド1からのデヌタの入力は次のようになりたす。

 void cCommand1::setNewData(void) { //          this->pResponse = (tCommand1Response*) this->pFrame->buildFrameBeforeData(COMMAND1, (tU8)sizeof(tCommand1Response)); this->pResponse->status1 = (tU8)0; this->pResponse->status2 = (tU8)0; this->pResponse->PrimaryVariableUnits = (tU8) pVariables->pTrimmer->getUnits(); this->pResponse->PrimaryVariableValue = std::swap<tF32>(pVariables->pTrimmer->getValue()); this->pFrame->setCheckSumm(); }
      
      





HARTはビッグ゚ンディアン衚珟を䜿甚しおおり、マむクロコントロヌラヌはリトル゚ンディアンであるため、ここではcConversionクラススワップメ゜ッドを䜿甚しおバむトを所定の堎所にスワップしたす。 たあ、それは私が欲しかったこずがほずんどわかった:)

実装党䜓は次のようになりたす。

basedwartcommand.h
 class iBaseDwartCommand { public: virtual void send(void) = 0; virtual void setNewData(void) = 0; };
      
      







dwartcommand.h
 #include "frame.h" #include "basecommand.h" #include "susuassert.h" template <class req, class resp> class iDwartCommand : public iBaseDwartCommand { public: explicit iDwartCommand(cFrame *pDwratFrame); req *pRequest; resp *pResponse; void send(void); protected: cFrame *pFrame; }; /******************************************************************************* * Function: constructor * Description: ******************************************************************************/ template <class req, class resp> iDwartCommand<req, resp>::iDwartCommand(cFrame *pDwartFrame) { ASSERT (pFrame != NULL); this->pFrame = pDwartFrame; } /******************************************************************************* * Function: send * Description:   ******************************************************************************/ template <class req, class resp> void iDwartCommand<req, resp>::send(void) { this->pFrame->send(); }
      
      







command0.h
 #include "command.h" #define COMMAND0 (tU8)0 #pragma pack(push, 1) typedef struct { tU8 status1; tU8 status2; tU8 expansion; tU8 manufacturer; tU8 deviceType; tU8 numberOfpreambuls; tU8 universalCommandRevision; tU8 deviceSpecificCommandRevision; tU8 softwareRevision; tU8 hardwareRevision; tU8 deviceFlags; tU8 deviceID[3]; } tCommand0Response; typedef struct { } tCommand0Request; #pragma pack(pop) class cCommand0: public iDwartCommand<tCommand0Request, tCommand0Response> { public: explicit cCommand0(cFrame *pDwartFrame); virtual void setNewData(void); };
      
      







command0.cpp
 include "susuassert.h" #include "command0.h" #include "frame.h" /******************************************************************************* * Function: constructor * Description: ******************************************************************************/ cCommand0::cCommand0(cFrame *pDwartFrame): iDwartCommand(pDwartFrame) { } /******************************************************************************* * Function: setNewData * Description:     ******************************************************************************/ void cCommand0::setNewData(void) { //          this->pResponse = (tCommand0Response*) this->pFrame->buildFrameBeforeData(COMMAND0, (tU8)sizeof(tCommand0Response)); this->pResponse->status1 = (tU8)0; this->pResponse->status2 = (tU8)0; this->pResponse->manufacturer = (tU8)0x37; this->pResponse->deviceType = (tU8)0x04; this->pResponse->expansion = (tU8)0; this->pResponse->deviceSpecificCommandRevision = (tU8)5; this->pResponse->universalCommandRevision = (tU8)5; this->pResponse->hardwareRevision = (tU8)1; this->pResponse->softwareRevision = (tU8)201; this->pResponse->numberOfpreambuls = (tU8)5; this->pResponse->deviceID[0] = (tU8)0; this->pResponse->deviceID[1] = (tU8)0; this->pResponse->deviceID[2] = (tU8)1; this->pResponse->deviceFlags = (tU8)0; this->pFrame->setCheckSumm(); }
      
      







command1.h
 #include "command.h" #include "vars.h" #define COMMAND1 (tU8)1 #pragma pack(push, 1) typedef struct { tU8 status1; tU8 status2; tU8 PrimaryVariableUnits; tF32 PrimaryVariableValue; } tCommand1Response; typedef struct { } tCommand1Request; #pragma pack(pop) class cCommand1: public iDwartCommand<tCommand1Request, tCommand1Response> { public: explicit cCommand1(cFrame *pDwartFrame,Variablesr *Vars); virtual void setNewData(void); private: Variables *pVariables; };
      
      







command1.cpp
 #include "susuassert.h" #include "command1.h" #include "frame.h" /******************************************************************************* * Function: constructor * Description: ******************************************************************************/ cCommand1::cCommand1(cFrame *pDwartFrame, Variables *pVars): iDwartCommand(pDwartFrame) { ASSERT(pVars != NULL); this->pVariables = pVars; } /******************************************************************************* * Function: setNewData * Description:     ******************************************************************************/ void cCommand1::setNewData(void) { //          this->pResponse = (tCommand1Response*) this->pFrame->buildFrameBeforeData(COMMAND1, (tU8)sizeof(tCommand1Response)); this->pResponse->status1 = (tU8)0; this->pResponse->status2 = (tU8)0; this->pResponse->PrimaryVariableUnits = (tU8) pVariables->pTrimmer->getUnits(); this->pResponse->PrimaryVariableValue = std::swap<tF32>(pVariables->pTrimmer->getValue()); this->pFrame->setCheckSumm(); }
      
      







他のチヌムも同じ原則に基づいお構築されおいたす。私は倧量のメモリを持っおいるので、すべおのコマンドがあればいいず刀断し、最倧254個のコマンドを1぀の配列に投げるこずができたす。そしお、なぜこれが䟿利なのかを説明したす。cCommandSetコンテナクラスを䜜成したした。

 #include "command.h" #include "variables.h" #define COMMANDS_COUNT 254 class cCommandSet { public: cCommandSet(cFrame *pFrame, Variables *pVariables); iBaseDwartCommand *pCommands[COMMANDS_COUNT]; };
      
      







PactwareずHartConfigの2぀のプログラムを暪河に連れお行くには、最小限のコマンドセットを実装し、それらをコンテナヌに入れる必芁がありたす。

commandset.cppは次のようになりたす。

 #include "susuassert.h" #include "commandset.h" #include "command0.h" #include "command1.h" #include "command2.h" #include "command3.h" #include "command12.h" #include "command13.h" #include "command14.h" #include "command15.h" #include "command157.h" #include "command159.h" #include "command160.h" #include "command180.h" cCommandSet::cCommandSet(cFrame *pFrame, cVariables *pVariables) { this->pCommands[COMMAND0] = new cCommand0(pFrame); this->pCommands[COMMAND1] = new cCommand1(pFrame, pVariables); this->pCommands[COMMAND2] = new cCommand2(pFrame, pVariables); this->pCommands[COMMAND3] = new cCommand3(pFrame, pVariables); this->pCommands[COMMAND13] = new cCommand13(pFrame); this->pCommands[COMMAND12] = new cCommand12(pFrame); this->pCommands[COMMAND14] = new cCommand14(pFrame); this->pCommands[COMMAND15] = new cCommand15(pFrame, pVariables); this->pCommands[COMMAND160] = new cCommand160(pFrame); this->pCommands[COMMAND157] = new cCommand157(pFrame); this->pCommands[COMMAND159] = new cCommand159(pFrame); this->pCommands[COMMAND180] = new cCommand180(pFrame); }
      
      





配列党䜓が初期化されおいないため、ここに゚ラヌがありたすが、私はそれをハンマヌで叩くのが面倒でした:)゚ラヌがあるこずを心に留めおおいおください。

チヌム157、159、および160が䜕をするのかわかりたせんたずえば、フロヌを蚈算するために、圧力倉数に基づいお蚈算されるナヌザヌ倉数があるず仮定しおいたすご存じのように、フロヌはルヌト抜出関数であるため、差圧、たたは圧力差に䟝存するレベルを蚈算するために蚀う、しかし、私はそれらをある皮のビリダヌドで満たしただけで、プログラムはそれを飲み蟌みたした。

コマンドの配列を䜜成したずいう事実により、コマンドの呌び出しは非垞に゚レガントに芋えたす-このように

 pCommandSet->pCommands[this->pFrame->getCurrentCommand()]->setNewData(); pCommandSet->pCommands[this->pFrame->getCurrentCommand()]->send();
      
      





ご芧のずおり、スむッチケヌスは必芁ありたせんが、「少しのメモリ」が必芁です:)



DWART 完了



残っおいるのは、マスタヌから受信したリク゚ストを解析するアクティブなクラスを䜜成するこずだけです。

前に蚀ったように、このクラスはcLinkLayerからの受信終了のむベントにサブスクラむブし、

このむベントのハンドラヌはタむマヌ割り蟌みから呌び出され、すぐに䜕かをしお終了する必芁があるので、凊理のためにりィザヌドからの芁求のボックスをチェックするだけですアクティブなタスクでこのフラグをポヌリングしたす。そうであれば、cFrameを䜿甚しおメッセヌゞをデコヌドし、すべおがうたくいった堎合、必芁なコマンドを呌び出しお送信したす。

同じクラスがcFrame、cLinkLayerおよびCommandSetをむンスタンス化し、cLinkLayerに受信および送信バッファヌぞのポむンタヌを枡したす。そしお、私の䜜業は芁求/応答モヌドで行われるため、送信ず受信の䞡方に1぀のバッファヌがあり、同時にメモリヌを節玄したす。

画像

dwart.h
 #include "susutypes.h" #include "frame.h" #include "observer.h" #include "linklayer.h" #include "variables.h" #include "commandset.h" #include "frtosWrapper.h" #define MAX_BUFFER_SIZE (tU8)255 class cDwart: private iObserver, public iActiveObject { public: cDwart(Variables *pVariables); virtual void eventHandle(const iObservable* pObservable); virtual void run(void); private: cCommandSet *pCommandSet; cLinkLayer *pLinkLayer; cFrame *pFrame; tU8 buffer[MAX_BUFFER_SIZE]; tBoolean isToken; static const tU8 deviceID[5]; };
      
      







dwart.cpp
 #include "susuassert.h" #include "frame.h" #include <stddef.h> #include "dwart.h" #define SHORT_ADDR (tU8)0 #define PREAMBULS_COUNT (tU8)7 #define DWART_WAITING (tU32) (50/portTICK_PERIOD_MS) const tU8 cDwart::deviceID[5] = {(tU8)0x37,(tU8)0x04,(tU8)0x00,(tU8)0x00,(tU8)0x01}; /******************************************************************************* * Function: constructor * Description:    cLinkLayer, cFrame cCommandSet  *         ******************************************************************************/ cDwart::cDwart(Variables *pVariables) { this->pLinkLayer = new cLinkLayer(this->buffer,MAX_BUFFER_SIZE, this->buffer, PREAMBULS_COUNT); this->pFrame = new cFrame((tU8*)deviceID, SHORT_ADDR,this->pLinkLayer); this->pCommandSet = new cCommandSet(this->pFrame, pVariables); this->pLinkLayer->addObserver(this); this->isToken = FALSE; } /******************************************************************************* * Function: eventHandle * Description:    .       ******************************************************************************/ void cDwart::eventHandle(const iObservable* pObservable) { ASSERT(pObservable != NULL); this->isToken = TRUE; } /******************************************************************************* * Function: run * Description:      ******************************************************************************/ void cDwart::run(void) { for(;;) { if (this->isToken) { this->isToken = FALSE; if (this->pFrame->decode() == FE_good) { pCommandSet->pCommands[this->pFrame->getCurrentCommand()]->setNewData(); pCommandSet->pCommands[this->pFrame->getCurrentCommand()]->send(); } } oRTOS.taskDelay(DWART_WAITING); } }
      
      







main.cppに新しいcDwartクラスの䜜成を远加し、怜蚌のために実行したす

 void main( void ) { const cAdcDirector* pAdcDirector = new cAdcDirector(); pAdcDirector->startConversion(); cVariables *pVariables = new cVariables(pAdcDirector); oRTOS.taskCreate(pVariablesDirector, VARIABLESDIRECTOR_STACK_SIZE, VARIABLESDIRECTOR_PRIORITY, "Var"); cDwart *pDwart = new cDwart(pVariablesDirector); oRTOS.taskCreate(pDwart, DWART_STACK_SIZE, DWART_PRIORITY, "Dwart"); ... oRTOS.startScheduler(); }
      
      





そしおここでは、パクトりェアず呌ばれるドむツの奇跡が日本の圧力センサヌを芋おいたす。







たた、圓瀟の囜内゜フトりェアもセンサヌを理解しおいたす。







もちろん、ここでは倚くのこずがあたり最適に行われおいたせん。たずえば、コマンドぞの255ポむンタヌの配列、それを削陀し、通垞のスむッチケヌスを介しおコマンドを実行できたす。たた、すべおのコマンドに察しお1぀のプレヌスホルダヌを䜿甚できたす。目的のコマンドを䜜成しおから削陀したす。

しかし、私の堎合、私の蚘憶は枬定されおおらず、最適化の問題はありたせんでした。



All Articles