1

私は RTOS の初心者で、C/C++ でのシステム側 (アプリケーション側) プログラミングの経験が数か月あります。しかし、この埋め込みドメインに入ると、いくつかの質問につまずきます。

パラメータをタスクに渡すとはどういう意味ですか? 以下の例がわかりませんでした。

static void TaskEx(void* pData) {
    while (1) {
    OS_Delay ((OS_TIME) pData);
        }
}


void OS_CreateTask ( OS_TASK * pTask,char * pName,unsigned char Priority,voidRoutine * pRoutine,void * pStack,unsigned StackSize,unsigned char TimeSlice );

OS_CreateTask(&TaskMain, NULL, 50, TaskEx, StackMain, sizeof(StackMain), 2);

// ^ これはパラメーターを渡すのではなく、タスクです。

void OS_CreateTaskEx ( OS_TASK * pTask, char * pName, unsigned char Priority, voidRoutine *pRoutine, void * pStack, unsigned StackSize, unsigned char TimeSlice, void * pContext );

OS_CREATETASK_EX(&TCBLP, "LP Task", TaskEx, 50, StackLP, (void*) 200);

// ^ これはパラメータを渡すタスクです。

  • 通常の C プログラミングでスタックを定義することを知っています。しかし、RTOSでは、CPUが実際にスタックとして使用できる領域に存在する必要があると定義したスタックを理解していませんでしたか?
4

2 に答える 2

2

embOSを使用しているようです。RTOSでは、タスクを開始する一般的な方法が2つあります。1つ(「Ex」バリアント)はvoid*、APIで指定したパラメーターを渡します。タスクを開始する別の方法では、パラメーターがタスクに渡されません。

渡すことができるのはvoid*(そのメソッドを選択した場合)だけなので、通常は、構造体にタスクの情報を入力し、その構造体へのポインターをパラメーターとして渡します。これにより、UART I / Oを管理する単一のタスク関数を作成し、特定のUARTインスタンスのI/Oポートを記述する構造体へのポインターを渡すようなことができます。このように、単一の関数は、たとえば、UARTごとに個別のタスクを開始し、それぞれに異なるUART記述子(およびタスクのスタック用の異なるメモリブロック)へのポインタを渡すことによって、デバイス上のすべてのUARTを処理できます。

紛らわしいことに、タスクを開始するためのこれらのメカニズムにはそれぞれ2つのAPIがあります。

  • タスクに提供しているスタック領域のサイズを自動的に把握するマクロ(ポインターではなく配列名をここに渡すか、スタックが小さすぎるように構成することをお勧めします)。
  • スタックサイズを明示的に渡す必要がある非マクロ

あなたが示す小さな例では、タスクが行うのは無限ループで繰り返し遅延することだけです。遅延は、渡されたパラメーター(構造体へのポインターとしてではなく、intとして使用されます)によって指定されます。したがって、各インスタンスに異なる遅延タイムアウトを渡すことで、それぞれが異なる期間遅延する複数のタスクを開始できます。明らかに有用な作業ではありませんが、テクニックを示すことだけを目的としています。

この例を使用するコードは次のようになります。

OS_TASK TCB_Task1;
OS_TASK TCB_Task2;

#define SHORT_DELAY 10
#define LONG_DELAY 1000

unsigned int task1_stack[64];
unsigned int task2_stack[64];

// start a task that delays only for 10ms
OS_CreateTaskEx ( &TCB_Task1, "short delay", 20, &TaskEx,
     &task1_stack, sizeof(task1_stack), 2, (void*)SHORT_DELAY);

// start a task (using same task function) that delays for 1000ms
OS_CreateTaskEx ( &TCB_Task2, "long delay", 20, &TaskEx, 
     &task2_stack, sizeof(task2_stack), 2, (void*)LONG_DELAY);

2番目の質問:

CPUが実際にスタックとして使用できる領域に存在する必要があることをスタックで理解していませんか?

これが意味するのは、一部のマイクロコントローラには、特別な用途がある可能性のある異なるメモリ範囲があるということです。一部のマイクロコントローラーでは、スタックは特定のメモリ範囲でのみ機能します。たとえば、これは8051のスタックを表します。

8ビット8051スタックポインタは、0x08と0xFFの間の内部RAMの部分に制限されていますが、このスペースをすべて使用するには、プログラマは2つのレジスタバンクとビットアドレス可能領域の使用を控える必要があります。したがって、スタックポインタを0x30以上の領域に制限し、192バイトのスタックスペースのみを残すのがより一般的です。

于 2010-12-16T06:30:01.187 に答える
0

一部省略しました。ご覧のとおり、OS_CREATETASK_EXのプロトタイプはなく、OS_CreateTaskExの上のプロトタイプにはさらに多くのパラメーターが必要です。

大文字のものがマクロのようなものであることは明らかです

OS_TASK * pTask、char * pName、unsigned char Priority、voidRoutine * pRoutine、void * pStack、unsigned StackSize、unsigned char TimeSlice、void * pContext);

考えてみると、StackSize(スタックスペースを予約する場所のようです。ただし、argumentVorVoidRoutine * argという名前のパラメーターはありません。pContextだけがあります)がある場合よりも、何も返さない関数へのポインターが必要です。 。これは上記の(void *)200と一致すると思います。

ルーチンが取るパラメータタイプがわからないため、任意のポインタであるvoid*を使用します。整数を取り、それをvoid *にキャストすることについて少し注意したいのですが、それはCです。

RAMの一部の領域をいわゆるスタックに分割できるようです。下の例では、このスタックポインタの名前はStackLPです。実際のコードを見なくても、私たちはまだ仮定することができます...

于 2010-12-16T06:28:44.370 に答える