[プログラミングの美しさ]マイクロコントローラーファームウェアのモジュール式アーキテクチャ設計に関する詳細な議論

[ガイド]なぜこの記事を書くのですか?最近、マイクロコントローラの初心者であり、マイクロコントローラの開発を始めたばかりで、まだRTOSの使用に関与していない学生に出会いました。RTOSを始めたばかりでは、RTOSを直接使用することが難しい場合があります。リソースが限られており、RTOSの実行に適さない比較的古いマイクロコントローラを使用する人もいます。 。またはRTOSを使用していると、全体的なアイデアに戸惑い、どこから始めればよいかわからないため、この記事では、MCUプログラムの全体的なフレーム設計に関する私の考えのいくつかについて説明します。

アーキテクチャについて議論する理由

マイクロコントローラシステム開発者の目標の1つは、プログラミング環境でファームウェアを作成して、低コストのシステム、ソフトウェアの信頼性、および迅速な開発反復時間を実現することです。このプログラミング環境を実装するためのベストプラクティスは、製品開発時にフレームワークとして機能し、「ファームウェアモジュール化」またはサブシステムをサポートする統合ファームウェアアーキテクチャアーキテクチャを使用することです。

統一された設計アーキテクチャが採用されていない場合、ビジネス要件間のカップリング関係は複雑になり、設計の最初から後の開発の方法論は採用されません。どこに書き込むかを考えると、プログラムの後のメンテナンスが非常に困難になり、潜在的なバグ/欠陥のリスクが発生しますまた、大幅に増加し、複数人による共同開発の可能性はありません。

ファームウェアのモジュール性、テスト容易性、互換性の正しい組み合わせと組み合わせることができる設計アーキテクチャー構造を任意のファームウェア開発プロジェクトに適用して、コードの再利用性を最大化し、ファームウェアのデバッグを高速化し、ファームウェアの移植性を向上させることができます。

モジュール式アーキテクチャ設計?

モジュール式プログラミングは、プログラム機能をファームウェアモジュール/サブシステムに分解します。各モジュールは機能を実行し、機能を完了するために必要なすべてのソースコードと変数を含みます。

モジュール化/サブシステム化は、チーム内の多くの人々の並行作業を調整し、プロジェクトのさまざまな部分間の相互依存を管理し、設計者とシステムインテグレーターが複雑なシステムを信頼できる方法で組み立てることを可能にします。具体的には、設計者が複雑さを実装および管理するのに役立ちます。アプリケーションのサイズと機能が大きくなるにつれて、それらを別々の部分(「コンポーネント」、「モジュール」、または「サブシステム」として)に分離するためのモジュール性が必要になります。次に、そのような分離された各パーツは、モジュラーアーキテクチャの要素になります。このようにして、明確に定義されたインターフェースを使用して、各コンポーネントを分離してアクセスできます。さらに、モジュール式プログラミングにより、ファームウェアの可読性が向上すると同時に、ファームウェアのデバッグ、テスト、保守が簡素化されます。

一人でプロジェクトを開発する場合でも、コードのデバッグ、可読性、および移植性の観点から、開発は依然としてベストプラクティスの全体的な戦略です。コードが適切に設計されていれば、他のプロジェクトに簡単に適用できます。さらに、モジュールは以前のプロジェクトによってテストおよび検証されており、新しいプロジェクトで再度使用する場合、欠陥のリスクは大幅に減少します。したがって、プロジェクトを実行するたびに、この戦略を使用してモジュールの「ホイール」コンポーネントを継続的に蓄積します。経験が増えるにつれて、蓄積された「ホイール」はますます良くなります。そうでなければ、すべてのプロジェクトは、長い開発時間は言うまでもなく、ホイールから構築され、開発レベルは改善されず、繰り返しの作業は退屈になります。たとえば、前の記事で説明した不揮発性ストレージ管理サブシステムは、適切に設計されていれば、信頼性が高くポータブルなホイールになります。この一節を深く理解し、感謝せずに取り上げてください!

ファームウェアモジュールの原理

ファームウェア開発におけるモジュール式プログラミングの基本概念は、ファームウェアモジュールを作成することです。概念的には、モジュールは関心の分離を表しますコンピュータサイエンスでは、関心事の分離は、コンピュータプログラムを重複することがほとんどない固有の機能に分解するプロセスです。フォーカスは、プログラムの任意のフォーカスまたは機能であり、機能または動作と同義です。懸念分離の開発は、伝統的にはモジュール化とカプセル化によって実現されてきました。これは実際にはデカップリングのアイデアです。

ファームウェアモジュールは、いくつかのタイプに分類できます。

  • 多くの上位ユーザーモジュールに関連するコードは、個別のファームウェアモジュールとして実装されます。基盤となるハードウェアに関連する一般的な抽象実装たとえば、hal_adc.cはADCユーザーモジュールのファームウェアモジュールで、hal_timer.cはタイマーユーザーモジュールのファームウェアモジュールです。

  • 特定の純粋なソフトウェアアルゴリズムのコードは、個別のファームウェアモジュールとして実装されます。たとえば、alg_filter.cは、ソフトウェアフィルター(中央値フィルター、平均フィルター、加重平均フィルター、IIR / FIRフィルターなど)を実行するファームウェアモジュールです。

  • 特定のアプリケーションのコードは、個別のファームウェアモジュールとして実装されます。たとえば、app_battery.cは、バッテリー充電器アプリケーションのファームウェアモジュールです。特定のツールのコードは、個別のファームウェアモジュールとして実装されます。たとえば、debug_print.cは、ログ印刷機能を実装するために使用されるファームウェアモジュールです。

  • ……

モジュール設計を推定するためのいくつかのルールを実装します。

  • すべてのモジュール関連の関数は、単一のソースファイルに統合する必要があります。これは高い凝集度の現れです

  • モジュールは、モジュールのすべてのリソースを宣言するヘッダーファイルを提供します(ハードウェアの依存関係/マクロ/定数/変数/関数)。構造体を使用して、密接に関連する変数をまとめてカプセル化します。

  • モジュールのすべてのセルフチェック機能を実現するには、ソースファイルにセルフチェックコード部分を含めます。

  • ファームウェアモジュールのインターフェイスは、注意深く設計および定義する必要があります。

  • ファームウェアはハードウェアに依存するため、ハードウェアの依存関係をソースファイルのヘッダーに明確に記載する必要があります。たとえば、マクロを使用してハードウェアの依存関係を定義に転送したり、関数を使用して基本的な操作をカプセル化したりします。新しいアーキテクチャシステムでは、実装のこの部分だけを移植する必要があるだけです。

  • 通常、ファームウェアモジュールは、他のプロジェクトの他のチームメンバーが使用できます。これには、管理の変更、欠陥の修復が含まれる場合があり、所有者はモジュールを保守する必要があります。ソースファイルのヘッダーには、「作成者」と「バージョン」の情報が含まれている必要があります。

  • ファームウェアはある程度コンパイラに依存しています。ソースファイルのヘッダーは、コンパイラまたはIDE関連の情報を指定するために検証が実行された開発環境に基づいて宣言する必要があります。

モジュラー設計では、呼び出しオーバーヘッドが発生し、ファームウェアのサイズが大きくなる可能性があることに注意してください。実際の実装では、考慮事項を妥協します。過変調にしないでください。高い凝集性と低い結合の実装戦略を採用することをお勧めします。前回の記事では、ベンチレーターPB560のデザインについて説明しました。コードを読んだ後、コードデザインを解釈することを計画しましたが、コードを読んだ後、デザインがモジュール化されすぎており、凝集度が高いという考えを実現していません。ソースコードの多くのソースファイルは、ある種の問題の抽象的な実現に焦点を合わせてコードの解釈を放棄するのではなく、関数のみを実装します。

モジュールを分割する方法は?

技術開発は需要主導型でなければなりません。まず、より合理的なフレームワークを設計する前に、要件を明確に理解する必要があります。何を達成する必要がありますか?大まかな設計プロセス戦略、私の基本的な考え方は次の図に示すとおりです(私は描画を好むので、人々はより直感的になります)

自問する最初の質問は、このプロジェクトの主な機能は何ですか?これはどこから来たのですか?実際の製品開発なら市場の需要かもしれませんが、自分のDIYプロジェクトなら絶対に思いつきますか?つまり、それがどこから来たとしても、最初に需要を整理する必要があります。では、一般的な意味での要件は何ですか?

  • スイッチ入力、ADCサンプリング、I2C / SPI通信などのハードウェアIOインターフェイス要件は何ですか。

  • センサーからのデータ収集や加熱装置の制御などのビジネスロジック要件は何ですか。これは、高い凝集性要件です。

  • 製品のどの信号をフィルタリングする必要があるか、どの信号を周波数領域で分析する必要があるかなど、アルゴリズムに関連する技術要件はどれですか。

  • 外部通信プロトコルの要件はありますか?

  • 履歴に保存する必要のあるビジネスデータがあるかどうか、または電源オフ後に機器パラメータを保存する必要があるかどうか

  • ログの印刷要件はありますか?

  • ........

  • たくさんあります。

ファームウェアモジュールの原則と関連する指針の原則を組み合わせると、関連性の高い要件が一連のモジュールに抽象的に実装されます。この一連のモジュールが連携して特定の関連性の高いビジネス要件を達成すると、これらのモジュールはサブシステム複数のサブシステムが連携して、main.cのスケジュールの下で製品の全体的な機能を完了します。

スケジューリングを統合する方法

RTOSを使用しない一部のアプリケーションでは、次のフレームワークを使用できます。

void main(void)
{
   /*各模块初始化*/
   init_module_1();
   init_module_2();   
   ....
   while(1)
   {
       /*实现一个定时调度策略*/
       if(timer50ms)
       {
           timer50ms = 0;
           app_module_1();
       }
       if(timer100ms)
       {
           timer100ms = 0;
           app_module_2();
       }
       
       /*异步请求处理,如中断后台处理*/
       if(flag1)
       {
           communication_handler();
       }
       .....
   }
}

RTOSベースの統合実装の例:

void task1(void)
{
    /*处理子系统相关的初始化*/
    init_task1();
    while(1)
    {
       /*应用相关调用*/
       task1_mainbody();
       ....
    }
}
....
void taskn(void)
{
    /*处理子系统相关的初始化*/
    init_taskn();
    while(1)
    {
       /*应用相关调用*/
       taskn_mainbody();
       ....
    }
}

void main(void)
{
    /*一些基本硬件相关初始化,比如IO,时钟,OS tick定时器等*/
    init_hal();
    ......
    
    /*一些基本RTOS初始化*/
    init_os();
    
    /*任务创建*/
    os_creat("task1",task1,栈设置,优先级,...);
    ......
    os_creat("taskn",taskn,栈设置,优先级,...);
    
    /*启动OS调度器,交由OS调度管理应用任务*/
    os_start();
}

異なるRTOSには異なる関数名がありますが、一般的な考え方は一般的に同じです。

結論として

この記事で、モジュラー設計の全体的な構造が必要な理由、その利点、具体的なガイドライン、実際に達成する方法、高い結合力と低い結合を達成する方法など、いくつかの個人的な経験とアイデアを提供します。同時に、ベアメタルプログラムの全体的なフレームワークと、基本的にフレームワークのほとんどのアイデアを解決できるRTOSに基づく統合フレームワークについて、2つのデモが行われました。前の記事で個人が推奨した原則のいくつかを太字で要約します。

  • すべてのモジュール関連の関数は、単一のソースファイルに統合する必要があります。これは、高い凝集度の現れです。

  • モジュールは、モジュールのすべてのリソースを宣言するヘッダーファイルを提供します(ハードウェアの依存関係/マクロ/定数/変数/関数)。構造体を使用して、密接に関連する変数をまとめてカプセル化します。

  • モジュールのすべてのセルフチェック機能を実現するには、ソースファイルにセルフチェックコード部分を含めます。

  • ファームウェアモジュールのインターフェイスは、注意深く設計および定義する必要があります。

  • ファームウェアはハードウェアに依存するため、ハードウェアの依存関係をソースファイルのヘッダーに明確に記載する必要があります。たとえば、マクロを使用してハードウェアの依存関係を定義に転送したり、関数を使用して基本的な操作をカプセル化したりします。新しいアーキテクチャシステムでは、実装のこの部分だけを移植する必要があるだけです。

  • 通常、ファームウェアモジュールは、他のプロジェクトの他のチームメンバーが使用できます。これには、管理の変更、欠陥の修復が含まれる場合があり、所有者はモジュールを保守する必要があります。ソースファイルのヘッダーには、「作成者」と「バージョン」の情報が含まれている必要があります。

  • ファームウェアはある程度コンパイラに依存しています。ソースファイルのヘッダーは、コンパイラまたはIDE関連の情報を指定するために検証が実行された開発環境に基づいて宣言する必要があります。

設計の最初から後の開発モデルを採用することを強くお勧めします。徐々にデバッグし、考えている場所に書き込むことはタブーです。もちろん、初心者の場合、後者のモードを徐々に繰り返したり、経験を比較的すばやく得ることができます。もちろん、選択は完全に個人的な希望に依存します。

詳細に読んで注意深く体験すれば、デザインのアイデアから洞察を得て改善する必要があると思います。私があなたを助けることができれば、私は非常に安心します。そして、私は非常に多くの単語をコーディングするために一生懸命に働きました。もちろん、その記事が貴重だと思われる場合は、私が読んだり、共有したりしてください。もちろん、MCU開発の神にとっては、より多くの友達に見てもらいましょう。この記事の見方は、表面的なものに見えます。鑑賞に関しては、好きなようにしてください。

おすすめ

転載: blog.csdn.net/u012846795/article/details/108544332