uCOS イベント関連の関数コードの理解

イベント制御ブロック/ハンドル/構造体:

構造体 os_flag_grp {                                       

    OS_OBJ_TYPE タイプ。/* OS_OBJ_TYPE_FLAG に設定する必要があります */

    CPU_CHAR *NamePtr; //イベントの名前を指す、文字列型

    OS_PEND_LIST PendList; //イベントの待機リスト

    OS_FLAG_GRP *DbgPrevPtr; //イベント デバッグ リスト内の前のイベントを指す

    OS_FLAG_GRP *DbgNextPtr; //イベント デバッグ リスト内の次のイベントを指す

    CPU_CHAR *DbgNamePtr; //デバッグ リスト内のイベントの名前

    OS_FLAGS Flags; //イベントフラグビットのステータス

    CPU_TS TS; //イベントが最後にリリースされたときのタイムスタンプを保存します

    CPU_INT32U FlagID; //サードパーティのデバッガとトレーサの一意の ID

};

イベント機能

{

OSFlagCreate() : イベント作成関数カーネル オブジェクトを作成する他の関数と同様に、最初にさまざまなチェックが実行され、次に構造要素の値が初期化されます。ここでユニークなのは、32 の異なるイベントを表す 32 ビット変数があり、通常は 0 に初期化され、すべてのイベント タイプが発生していないことを示します作成が成功したら、イベント グローバル変数 OSFlagQty に 1 を加えるのを忘れないでください。これは uCOS の伝統です。カーネル オブジェクトが作成されるたびに、対応するグローバル カーネル オブジェクトの数を 1 ずつ増やす必要があります。

OSFlagDel() : イベント削除関数

{

カーネル オブジェクトを削除する関数は、その内容をクリアします。したがって、イベントの削除機能も例外ではありません。削除する場合は常に 2 つのオプションがあります。待機リストにタスクがない場合は削除するか、タスクの有無に関係なく削除します。したがって、最初のステップは、待機リストにタスクがあるかどうかを確認し、その数を記録することです。次に、OS_OPT_DEL_NO_PEND オプションの下で、待機中のタスクの数が 0 の場合にのみ、イベントはデバッグ リストから削除され、イベントの数は 1 減分されます。そして、OS_FlagClr() を呼び出して構造体の内容をクリアします。イベントが作成後に削除されたことを示すために、構造体のクリア関数は type 要素を no type に割り当てます。名前の位置は不明な名前です。イベント フラグ Flags は0 にクリアされ、OS_PendListInit () を呼び出します。待機リストの作成時に初期化します。つまり、待機リスト内の要素を 0 にクリアします。OS_OPT_DEL_ALWAYS オプションの下にある場合は、while ループを使用して、まず待機リストからすべてのタスクを削除してから、上記の操作を実行します。待機リストから削除されたタスクが存在する可能性があるため、システムのリアルタイム パフォーマンスを向上させるために、OSSched() が呼び出され、タスクの切り替えが実行されることに注意してください。

戻り値: 待機リスト内のタスクの数。

}

OSFlagPost() : イベント設定関数  

{

関数アイデア: OSFlagPost()は、イベントグループ内の指定されたビットをセットするために使用されます(パラメータで指定されたイベントフラグを通じてイベントフラグをセットします) ビットがセットされている(1にセットされている)場合、イベントが発生したことを示しますまたは保留中です。次に、イベント オブジェクトを待機しているイベント待機リストを調べて、イベントのアクティブ化要件が現在のイベント オブジェクト フラグの値と一致するタスクがあるかどうかを確認し、存在する場合はタスクを起動します。

4 つのエントリ パラメータ: イベントへのポインタ、イベント フラグ、オプション、返されたエラー タイプ。ここには OS_OPT_POST_FLAG_SET、OS_OPT_POST_FLAG_CLR、OS_OPT_POST_NO_SCHED の 3 つのオプションがありますが、フラグ ビットを 1 に設定し、0 にクリアするオプションの 1 つを含める必要があります。1 を設定するか、0 をクリアすることによってトリガーできます

戻り値: イベントの現在のタグ値。

: イベントにはバイナリ セマフォと同じ同期効果があるため、タスク間で動作するだけでなく、タスクと割り込み間の同期も実現できます。したがって、この関数は割り込みで呼び出すことができます。

関数処理: ① OS_TS_GET()を呼び出し、公開時のタイムスタンプとしてタイムスタンプを取得します。② 割り込み遅延発行が有効で、割り込み内でイベント設定関数 OSFlagPost()が呼び出された場合、OS_IntQPost()を呼び出してイベントを割り込みメッセージキューに発行する必要があります。割り込み遅延パブリッシュでは、指定したパブリッシュタスクにイベント(メッセージなど)を設定(送信)しますが、このときシステムはレンタルメッセージキューにイベント(メッセージなど)をパブリッシュし、割り込みパブリッシュが完了するまで待ちます。タスクはイベントを設定(送信)する前に起動します。情報)。③ 割り込み遅延解除が有効でない場合は、OS_FlagPost()を呼び出してイベント対応ビットを直接セット/クリアしてください。

- OS_FlagPost() を呼び出します

5 つのエントリ パラメータ: OSFlagPost() の 4 つのパラメータに加えて、タイムスタンプ パラメータがここに追加されます。これはイベント構造体変数にタイムスタンプを割り当てるために使用されます。そのため、イベント構造体のタイムスタンプ変数 CPU_TS TS は、イベント構造体のタイムスタンプ変数 CPU_TS TS を使用してイベントが最後にリリースされたときのタイムスタンプ。

戻り値: イベントの現在のタグ値。

関数処理: ① 割り込みをオフにし、オプションパラメータおよびイベントフラグパラメータフラグに従ってイベント構造体のイベントフラグ要素を変更します。エントリ パラメータ フラグの各ビットはイベント フラグのみを表すため、ビットのセットには OR 演算が使用され、ビットのクリアには AND 演算が使用されます。オプションの set または clr に従って、イベント構造要素 Flags が実行されます。 0 をクリアするということは、フラグをビットごとに反転してイベントと結合することを意味します。構造体 p_grp->Flags の要素は AND 演算されるため、0 にクリアできます。次に、タイムスタンプをイベントに保存します。② 待ちリスト内のタスク数を取得 イベントを待っているタスクがない場合(タスク数が 0 の場合)、割り込みを ON にし、イベントの現在のマーク値をそのまま返します。(注:イベントはセマフォに似ています。これは単なる記号です。必要なのは、どのイベントが発生するかどうかをマークすることだけです。メッセージ キューとは異なり、メッセージ キューは、タスクがないときにメッセージをメッセージ リストに送信する必要があります。データ損失を避けるためにメッセージを待機します)。③ イベントを待っているタスクがある場合は、待機リスト内のタスクを走査して、そのタスクが待っているイベントが発生するかどうかを確認し、すべてのイベントがトリガーされるか、またはそのうちの 1 つだけがトリガーされるかを確認する必要があります。while ループでは、タスク TCB のイベントオプションの要素 FlagsOpt とマクロ OS_OPT_PEND_FLAG_MASK の論理積をとり、switch--case 文でモードを判定することでタスクのイベントモードを取得します。モード OS_OPT_PEND_FLAG_SET_ALL では、タスクのすべてのイベントが発生する必要があり、イベント フラグとタスク待機イベント フラグを p_grp->Flags および p_tcb->FlagsPend で AND 演算します。AND の結果のみが p_tcb->FlagsPend と等しくなります (タスクはイベント待機関数を呼び出します。その関数では、タスクが関心のあるイベントが p_tcb->FlagsPend 要素に割り当てられます。) は、すべてのイベントが発生したことを示し、タスクはブロックされて待機していなくなり、関数 OS_FlagTaskRdy() が呼び出されて、タスク待機イベント ステータスの要素 FlagsRdy を flags_rdy に割り当てます。その後、タスクは待機リストから削除されます。タスクのステータスに。待機タイムアウトが発生した場合は、タスクをタイムベース リストから削除してから、準備完了リストに追加する必要があることに注意してください。待機リストからタスクを削除する関数 OS_PendListRemove() は、待機リストからタスクを削除するだけであり、実行可能リストおよびタイムベース リストからタスクを削除または挿入する操作とは関連付けられていません。モード OS_OPT_PEND_FLAG_SET_ANY は、タスク待機イベント内の任意のイベントがタスクをウェイクアップできることを示します。p_grp->Flags & p_tcb->FlagsPend でイベントフラグとタスク待機イベントフラグを比較した後の値が 0 でない限り、イベントが発生したことを意味し、関数 OS_FlagTaskRdy() を呼び出すことができます。タスクを準備します。イベント フラグ 0 にクリアされる 2 つのフラグ OS_OPT_PEND_FLAG_CLR_ALL および OS_OPT_PEND_FLAG_CLR_ANY にも同じことが当てはまります。ただし、 ~p_grp->Flags および p_tcb->FlagsPend では、最初にイベント フラグをビットごとに反転してから AND 演算できる点が異なります。ここのエントリ パラメータ flags も、TCB のイベント待機フラグ要素 FlagsPend も、ビット 0、4、および 5 の設定またはクリアなどの clr および set 属性を持たないため、これら 2 つのパラメータは 0x31 に等しく、そうではありません。属性に対して、 set は 0x31 に等しく、 clr は 0xFFFFFFCE に等しいもちろんパラメータフラグの値を計算する必要はなく、対応する位置をずらして設定することも可能です。たとえば、イベント マスクのビット 0 を設定するには、#define EVENT_0 (0x01 << 0)、イベント マスクのビット 1 を設定するには、次に #define EVENT_1 (0x01 <<1)、n 番目のビットを設定します。 n ビットを左にシフトします。複数のイベントの組み合わせの場合は、それらの OR を計算します。④ OS_OPT_POST_NO_SCHED が選択されていない場合は、OSSched()を呼び出してタスクを切り替えます。見つかりましたか?カーネル オブジェクトのポスト関数はすべてオプションのタスク スケジューリングです。タスクがpost関数を呼び出してもタスクの状態は変化しないため、必要がなければ切り替える必要はありませんが、待ちリストにカーネルオブジェクトを取得するタスクが存在するため、カーネルオブジェクトを削除します。タスクの優先順位は比較的高いため、より緊急のタスクに迅速に対応できるようにスケジュールを切り替える必要があります⑤ マークに誤りがなければ、現在のイベントマーク flags_cur = p_grp->Flags; を取得し、flags_cur を返します。

次に、uCOS モード選択プログラムを見てみましょう。タスク イベント モードは、タスク TCB 内のイベント オプション要素 FlagsOpt とマクロ OS_OPT_PEND_FLAG_MASK の AND 演算によって取得されます。パターンの種類は次のとおりです。

#define OS_OPT_PEND_FLAG_MASK (OS_OPT)(0x000Fu) 1111

#define OS_OPT_PEND_FLAG_CLR_ALL (OS_OPT)(0x0001u) 0001

#define OS_OPT_PEND_FLAG_CLR_ANY (OS_OPT)(0x0002u) 0010

#define OS_OPT_PEND_FLAG_SET_ALL (OS_OPT)(0x0004u) 0100

#define OS_OPT_PEND_FLAG_SET_ANY (OS_OPT)(0x0008u) 1000

各モード タイプは 16 ビットであることがわかります(16 進数の 1 つの 0 は 4 つの 2 進数、つまり 4 つの 2 進数 0 を表します)。実際、ここでの各モード タイプは一意の位置 1 で表されます。uCOS はこの方法を好んで使用します。mode = p_tcb->FlagsOpt & OS_OPT_PEND_FLAG_MASK; であるため、イベント待ち関数の待ちリストに入る際には、TCB のイベント オプションの要素 FlagsOpt にも上記の種類の値が割り当てられる必要があります

}

OSFlagPend() : イベント待ち関数

{

機能アイデア:タスクがイベント待ち関数を呼び出す際に、タイムアウトを指定することができます(タイムアウトを指定しなくても、0の場合は永久待ちを意味します)。イベントが発生した場合、待機オプションを使用して、イベントの対応するフラグ ビットをクリアし、イベント フラグ ビットの値を返すかどうかを決定します。イベントがまだ発生していない場合は、待機リストに入り、イベントが発生するのを待ちます。待機がタイムアウトになると、待機リストから自動的に削除され、準備完了状態に戻ります。オペレーティング システムのリアルタイム性を効果的に反映します。イベント フラグは、すべてのイベントに対して 1 を設定/0 をクリアするモードと、任意のイベントに対して 1 を設定/0 をクリアするモードに分かれています。したがって、モードに応じてタスクを待機リストに入れるかどうかを判断する必要があります。

:セマフォとイベントの待機関数はタスクに限定されており、割り込みで呼び出すことはできません。割り込みは早送りと早出しに続きます。割り込みが解放関数を呼び出せる理由は、タスクが実行されていることを示すフラグを設定するのと同じです。セマフォが利用可能になった場合やイベントが発生した場合など、割り込みサービス関数を待機リストに入れるのは愚かです。

6 つのエントリ パラメータ: イベント ポインタ、イベント フラグ、タイムアウト、オプション、返されたタイムスタンプ (通常、カーネル オブジェクト待機関数のタイムスタンプには、タスクがイベントを取得したときにイベントが最後に作成されたときのタイムスタンプが割り当てられます)、返されたエラー タイプ。

オプションには、OS_OPT_PEND_FLAG_CLR_ALL、OS_OPT_PEND_FLAG_CLR_ANY、OS_OPT_PEND_FLAG_SET_ALL、OS_OPT_PEND_FLAG_SET_ANY があります。ここではいずれかを選択する必要があります。さらに、OS_OPT_PEND_FLAG_CONSUME (一致後にフラグ ビットが自動的に反転されます) を選択することもできます。また、イベントが発生しない場合に待機ブロック リストに入るように OS_OPT_PEND_NON_BLOCKING および OS_OPT_PEND_BLOCKING を選択することもできます。

戻り値: flags_rdy、フラグを待っています。値は 0 ではなく、待機中のイベントが成功したことを示します (通常、ペンド関数のエントリ パラメーター フラグの値、つまりタスクに必要なイベント マークの値です。ユーザーはこの値を必要なイベント マークの値と比較します)タスクによってそれらが等しいかどうかを確認し、すべての待機中のイベントが発生するかどうかを判断します); 値 0 は、待機中のイベントが失敗したことを示します (待機リストに入るなど、まだ待機されていないことを示します)。はブロッキングされておらず、スケジューラはロックされています)。

関数処理: ① まずセキュリティチェック、割り込み時の不正呼び出しチェック、パラメータオプションチェック、オブジェクトタイプチェックを行います。マクロ値が 0x0000u であるため、オプション チェックに OS_OPT_PEND_BLOCKING がないか、または結果が同じです。これは、イベントが発生しない場合にデフォルトで待機リストに入るのと同じです。②option と opt & OS_OPT_PEND_FLAG_CONSUME の結果が 0 でない場合、OS_OPT_PEND_FLAG_CONSUME が選択されていることを意味します。つまり、フラグ ビットは一致後に自動的に反転されます。イベントは他のカーネルオブジェクトとは異なるため、他のカーネルオブジェクトにはモードタイプがありませんたとえば、セマフォが使用可能な場合は取得され、使用可能なセマフォがない場合は待機リストに送信されて待機されます。イベントのモードが異なれば動作も異なります(たとえば、すべてのイベントが発生する必要がある場合と、いずれか 1 つのイベントのみが発生する必要がある場合、すべてのイベントが発生する場合の判定条件と任意のイベントが発生する場合の判定条件が異なるため、種類が異なれば必要なコードも異なります)実装されており、組み合わせることはできません) 。そのため、モード タイプを取得するには、イベントが異なるモードで発生するかどうか、および待機リストに入れるかどうかを判断する必要がありますここで、モード タイプは、フラグ ビットの要件である opt & OS_OPT_PEND_FLAG_MASK を通じて取得されます。モード切り替え - ケース分類に従って、タスクの必要なすべてのイベントが発生したかどうかを判断します。④ モードが OS_OPT_PEND_FLAG_SET_ALL の場合、flags_rdy = p_grp->Flags & flags とし、すべてのイベントが発生した場合 (つまり、結果 flags_rdy が flags に等しい)、FLAG_CONSUME が設定されている場合、p_grp->Flags &= ~flags_rdy とします。つまり、イベント フラグを否定し (これは、イベントが処理されたことを示す 0 をクリアするのと同じです)、flags_rdy の値をタスク TCB 要素 FlagsRdy に割り当て、flags_rdy を返します。すべてのイベントが発生しない場合 (つまり、結果の flags_rdy が flags と等しくない場合)、待機リストに入る必要があります。OS_OPT_PEND_NON_BLOCKING が選択されているかどうかを確認し、選択されている場合は、「ブロックを待機する必要があります」というエラーを返し、0 を返します。待機リストに登録しないことを選択しない場合は、待機リストに登録されます。タスクのステータスを変更する必要があるため、スケジューラがロックされているかどうかを判断し、「スケジューラがロックされています」というエラーを返し、0 を返す必要があります。そうでない場合は、スケジューラをロックし、関数 OS_FlagBlock() を呼び出してタスクをタスクに送信します。順番待ちリスト。⑤ モードが OS_OPT_PEND_FLAG_SET_ANY の場合、set_all と判定が異なるだけで、p_grp->Flags & flags の結果が 0 以外であるだけで、その他の動作は同じです。⑥ CLR モードの場合は flags_rdy = ~p_grp->Flags & flags とします イベント関数作成時に解析されています フラグは 0 をクリアするか 1 をセットする性質がないので、どのビットをクリアしたいのか0 または 1 を設定すると値はすべて同じなので、イベントが発生した場合、p_grp->Flags の対応するビットは 0 にクリアされているため、最初に反転する必要があります。flags が 0x03 の場合、性質は clr で、イベントが発生した場合は 0xx0 になるはずで、ビット 0 と 1 は 0 にクリアされているため、次の判断を行う前に、最初に反転してから AND 演算する必要があります。実際には、ここで直接 AND を行うこともできます。これは AND の結果が 0 に等しいかどうかを判定するだけですが、ここでの否定は主に判定後の演算と戻り値を統合するために行われます。これ以降の動作は set と同じで、イベントが発生した場合、戻り値は関数のエントリ パラメータ フラグの値と同じになり、それ以外の場合は 0 が返されますCLR モードと SET モードのもう 1 つの違いは、OS_OPT_PEND_FLAG_CONSUME が選択されている場合、イベントの発生後、p_grp->Flags |= flags_rdy が OR 演算を実行してフラグ ビットを一致させて反転することです (SET は 0 にクリアされ、CLR は 1 に設定されます)。 。⑦ OSSched()を呼び出してタスクを切り替えます。ここまで実行できるということは、タスクが待機リストに入ったことを意味します。イベントを待ったり、無効な操作があった場合、タスクはすでに を返しているからです⑧ ここで関数が実行されるということは、タスクが待機リストから削除されたか、イベントが発生したか、タイムアウトしたか、一時停止または削除されたことを意味するため、タスクの状態に応じて処理されます。他のカーネルオブジェクトとは異なり、OS_OPT_PEND_FLAG_CONSUMEオプションがあるため、このイベント発生後、イベント構造体の変数p_grp->Flagをイベントモードに応じてAND演算またはOR演算を使用して変更する必要があります。最後に flags_rdy を返しますが、エラーはありません。

- OS_FlagBlock() を呼び出します

①まずタスクのTCB要素FlagsPend、FlagsOpt、FlagsRdyに値を代入します。イベント作成関数ではイベントを作成し、待機リスト内のタスクの状態をトラバースするため、タスクのイベントオプションの種類FlagsOpt(全イベント発生またはいずれか1つのイベント発生)と、待機中のタスクを判断する必要があります。イベント待ちフラグ FlagsPend (どのイベントが来るか) 結果は目的のイベントが来るかどうかです。FlagsRdy に値 0 が割り当てられている場合は、待機中のイベントがまだ発生していないことを意味し、0 の場合はイベント待機が失敗したことを意味します。② OS_Pend() を呼び出します。この関数は、まず OS_TaskBlock() を呼び出して、実行可能リストからタスクを削除します。タイムアウトが発生した場合は、タイムベース リストも挿入します。次に、OS_PendListInsertPrio() を呼び出して、優先度に従ってタスクを待機リストに挿入します。

}

}

おすすめ

転載: blog.csdn.net/m0_43443861/article/details/126250049