freertos手册_Freertos操作系统基础篇【第一篇】

1、为啥使用Freertos操作系统

还没有说明为啥使用Freertos操作系统啊,市面上那么多操作系统Linux、uCOS、VxWorks…等等,其实有一块linux开发板,嫌弃接线太多了,每次准备大半天,懒得弄它了,等以后有空余地方了在弄它吧….后来就买了块stm32C8T6最小板,一个最小板,一个下载器,加一个串口线,搞定了,后来查了查学哪个操作系统时候发现Freertos啥啥简单啥的,文件少啊占用RAM小啊啥的,突然看到免费!!!,嗯嗯…就是它了。

最开始接触嵌入式时候,我使用的是51单片机进行裸机开发,一般都是在主函数main里面用while(1)做个大循环来完成所有的任务处理,有时候也需要一些中断来完成一些处理操作。这相对于多任务系统而言,就是所谓的单任务系统,也叫做前后台程序,中断函数为前台程序,大循环为后台程序。如图1所示。前后台程序实时性比较差,所有任务都是轮流执行,无论任务模块多么重要,只有没有轮到你,你就得乖乖的等着。但是前后台程序简单啊,资源消耗少啊,这就是它十足的优点。但是随着项目越来越复杂,应用程序越来越大,前后台程序就会慢慢的显得力不从心了。此时多任务系统的优势就会慢慢的体现出来了。

8cf5e2e8825e4550414c1a4061eb980a.png

图 1 前后台程序

  多任务系统会将大任务化小任务,大事化小,小的就各个击破,从而将大任务解决。各个小任务是“并行”执行的,之所以加引号是因为看上去是同一时刻执行了好多任务似的,实际上CPU在任意时刻只能执行单一任务,而每个任务执行时间又很短,所以导致看上去像每一时刻执行了多个任务一样。多任务系统将会面临一个新的问题,将大任务分解成那么多小任务,这些小任务执行顺序怎么决定啊,哪个先执行,哪个后执行?完成这个功能的便是操作系统的“大脑——任务调度器,不同的操作系统任务的任务调度器实现的方法是不一样的,Freertos 的任务调度器是抢占式的,如图2 所示

a34326eb44baca404b8ad02ea2292809.png

图 2 抢占式多任务系统

2、Freertos操作系统任务状态

       Freertos操作系统主要有运行态、就绪态、挂起态和阻塞态,相关状态之间转换如图3所示。

  • 运行态:当一个任务正在运行时,那么它便处于运行态,处于运行态的任务就是当前正在使用CPU的任务,stm32C8T6单片机是单核的,那么任意时刻只有一个任务处于运行态。

  • 就绪态:处在就绪态的任务就是那些已经准备好运行的任务(没有被挂起或阻塞),为啥它没有运行呢,因为CPU此时被同一优先级或更高优先级占用着。

  • 阻塞态:一个任务正在等待某个外部事件的话就说它处于阻塞态,例如调用vTaskDelay函数就会进入阻塞态,直到延时结束,任务在等待队列、信号量、事件组、通知或互斥信号量时也会进入阻塞态,任务进入阻塞态后会有个延时时间,当时间超过这个延时时间就会退出阻塞态,即使等待的事件没有到来。

  • 挂起态;任务被挂起后调度器不能被调度器调用进入运行态,但是挂起态没有超时,任务挂起和任务退出挂起用vTaskSuspend和vTaskResume函数,后面使用时会详细介绍。

Freertos官网https://www.freertos.org/上有本开发手册《FreeRTOS_Reference_Manual_V10.0.0》讲解了Freertos操作系统中的API函数。具体使用在开发手册中有详细介绍。

c607414b8408c861404eff1d83c56dc1.png

图3 Freertos操作系统任务状态

3、Freetos创建第一个任务

  创建第一个任务是需要使用到的函数主要有xTaskCreate(动态创建任务),vTaskDelay, vTaskStartScheduler。

创建任务函数:

1BaseType_t xTaskCreate(     2                  TaskFunction_tpxTaskCode,3                  const char * constpcName,4                   constconfigSTACK_DEPTH_TYPE usStackDepth,5                    void* const pvParameters,6                    UBaseType_tuxPriority,7                    TaskHandle_t* const pxCreatedTask )8

参数:

  • pxTaskCode:指向的是需要执行某个特定任务的C语言函数的指针,即任务函数的函数名,需要特殊说明的是该任务函数是个无限循环的函数,不要用return等返回,不需要执行该任务时候有其他方式,以后会说到。

  • pcName:任务的描述名称,方便调试,这里不做过多解释,需要说明一点名字的长度不能超过configMAX_TASK_NAME_LEN定义的字符串的最大长度。

  • usStackDepth:任务的堆栈,每个任务都有自己唯一的堆栈,在创建任务时,告诉内核自己的堆栈多大,然后内核给该任务分配堆栈。需要注意的是内核实际分配给任务的堆栈是usStackDepth的四倍。

  • pvParameters:需要传递给任务的参数,若不需要传递参数时,设置为NULL。

  • uxPriority:任务的优先级,该任务在整个项目所有任务中执行的次序,   其数值可以从0~ (configMAX_PRIORITIES– 1),数值越大,优先级越高。

  • pxCreatedTask:该任务的句柄,该句柄可以被其他API函数使用,若不需要该任务句柄,设置为NULL。

返回值:

pdPASS:任务创建成功;

errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY:显示没有足够的堆栈空间创建任务;

延时函数:

void vTaskDelay(TickType_t xTicksToDelay ):函数设置任务的延时时间,当使用该延时函数时,该任务阻塞,直到延时结束。

参数:xTicksToDelay延时时间参数

任务调度函数:

voidvTaskStartScheduler( void ):开启Freertos任务调度器。

4、测试

   创建两个任务分别打印任务调用次数,测试代码如下:

 1#include "delay.h"
2#include "USART.h"
3#include "led.h"
4#include "key.h"
5//操作系统
6#include "FreeRTOS.h"
7#include "task.h"
8#include "queue.h"
9
10/***************函数声明区*******************/
11
12#define START_TASK_PRIO 1
13#define START_STK_SIZE  128  
14TaskHandle_t StartTask_Handler;
15void start_task(void *pvParameters);
16
17
18#define TASK1_TASK_PRIO 2 
19#define TASK1_STK_SIZE  128  
20TaskHandle_t Task1Task_Handler;
21void task1_task(void *pvParameters);
22
23
24#define TASK2_TASK_PRIO 3 
25#define TASK2_STK_SIZE  128  
26TaskHandle_t Task2Task_Handler;
27void task2_task(void *pvParameters);
28
29/*************************************************/
30int main(void)31{
32/*驱动相关初始化*/
33NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4); 
34delay_init();
35LED_Init();
36USART1_Config(); 
37KEY_Init();
38/*************UserFunction*********************/
39    xTaskCreate((TaskFunction_t )start_task,            
40                (const char*    )"start_task",          
41                (uint16_t       )START_STK_SIZE,       
42                (void*          )NULL,              
43                (UBaseType_t    )START_TASK_PRIO,       
44                (TaskHandle_t*  )&StartTask_Handler);               
45    vTaskStartScheduler();          
46}
47
48void start_task(void *pvParameters)49{
50
51    xTaskCreate((TaskFunction_t )task1_task,             
52                (const char*    )"task1_task",           
53                (uint16_t       )TASK1_STK_SIZE,        
54                (void*          )NULL,                  
55                (UBaseType_t    )TASK1_TASK_PRIO,        
56                (TaskHandle_t*  )&Task1Task_Handler);   
57
58    xTaskCreate((TaskFunction_t )task2_task,     
59                (const char*    )"task2_task",   
60                (uint16_t       )TASK2_STK_SIZE,
61                (void*          )NULL,
62                (UBaseType_t    )TASK2_TASK_PRIO,
63                (TaskHandle_t*  )&Task2Task_Handler); 
64    vTaskDelete(StartTask_Handler); 
65}
66
67//task1
68void task1_task(void *pvParameters)69{
70uint8_t  n=0;
71while(1)
72{
73    n++;
74    printf("task1.......%d\r\n",n);
75    vTaskDelay(1000);  
76}
77}
78
79//task2
80void task2_task(void *pvParameters)81{
82      uint8_t i=0;
83while(1)
84{
85    i++;
86    printf("task2.......%d\r\n",i);
87            vTaskDelay(1000);                           
88}
89}

测试结果如下:

为啥任务2先输出嘞?因为任务2优先级高于任务1,所以任务二首先输入打印次数。

eff9effba0e6c0e7806c0b59a32d63cd.png

  有没有小伙伴好奇为啥单片机中能够调用prinf(“*****%d\n\r”),下一篇会告诉你哦~

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值