本文致力于精简的语言介绍,freertos的使用。对于其背后的原理,不做太多的解释。
只针对有一定基础的
只针对有一定基础的
只针对有一定基础的
任务创建与删除
第一节创建任务
创建任务时可以使用2个函数:动态分配内存、静态分配内存。
动态分配内存
xTaskCreate(RTC_Task, "RTCTask", 128, NULL, osPriorityNormal, NULL);
静态分配内存
使用静态分配内存的函数如下:
TaskHandle_t xTaskCreateStatic (
TaskFunction_t pxTaskCode, // 函数指针, 任务函数
const char * const pcName, // 任务的名字
const uint32_t ulStackDepth, // 栈大小,单位为word,10表示40字节
void * const pvParameters, // 调用任务函数时传入的参数
UBaseType_t uxPriority, // 优先级
StackType_t * const puxStackBuffer, // 静态分配的栈,就是一个buffer
StaticTask_t * const pxTaskBuffer // 静态分配的任务结构体的指针,用它来操作这个任务
);
动态与静态区别
静态要其定义一个
StackType_t * const puxStackBuffer, // 静态分配的栈,就是一个buffer
怎么写?
static uint8_t g_pusStackOfLightTask[128*4];
static StaticTask_t g_TCBofLightTask;
/*
其他的省略
*/
xTaskCreateStatic(函数,"任务名",128,NULL,优先级,g_pusStackOfLightTask,&g_TCBofLightTask);
第二节任务的删除
void vTaskDelete( TaskHandle_t xTaskToDelete );
第三节任务优先级
使用uxTaskPriorityGet来获得任务的优先级:
UBaseType_t uxTaskPriorityGet( const TaskHandle_t xTask );
//使用参数xTask来指定任务,设置为NULL表示获取自己的优先级。
使用vTaskPrioritySet 来设置任务的优先级:
void vTaskPrioritySet( TaskHandle_t xTask,
UBaseType_t uxNewPriority );
/*
使用参数xTask来指定任务,设置为NULL表示设置自己的优先级;
参数uxNewPriority 表示新的优先级,取值范围是0~(configMAX_PRIORITIES – 1)。
*/
任务状态
我们可以把任务简单的分为:运行态 和 非运行态。
在非运行态可以分为:
- 阻塞状态(Blocked)
- 暂停状态(Suspended)
- 就绪状态(Ready)
阻塞状态
核心是等待
- 等待一件事情发生(不如中断,写入队列,同步)
- 等待时间(等5s)
暂停状态
进入暂停状态
void vTaskSuspend( TaskHandle_t xTaskToSuspend );
参数xTaskToSuspend 表示要暂停的任务,如果为NULL,表示暂停自己。
退出暂停状态
只能由别人来操作
只能由别人来操作
只能由别人来操作
- 别的任务调用:vTaskResume
- 中断程序调用:xTaskResumeFromISR
就绪状态(Ready)
这个任务完全准备好了,随时可以运行:只是还轮不到它。这时,它就处于就绪态(Ready)
两个Delay 函数
vTaskDelay
至少等待指定个数的Tick Interrupt才能变为就绪状态
void vTaskDelay( const TickType_t xTicksToDelay ); /* xTicksToDelay: 等待多少给Tick */
示例:
vTaskDelay(500)
vTaskDelayUntil
等待到指定的绝对时刻,才能变为就绪态。
/* pxPreviousWakeTime: 上一次被唤醒的时间
* xTimeIncrement: 要阻塞到(pxPreviousWakeTime + xTimeIncrement)
* 单位都是Tick Count
*/
BaseType_t xTaskDelayUntil( TickType_t * const pxPreviousWakeTime,
const TickType_t xTimeIncrement );
示例:
TickType_t xLastWakeTime;
xLastWakeTime = xTaskGetTickCount();
//先获得当前时间
//执行的代码
vTaskDelayUntil( &xLastWakeTime, 1000);
同步互斥与通信
不想介绍概念了
实现同步互斥的内核方法
- 任务通知(task notification)
- 队列(queue)
- 事件组 (event group)
- 信号量(semaphoe)
- 互斥量(mutex)。
队列(queue)
大家应该都知道队列是啥吧?
我们直接开整!!!
队列函数
动态创建
QueueHandle_t xQueueCreate( UBaseType_t uxQueueLength, UBaseType_t uxItemSize );
示例:
QueueHandle_t Test_Queue;
struct input_data
{
uint32_t del;
uint16_t val;
};
/* 创建Test_Queue */
Test_Queue = xQueueCreate(10,sizeof(struct input_data));
if(NULL != Test_Queue)
printf("创建Test_Queue消息队列成功!\r\n");
静态创建
QueueHandle_t xQueueCreateStatic(
UBaseType_t uxQueueLength,
UBaseType_t uxItemSize,
uint8_t *pucQueueStorageBuffer,
StaticQueue_t *pxQueueBuffer
);
示例代码:
// 示例代码
#define QUEUE_LENGTH 10
#define ITEM_SIZE sizeof( uint32_t )
// xQueueBuffer用来保存队列结构体
StaticQueue_t xQueueBuffer;
// ucQueueStorage 用来保存队列的数据
// 大小为:队列长度 * 数据大小
uint8_t ucQueueStorage[ QUEUE_LENGTH * ITEM_SIZE ];
void vATask( void *pvParameters )
{
QueueHandle_t xQueue1;
// 创建队列: 可以容纳QUEUE_LENGTH个数据,每个数据大小是ITEM_SIZE
xQueue1 = xQueueCreateStatic( QUEUE_LENGTH,
ITEM_SIZE,
ucQueueStorage,
&xQueueBuffer );
}
复位
队列刚被创建时,里面没有数据;使用过程中可以调用xQueueReset()把队列恢复为 初始状态,此函数原型为:
/* pxQueue : 复位哪个队列;
* 返回值: pdPASS(必定成功)
*/
BaseType_t xQueueReset( QueueHandle_t pxQueue);
删除
删除队列的函数为vQueueDelete(),只能删除使用动态方法创建的队列,它会释放内 存。原型如下:
void vQueueDelete( QueueHandle_t xQueue );
写队列
可以把数据写到队列头部,也可以写到尾部,这些函数有两个版本:在任务中使用、在 ISR中使用。
往队列尾部写入数据
任务中使用
/*
等同于xQueueSend
* 往队列尾部写入数据,如果没有空间,阻塞时间为xTicksToWait
*/
BaseType_t xQueueSendToBack(
QueueHandle_t xQueue,
const void *pvItemToQueue,
TickType_t xTicksToWait
);
中断中使用
/*
* 往队列尾部写入数据,此函数可以在中断函数中使用,不可阻塞
*/
BaseType_t xQueueSendToBackFromISR(
QueueHandle_t xQueue,
const void *pvItemToQueue,
BaseType_t *pxHigherPriorityTaskWoken
);
往队列头部写入数据
任务中使用
*
* 往队列头部写入数据,如果没有空间,阻塞时间为xTicksToWait
*/
BaseType_t xQueueSendToFront(
QueueHandle_t xQueue,
const void *pvItemToQueue,
TickType_t xTicksToWait
);
中断中使用
/*
* 往队列头部写入数据,此函数可以在中断函数中使用,不可阻塞
*/
BaseType_t xQueueSendToFrontFromISR(
QueueHandle_t xQueue,
const void *pvItemToQueue,
BaseType_t *pxHigherPriorityTaskWoken
);
示例:
extern QueueHandle_t Test_Queue;
struct input_data idata;
BaseType_t xReturn = pdPASS;/* 定义一个创建信息返回值,默认为pdPASS */
idata.dev=0;
idata.val=0;
xReturn=xQueueSend(Test_Queue,&idata,0);
if(pdPASS == xReturn)
printf("消息send_data1发送成功!\n\n");
读队列
使用xQueueReceive()函数读队列,读到一个数据后,队列中该数据会被移除。这个 函数有两个版本:在任务中使用、在ISR中使用。
在任务中使用
BaseType_t xQueueReceive( QueueHandle_t xQueue,
void * const pvBuffer,
TickType_t xTicksToWait );
在ISR中使用
BaseType_t xQueueReceiveFromISR(
QueueHandle_t xQueue,
void *pvBuffer,
BaseType_t *pxTaskWoken
);
示例:
xReturn = xQueueReceive( Test_Queue, /* 消息队列的句柄 */
&i_data, /* 发送的消息内容 */
portMAX_DELAY); /* 等待时间 一直等 */
if(pdTRUE == xReturn)
printf("本次接收到的数据是%d\n\n",r_queue);
else
printf("数据接收出错,错误代码0x%lx\n",xReturn);