创建任务
创建 静态任务 和 动态任务
如果要求系统稳定(军工产品之类的)则利用静态任务创建函数;
如果一般的工业要求则可以利用动态创建任务函数,效率高
静态任务 xTaskCreateStatic():
创建静态任务需要在全局变量中定义的东西很多:
1.任务栈(Stack):用于存任务的一些变量、参数等数据
2.任务控制块(TCB):相当于任务的身份证,控制块结构体中含有节点,可以挂在链表中;
链表可以指的是 任务就绪列表、任务阻塞列表等等
3.任务句柄(Handle):创建任务后 create函数返回的数值用句柄来接。
AppTaskCreate_Handle = xTaskCreateStatic((TaskFunction_t)AppTaskCreate,//任务函数
(const char*)"AppTaskCreate",//任务名称
(uint32_t)128, //任务堆栈大小
(void*)NULL,//传递给任务函数的参数
(UBaseType_t)3,//任务优先级
(StackType_t*)AppTaskCreate_Stack,//任务堆栈
(StaticTask_t*)&AppTaskCreate_TCB); //任务控制块
if(NULL != AppTaskCreate_Handle)/* 创建成功 */
vTaskStartScheduler(); /* 启动任务,开启调度 */
动态任务xTaskCreate():
创建之前只需要创建一个:
1.任务句柄:用于函数参数
xReturn = xTaskCreate((TaskFunction_t )AppTaskCreate, /* 任务入口函数 */
(const char* )"AppTaskCreate",/* 任务名字 */
(uint16_t )512, /* 任务栈大小 */
(void* )NULL,/* 任务入口函数参数 */
(UBaseType_t )1, /* 任务的优先级 */
(TaskHandle_t* )&AppTaskCreate_Handle);/* 任务控制块指针 */
/* 启动任务调度 */
if(pdPASS == xReturn)
vTaskStartScheduler(); /* 启动任务,开启调度 */
动态和静态的差别:
1.全局变量参数创建
1.静态在全局变量中要创建好 1.任务栈 2.任务控制块 3.任务句柄 等各个参数
2.而动态创建函数只需要创建好1.任务句柄。
2.返回函数不同
1.静态:返回的是 任务控制块指针:也就是任务句柄
2.动态:返回的是 信息返回值 在mian函数中创建。
3.形参不一样
自己对比一下。
消息队列、信号量、互斥量
1. 消息队列:
可以传递某些消息 创建时首先定义消息队列的长度和大小还有消息队列句柄
/* 创建Test_Queue */
Test_Queue = xQueueCreate((UBaseType_t ) QUEUE_LEN,/* 消息队列的长度 */
(UBaseType_t ) QUEUE_SIZE);/* 消息的大小 */
消息队列的长度和大小与发送接收的阻塞有关
1.消息队列发送函数:
uint32_t send_data4 = 4;
xReturn = xQueueSend( Test_Queue, /* 消息队列的句柄 */
&send_data4,/* 发送的消息内容 */
0 ); /* 等待时间 0 */
发送时:等待时间为 如果队列已满则等待,0则不等待直接返回队列已满。
2.消息队列接收函数:
uint32_t r_queue; /* 定义一个接收消息的变量 */
xReturn = xQueueReceive( Test_Queue, /* 消息队列的句柄 */
&r_queue, /* 发送的消息内容 */
portMAX_DELAY); /* 等待时间 一直等 */
if(pdTRUE == xReturn)
printf("本次接收到的数据是%d\n\n",r_queue);
else
printf("数据接收出错,错误代码0x%lx\n",xReturn);
接收时:等待时间为 消息队列为空时 ,portMAX_DELAY为一直等待 直到有数据时才进行接收。
2.信号量(可以理解为消息队列的简化版 ):
信号量的 xSemaphoreTake() = 消息队列的 xQueueReceive()
信号量的 xSemaphoreGive() = 消息队列的 xQueueSend()
1.二值信号量:(主要用于同步)
二值信号量主要用于同步信号
1.创建二值信号量:(要先创建二值信号量句柄)
BinarySem_Handle = xSemaphoreCreateBinary();
2.二值信号量的接收:xSemaphoreTake()(+ISR在中断使用)
//获取二值信号量 xSemaphore,没获取到则一直等待
xReturn = xSemaphoreTake(BinarySem_Handle,/* 二值信号量句柄 */
portMAX_DELAY); /* 等待时间 */
if(pdTRUE == xReturn)
printf("BinarySem_Handle二值信号量获取成功!\n\n");
如果没有接收到则一直等待,任务出于堵塞状态,接收到后,任务执行。
3.二值信号量的发送:xSemaphoreGive()(+ISR在中断使用)
xReturn = xSemaphoreGive( BinarySem_Handle );//给出二值信号量
if( xReturn == pdTRUE )
printf("BinarySem_Handle二值信号量释放成功!\r\n");
else
printf("BinarySem_Handle二值信号量释放失败!\r\n");
}
2.计数信号量(give(释放)相当于+1,take(获取)相当于-1)
用于计数之类的吧!
1.创建计数信号量:
/* 创建Test_Queue */
CountSem_Handle = xSemaphoreCreateCounting(5,5);
xSemaphoreCreateCounting( uxMaxCount, uxInitialCount )
第一个参数是 总共的计数数值, 第二是初始化多少个计数值
2.释放(发送/获取)一个计数信号量(give 相当于+1)
/* 获取一个计数信号量 */
xReturn = xSemaphoreGive(CountSem_Handle);//给出计数信号量
if ( pdTRUE == xReturn )
printf( "KEY2被按下,释放1个停车位。\n" );
else
printf( "KEY2被按下,但已无车位可以释放!\n" );
3.接收(获取)一个计数信号量(take相当于 -1)
/* 获取一个计数信号量 */
xReturn = xSemaphoreTake(CountSem_Handle, /* 计数信号量句柄 */
0); /* 等待时间:0 */
if ( pdTRUE == xReturn )
printf( "KEY1被按下,成功申请到停车位。\n" );
else
printf( "KEY1被按下,不好意思,现在停车场已满!\n" );
3. 二值信号量与计数信号量的异同:
相同:
1.两个函数的 接收和发送信号量的函数相同均是xSemaphoreTake() 和 xSemaphoreGive()。
不同:
1.创建函数不同。
2.形参不同
4.互斥量(有个递归的互斥量我不太懂 所以这里不做分析)
讲解
互斥量主要是有 任务优先级继承机制
消息队列和信号量,会容易导致优先级翻转机制,使得处理更高级任务没那么及时。
互斥量需要自己接收后自己释放,有占有权
互斥量创建函数 xSemaphoreCreateMutex()
/* 创建MuxSem */
MuxSem_Handle = xSemaphoreCreateMutex();
释放互斥量 xSemaphoreGive()
xReturn = xSemaphoreGive( MuxSem_Handle );//给出互斥量.
获取互斥量xSemaphoreTake()
//获取互斥量 MuxSem,没获取到则一直等待
xReturn = xSemaphoreTake(MuxSem_Handle,/* 互斥量句柄 */
portMAX_DELAY); /* 等待时间 */
互斥量与二值信号量的区别:
1.互斥信号量需要 先take获取到了 再自己释放give,释放后,再通过高优先级任务的take获得。
计数信号量 是 先释放give后,再同步获取take到,并且可以再任何任务中释放give。
2.互斥量油优先级继承机制而 二值信号量会有优先级翻转现象。
翻转现象主要表现在 如果低优先级和高优先级的任务是获取同一个二值信号量,低优先级的先获取到了则会先运行低优先级的,在运行低优先级任务时可能会被中间优先级的抢占,高优先级的任务不能运行。
事件(如果说信号量是一对一则事件则是一对多)
信号量可能只能一个任务释放一个信号量 一个任务接收。
而事件则是可以 几个任务释放几个信号量, 再一个任务进行接收。