FreeRTOS

FreeRTOS

1. FreeRTOS简介

RTOS指一类系统:

RTOS类操作系统:UCOS,μ-cos II,μ-cos III FreeRTOS RT-thread

PC端:win,linux,安卓

文件操作系统:FATFS

界面系统GUI:emWin

FreeRTOS( Real Time Operating System 实时操作系统):FreeRTOS是一个迷你的实时操作系统内核。作为一个轻量级的操作系统,功能包括:任务管理、时间管理、信号量、消息队列、内存管理、记录功能、软件定时器、协程等,可基本满足较小系统的需要。

在这里插入图片描述

轮询系统:有规律性

​ 自上而下一行一行代码运行。

前后台系统:处理突发事件,

​ 中断:时间片

多任务系统:实现多任务同时进行

​ 函数1— While1----串口打印

​ 函数2— While1----led闪烁

​ 函数3— While1----按键检测

FreeRTOS特点:

在这里插入图片描述

1.1学习目的

  1. 项目需要 :实现的功能越来越多 ,裸机系统不能够完美地解决问题,降低编程的难度,实现多任务管理 。
  2. 学习需要 :学习更高级的东西,实现更好的职业规划,为以后做准备

2. FreeRTOS移植

FreeRTOS 的源码和相应的官方书籍均可从官网 www.freertos.org 获得

1.找一个轻便的工程:

2.在工程内部建立文件夹:

在这里插入图片描述

3.在新建的文件夹内部创建三个子文件夹:

在这里插入图片描述

4.移植.h文件:(全复制)

在这里插入图片描述

5.移植.h:
在这里插入图片描述

6.移植port:(系统内部管理):

在这里插入图片描述

7.移植heap4.c文件:

8.关闭SYStick系统滴答定时器:(屏蔽三个函数):

9.关闭主程序的sysytick_Config():
在这里插入图片描述

10创建钩子函数:(空闲时刻,程序进入钩子函数):
在这里插入图片描述

11.主频:72000000:
在这里插入图片描述

3.任务创建

3.1 变量名

定义变量时加上前缀:

char----c

short----s

long-----l

portBASE_TYPE,数据结构,任务句柄,队列句柄-----x

3.2 函数名

包含返回值类型,所在文件名,函数功能

prv(私有的private)

eg:

vTaskPrioritySet():返回值位void,在task.c中定义

3.3 创建、删除、启动任务

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

3.4 进入(退出)临界区

在这里插入图片描述

3.5 任务状态迁移

任务状态迁移图:

在这里插入图片描述

任务1—优先级3

任务2—优先级2

任务3—优先级5

优先级:优先级高的任务可以打断优先级的任务(3正在执行,5来到)

任务调度器:根据优先级的大小----抢占CPU资源

​ 就绪态(Ready):任务创建完成后进入就绪态,表明任务已准备就绪,随时可以运行,只等待调度器进行调度(3、2、5同时运行)

​ 运行态(Running):经过调度器按照优先级高低调度任务,从就绪态进入运行态。(3、2、5同时运行)

​ 阻塞态( Blocked):正在运行的任务发生阻塞(挂起、延时、读信号量等待)时,该任务会从就绪列表中删除,任务状态由运行态变成阻塞态,然后发生任务切换,运行就绪列表中当前最高优先级任务。(5执行完,进入阻塞态,3和2有机会运行)

​ 挂起态( Suspended):任务可以通过调用 vTaskSuspend() API 函数都可以将处于任何状态的任务挂起,被挂起的任务得不到CPU 的使用权,也不会参与调度,除非它从挂起态中解除。(把一个挂起状态的任务恢复的唯一途径就是调用vTaskResume()或vTaskResumeFromISR() API 函数,如果此时被恢复任务的优先级高于正在运行任务的优先级,则会发生任务切换,将该任务将再次转换任务状态,由就绪态变成运行态。)

3.6 挂起/恢复任务

在这里插入图片描述

实现功能: 按下按键1,进入挂起态

​ 按下按键2,进入恢复任务

void Task_Key( void *p)
{
	uint8_t keyval = 0;
	while(1)
	{
		keyval = key_getval();
		if(keyval == 1)
		{
			printf("按键 1 按下\r\n");
			vTaskSuspend(TaskHandle_Test);//把测试函数挂起
		}
		else if(keyval == 2)
		{
			printf("按键 2 按下\r\n");
			vTaskResume(TaskHandle_Test);
		}

		vTaskDelay(1000);
	}
}

4. 任务间通信

4.1 消息队列

队列:先进先出原则(FIFO)—管道

堆栈:后进先出原则(LIFO)–电梯门
在这里插入图片描述

4.1.2 创建消息队列

在这里插入图片描述

4.2 计数信号量

实现目的:停车场道闸显示的当前剩余车位,按键1按下,信号量+1,按键2按下信号量-1;(先获取在释放)

4.2.1 创建计数信号量

在这里插入图片描述

4.2.2 获取信号量


在这里插入图片描述

4.2.2 释放信号量

在这里插入图片描述

void Task_Key( void *p)
{
	BaseType_t queueret = 0;
	uint8_t keyval = 0;
	uint8_t i = 0;
	char queuebuf[10]= "\0";
	while(1)
	{
		keyval = key_getval();
		if(keyval == 1)
		{
			printf("按键 1 按下车辆入库\r\n");
			queueret = xSemaphoreGive(TaskHandle_Counting);//释放信号量
      if(queueret == pdPASS)
			{
				printf("车辆入库成功\r\n");
				printf("\r\n");
			}		
			else 
			{
				printf("车辆入库失败\r\n");
			}			

		}
		else if(keyval == 2)
		{
			printf("按键 2 按下车辆出库\r\n");
			queueret = xSemaphoreTake(TaskHandle_Counting,0);//获取信号量
			if(queueret == pdPASS)
			{
				printf("车辆出库成功");
				printf("\r\n");
			}
			else 
			{
				printf("车辆出库失败");
			}

		}

		vTaskDelay(10);
	}
}

5.二值信号量

在这里插入图片描述

在这里插入图片描述

应用案例:两人公用一个电话,一方接打电话,挂断后。另一方才能打电话。

//创建二值信号量句柄
SemaphoreHandle_t SemaphoreHandle_Binary = NULL;
void Task_Create( void *p)
{
	while(1)
	{
		taskENTER_CRITICAL(); //进入临界区
		
		//创建计数信号量
//	  TaskHandle_Counting = xSemaphoreCreateCounting(10,10);//共有10个车位,现有10
//		if(TaskHandle_Counting != NULL)
//		{
//			printf("计数信号量创建成功\r\n");
//		}
		
		
		//创建二值信号量
		SemaphoreHandle_Binary = xSemaphoreCreateBinary();
		if(NULL != SemaphoreHandle_Binary)
		{
			printf("二值信号量创建成功\r\n");
		}
		xSemaphoreGive(SemaphoreHandle_Binary);
		
		xTaskCreate(Task_Printf,"task_Printf",64,NULL,3,&TaskHandle_printf);
		xTaskCreate(Task_Test,"task_Test",64,NULL,4,&TaskHandle_Test);
//	  xTaskCreate(Task_LED,"task_LED",64,NULL,2,&TaskHandle_LED);
//		xTaskCreate(Task_Key,"task_Key",64,NULL,5,&TaskHandle_Key);
//		xTaskCreate(Task_give,"task_give",64,NULL,1,&TaskHandle_give);
//		xTaskCreate(Task_Take,"task_Take",64,NULL,1,&TaskHandle_Take);
		vTaskDelete(p);
		taskEXIT_CRITICAL(); //退出临界区
	}
}

void Task_Printf( void *p)
{
	while(1)
	{
		xSemaphoreTake(SemaphoreHandle_Binary,portMAX_DELAY);//获取信号量
		printf("----打印\r\n");
		printf("\r\n");
		vTaskDelay(1000);
		xSemaphoreGive(SemaphoreHandle_Binary);
		vTaskDelay(10);
	}
}




void Task_Test( void *p)
{
	while(1)
	{
		xSemaphoreTake(SemaphoreHandle_Binary,portMAX_DELAY);//获取信号量
		printf("测试函数----\r\n");
		vTaskDelay(500);
		xSemaphoreGive(SemaphoreHandle_Binary);
		vTaskDelay(10);
	}
}

6. 互斥信号量

互斥信号量其实是特殊的二值信号量,由于其特有的优先级继承机制从而使它更适用于简单互锁,也就是保护临界资源 。

优先级翻转:high 7

​ low 2

​ mid 4

​ high \ low抢占二值信号量

low运行完后,high抢占到信号进入运行态

mid来到,此时先运行mid

在这里插入图片描述

怎么避免优先级翻转现象?

​ 互斥信号量:优先级继承(不能完全避免优先级翻转,只是缩短了高优先级等待的时间)

在这里插入图片描述

6.1 创建互斥信号量

释放、获取函数(和二值信号量运用的函数相同)

//创建互斥信号量
SemaphoreHandle_t SemaphoreHandle_Mutex = NULL;
void Task_Create( void *p)
{
	while(1)
	{
		taskENTER_CRITICAL(); //进入临界区
		
		//创建计数信号量
//	  TaskHandle_Counting = xSemaphoreCreateCounting(10,10);//共有10个车位,现有10
//		if(TaskHandle_Counting != NULL)
//		{
//			printf("计数信号量创建成功\r\n");
//		}
		
		
		//创建二值信号量
//		SemaphoreHandle_Binary = xSemaphoreCreateBinary();
//		if(NULL != SemaphoreHandle_Binary)
//		{
//			printf("二值信号量创建成功\r\n");
//		}
//		xSemaphoreGive(SemaphoreHandle_Binary);
		
		//创建互斥信号量
		SemaphoreHandle_Mutex = xSemaphoreCreateMutex();
		if(SemaphoreHandle_Mutex != NULL)
		{
			printf("互斥信号量创建成功\r\n");
		}
		xSemaphoreGive(SemaphoreHandle_Mutex);
		
		
		xTaskCreate(Task_Low,"task_Low",64,NULL,2,&TaskHandle_Low);
		xTaskCreate(Task_High,"task_High",64,NULL,6,&TaskHandle_High);
		xTaskCreate(Task_Mid,"task_Mid",64,NULL,4,&TaskHandle_Mid);
//	  xTaskCreate(Task_LED,"task_LED",64,NULL,2,&TaskHandle_LED);
//		xTaskCreate(Task_Key,"task_Key",64,NULL,5,&TaskHandle_Key);
//		xTaskCreate(Task_give,"task_give",64,NULL,1,&TaskHandle_give);
//		xTaskCreate(Task_Take,"task_Take",64,NULL,1,&TaskHandle_Take);
		vTaskDelete(p);
		taskEXIT_CRITICAL(); //退出临界区
	}
}

void Task_High( void *p)
{
	BaseType_t xReturn;
	while(1)
	{
		xReturn = xSemaphoreTake(SemaphoreHandle_Mutex,portMAX_DELAY);//获取信号量
		if(xReturn == pdPASS)
		{
			printf("High runing\r\n");
		}
		printf("\r\n");
		delay_nms(3000);
		xSemaphoreGive(SemaphoreHandle_Mutex);
		vTaskDelay(10);
	}
}

void Task_Mid( void *p)
{
	while(1)
	{
		printf("mid runing\r\n");
		vTaskDelay(1000);
	}
}



void Task_Low( void *p)
{
	BaseType_t xReturn;
	while(1)
	{
		xReturn = xSemaphoreTake(SemaphoreHandle_Mutex,portMAX_DELAY);//获取信号量
		if(xReturn == pdPASS)
		{
			printf("low runing\r\n");
		}
		delay_nms(2000);
		xSemaphoreGive(SemaphoreHandle_Mutex);
		
		vTaskDelay(10);
	}
}

7. 事件

​ 事件是一种实现任务间通信的机制,主要用于实现多任务间的同步,但事件通信只能是事件类型的通信,无数据传输。与信号量不同的是,它可以实现一对多,多对多的同步。

​ 一个任务可以等待多个事件的发生:可以是任意一个事件发生时唤醒任务进行事件处理;也可以是几个事件都发生后才唤醒任务进行事件处理。同样,也可以是多个任务同步多个事件。

事件特点:

​ 1.事件只与任务相关联,事件相互独立,一个 32 位的事件集合( EventBits_t 类型的变量, 实际可用与表示事件的只有 24 位),用于标识该任务发生的事件类型,其中每一位表示一种事件类型( 0 表示该事件类型未发生、1 表示该事件类型已经发生),一共 24 种事件类型。
​ 2.事件仅用于同步,不提供数据传输功能。
​ 3.事件无排队性,即多次向任务设置同一事件(如果任务还未来得及读走), 等效于只设置一次。
​ 4.允许多个任务对同一事件进行读写操作。
​ 5.支持事件等待超时机制。

7.1 事件应用场景

​ 事件可使用于多种场合,它能够在一定程度上替代信号量,用于任务与任务间,中断与任务间的同步。一个任务或中断服务例程发送一个事件给事件对象,而后等待的任务被唤醒并对相应的事件进行处理。

​ 各个事件可分别发送或一起发送给事件对象,而任务可以等待多个事件

7.2 事件运作机制

​ 事件不与任务相关联,事件相互独立

在这里插入图片描述

事件唤醒机制,当任务因为等待某个或者多个事件发生而进入阻塞态,当事件发生的时候会被唤醒 。

在这里插入图片描述

任务 1 对事件 3 或事件 5 感兴趣(逻辑或),当发生其中的某一个事件都会被唤醒,并且执行相应操作。而任务 2 对事件 3 与事件 5 感兴趣(逻辑与),当且仅当事件 3 与事件 5 都发生的时候, 任务 2 才会被唤醒,如果只有一个其中一个事件发生,那么任务还是会继续等待事件发生。如果接在收事件函数中设置了清除事件位 xClearOnExit,那么当任务唤醒后将把事件 3 和事件 5 的事件标志清零,否则事件标志将依然存在 。

7.3 事件创建函数 xEventGroupCreate()

​ xEventGroupCreate()用于创建一个事件组,并返回对应的句柄。 要想使用该函数必须在头文件 FreeRTOSConfig.h 定义宏.

​ FreeRTOS 给我们提供了一个创建事件的函数 xEventGroupCreate(),当创建一个事件时, 系统会首先给我们分配事件控制块的内存空间,然后对该事件控制块进行基本的初始化,创建成功返回事件句柄;创建失败返回 NULL。

7.4 事件删除函数 vEventGroupDelete()

​ FreeRTOS 给我们提供了一个删除事件的函数——vEventGroupDelete(),使用它就能将事件进行删除了。当系统不再使用事件对象时,可以通过删除事件对象控制块来释放系统资源 。

8. 软件定时器

8.1 软件定时器的基本概念

​ 定时器,是指从指定的时刻开始,经过一个指定时间,然后触发一个超时事件,用户可以自定义定时器的周期与频率。

定时器有硬件定时器和软件定时器之分:
硬件定时器是芯片本身提供的定时功能。一般是由外部晶振提供给芯片输入时钟,芯片向软件模块提供一组配置寄存器,接受控制输入,到达设定时间值后芯片中断控制器产生时钟中断。硬件定时器的精度一般很高,可以达到纳秒级别,并且是中断触发方式。
软件定时器,软件定时器是由操作系统提供的一类系统接口,它构建在硬件定时器基础之上,使系统能够提供不受硬件定时器资源限制的定时器服务,它实现的功能与硬件定时器也是类似的。

FreeRTOS 软件定时器功能上支持:

裁剪:能通过宏关闭软件定时器功能。
软件定时器创建、启动、软停止、复位、删除 。

8.2 软件定时器应用场景

​ 硬件定时器受硬件的限制,数量上不足以满足用户的实际需求,无法提供更多的定时器,那么可以采用软件定时器来完成,由软件定时器代替硬件定时器任务。

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

​ 动态创建软件定时器 xTimerCreate()

​ 静态创建方式 xTimerCreateStatic()

Swtmr2_Handle=xTimerCreate((const char* )"OneShotTimer",		(TickType_t)5000,/* 定时器周期 5000(tick) */
		(UBaseType_t )pdFALSE,/* 单次模式 */
		(void*)2,/* 为每个计时器分配一个索引的唯一 ID */
		 (TimerCallbackFunction_t)Swtmr2_Callback);

8.4 软件定时器启动函数 xTimerStart()

xTimerStart( xTimer, xTicksToWait ) 
     xTimerGenericCommand( ( xTimer )//要操作的软件定时器句柄, 
			tmrCOMMAND_START// xCommandID 参数可以指定多个命令
		( xTaskGetTickCount() )//获取当前系统时间, 
		NULL//参数在中断中发送命令才起作用, 
		 ( xTicksToWait ) )//用户指定超时阻塞时间

xTimerStart()函数就是一个宏定义,真正起作用的是 xTimerGenericCommand()函数。

8.5 软件定时器停止函数xTimerStop()

​ xTimerStop() 用于停止一个已经启动的软件定时器, 该函数的实现也是通过“定时器命令队列”发送一个停止命令给软件定时器任务,从而唤醒软件定时器任务去将定时器停止。

在这里插入图片描述

8.6 软件定时器删除函数 xTimerDelete()

在这里插入图片描述

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值