freertos简单使用

目录

api

SRAM静态创建: xTaskCreateStatic

动态创建任务

消息队列

信号量(Semaphore)

事件

软件定时器

任务通知

内存管理

中断管理


api

vTaskStartScheduler() 开启任务调度器

taskENTER_CRITICAL(); 进入临界区

taskEXIT_CRITICAL(); 退出临界区

vTaskDelete(AppTaskCreate_Handle); 删除任务 参数:任务句柄

xTaskCreateStatic() sram静态创建任务 详见后面

xTaskCreate() 动态创建任务

vTaskDelete() 删除任务 如果是删除自身, 则形参为 NULL

vTaskDelay() 延时函数 INCLUDE_vTaskDelay置1

vTaskDelayUntil() 绝对延时

vTaskSuspend() 任务挂起 参数:任务句柄

vTaskResume() 任务恢复 参数:任务句柄

xTaskResumeFromISR() 任务恢复 中断中使用 需INCLUDE_vTaskSuspend 和 INCLUDE_vTaskResumeFromISR置1

vTaskSuspendAll() 挂起所有任务

xTaskResumeAll() 恢复所有挂起任务 vTaskSuspendAll() 多少次,他就要多少次

taskYIELD() 任务切换

SRAM静态创建: xTaskCreateStatic

任务必须死循环,阻塞

1 . configSUPPORT_STATIC_ALLOCATION开启

2 .实现vApplicationGetIdleTaskMemory()与 vApplicationGetTimerTaskMemory() 设定的空闲(Idle)任务与定时器(Timer)任务的堆栈大小

 

​
static StackType_t Idle_Task_Stack[configMINIMAL_STACK_SIZE];
static StackType_t Timer_Task_Stack[configTIMER_TASK_STACK_DEPTH];
​
static StaticTask_t Idle_Task_TCB;  
static StaticTask_t Timer_Task_TCB;
​
void vApplicationGetTimerTaskMemory(StaticTask_t **ppxTimerTaskTCBBuffer, 
                                    StackType_t **ppxTimerTaskStackBuffer, 
                                    uint32_t *pulTimerTaskStackSize)
{
    *ppxTimerTaskTCBBuffer=&Timer_Task_TCB;
    *ppxTimerTaskStackBuffer=Timer_Task_Stack;
    *pulTimerTaskStackSize=configTIMER_TASK_STACK_DEPTH;
}
void vApplicationGetIdleTaskMemory(StaticTask_t **ppxIdleTaskTCBBuffer, 
                                   StackType_t **ppxIdleTaskStackBuffer, 
                                   uint32_t *pulIdleTaskStackSize)
{
    *ppxIdleTaskTCBBuffer=&Idle_Task_TCB;
    *ppxIdleTaskStackBuffer=Idle_Task_Stack;
    *pulIdleTaskStackSize=configMINIMAL_STACK_SIZE;
}
​

3.创建任务

static StackType_t AppTaskCreate_Stack[128];
static StaticTask_t AppTaskCreate_TCB;
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);//任务控制块

4.开启任务调度器

vTaskStartScheduler()

动态创建任务

xReturn = xTaskCreate((TaskFunction_t )AppTaskCreate, /* 任务入口函数 */
                    (const char* )"AppTaskCreate",/* 任务名字 */
                    (uint16_t )512, /* 任务栈大小 */
                    (void* )NULL,/* 任务入口函数参数 */
                    (UBaseType_t )1, /* 任务的优先级 */
                    (TaskHandle_t* )&AppTaskCreate_Handle);/* 任务控制块指针 */
 /* 启动任务调度 */
 if (pdPASS == xReturn)
    vTaskStartScheduler(); /* 启动任务,开启调度 */
 else
    return -1;

消息队列

1.创建消息队列 xQueueCreate() xQueueCreateStatic()

 #define QUEUE_LEN 4 /* 队列的长度,最大可包含多少个消息 */
 #define QUEUE_SIZE 4 /* 队列中每个消息大小(字节) */
 QueueHandle_t Test_Queue;
 Test_Queue = xQueueCreate((UBaseType_t ) QUEUE_LEN,/* 消息队列的长度 */ 
                    (UBaseType_t ) QUEUE_SIZE);/* 消息的大小 */ 
 if (NULL != Test_Queue) 
 printf("创建 Test_Queue 消息队列成功!\r\n");
 #define QUEUE_LENGTH 10
 #define ITEM_SIZE sizeof( uint64_t )
 
 /* 该变量用于存储队列的数据结构 */
 static StaticQueue_t xStaticQueue
  /* 该数组作为队列的存储区域,大小至少有 uxQueueLength * uxItemSize 个字节 */
 uint8_t ucQueueStorageArea[ QUEUE_LENGTH * ITEM_SIZE ]; 
xQueue = xQueueCreateStatic( QUEUE_LENGTH, /* 队列深度 */ 
                            ITEM_SIZE, /* 队列数据单元的单位 */ 
                            ucQueueStorageArea,/* 队列的存储区域 */ 
                            &xStaticQueue ); /* 队列的数据结构 */

删除消息队列vQueueDelete()

发送消息xQueueSend()

xReturn = xQueueSend( Test_Queue, /* 消息队列的句柄 */ 
                    &send_data1,/* 发送的消息内容 */ 
                    0 ); /* 等待时间 0 */ 
if (pdPASS == xReturn) 
printf("消息 send_data1 发送成功!\n\n");

接受消息xQueueReceive() xQueuePeek()

xReturn = xQueueReceive( Test_Queue, /* 消息队列的句柄 */ 
                        &r_queue, /* 发送的消息内容 */ 
                         portMAX_DELAY); /* 等待时间 一直等 */ 
 if (pdTRUE== xReturn) 
    printf("本次接收到的数据是:%d\n\n",r_queue); 
 else 
    printf("数据接收出错,错误代码: 0x%lx\n",xReturn);

xQueuePeek() 不会删除消息队列中的消息使用同上

信号量(Semaphore)

信号量释放函数xSemaphoreGive()

信号量获取函数xSemaphoreTake()

信号量删除函数 vSemaphoreDelete()

二值信号量xSemaphoreCreateBinary()

互斥量有优先级继承机制,二值信号量则没有这个机制,这使得二值信号量更偏 向应用于同步功能,用作同步时,信号量在创建后应被置为空

SemaphoreHandle_t BinarySem_Handle =NULL;
BinarySem_Handle = xSemaphoreCreateBinary();
if (NULL != BinarySem_Handle) 
 printf("BinarySem_Handle 二值信号量创建成功!\r\n");
 
 BaseType_t xReturn = pdPASS;/* 定义一个创建信息返回值,默认为 pdPASS */ 
 xReturn = xSemaphoreTake(BinarySem_Handle,/* 二值信号量句柄 */ 
                        portMAX_DELAY); /* 等待时间 */ 
 if (pdTRUE == xReturn) 
     printf("BinarySem_Handle 二值信号量获取成功!\n\n");
 
 
 xReturn = xSemaphoreGive( BinarySem_Handle );//给出二值信号量 
 if ( xReturn == pdTRUE ) 
    printf("BinarySem_Handle 二值信号量释放成功!\r\n"); 
 else 
    printf("BinarySem_Handle 二值信号量释放失败!\r\n"); 

计数信号量xSemaphoreCreateBinary()

 SemaphoreHandle_t CountSem_Handle =NULL; 
CountSem_Handle = xSemaphoreCreateCounting(5,5);//计数信号量的最大值,创建计数信号量的初始值
if (NULL != CountSem_Handle) 
 printf("CountSem_Handle 计数信号量创建成功!\r\n");

互斥信号量xSemaphoreCreateMutex()

是特殊的二值信号量,更适用 于简单互锁,也就是保护临界资源

MuxSem_Handle= xSemaphoreCreateMutex(); 
 
 if (MuxSem_Handle!= NULL ) { 
 /* 互斥量创建成功 */ 
 } 
​

递归信号量xSemaphoreCreateRecursiveMutex()

configSUPPORT_DYNAMIC_ALLOCATION 和 configUSE_RECURSIVE_MUTEXES 均定义 为 1

对于已经获取递归互斥量的任务可以重复获取该递归互斥量,该任务拥有递归信号量的所有权,任务成功获取几次递 归互斥量,就要返还几次,在此之前递归互斥量都处于无效状态,其他任务无法获取,只 有持有递归信号量的任务才能获取与释放。

xMutex = xSemaphoreCreateRecursiveMutex(); 
 
 if ( xMutex != NULL ) { 
 /* 递归互斥量创建成功 */ 
 } 
​

递归互斥量获取函数 xSemaphoreTakeRecursive()

递归互斥量释放函数 xSemaphoreGiveRecursive()

事件

事件是一种实现任务间通信的机制,主要用于实现多任务间的同步,但事件通信只能 是事件类型的通信,无数据传输。与信号量不同的是,它可以实现一对多,多对多的同步。 即一个任务可以等待多个事件的发生:可以是任意一个事件发生时唤醒任务进行事件处理; 也可以是几个事件都发生后才唤醒任务进行事件处理

事件只与任务相关联,事件相互独立,一个 32 位的事件集合(EventBits_t 类型的 变量,实际可用与表示事件的只有 24位),用于标识该任务发生的事件类型,其 中每一位表示一种事件类型(0 表示该事件类型未发生、1 表示该事件类型已经发 生),一共 24 种事件类型。

事件仅用于同步,不提供数据传输功能。

事件无排队性,即多次向任务设置同一事件(如果任务还未来得及读走),等效于 只设置一次。

允许多个任务对同一事件进行读写操作。

支持事件等待超时机制

事件创建函数 xEventGroupCreate()

事件删除函数 vEventGroupDelete()

static EventGroupHandle_t Event_Handle =NULL;
 
 /* 创建 Event_Handle */
 Event_Handle = xEventGroupCreate();
 if (NULL != Event_Handle)
 {
 printf("Event_Handle 事件创建成功!\r\n");
 
 /* 创建成功,可以删除 */ 
 xEventGroupCreate(Event_Handle); 
 } else
 /* 创建失败,应为内存空间不足 */

事件组置位函数xEventGroupSetBits()

#define KEY1_EVENT (0x01 << 0)//设置事件掩码的位 0
xEventGroupSetBits(Event_Handle,KEY1_EVENT); 

等待事件函数 xEventGroupWaitBits()

EventBits_t r_event;
r_event = xEventGroupWaitBits(Event_Handle, /* 事件对象句柄 */ 
             KEY1_EVENT|KEY2_EVENT,/* 接收任务感兴趣的事件 */ 
             pdTRUE, /* 退出时清除事件位 */ 
             pdTRUE, /* 满足感兴趣的所有事件 */ 
             portMAX_DELAY);/* 指定超时事件,一直等 *

软件定时器

软件定时器创建函数 xTimerCreate()

configUSE_TIMERS 和 configSUPPORT_DYNAMIC_ALLOCATION 均 定义为 1

软件定时器在创建成功后是处于休眠状态的,可以使用 xTimerStart()、xTimerReset()、 xTimerStartFromISR() 、 xTimerResetFromISR() 、 xTimerChangePeriod() 和 xTimerChangePeriodFromISR()这些函数将其状态转换为活跃态

static TimerHandle_t Swtmr1_Handle =NULL; /* 软件定时器句柄 */
static TimerHandle_t Swtmr2_Handle =NULL; /* 软件定时器句柄 */
 /* 周期模式的软件定时器 1,定时器周期 1000(tick)*/
 Swtmr1_Handle=xTimerCreate((const char*)"AutoReloadTimer", 
                        (TickType_t)1000,/* 定时器周期 1000(tick) */ 
                        (UBaseType_t)pdTRUE,/* 周期模式 */ 
                        (void* )1,/* 为每个计时器分配一个索引的唯一 ID */ 
                        (TimerCallbackFunction_t)Swtmr1_Callback); /* 回调函数 */ 
 if (Swtmr1_Handle != NULL){
            xTimerStart(Swtmr1_Handle,0); //开启周期定时器
 }
xTimerStop(Swtmr1_Handle,0); //停止软件定时器 
xTimerDelete(Swtmr1_Handle,0); //删除软件定时器 

xTimerStart()

xTimerStop()

xTimerDelete()

任务通知

任务通知可以替代二值信号量、计数信号量、事件组,也可以替代 长度为 1 的队列

二值信号

static TaskHandle_t xTask1 = NULL
xTaskCreate(prvTask1, "Task1", 200, NULL, tskIDLE_PRIORITY, &xTask1);
/* 向 prvTask2()发送一个任务通知,让其退出阻塞状态 */
xTaskNotifyGive( xTask2 );
 
 /* 阻塞在 prvTask2()的任务通知上
 如果没有收到通知,则一直等待*/
 ulTaskNotifyTake( pdTRUE, portMAX_DELAY )

消息

发送

BaseType_t xReturn = pdPASS;/* 定义一个创建信息返回值,默认为 pdPASS */ 
 #if USE_CHAR 
 char test_str1[] = "this is a mail test 1";/* 消息 test1 */ 
 char test_str2[] = "this is a mail test 2";/* 消息 test2 */ 
 #else 
 uint32_t send1 = 1; 
 uint32_t send2 = 2; 
 #endif 
xReturn = xTaskNotify( Receive1_Task_Handle, /*任务句柄*/ 
 #if USE_CHAR 
    (uint32_t)&test_str1, /*发送的数据,最大为 4 字节 */ 
 #else 
    send1, /* 发送的数据,最大为 4 字节 */ 
 #endif 
    eSetValueWithOverwrite );/*覆盖当前通知*/ 
 
 if ( xReturn == pdPASS ) 
 printf("Receive1_Task_Handle 任务通知释放成功!\r\n"); 
 }

接收

xReturn=xTaskNotifyWait(0x0, //进入函数的时候不清除任务 bit 
    ULONG_MAX, //退出函数的时候清除所有的 bit 
             #if USE_CHAR 
                (uint32_t *)&r_char,//保存任务通知值 
            #else 
                &r_num, //保存任务通知值 
            #endif 
                portMAX_DELAY); //阻塞时间 
 if ( pdTRUE == xReturn ) 
 #if USE_CHAR 
 printf("Receive1_Task 任务通知为 %s \n",r_char); 
 #else 
 printf("Receive1_Task 任务通知为 %d \n",r_num); 
 #endif

任务通知代替计数信号量

获取任务通知 ,没获取到则不等待 
 take_num=ulTaskNotifyTake(pdFALSE,0);//
 if (take_num > 0) 
    printf( "KEY1 被按下,成功申请到停车位。当前车位为 %d \n", take_num - 1); 
 else 
     printf( "KEY1 被按下,车位已经没有了。按 KEY2 释放车位\n" );
 
 /* 释放一个任务通知 */ 
 xTaskNotifyGive(Take_Task_Handle);//发送任务通

任务通知代替事件组

 #define KEY1_EVENT (0x01 << 0)//设置事件掩码的位 0 
 #define KEY2_EVENT (0x01 << 1)//设置事件掩码的位 1 
​
xReturn = xTaskNotifyWait(0x0, //进入函数的时候不清除任务 bit 
                         ULONG_MAX, //退出函数的时候清除所有的 bitR 
                        &r_event, //保存任务通知值 
                        portMAX_DELAY); //阻塞时间 
 if ( pdTRUE == xReturn ) { 
 last_event |= r_event; 
 /* 如果接收完成并且正确 */ 
 if (last_event == (KEY1_EVENT|KEY2_EVENT)) { 
 last_event = 0; /* 上一次的事件清零 */ 
 printf ( "Key1 与 Key2 都按下\n"); 
 LED1_TOGGLE; //LED1 反转 
 } else /* 否则就更新事件 */ 
 last_event = r_event; /* 更新上一次触发的事件 */ 
 } 
 
 }
 
 
 xTaskNotify((TaskHandle_t)LED_Task_Handle,//接收任务通知的任务句柄 
                        (uint32_t)KEY1_EVENT, //要触发的事件 
                        (eNotifyAction)eSetBits); //设置任务通知值中的位 
 
 } 
​

内存管理

1 void *pvPortMalloc( size_t xSize ); //内存申请函数

2 void vPortFree( void *pv ); //内存释放函数

3 void vPortInitialiseBlocks( void ); //初始化内存堆函数

4 size_t xPortGetFreeHeapSize( void ); //获取当前未分配的内存堆大小

5 size_t xPortGetMinimumEverFreeHeapSize( void ); //获取未分配的内存堆历史最小值

 uint8_t *Test_Ptr = NULL; 
Test_Ptr = pvPortMalloc(1024);
​
uint32_t g_memsize; 
/* 获取当前内剩余存大小 */ 
g_memsize = xPortGetFreeHeapSize();
​
vPortFree(Test_Ptr); //释放内存 

中断管理

最低优先级 #define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 15

管理的最高优先级 #define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5

可以管理5-15优先级的中断

portDISABLE_INTERRUPTS() 关中断

portENBABLE_INTERRUPTS() 开中断

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值