什么是在 RTOS 中向堆栈传递参数?
我是 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
看起来您正在使用 embOS - 在该 RTOS 中,有两种启动任务的通用方法。其中一种(“Ex”变体)将传递您在 API 中指定的
void*
参数。另一种启动任务的方法不会将参数传递给您的任务。由于您要传递的只是一个
void*
(如果您选择该方法),通常会发生的情况是您将使用任务信息填充一个结构,并将一个指向该结构的指针作为范围。这使您可以执行一些操作,例如使用单个任务函数来管理 UART I/O,并将指针传递到描述特定 UART 实例的 I/O 端口的结构。这样,单个函数就可以处理设备上的所有 UART,方法是为每个 UART 启动一个单独的任务,将指向不同 UART 描述符(以及任务堆栈的不同内存块)的指针传递给每个任务。令人困惑的是,这些启动任务的机制都有 2 个 API:
在您显示的小示例中,所有任务所做的都是在无限循环中重复延迟。延迟由传递的参数指定(用作 int 而不是指向结构的指针)。因此,您可以通过向每个实例传递不同的延迟超时来启动多个任务,每个任务延迟不同的时间段。显然这不是一个有用的工作,但它只是为了演示该技术。
使用此示例的一些代码可能如下所示:
对于您的第二个问题:
这意味着某些微控制器具有不同的内存范围,可能有特殊用途。在某些微控制器上,堆栈仅在某些内存范围上工作。例如,这描述了 8051 的堆栈:
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:
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:
For your second question:
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:
你省略了一些部分。正如你所看到的,没有 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...