FreeRTOS 常用函数详解


提示:此内容涉及部分汇编+数据结构+计算机操作系统


FreeRTOS调度机制

优先级与状态

  • 优先级不同
    • 高优先级的任务,优先执行,可以抢占低优先级的任务
    • 高优先级的任务不停止,低优先级的任务永远无法执行
    • 同等优先级的任务,轮流执行:时间片轮转
  • 状态

不同的状态通过对应的链表来管理

  • 运行态:running
  • 就绪态:ready
  • 阻塞:blocked,等待某件事(时间、事件)
  • 暂停:suspend,休息去了
  • 怎么管理?
    • 怎么取出要运行的任务?
      • 找到最高优先级的运行态、就绪态任务,运行它
      • 如果大家平级,轮流执行:排队,链表前面的先运行,运行1个tick后乖乖地去链表尾部排队

调度方法:TICK中断

如果优先级为0 则需要注意空闲任务

FreeRTOS调度链表

相关函数

一、xTaskCreate 创建任务相关

作用为:

  1. 分配TCB结构体
  2. 分配栈区 在栈区
  3. 写入的函数地址和参数

xTaskCreate:函数原型:

BaseType_t xTaskCreate(
            	

               TaskFunction_t pxTaskCode,//任务函数
   		        const char * const pcName,//任务名字		
   		        const configSTACK_DEPTH_TYPE usStackDepth,//栈大小 (用来保护寄存器的值)
   		        void * const pvParameters,//传递给任务函数的参数(就是传给第一行的任务函数)
   		        UBaseType_t uxPriority,//任务优先级
   		        TaskHandle_t * const pxCreatedTask//TCB结构体 (传出的函数)

		        //TCB 任务控制块
                   )

任务控制块结构体 tskTaskControlBlock。

在FreeRTOS中,任务的执行是由系统调度的。系统为每个任务都定义了一个任务控制块,这个任务控制块里面存有任务的所有信息,如任务的栈指针,任务名称,任务的形参等。系统对任务的全部操作都可以通过这个任务控制块来实现。任务控制块结构体:

   为什么任务控制块中没有看到 :函数指针以及传入给函数的参数 
   因为栈中  R15:PC会保存函数指针 R0:会保存函数参数 以便下次调用时使用

函数原型:tskTaskControlBlock

typedef struct tskTaskControlBlock
{
	volatile StackType_t	*pxTopOfStack;	/*< Points to the location of the last item placed on the tasks stack.  THIS MUST BE THE FIRST MEMBER OF THE TCB STRUCT. */
  //pxTopOfStack指向栈顶 此栈顶的值由 是由PC寄存器 赋给RO寄存器 函数就会开始执行
  //PC寄存器保存的就是函数地址

	ListItem_t			xStateListItem;	//<任务的状态列表项被引用的列表表示该任务的状态(Ready, Blocked, Suspended)。* /


	ListItem_t			xEventListItem;		//用于从事件列表中引用任务。
	UBaseType_t			uxPriority;			//任务的优先级。0为最低优先级
	StackType_t			*pxStack;			/*指向堆栈的开始。* /
	//注意此处的指针在freeRtos中 是指向一个全局数组 此数组的内存用来分配给栈

} tskTCB;

三、 QueueDefinition(队列结构体)

typedef struct QueueDefinition
{
	int8_t *pcHead;					
	/*指向队列数据存储的起始位置*/
	int8_t *pcTail;					
	/*指向队列存储区域末尾的字节。一旦分配了多余的字节来存储队列项,这是用来做记号的。 */
	int8_t *pcWriteTo;				
	/*< 指向存储区域中空闲的下一个位置。 */

	union/* 使用union是编码标准的一个例外,以确保两个互斥结构成员不会同时出现(浪费RAM)。*/
	{
		int8_t *pcReadFrom;			
		/*指向结构用作队列时读取队列项的最后一个位置。*/
		UBaseType_t uxRecursiveCallCount;
		/*在结构用作互斥锁时,维护递归互斥锁被递归地“占用”的次数的计数。*/
	} u;

	List_t xTasksWaitingToSend;		
	/*阻塞的任务列表,这些任务等待发送到此队列。按优先顺序存储。*/
	List_t xTasksWaitingToReceive;	
	/*队列等待读取的任务列表,这些任务等待接收此队列的数据。按优先顺序存储。 */

	volatile UBaseType_t uxMessagesWaiting;
	/*当前队列中的列表项数目。 */
	UBaseType_t uxLength;			
	/*队列的长度定义为它将持有的链表项的数量,而不是字节的数量。*/
	UBaseType_t uxItemSize;			
	/*队列持有的每个列表项的大小 */

	volatile int8_t cRxLock;		
	/*存储在锁定队列时从队列接收(从队列中删除)的项数。当队列未锁定时,设置为queue解锁。*/
	volatile int8_t cTxLock;		
	/*< 存储传输到队列的项数(添加到队列中)当队列被锁定时。当队列未锁定时,设置为queue解锁。*/
} xQUEUE;

四、 EventGroup_t(事件组结构体)

struct EventGroupDef_t;
typedef struct EventGroupDef_t   * EventGroupHandle_t; //控制块句柄(指针)
 
 
typedef struct EventGroupDef_t  //事件标志组结构体(控制块)
{
    EventBits_t uxEventBits;  // 当前事件 每一位用来表示一个任务
    List_t xTasksWaitingForBits; /*< List of tasks waiting for a bit to be set. */
    //等待被设置的任务列表
    #if ( configUSE_TRACE_FACILITY == 1 )
        UBaseType_t uxEventGroupNumber;
    #endif
 
    #if ( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) )
        uint8_t ucStaticallyAllocated; /*< Set to pdTRUE if the event group is statically allocated to ensure no attempt is made to free the memory. */
    #endif
 
} EventGroup_t;

进程通信方式:

  1. 信号量
  2. 消息队列
  3. 管道
    匿名(需要血缘关系)
    有名(不需要血缘关系)
    高级(另一个程序在当前程序打开,算是当前程序的子进程,称高级管道)
  4. socket(套接字)
  5. 共享内存通信(最快)

共享内存怎么做?

特别提醒:共享内存并未提供同步机制,也就是说,在第一个进程结束对共享内存的写操作之前,并无自动机制可以阻止第二个进程开始对它进行读取。所以我们通常需要用其他的机制来同步对共享内存的访问,例如信号量。

  1. 创建共享内存,指定key、size、mode(权限)
  2. 将当前进程连接到共享内存
  3. 把共享内存的地址读取出来,并强制转换为本地变量
  4. 读写操作了

做法:将同一段物理内存映射到堆与栈之间的那一段虚拟内存中,

详细出处

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值