什么是在 RTOS 中向堆栈传递参数?

发布于 2024-10-08 01:21:13 字数 901 浏览 3 评论 0原文

我是 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实际可以用作堆栈的区域

I'm a newbie to RTOS, 've around few months of experience on System side(Application side) programming in C/C++. But entering into this embedded domain, I'm stumbled by few questions.

What is meant by Passing a parameter to a task ? I didn't understand the below given example.

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);

// ^ This is not passing a parameter is a task.

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);

// ^ This is passing a parameter is a task.

  • I know to define a stack in normal C programming. But in RTOS, I didn't understand by stack that you define has to reside in an area that the CPU can actually use as stack?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

一人独醉 2024-10-15 01:21:13

看起来您正在使用 embOS - 在该 RTOS 中,有两种启动任务的通用方法。其中一种(“Ex”变体)将传递您在 API 中指定的 void* 参数。另一种启动任务的方法不会将参数传递给您的任务。

由于您要传递的只是一个 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);

对于您的第二个问题:

我不明白你定义的堆栈必须驻留在CPU实际可以用作堆栈的区域中?

这意味着某些微控制器具有不同的内存范围,可能有特殊用途。在某些微控制器上,堆栈仅在某些内存范围上工作。例如,这描述了 8051 的堆栈

8 位 8051 堆栈指针仅限于内部 RAM 0x08 和 0xFF 之间的部分,但要使用所有这些空间,程序员必须放弃使用两个寄存器组以及位可寻址区域。因此,比较正常的情况是,将堆栈指针限制在0x30以上的区域,只留下192字节的堆栈空间

It looks like you're using embOS - in that RTOS there are 2 general ways to start a task. One (the 'Ex' variant) will pass a void* parameter you specify in the API. The other way to start a task will not pass a parameter to your task.

Since all you get to pass is a void* (if you chose that method), typically what will happen is you'll populate a structure with information for the task and pass a pointer to that structure as the parameter. This lets you do something like have a single task function that manages UART I/O, and pass a pointer to a structure that describes the I/O ports for a particular UART instance. That way the single function could, for example, handle all UARTs on your device by starting a separate task for each UART, passing a pointer to a different UART descriptor (and a different block of memory for the task's stack) to each.

Confusingly, each of these mechanisms to start a task has 2 APIs:

  • a macro that automatically figures out the size of the stack area you're providing for the task (you had better pass an array name here, and not a pointer or it'll configure a stack that's far too small).
  • a non macro that you have to explicitly pass the stack size with

In the small example you show, all the task does is delay repeatedly in an infinite loop. The delay is specified by the passed parameter (which is used as an int rather than as a pointer to a structure). So, you can start multiple tasks that each delay for different periods of time by passing a different delay timeout to each instance. Obviously not a useful bit of work, but it's intended to just demonstrate the technique.

Some code using this example might look like:

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);

For your second question:

I didn't understand by stack that you define has to reside in an area that the CPU can actually use as stack?

All that is meant by this is that some microcontrollers have different memory ranges that might have special uses. On some microcontrollers, the stack will work only on certain memory ranges. For example, this describes the 8051's stack:

The 8-bit 8051 stack pointer is restricted to the portion of the internal RAM between 0x08 and 0xFF, though to use all of this space the programmer must forego use of two of the register banks and also the bit-addressable area. It is more normal, therefore, to restrict the stack pointer to the region from 0x30 upwards, leaving only 192 bytes of stack space

屌丝范 2024-10-15 01:21:13

你省略了一些部分。正如你所看到的,没有 OS_CREATETASK_EX 的原型
而上面的OS_CreateTaskEx原型需要更多的参数。

很明显,大写的内容是某种 Macro

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。在没有看到实际代码的情况下,我们仍然可以假设......

You omitted some parts. As you can see there is no Prototype for OS_CREATETASK_EX
and the prototy above OS_CreateTaskEx needs more parameters.

It's obvious that the stuff in upper case is some sort of Macro

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

if we look thought it we see:
a pointer to a function returning nothing is required
than we have a StackSize (which seems to be the place for reserving stack space.
there is however no parameter named argumentVorVoidRoutine * arg, the only thing there is pContext. I assume that this will match with the above (void*) 200.

We never will know what parameter type the Routine will take and so we use the void* which can be any pointer. I'd a little bit cautiosu about just taking an integer and cast it to void* but it's C. So well maybe we are supposed to live with it forever ;-)

It seems you can put apart some area of RAM into the so called Stack and in the lower example this Stack pointer is named StackLP. Without seeing the actual code, we still can just assume...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文