FreeRTOSFreeRTOS学习笔记(10)— FreeRTOS的osThreadDef创建任务(CMSIS_API)
Posted 果果小师弟
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了FreeRTOSFreeRTOS学习笔记(10)— FreeRTOS的osThreadDef创建任务(CMSIS_API)相关的知识,希望对你有一定的参考价值。
一、osThreadDef是一个宏定义
#define osThreadDef(name, thread, priority, instances, stacksz) \\
const osThreadDef_t os_thread_def_##name = \\
{ #name, (thread), (priority), (instances), (stacksz), NULL, NULL }
所以
osThreadDef(defaultTask, StartDefaultTask, osPriorityNormal, 0, 128);
//相当于
const osThreadDef_t os_thread_def_defaultTask = { "defaultTask", (StartDefaultTask), (osPriorityNormal), (0), (128) }
相当于定义了一个结构体类型为osThreadDef_t
的结构体常量os_thread_def_defaultTask
常量,并且赋值。
宏定义中,##的作用就是把2个宏参数连接为1个数,或实现字符串的连接。
#的作用就是将#后面的宏参数进行字符串的操作,也就是将#后面的参数两边加上一对双引号使其成为字符串。
osThreadDef_t
是一个结构体定义,记住在单片机的库函数中一般变量名后缀是_t
结尾的都是一个结构体。
在这个结构体中
typedef struct os_thread_def {
char *name; //线程名,字符串止指针类型
os_pthread pthread; //线程函数的起始地址,函数指针
osPriority tpriority; //初始化线程优先级,结构体类型
uint32_t instances; //该线程函数的最大实例数,一般为0
uint32_t stacksize; //堆栈大小要求(字节);0是默认堆栈大小
#if( configSUPPORT_STATIC_ALLOCATION == 1 )
uint32_t *buffer; //用于静态分配的堆栈缓冲区;动态分配为空
osStaticThreadDef_t *controlblock; //控制块,用于保存用于静态分配的线程数据;动态分配为空
#endif
} osThreadDef_t;
解释:使用typedef将结构体os_thread_def
取一个osThreadDef_t
的别名,以后就用osThreadDef_t
代替结构体os_thread_def
。当使用动态创建函数也就是采用动态内存分配时有5个成员变量,当使用静态创建函数也就是采用动态内存分配时有7个成员变量。一般在工程应用中采用动态内存分配,简单一些,不用自己设置堆栈大小和控制块。
-
*name:指定一个名字,比如指定为 defaultTask。在定义结构体变量时,会使用##(连接符) 自动在 defaultTask 前面加os_thread_def_前缀,最终的结构体变量名为 os_thread_def_defaultTask。
-
hread:指定线程函数,创建线程时该函数就会被注册为线程函数,运行线程时就是在执行线程函数的代码,不过如果以普通方式来调用线程函数的话,线程函数就是一个普通的函数。线程函数的格式是固定的,为
void 函数名(void const * 参数名)
,函数名和参数名可以自己定,但是返回值和参数的类型必须是void
和void const *
。宏的第二个参数thread
就应该写为 StartDefaultTask。
疑问:谁会传递参数给线程函数?
答:后面讲 osThreadCreate 函数时再介绍。 -
priority:指定线程的优先级。
有关线程优先级,后面讲枚举类型osPiority
时会详细介绍,一般的话会指定为普通优
先级osPriorityNormal
即可。 -
instances:线程实例
0:表示 osThreadDef 宏所定义的结构体变量(数据结构)只能用来创建一个线程(线程实例)
其它值>0 的值:比如 3,表示使用该数据结构可以创建 3 个线程,这三个线程使用的都是相同的线程函数,后面会具体举例。
疑问:一个线程函数可以被多个线程使用吗?
答:当然可以,虽然几个线程所用的线程函数都是一样的,但是各自运行各自的,互不
干扰。 -
stacksz:指定线程栈的大小
一般指定为 128 字节就够了。由于线程栈比较小,因此当线程函数要使用很大的数组时,最好定义为全局变量或者动态开辟在堆中,否者可能会导致线程栈的空间不够用。
函数指针 void (*os_pthread)
typedef void (*os_pthread) (void const *argument);
结构体 osPriority
typedef enum {
osPriorityIdle = -3, ///< priority: idle (lowest)
osPriorityLow = -2, ///< priority: low
osPriorityBelowNormal = -1, ///< priority: below normal
osPriorityNormal = 0, ///< priority: normal (default)
osPriorityAboveNormal = +1, ///< priority: above normal
osPriorityHigh = +2, ///< priority: high
osPriorityRealtime = +3, ///< priority: realtime (highest)
osPriorityError = 0x84 ///< system cannot determine priority or thread has illegal priority
} osPriority;
二、osThreadCreate创建任务
在前面的案例中使用osThreadDef
宏定义了一个结构体变量,变量最终的名字为os_thread_def_defaultTask
,创建任务(线程)时会使用该结构体变量,但是我们在使用 osThreadDef
宏时所指定的名字叫defaultTask
,因此需要在前面加os_thread_def_
前缀,以构建出完整的名字,然后才能访问该结构体变量。
osThread
的作用即是在前面加os_thread_def_
前缀并加上取地址符&
,表示对结构体变进行取地址。
defaultTaskHandle = osThreadCreate(osThread(defaultTask), NULL);
其中的参数osThread(defaultTask)
也是一个宏定义。
所以
defaultTaskHandle = osThreadCreate(osThread(defaultTask), NULL);
相当于
defaultTaskHandle = osThreadCreate(os_thread_def_defaultTask, NULL);
其中osThreadCreate
函数定义如下
osThreadId osThreadCreate (const osThreadDef_t *thread_def, void *argument)
{
TaskHandle_t handle;
if (xTaskCreate((TaskFunction_t)thread_def->pthread,
(const portCHAR *)thread_def->name,
thread_def->stacksize, argument,
makeFreeRtosPriority(thread_def->tpriority),&handle)
!= pdPASS)
{
return NULL;
}
return handle;
}
函数原型
osThreadId osThreadCreate (const osThreadDef_t *thread_def, void *argument)
功能:使用 osThreadDef 宏所定义的结构体变量来创建一个线程。创建好线程后,然后进入 READY 状态,等待任务管理来调度运行。
参数
-
参数 1:指定
osThreadDef
所定义结构体变量的指针,通过该指针即可访问结构体变量,然后使用里面的信息来创建线程。由于结构体变量名字的前面有一个os_thread_def_
前缀,所以需要使用osThread
宏来添加前缀,如果指定的名字为task1
的话,第一个参数应该写为osThread(task1)
,进行宏替换后的最终效果为&os_thread_def_task1
。实际上我们完全可以将第一个参数直接写为&os_thread_def_task1
,不过使用osThread
宏显然会更方便一些。 -
参数 2:传递给线程函数的参数。线程函数的参数 argument 的值就来自于这里,如果没有什么参数要传递的,就设置为NULL。
返回值:
- 函数调用成功就返回唯一标识线程的线程 ID(句柄),如果失败就返回 NULL。
其中优先级还要经过计算才得到
如果想直接用数字定义优先级,可以通过修改以下2处实现
osThreadDef(defaultTask, StartDefaultTask, osPriorityNormal, 0, 128);
defaultTaskHandle = osThreadCreate(osThread(defaultTask), NULL);
相当于
const osThreadDef_t os_thread_def_defaultTask = { "defaultTask", (StartDefaultTask), (osPriorityNormal), (0), (128) }
defaultTaskHandle = osThreadCreate(os_thread_def_defaultTask, NULL);
以上是关于FreeRTOSFreeRTOS学习笔记(10)— FreeRTOS的osThreadDef创建任务(CMSIS_API)的主要内容,如果未能解决你的问题,请参考以下文章
FreeRTOSFreeRTOS学习笔记— 手写FreeRTOS双向链表/源码分析
FreeRTOSFreeRTOS学习笔记— 开始创建任务并测试任务代码
FreeRTOSFreeRTOS学习笔记— 学习FreeRTOS的编程风格和本质
FreeRTOSFreeRTOS学习笔记— 任务创建删除挂起和恢复