uCOS ソフトウェアのタイマー関連機能を理解する

ソフトウェアタイマー制御ブロック(構造)

構造体 os_tmr {

OS_OBJ_TYPE Type; //カーネルオブジェクトタイプはOS_OBJ_TYPE_TMRです

    CPU_CHAR *NamePtr; //ソフトウェアタイマー名 

    OS_TMR_CALLBACK_PTR CallbackPtr; //コールバック関数へのポインタ

    void *CallbackPtrArg; //コールバック関数パラメータへのポインタ   

    OS_TMR *NextPtr; //次のタイマーを指す

    OS_TMR *PrevPtr; //前のタイマーを指す

    OS_TICK Remain; //タイマーの計時時間に達するまで、タイムベースは何回残っていますか?                       

    OS_TICK Dly; //タイマー初期タイミング値

    OS_TICK Period; //タイマータイムベースを最小単位とするタイマータイミング周期

    OS_OPT Opt; //タイマーオプション

    OS_STATE State; //タイマーのステータス

    OS_TMR *DbgPrevPtr; //タイマー デバッグ リスト内の前のタイマーを指します

    OS_TMR *DbgNextPtr; //タイマー デバッグ リスト内の次のタイマーをポイントします

};

ここには 2 つのタイマー オプションがあります: OS_OPT_TMR_ONE_SHOT (シングル モード、一度だけ計時され、繰り返されない)、OS_OPT_TMR_PERIODIC (定期モード)。

ソフトウェアタイマータスク:

{

ソフトウェア タイマー タスクの作成プロセス: ソフトウェア タイマー タスクの作成は、システムが OSInit() を初期化するときに完了します。マクロ OS_CFG_TMR_EN が有効な場合、OSInit() は OS_TmrInit() を呼び出してクロック管理モデルを初期化します。OS_TmrInit() では、OSTaskCreate() が呼び出され、ソフトウェア タイマー タスクが作成されます。

OS_TmrInit(): タイマー管理モデルの初期化

{

1 エントリパラメータ: 返されたエラーの種類 関数呼び出し時にエラー *p_err != OS_ERR_NONE が発生した場合はリターンします。

機能処理: ① まず安全確認を行います。次に、ソフトウェア タイマー デバッグが有効かどうかを確認します。有効な場合は、タイマーがまだ作成されておらず、当然デバッグ リストにタイマーが存在しないため、タイマー デバッグ リストを指すグローバル ポインタ変数 OSTmrDbgListPtr を NULL に割り当てます。② タイマーを指すグローバル ポインター OSTmrListPtr に値 NULL を割り当て、タイマーの数をカウントするグローバル変数に値 0 を割り当てます。これがタイマー リストであり、作成されたすべてのタイマーを連結して二重リンク リストを形成します。 。(実際に f103 で使用されるハッシュ アルゴリズムがリストされています。 ) ③ ミューテックスが有効な場合は、OSMutexCreate() を呼び出して、タイマーを保護するミューテックスを作成します。タイマー作成関数 OSTmrCreate() で定義したタイマー構造体変数を初期化するときに、このクリティカル セクションを保護するためにミューテックスが使用されます (おそらく、ソフトウェア タイマーがタスクの実行中に作成され、スイッチ割り込みメソッドを使用すると割り込み遅延が発生するためです)。 f4 はいくつかの改良を加えました) (このミューテックスは os.h で定義されており、グローバル属性を持っています。ミューテックスは、クリティカル セクションに入るときに取得され、クリティカル セクションの値を変更する権利を取得します。クリティカル セクションから出るときに解放されます。複数のタイマーは 1 つのミューテックスのみを使用できます)。④ uCOS は、この関数内で OSTaskCreate() を呼び出してタスクを作成するだけですが、当然のことですが、タスク作成時と同様に、グローバルタスクスタック、タスク優先度、タスクサイズ (os_cfg_app.c) が定義されており、ソフトウェアタイマータスク関数(os.h)。これらのパラメータはユーザーが変更できるため、タスクを作成する前に、OSTaskCreate() は優先度が範囲外かどうか、スタック ポインタが NULL を指しているかどうかなどをチェックします。⑤ OSTaskCreate()を呼び出してソフトウェアタイマータスクを作成します。

}

OS_TmrTask(): タイマータスク関数

{

関数のアイデア: 前に述べたように、タイマー タスクが存在する理由は、タイマー時間が到来したかどうかを判断し、タイマー時間が到来した場合は、対応するコールバック関数を呼び出すためです。では、タイマー タスクは、スケジュールされた時間がいつ終了するかをどのように判断するのでしょうか? これはソフトウェア タイマーであり、ハードウェア タイマーのレジスタやその他の構造を持たないことに注意してください。ハードウェア タイマー時間が経過すると、レジスタ内の対応するフラグ ビットが 1 に設定されます。したがって、ソフトウェア タイマーの場合、ハードウェア タイマーのフラグ ビットをシミュレートできます。ただし、ソフトウェア タイマーの数は不確実であり、マーク付けに特定の数のグローバル変数を使用することはできませんハードウェア タイマーのタイミング プロセスを思い出してください。最初にハードウェア タイマーのビートを決定し、次にタイミング値 (つまり、タイミング ビートの数) をハードウェア タイマーに割り当てます。ビート番号が 0 に達すると、フラグの位置は 1 になります。実際、フラグビットの出現は同期のためです。したがって、ソフトウェア タイマーもこのプロセスに従います: ソフトウェア タイマーのビートを決定し、各タイマーは異なるタイミング値を持ちます。1 つのタスク内のすべてのタイマーを決定するには、すべてのソフトウェア タイマーをタイマー リストにつなぎます。各タイマーのビートが到着したときにリスト全体を調べて、タイマーが期限切れになっているかどうかを判断しますソフトウェアタイマのビートに同期するために、ソフトウェアタイマタスクでセマフォを取得します。タイマのビートがセマフォを解放した場合にのみ、タスクはセマフォを取得し、ビートの到着を示すレディ状態に戻り、タイミングがあるかどうかを判断します。 タイマー タイマーが終了します。

関数プロセス: 他のタスク関数と同様に、タイマー タスク関数にも戻りのない無限ループがあり、エントリ パラメーターは 1 つだけあり、返されるエラーの種類です。① while(p_tmr != (OS_TMR *)0) ループに入り、タスクセマフォ待ち関数 OSTaskSemPend()を呼び出します。: セマフォを待機している関数がセマフォを待機しない場合、待機がタイムアウトするか終了するか、セマフォを待機するまでブロック状態になります。② セマフォを待つ場合は、リスト全体を調べて、期限切れになったタイマーがないかどうかを確認します。クリティカル セクションに入ります。ここでは、ソフトウェア タイマー タスク関数の実行時間を測定するため、現在のタイムスタンプが取得されます。現在のタイマー時間レコードが増加し、グローバル変数 OSTmrTickCtr の値が 1 増加します。グローバル変数 OSTmrListPtrはリストの先頭を指すクロックであり、 while() ループを通じてリスト内の各クロックを横断します。: OSSchedLock() は、クロック リストをトラバースするときにスケジューラをロックするためにここで呼び出されます。他の高レベルのタスクがタスクを中断してタイミングの不正確性が増大するのを防ぐために、スケジューラは実際にロックされている必要があります。③タイマー終了の判断方法は?これは、クロック構造の 1 つの要素が Remain であり、これはタイマー タイミング時刻に到達するまでにいくつのタイム ベースがあるかを示し、このパラメータは作成時に初期化されているためです。したがって、while ループでは、Remain 要素を減少させ、それが 0 に減少するかどうかを判断するだけで済みます。0 に減少することは、タイミング時間が経過したことを意味します。タイミングタイムアップの場合、クロック構造要素optに応じてクロックが単発モードか周期モードかを判定し、周期モードの場合は再度RemainをPeriodに割り当て、単発モードの場合はRemainをPeriodに割り当てますOS_TmrUnlink() 関数を使用してリストからタイマーを削除し、タイマーのステータスを OS_TMR_STATE_COMPLETED に変更して、タイマーが完了したことを示します。モードに関係なく、コールバック関数を指すクロック構造体のポインタ CallbackPtr が存在するかどうかを確認する必要があります。存在する場合は、コールバック関数を呼び出してから、OS_TmrUnlock を呼び出してスケジューラのロックを解除します。(OS_TmrUnlink() 関数は、二重リンク リストのノードを削除するために使用されます。リンク リストを管理するヘッド ポインタ OSTmrListPtr があるため、最初のノードの削除は他のノードの削除と同じではありません。この関数では、削除に成功した後、タイマーのステータスを OS_TMR_STATE_STOPPED に変更し、リスト タイマー OSTmrListEntries の数を 1 つ減らします)。⑤ while()ループを終了し、再度タイムスタンプを取得し、前にループに入ったタイムスタンプと比較し、OS_TmrUnlock()を呼び出してミューテックスを解放またはスケジューラのロックを解除します。グローバル変数タイマータスク OSTmrTaskTimeMax の最大実行時間がこの差より小さい場合、その値が差に代入されます。

補足---関数ポインタを介した関数の呼び出し:

{

通常、関数を呼び出すときは、関数名 + 関数パラメータを使用します。関数名はコンパイラによって関数ポインタに変換されて使用されるため、(*関数ポインタ) + 関数パラメータを関数ポインタとして関数名を取得することができ、この形式でコールバック関数を呼び出します。ここ。*関数ポインタ = 関数名

}

--タイマービートのセマフォを解放します

{

uCOS は Tick タスク (OS_TickTask) を使用してシステムのタイム ビートを管理し、タイマー ビートはシステム ビートで除算されます。したがって、セマフォを送信する場所も、もちろん SysTick 割り込みサービス関数である OS_CPU_SysTickHandler() 内にあります。 -- OSTimeTick()。ただし、uCOS は割り込み遅延の使用をサポートしており、割り込み遅延を使用する場合、タスク セマフォの送信場所は割り込み発行タスク (OS_IntQTask) 内になります。

 上記のコードからわかるように、ソフトウェア タイマーは、OSTmrUpdateCtr が 0 に等しいかどうかを判断してセマフォを送信します。systick 割り込みが入るたびにティック時間が終了するため、通常は 1ms の周期を設定します。ここで、各ティック サイクルが到来し、OSTmrUpdateCtr 自体がデクリメントされ、0 に減少すると、ソフトウェア タイマー セマフォが送信されます。これは、ソフトウェア タイマー タイム ベースが OSTmrUpdateCtr*ティック サイクルであることに相当します。初期化ソフトウェア タイマー関数 OS_TmrInit() では、OSTmrUpdateCtr と OSTmrUpdateCnt の両方が 100 です。これは、ソフトウェア タイマーのタイム ベースが 100ms (10Hz) であることを意味します}

ソフトウェアタイマー関連機能

{

OSTmrCreate: タイマー作成関数

{

:カーネル オブジェクトの作成機能は、カーネル オブジェクトを作成することを意味するものではありません。最初にカーネル オブジェクトをファイルに定義する必要があります。カーネル オブジェクトの作成機能は、カーネル オブジェクト制御ブロックの初期化と同等です。タスクと同様に、まずファイル内でタスクを定義します。管理タスクを制御するために、タスクのすべての内容を含むタスク制御ブロック構造を定義します。TCB の内容はタスク作成時に初期化されます。機能

8 つのエントリ パラメータ: タイマーへのポインタ、タイマーの名前、初期タイミング値、周期的タイミング値、オプション (単一または周期)、コールバック関数へのポインタ、コールバック関数を指す仮パラメータ、返されるエラー タイプ。

関数処理: ① オプションチェックを含む一連のチェックを実行します。 シングルモードの場合、dly パラメータが 0 であるかどうかをチェックする必要があります。 0 の場合、「タイミング初期パラメータが無効です」というエラーが返されます。周期モードの場合、パラメータ period が 0 であるかどうかを確認します。0 の場合、「周期リロード パラメータが無効です」というエラーが返されます。② カーネルオブジェクトタイプは OS_OBJ_TYPE_TMR、タイマーの初期状態は OS_TMR_STATE_STOPPED で、エントリパラメータに従ってソフトウェアタイマー制御ブロック内の要素に値を代入する以外はすべて 0 または NULL です。③OS_TmrLock()を呼び出します。この関数は、ミューテックスが有効な場合、OSMutexPend()を呼び出してミューテックスを取得し、そのミューテックスを使用してタイマーを保護することを意味します。スケジューラをロックする必要はなく、中断は発生しません。遅延 (実際には、割り当て操作を初期化するためにミューテックスを使用してタイマー構造を保護しようとしています。また、他のカーネル オブジェクトの作成では、クリティカル セクション保護を直接使用します)。ミューテックスが有効になっていない場合は、OSSchedLock() を呼び出してスケジューラをロックします④ 従来の手順: OS_TmrDbgListAdd() を呼び出して、タイマーをタイマー デバッグ リストに挿入します。タイマーが正常に作成され、タイマーの数を記録するグローバル変数 OSTmrQty が 1 増加します。⑤ OS_TmrUnlock() を呼び出します。この関数は、ミューテックスが有効な場合 (デフォルトで有効)、OSMutexPost() を呼び出してミューテックスを解放し、それ以外の場合は OSSchedUnlock() を呼び出してスケジューラのロックを解除することを意味します。(注: スイッチ割り込み保護クリティカル セクションは f103 で引き続き使用されます。 f407 での保護タイマーのミューテックスの作成は、初期化クロック管理モデル)

}

OSTmrStart() : ソフトウェアタイマー関数の開始 

{

主な目的:作成したソフトウェアタイマーをタイマーリストに追加します。f4 は二重リンクリストに追加します。OSTmrListPtr は、リンク リストの先頭ポインタです。タイマ作成関数によりタイマが初期化された後、タイマは停止されます

2 つのエントリ パラメータ: ソフトウェア タイマーへのポインタ、返されたエラー タイプ

戻り値: 0/1。0 はエラーがありタイマーの開始に失敗したことを意味し、1 はタイマーが正常に開始されたことを意味します。

関数処理: ①セキュリティチェック、割り込み不正呼び出しチェック、パラメータチェック、パラメータオブジェクトタイプチェック等を行う。ここでのセキュリティチェックは、パラメータエラー型ポインタがヌルポインタNULLであり、ヌルポインタが操作できないかどうかをチェックするものである。② タイマーのステータス、スイッチケースに応じて操作を分類します (見つかりません。uCOS は、ユーザーが任意にタイマーを開始することを懸念して、非常に包括的に検討し、一連のチェックを実施し、タイマーのすべてのステータスをリストしました) 、ステータスに応じて操作を分類し、ユーザーのデバッグ用に異なるエラー メッセージを返します)。③ タイマーが動作中の場合は、タイマーを再起動し、タイマー構造体要素 Remain を Dly (タイマー初期タイミング値) に再割り当てします。タイマーが実行中であるということは、タイマー リストに追加されたことを意味し、タイマー リストを再度挿入する必要はありません。④ タイマーが停止中またはスケジュールされている場合は、ステータスを実行中に変更し、Dly の値が 0 かどうかに応じて Remain に値を割り当てます。0 の場合は Remain =Period、0 以外の場合は Remain = Dly 。次に、二重リンクリストの挿入作業ですが、主にリンクリスト内に他のノードが無いかどうかを判断するためと、タイマーリスト内のタイマー値OSTmrListEntriesを変更するために、ノードを先頭に挿入する操作です。エラーなしで 1 を返します。⑤ タイマが作成されていない(未使用)場合は未作成エラーとなり0を返し、それ以外の場合は不正なエラー種別となり0を返します。

}

OSTmrStop: タイマー機能の停止

{

uCOS の停止タイマー機能には 2 つの機能があります。 1 つ目は、停止タイマーは何も動作しません。2つ目はタイマーを停止してコールバック関数を呼び出す方法で、コールバック関数のパラメータを選択できます(作成時のパラメータでも新規パラメータでもoptオプションに従って動作します)。2 番目の関数は、タイマーを早めに終了し、コールバック関数をすばやく実行して、必要なデータを取得したり、いくつかの関数を実装したりすることに相当します。

戻り値: 0、停止に失敗しました。1. 正常に停止します。

関数処理: ① タイマを停止するには、OS_TmrUnlink()を呼び出して、タイマリストからタイマを削除します OS_TmrUnlink()関数では、二重リンクリスト内のノードを削除するとともに、タイマのステータスも に変更されます。 OS_TMR_STATE_STOPPED を設定し、リスト OSTmrListEntries 内のタイマーの数を 1 つ減らします。②その後はタイマーの状態に応じて動作し、進行中のみ①の処理を実行し、オプションoptに応じてコールバック関数を呼び出すかどうかを確認します。OS_TMR_STATE_COMPLETED および OS_TMR_STATE_STOPPED の場合は、タイミングが完了し、停止したが開始されていないことを示し、エラー タイプ「OS_ERR_TMR_STOPPED」と 1 が返されます。その他の状態は、タイマーが作成されていないか (作成後に削除された可能性があります)、または不正な状態にあります。対応するエラー タイプと 0 を返すだけです。

}

OSTmrDel(): タイマー関数の削除

{

削除と停止の違い: タイマーの停止操作とは異なり、タイマーの停止はタイマー リストから削除されるだけであり、タイマー開始関数を呼び出すことで再開できます。タイマーの削除はタイマーの内容をクリアすることを意味します。再度使用する場合は、タイマーを作成してからスタートアップ関数を呼び出す必要があります。

関数処理: タイマーはタイマーリストに追加され、タイマータスクを通じて一元的に管理されるため、タイマーの状態に応じて異なる操作を実行する必要があります。重要なのはタイマーが実行状態であるかどうかであり、実行状態である場合はタイマー リストから削除する必要があります。「Complete または Stopped」状態などの他の有効な状態については、OS_TmrClr() を呼び出してタイマー構造体の内容をクリアするだけで済みます。この関数では、主にタイマーの状態を「OS_TMR_STATE_UNUSED」に変更し、その後タイマーのカウントを減らします。値 OSTmrQty by 1. 、エラーなしと 1 を返します。

}

}

ソフトウェアタイマーの使用: ① 最初にタイマー構造を定義します。② OSTmrCreate() を呼び出してタイマーを初期化します (初期化する前にコールバック関数を記述する必要があります)。③ OSTmrStart() を呼び出してタイマーを開始すると、実際にタイマーがクロック リストに追加されます。④削除や停止などの操作も呼び出すことができます。

ソフトウェアタイマの概要: ソフトウェアタイマを作成・起動すると、タイマリストに追加され、ソフトウェアタイマタスクで管理されます OSがソフトウェアタイマタスクに切り替わると、ソフトウェアタイマタスクはソフトウェアタイマの到着を待ちますセマフォ。セマフォが使用できない場合は、ソフトウェア タイマーのタイム ベースがまだ終了していないことを意味し、待機リストに入ります。ソフトウェアタイマセマフォはsystick割り込みで送信されます。ティックタイマが終了すると割り込みに入ります。割り込み内でタイマタイムベースも終了したかどうかを判断し、終了した場合はタイマセマフォを送信します。セマフォ機能により、待機リストにタスクがある場合、そのタスクは待機リストから削除され、実行可能リストに追加されます。ここでは、以前にブロックされていたタイマータスクをレディリストに追加し、OSがそのタスクに切り替わる際に期限切れのタイマーがあるかどうかを判定し、期限切れのタイマーがある場合にはそのコールバック関数を呼び出します。したがって、タイミング時間の精度を測定したい場合は、OSTmrStart() を呼び出してタイマーを開始した後にタイムスタンプを取得する必要があります。これは、この時点でタイマーがタイマー リストに挿入されており、各タイマーのタイム ベースがタイマーが満了するかどうかは、タイマーが時間を計測し始めるのと同じです。次に、コールバック関数でタイムスタンプを取得します。コールバック関数はタイマーの期限が切れた後に呼び出される関数であるため、その中でタイムスタンプを取得することはタイマーの終了と同等です。この 2 つを引いた時間が予定時刻となります。(ここでは、タスクの優先順位と割り込みの優先順位の区別に注意してください。最終的には、タスクは単なる無限ループ関数であり、どの割り込みもこれらの関数の実行を中断する可能性があります。割り込みには割り込みと比較した優先順位があり、タスクにはタスクを優先します。

おすすめ

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