RT-Threadソフトウェアタイマー(研究ノート)

この記事では、[WildfireEmbedFire]「RTスレッドカーネルの実装とアプリケーション開発-STM32に基づく」について説明します。これは個人的な学習ノートとしてのみ使用されます。詳細な内容と手順については、元のテキストを確認してください(Wildfire Data Download Centerからダウンロードできます)。

タイマーの基本的な考え方

タイマーとは、指定された時間から開始し、指定された時間の後にタイムアウトイベントをトリガーすることを指します。ユーザーは、タイマーの期間と頻度をカスタマイズできます。人生の目覚まし時計と同じように、目覚まし時計が毎日鳴るタイミングを設定したり、鳴る回数を1回か毎日かを設定することもできます。

タイマーは、ハードウェアタイマーとソフトウェアタイマーに分けられます。

ハードウェアタイマーは、チップ自体によって提供されるタイミング機能です。一般に、入力クロックは外部水晶発振器によってチップに提供され、チップは制御入力を受け入れるためにソフトウェアモジュールに一連の構成レジスタを提供します。設定された時間値に達すると、チップ割り込みコントローラはクロック割り込みを生成します。 。ハードウェアタイマーの精度は一般に非常に高く、ナノ秒レベルに達する可能性があり、割り込みによってトリガーされます。

ソフトウェアタイマー、ソフトウェアタイマーは、オペレーティングシステムによって提供されるシステムインターフェイスの一種であり、ハードウェアタイマーに基づいて構築されているため、システムはハードウェアタイマーリソースに制限されないタイマーサービスを提供できます。実装する機能は、ハードウェアタイマータイマーは似ています。

RT-Threadオペレーティングシステムはソフトウェアタイマー機能を提供します。ソフトウェアタイマーを使用することは、タイマーの数を増やすことと同じであり、より多くのタイミングサービスを作成できます。

- オリジナル

タイマーのアプリケーションシナリオ

マイクロプロセッサまたはマイクロコントローラのハードウェアタイマーの数には限りがあるため、ユーザーがより多くのタイマーを必要とする場合は、ソフトウェアタイマーを使用して完了する必要があります。

ただし、ソフトウェアタイマーは、ハードウェアタイマーと比較して精度が非常に低く、ソフトウェアタイマーが他のスレッドによって簡単に中断されるため、高い時間精度を必要としないスレッドにのみ適しています(ソフトウェアタイマーはスレッドであり、優先度はデフォルトで4)。

タイマーの精度

オペレーティングシステムでは、通常、ソフトウェアタイマーはタイミングユニットとしてシステムティックサイクルを取ります。システムビートはシステムのハートビートビートであり、システムクロックの周波数を示します。これは、人間のハートビートに似ています。1秒間にビートできるビート数、システムビートはRT_TICK_PER_SECONDとして構成され、このマクロはrtconfigで定義されます。 .h、デフォルトは1000です。その場合、システムのクロックサイクルは1msです(1sは1000回ビートし、毎回1msです)。ソフトウェアタイマーのタイミング値は、ビート周期の整数倍である必要があります。たとえば、ビート周期が10msの場合、上位層のソフトウェアタイマーのタイミング値は10ms、20ms、100msなどになりますが、 15msではありません。ティックはシステム内のタイマーが区別できる精度を定義するため、システムは実際のシステムCPU処理能力とリアルタイム要件に応じて適切な値を設定できます。システムティック期間の値が小さいほど、精度は高くなります。 、ただし、システムのオーバーヘッドが高くなります。システムが1秒間にクロック割り込みに入る回数が増えるため、大きくなります。

- オリジナル

タイマーのしくみ

ユーザーがソフトウェアタイマーを作成すると、システムはrt_tick時間とユーザーが設定したタイミングに従ってタイマーのウェイクアップ時間タイムアウトを決定し、タイマー制御ブロックをソフトウェアタイマーリストrt_soft_timer_listにハングアップします。

rt_tickは、システムの現在の実行時間を記録するために使用される32ビットの符号なし変数です。クロックビートが経過するたびに、rt_tickは1ずつ増加します。

rt_soft_timer_listは、アクティブ化されたすべてのタイマーを時間の昇順で保存するタイマータスクを保存します。

タイマーが追加されるたびに、そのタイムアウト機能のウェイクアップ時間のタイムアウトは、現在のシステム時間rt_tick+タイミング時間に等しくなります。

タイマー制御ブロック

struct rt_timer
{
    
    
    struct rt_object parent;                            /**< 继承自rt_object */

    rt_list_t        row[RT_TIMER_SKIP_LIST_LEVEL];     /**< 定时器列表算法用到的队列 */

    void (*timeout_func)(void *parameter);              /**< 定时器超时调用的函数 */
    void            *parameter;                         /**< 超时函数用到的入口参数 */

    rt_tick_t        init_tick;                         /**< 定时器初始超时节拍数 */
    rt_tick_t        timeout_tick;                      /**< 定时器实际超时时的节拍数 */
};

タイマータイムアウト機能

タイマータイムアウト機能は、カウント値が設定値に達したときにタイマーが自動的に実行する機能です。この機能は、単独で定義する必要があります。タイマータイムアウト機能には、次の2つの状況があります。

  1. タイムアウト機能は(システムクロック)割り込みコンテキスト(ハードウェアタイマー)で実行され、タイマー制御ブロックでRT_TIMER_FLAG_HARD_TIMERを指定する必要があります。
  2. タイムアウト関数はスレッドのコンテキストで実行され、タイマー制御ブロックでRT_TIMER_FLAG_SOFT_TIMERを指定する必要があります。

タイマー機能インターフェース

タイマーrt_timer_createを作成します

rt_timer_t rt_timer_create(const char * name、
void(* timeout)(void * parameter)、void * parameter、
rt_tick_t time、rt_uint8_t flag);

この関数インターフェースを呼び出した後、カーネルは最初に動的メモリヒープからタイマー制御ブロックを割り当て、次に制御ブロックの基本的な初期化を実行します。
指定されたフラグがRT_IMER_FLAG_HARD_TIMERの場合、タイマーがタイムアウトすると、タイマーのコールバック関数がクロック割り込みのサービスルーチンのコンテキストで呼び出されます。指定されたフラグがRT_TIMER_FLAG_SOFT_TIMERの場合、タイマーがタイムアウトすると、タイマーのコールバック関数が呼び出されます。システムクロックタイマースレッドのコンテキストで呼び出されます。

パラメータ 説明
名前 タイマーの名前
タイムアウト タイマースーパーマーケット関数ポインター
パラメータ タイマータイムアウト機能入力パラメータ
時間 タイムアウト時間、ユニットはシステムビートです
国旗 パラメータオプション

タイマーの削除rt_timer_delete

rt_err_t rt_timer_delete(rt_timer_tタイマー);

この関数インターフェースを呼び出した後、システムはrt_timer_listリンクリストからタイマーを削除し、対応するタイマー制御ブロックによって占有されていたメモリを解放します。

パラメータ 説明
タイマー タイマーハンドル

タイマーを初期化しますrt_timer_init

void rt_timer_init(rt_timer_t timer、
const char * name、void(* timeout)(void * parameter)、void * parameter、
rt_tick_t time、rt_uint8_t flag);

この機能インターフェースを使用すると、対応するタイマー制御ブロックが初期化され、対応するタイマー名、タイマータイムアウト機能などが初期化されます。
指定されたフラグがRT_IMER_FLAG_HARD_TIMERの場合、タイマーがタイムアウトすると、タイマーのコールバック関数がクロック割り込みのサービスルーチンのコンテキストで呼び出されます。指定されたフラグがRT_TIMER_FLAG_SOFT_TIMERの場合、タイマーがタイムアウトすると、タイマーのコールバック関数が呼び出されます。システムクロックタイマースレッドのコンテキストで呼び出されます。

パラメータ 説明
タイマー タイマーハンドル
名前 タイマーの名前
タイムアウト タイマースーパーマーケット関数ポインター
パラメータ タイマータイムアウト機能入力パラメータ
時間 タイムアウト時間、ユニットはシステムビートです
国旗 パラメータオプション

タイマーの開始rt_timer_start

rt_err_t rt_timer_start(rt_timer_tタイマー);

タイマー開始機能インターフェースを呼び出した後、タイマーの状態はアクティブ状態(RT_TIMER_FLAG_ACTIVATED)に変更され、タイムアウト順にrt_timer_listキューリンクリストに挿入されます。

パラメータ 説明
タイマー タイマーハンドル

タイマーの停止rt_timer_stop

rt_err_t rt_timer_stop(rt_timer_tタイマー);

タイマー停止機能インターフェースを呼び出した後、タイマー状態は停止状態に変更され、rt_timer_listリストから分離され、タイマータイムアウトチェックに参加しません。(定期的な)タイマーが期限切れになると、この関数インターフェイスを呼び出して(定期的な)タイマー自体を停止することもできます。

パラメータ 説明
タイマー タイマーハンドル

制御タイマーrt_timer_control

rt_err_t rt_timer_control(rt_timer_tタイマー、rt_uint8_t cmd、void * arg);

制御タイマー機能インターフェースは、コマンドタイプパラメータに従ってタイマー設定を表示または変更できます。現在、4つのコマンドインターフェイス、つまり、タイミング時間の設定、タイミング時間の表示、単一トリガーの設定、およびサイクルトリガーの設定をサポートしています。

パラメータ 説明
タイマー タイマーハンドル
cmd タイマーを制御するコマンド
arg cmdに対応する制御コマンドパラメータ

タイマー実験

実験は比較的簡単で、2つのタイマーを定義し、それぞれシングルタイミングモードと周期的タイミングモードを使用します。

#include "board.h"
#include "rtthread.h"


// 定义软件定时器控制块
static rt_timer_t tmr1 = RT_NULL;
static rt_timer_t tmr2 = RT_NULL;

// 可能用到的全局变量
static rt_uint32_t TmrCb_Cnt1 = 0;
static rt_uint32_t TmrCb_Cnt2 = 0;



/******************************************************************************
* @ 函数名  : timer1_callback
* @ 功  能  : 定时器1回调函数
* @ 参  数  : parameter 外部传入的参数
* @ 返回值  : 无
******************************************************************************/
static void timer1_callback(void *parameter)
{
    
    
	rt_uint32_t tick_num1 = 0;
	
	TmrCb_Cnt1++;
	
	tick_num1 = (rt_uint32_t)rt_tick_get();   // 获取滴答定时器的计数值
	
	rt_kprintf("timer1_callback 函数被执行%d次\n", TmrCb_Cnt1);
	rt_kprintf("滴答定时器的数值=%d\n", tick_num1);
}

/******************************************************************************
* @ 函数名  : timer2_callback
* @ 功  能  : 定时器2回调函数
* @ 参  数  : parameter 外部传入的参数
* @ 返回值  : 无
******************************************************************************/
static void timer2_callback(void *parameter)
{
    
    
		rt_uint32_t tick_num2 = 0;
	
	TmrCb_Cnt2++;
	
	tick_num2 = (rt_uint32_t)rt_tick_get();   // 获取滴答定时器的计数值
	
	rt_kprintf("timer2_callback 函数被执行%d次\n", TmrCb_Cnt2);
	rt_kprintf("滴答定时器的数值=%d\n", tick_num2);
}

int main(void)
{
    
    
	// 硬件初始化和RTT的初始化已经在component.c中的rtthread_startup()完成

	// 创建一个软件定时器
	tmr1 =  rt_timer_create("tmr1",                 // 软件定时器名称       
						timer1_callback,            // 软件定时器超时函数
						RT_NULL,                    // 超时函数参数
						3000,                       // 超时时间
						RT_TIMER_FLAG_ONE_SHOT |   
						RT_TIMER_FLAG_SOFT_TIMER);  // 软件定时器模式,一次模式
					
	
	// 启动定时器
	if(tmr1 != RT_NULL)
		rt_timer_start(tmr1);
							
	// 创建一个软件定时器
	tmr2 =  rt_timer_create("tmr2",                 // 软件定时器名称       
						timer2_callback,            // 软件定时器超时函数
						RT_NULL,                    // 超时函数参数
						1000,                       // 超时时间
						RT_TIMER_FLAG_PERIODIC |   
						RT_TIMER_FLAG_SOFT_TIMER);  // 软件定时器模式,周期模式
					
	
	// 启动定时器
	if(tmr2 != RT_NULL)
		rt_timer_start(tmr2);
}

実験現象

タイマー1タイムアウト機能は1回だけ実行されますが、タイマー2タイムアウト機能は定期的に実行されます。

ここに画像の説明を挿入

おすすめ

転載: blog.csdn.net/weixin_43772810/article/details/124191497