【FreeRTOS】从0到1写内核(总结)

《FreeRTOS 内核实现与应用开发实战—基于STM32》

系统

模型事件响应事件处理特点
轮询主程序主程序(无限大循环)轮询响应事件,轮询处理事件
前后台中断主程序(无限大循环)实时响应事件,轮询处理事件
多任务中断任务实时响应事件,实时处理事件

轮询是没有突发事件,或者是靠轮询速度来响应突发事件,但是可能会忽略掉突发事件
前后台是实时响应了事件,所有事件都会记录,但是处理事件的时候就需要等待时间
多任务是实时响应到事件,立马就解决(任务是并行的,达到同时处理多个任务)

链表

链表虽然看过,但是没用过,然后自己也…,都忘了
链表主要用于多任务的管理,任务延时的管理
在这里插入图片描述

链表结构体

/* 链表结构体定义 */
typedef struct xLIST
{
	UBaseType_t uxNumberOfItems;    /* 链表节点计数器 */
	ListItem_t *  pxIndex;			/* 链表节点索引指针 */
	MiniListItem_t xListEnd;		/* 链表最后一个节点 */
} List_t;

mini节点结构体

/* mini节点结构体定义,作为双向链表的结尾
   因为双向链表是首尾相连的,头即是尾,尾即是头 */
struct xMINI_LIST_ITEM
{
	TickType_t xItemValue;                      /* 辅助值,用于帮助节点做升序排列 */
	struct xLIST_ITEM *  pxNext;                /* 指向链表下一个节点 */
	struct xLIST_ITEM *  pxPrevious;            /* 指向链表前一个节点 */
};
typedef struct xMINI_LIST_ITEM MiniListItem_t;  /* 最小节点数据类型重定义 */

节点结构体

/* 节点结构体定义 */
struct xLIST_ITEM
{
	TickType_t xItemValue;             /* 辅助值,用于帮助节点做顺序排列 */			
	struct xLIST_ITEM *  pxNext;       /* 指向链表下一个节点 */		
	struct xLIST_ITEM *  pxPrevious;   /* 指向链表前一个节点 */	
	void * pvOwner;					   /* 指向拥有该节点的内核对象,通常是TCB */
	void *  pvContainer;		       /* 指向该节点所在的链表 */
};
typedef struct xLIST_ITEM ListItem_t;  /* 节点数据类型重定义 */

函数

void vListInitialise( List_t * const pxList );									//初始化链表根节点
void vListInitialiseItem( ListItem_t * const pxItem );							//初始化节点
void vListInsertEnd( List_t * const pxList, ListItem_t * const pxNewListItem );	//添加到最后
void vListInsert( List_t * const pxList, ListItem_t * const pxNewListItem );	//顺序添加

任务的定义和切换

定义

TaskHandle_t Task1_Handle;
#define TASK1_STACK_SIZE                    128		//128个字=128*4字节=512 byte
StackType_t Task1Stack[TASK1_STACK_SIZE];			//任务运行的空间
TCB_t Task1TCB;

在这里插入图片描述

typedef struct tskTaskControlBlock
{
	volatile StackType_t    *pxTopOfStack;    /* 栈顶 */

	ListItem_t			    xStateListItem;   /* 任务节点 */
    
    StackType_t             *pxStack;         /* 任务栈起始地址 */
	                                          /* 任务名称,字符串形式 */
	char                    pcTaskName[ configMAX_TASK_NAME_LEN ];

    TickType_t xTicksToDelay;			//延时tick
    UBaseType_t			uxPriority;		//优先级
} tskTCB;
typedef tskTCB TCB_t;
就绪列表

就绪列表,用于任务切换使用

实现调度器

任务调度

负责将任务进行调度;什么时候进行任务切换很关键!
配置 PendSV 和 SysTick 的中断优先级为最低。SysTick 和PendSV 都会涉及到系统调度,系统调度的优先级要低于系统的其它硬件中断优先级,即优先相应系统中的外部硬件中断,所以 SysTick 和 PendSV 的中断优先级配置为最低。

SysTick

用于延时计数,判断是否进入任务切换,即触发PendSV

PendSV

用于任务切换

任务切换

需要对上一个任务寄存器进行保存,提取下一个任务的寄存器写入

临界段保护

一旦这部分代码开始执行,则不允许任何中断打断;
FreeRTOS对中断的开和关是通过操作 BASEPRI 寄存器来实现的,即大于等于 BASEPRI 的值的中断会被屏蔽,小于 BASEPRI 的值的中断则不会被屏蔽。这样子的好处就是用户可以设置 BASEPRI 的值来选择性的给一些非常紧急的中断留一条后路。

RTOS特点
FreeRTOS通过操作 BASEPRI 寄存器来实现,可以有选择的给紧急中断留一条后路。
RT-Thread或μC/OS全关,一般临界段的处理时间是比较短的,关了再开其实并没有太大的影响。

空闲任务和阻塞延时

#define configCPU_CLOCK_HZ (( unsigned long ) 25000000)
#define configTICK_RATE_HZ (( TickTypet ) 100)
  1. 如果有具体的硬件,则配置成与硬件的系统时钟一样。
  2. SysTick 每秒中断多少次,目前配置为 100,即每 10ms 中断一次

阻塞延时

任务运行到一定是会,需要延时等待,这时候就可以放弃CPU的使用权,启动任务调度器,也可以说是任务切换的一个控制入口;实际还涉及到优先级、任务延时、时间片
延时通过 【SysTick 中断周期】(可以设置)进行计数,vTaskDelay( 2 )=2*SysTick

空闲任务(启动调度器时就会一并创建)

如果进入到阻塞,并且没有任务就绪,那么CPU就会跑到【空闲任务】,优先级最低的任务;主要用于系统内存的清理工作

优先级

RTOS特点
FreeRTOS数字优先级越小,逻辑优先级也越小
RT-Thread或μC/OS数字优先级越小,逻辑优先级越大

就绪列表

  1. uxReadyPriorities 的每个位号对应的是任务的优先级,任务就绪时,则将对应的位置 1,反之则清零。
  2. 就绪列表 pxReadyTasksLists[ configMAX_PRIORITIES ]是一个数组,数组里面存的是就绪任务的 TCB(准确来说是 TCB 里面的 xStateListItem 节点),数组的下标对应任务的优先级,优先级越低对应的数组下标越小。空闲任务的优先级最低,对应的是下标为 0 的链表。

任务调度

当任务正常运行时,没有其他中断,则进入PendSV,查询就绪列表,进行任务切换

任务延时列表

void vTaskDelay( const TickTypet xTicksToDelay )

  1. 将任务插入延时列表中,更新最近的 xNextTaskUnblockTime

  2. 任务延时到期,将任务插入到就绪列表中,并从延时列表中移除

时间片

RTOS特点
FreeRTOS最小的时间单位为一个 tick,即 SysTick 的中断周期
RT-Thread或μC/OS可以指定时间片的大小为多个 tick,

相同优先级任务之间的切换
当相同优先级任务都就绪时,每一个Tick切换一次

总结

  1. 每个时间片(SysTick 的中断周期)判断是否有任务就绪
  2. 优先级大于或等于当前优先级(就绪情况下),无需等待当前任务遇到阻塞API函数,进行任务切换
  3. 低于当前任务优先级的就绪任务,需要等待任务遇到阻塞API函数
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值