stm32_1:FreeRTOS

1.前后台系统

早期嵌入式开发没有嵌入式操作系统概念,直接操作裸机,直接在逻辑上写程序,比如51单片机没有操作系统的概念。通常把程序分为前台系统和后台系统。

签单的小系统通常是前后台系统。这样的程序包括一个死循环和若干个中断服务程序:应用程序是一个无限循环,循环中调用API库函数完成作需的操作,大循环叫做后台系统。中断服务程序用于处理系统的异步事件,也就是前台系统。前台是中断级,后台是任务级。

2.FreeRTOS

RTOS全称为:Real time OS ,就是实时操作系统,强调的是:实时性。实时操作系统又分为软实时和硬实时。硬实时要求在规定的时间内必须完成操作,硬实时不允许超时,软实时里面处理过程超时的后果就没有那么严格。

在实时操作系统种,我们可以把要实现的功能划分为多个任务,每个任务负责实现其中的一部分,每个任务都是一个很简单的程序,通常是一个死循环。

RTOS操作系统: Freertos, UCOS,RTX,RT-THread,DJYOS等

RTOS操作系统的核心内容在于: 实时内核。

3.可剥夺型内核

RTOS的内核负责管理所有的任务,内核决定了运行哪个任务,何时停止当前任务切换到其他任务,这个是内核的多任务管理能力。多任务管理给人的感觉就是芯片有多个CPU,多任务管理实现了CPU资源的最大化利用,多任务管理有助于实现程序的模块化开发,能够实现复杂的实时利用。

可剥夺型内核顾名思义就是可以剥夺其他任务的CPU使用权,他总是运行就绪任务中优先级最高的任务。

Freertos是一个可剪裁,可剥夺型的多任务内核,而且没有任务数限制。Freertos提供了实时操作系统所需的所有功能,包括资源管理、同步、任务通信等。

Freertos是用C和汇编来写的,其中绝大部分都是用C语言编写的,只有极少数的与处理器密切相关的部分代码才是用汇编写的,Freertos结构简洁,可读性很强!最主要的是非常适合初次接触嵌入式实时操作系统开发者。

4.宏

"INCLUDE_" 开始的宏

使用 "INCLUDE_" 开头的宏用来表示使能或除能FreeRTOS中相应的API函数,作用就是用来配置FreeRTOS中的可选API函数。

"config" 开始的宏

"config " 开始的宏和 "INCLUDE_" 开始的宏一样,都是用来完成Freertos的配置和裁剪的。

5.FreeRTOS任务特性

  • 1.任务简单
  • 2.任务没有数量使用限制
  • 3.任务支持抢占(抢占式内核)
  • 4.任务支持优先级
  • 5.每个任务都拥有堆栈导致了RAM使用量增大
  • 6.如果使用抢占的话必须仔细的考虑重入问题

6.FreeRTOS任务状态

四种任务状态(任务调度器)

1.运行态

2.就绪态

3.阻塞态:等待某个事件:信号量、队列...

4.挂起态:暂停运行(解挂)

7.优先级

任务优先级决定了任务的执行优先级别,在FreeRTOS中优先级可选范围位:

0 ~ configMAX_PRIORITIES-1

数字越大,优先级越高

8.任务创建和删除API函数

任务创建和删除本质就是调用FreeRTOS的API函数

9.任务动态创建和删除

cs 复制代码
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "FreeRTOS.h"
#include "task.h"


#define Start_Task_Size 120
#define Start_Task_Prio 1
TaskHandle_t Start_Task_Handler;
void Start_Task(void *pvParamaters);

#define Task1_Task_Size 120
#define Task1_Task_Prio 2
TaskHandle_t Task1_Task_Handler;
void Task1_Task(void *pvParamaters);

#define Task2_Task_Size 120
#define Task2_Task_Prio 3
TaskHandle_t Task2_Task_Handler;
void Task2_Task(void *pvParamaters);

int main(void)
{
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4	 
	delay_init();	    				//延时函数初始化	  
	uart_init(115200);					//初始化串口
	LED_Init();		  					//初始化LED
	
	
	 xTaskCreate( (TaskFunction_t) 					Start_Task,
                (char *)  								"Start_Task", 
                (configSTACK_DEPTH_TYPE) 	Start_Task_Size,
                (void *)  								NULL,
                (UBaseType_t) 						Start_Task_Prio,
                (TaskHandle_t *)  				&Start_Task_Handler );
	
	
	vTaskStartScheduler();
}

void Start_Task(void *pvParamaters)
{
	xTaskCreate( (TaskFunction_t) 					Task1_Task,
                (char *)  								"Task1_Task", 
                (configSTACK_DEPTH_TYPE) 	Task1_Task_Size,
                (void *)  								NULL,
                (UBaseType_t) 						Task1_Task_Prio,
                (TaskHandle_t *)  				&Task1_Task_Handler );
								
	xTaskCreate( (TaskFunction_t) 					Task2_Task,
                (char *)  								"Task2_Task", 
                (configSTACK_DEPTH_TYPE) 	Task2_Task_Size,
                (void *)  								NULL,
                (UBaseType_t) 						Task2_Task_Prio,
                (TaskHandle_t *)  				&Task2_Task_Handler );
								
	vTaskDelete(Start_Task_Handler);
}

void Task1_Task(void *pvParamaters)
{
	uint8_t task1_num = 0;
	
	while(1)
	{
		task1_num++;
		if(task1_num == 5)
		{
			printf("Task2 is delete.\r\n");
			vTaskDelete(Task2_Task_Handler);
		}
		vTaskDelay(1000);
		printf("Task1 is running %d\r\n",task1_num);
		
		
		
	}
}

void Task2_Task(void *pvParamaters)
{
	uint8_t task2_num = 0;
	
	while(1)
	{
		task2_num++;
		vTaskDelay(1000);
		printf("Task2 is running %d\r\n",task2_num);
	}
}

10.任务静态的创建和删除

如果要使用静态方法需要将宏

ConfigSUPPORT_STATIC_ALLOCATION

设置为1

1.修改宏 , ConfigSUPPORT_STATIC_ALLOCATION = 1

2.有两个函数未定义

  1. vApplicationGetIdleTaskMemory 给空闲任务分配内存
  2. vApplicationGetTimerTaskMemory 给定时器任务分配内存
cs 复制代码
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "FreeRTOS.h"
#include "task.h"

#define Start_Task_Size 120
#define Start_Task_Prio 1
StackType_t StartTaskStack[Start_Task_Size];
StaticTask_t StartTaskTCP;
TaskHandle_t StartTask_Handle;
void START_TASK( void * pvParameters );

#define Task1_Task_Size 120
#define Task1_Task_Prio 2
StackType_t Task1TaskStack[Task1_Task_Size];
StaticTask_t Task1TaskTCP;
TaskHandle_t Task1Task_Handle;
void Task1_TASK( void * pvParameters );

#define Task2_Task_Size 120
#define Task2_Task_Prio 3
StackType_t Task2TaskStack[Task2_Task_Size];
StaticTask_t Task2TaskTCP;
TaskHandle_t Task2Task_Handle;
void Task2_TASK( void * pvParameters );

static StaticTask_t IdleTaskTCB;
static StackType_t 	IdleTaskStack[configMINIMAL_STACK_SIZE];

void vApplicationGetIdleTaskMemory( StaticTask_t ** ppxIdleTaskTCBBuffer,
																		StackType_t ** ppxIdleTaskStackBuffer,
																		uint32_t * pulIdleTaskStackSize )
{
	*ppxIdleTaskTCBBuffer 	= &IdleTaskTCB;
	*ppxIdleTaskStackBuffer = IdleTaskStack;
	*pulIdleTaskStackSize 	= configMINIMAL_STACK_SIZE;
}
																
static StaticTask_t TimerTaskTCB;
static StackType_t	TimerTaskStack[configTIMER_TASK_STACK_DEPTH];

void vApplicationGetTimerTaskMemory( StaticTask_t ** ppxTimerTaskTCBBuffer,
                                     StackType_t ** ppxTimerTaskStackBuffer,
                                     uint32_t * pulTimerTaskStackSize )
{
	*ppxTimerTaskTCBBuffer 		= &TimerTaskTCB;
	*ppxTimerTaskStackBuffer 	= TimerTaskStack;
	*pulTimerTaskStackSize	 	= configTIMER_TASK_STACK_DEPTH;
}

int main(void)
{
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4	 
	delay_init();	    				//延时函数初始化	  
	uart_init(115200);					//初始化串口
	LED_Init();		  					//初始化LED
	

  StartTask_Handle = xTaskCreateStatic ( 		(TaskFunction_t) 		START_TASK,
																						(char *) 	 					"Start_Task", 
																						(uint32_t) 					Start_Task_Size,
																						(void *)  					NULL,
																						(UBaseType_t) 			Start_Task_Prio,
																						(StackType_t *) 		StartTaskStack,
																						(StaticTask_t *) 	 	&StartTaskTCP  );
	
	
	vTaskStartScheduler();
}

void START_TASK( void * pvParameters )
{
	Task1Task_Handle = xTaskCreateStatic ( 		(TaskFunction_t) 		Task1_TASK,
																						(char *) 	 					"Task1_Task", 
																						(uint32_t) 					Task1_Task_Size,
																						(void *)  					NULL,
																						(UBaseType_t) 			Task1_Task_Prio,
																						(StackType_t *) 		Task1TaskStack,
																						(StaticTask_t *) 	 	&Task1TaskTCP  );
																				
	
	Task2Task_Handle = xTaskCreateStatic ( 		(TaskFunction_t) 		Task2_TASK,
																						(char *) 	 					"Task2_Task", 
																						(uint32_t) 					Task2_Task_Size,
																						(void *)  					NULL,
																						(UBaseType_t) 			Task2_Task_Prio,
																						(StackType_t *) 		Task2TaskStack,
																						(StaticTask_t *) 	 	&Task2TaskTCP  );
	

	vTaskDelete(StartTask_Handle);
}

void Task1_TASK(void *pvParamaters)
{
	uint8_t task1_num = 0;
	
	while(1)
	{
		task1_num++;
		if(task1_num == 5)
		{
			printf("Task2 is delete.\r\n");
			vTaskDelete(Task2Task_Handle);
		}
		vTaskDelay(1000);
		printf("Task1 is running %d\r\n",task1_num);
		
	}
}

void Task2_TASK(void *pvParamaters)
{
	uint8_t task2_num = 0;
	
	while(1)
	{
		task2_num++;
		vTaskDelay(1000);
		printf("Task2 is running %d\r\n",task2_num);
	}
}

11.任务挂起和恢复API

|----------------------|------------------|
| 函数 | 描述 |
| vTaskSuspend() | 挂起一个任务 |
| vTaskResume() | 恢复一个任务 |
| vTaskResumeFromISR() | 中断服务函数中恢复一个任务的运行 |

cs 复制代码
#include "key.h"
#include "stm32f10x.h"
#include "stdio.h"
#include "delay.h"
#include "FreeRTOS.h"
#include "task.h"
#include "exti.h"

void EXTI_Key_Init(void)
{
	EXTI_InitTypeDef 	EXTI_InitStructure;
	NVIC_InitTypeDef 	NVIC_InitStructure;
 	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
	
	Key_Init();
	
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOC,GPIO_PinSource13);
	
	EXTI_InitStructure.EXTI_Line = EXTI_Line13;
	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
	EXTI_InitStructure.EXTI_LineCmd = ENABLE;
	EXTI_Init(&EXTI_InitStructure);
	
	NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x06;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x00;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);
}

extern TaskHandle_t Task1_Task_Handler;

void EXTI15_10_IRQHandler(void)
{
	BaseType_t YieldRequired;
	
	//if(GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_13) == 0)
	if(EXTI_GetITStatus(EXTI_Line13) == 1)
	{
		EXTI_ClearITPendingBit(EXTI_Line13);
		
		YieldRequired = xTaskResumeFromISR( Task1_Task_Handler );
		printf("Task is resume\r\n");
		
		if(YieldRequired == pdTRUE)
		{
			portYIELD_FROM_ISR(YieldRequired);
		}
	}
}
cs 复制代码
#include "key.h"
#include "stm32f10x.h"
#include "stdio.h"
#include "delay.h"
#include "FreeRTOS.h"
#include "task.h"

extern TaskHandle_t Task1_Task_Handler;

void Key_Init(void)
{
	GPIO_InitTypeDef  GPIO_InitStructure;
 	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC,ENABLE);	 //使能时钟
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;				 		 //Key2-->PA0 端口配置
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; 		 //推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		 //IO口速度为50MHz
	GPIO_Init(GPIOA, &GPIO_InitStructure);					 
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;				 		 //Key3-->PC13 端口配置
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; 		 //推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		 //IO口速度为50MHz
	GPIO_Init(GPIOC, &GPIO_InitStructure);

}
cs 复制代码
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "FreeRTOS.h"
#include "task.h"
#include "key.h"
#include "exti.h"

#define Start_Task_Size 120
#define Start_Task_Prio 1
TaskHandle_t Start_Task_Handler;
void Start_Task(void *pvParamaters);

#define Task1_Task_Size 120
#define Task1_Task_Prio 4
TaskHandle_t Task1_Task_Handler;
void Task1_Task(void *pvParamaters);

#define Task2_Task_Size 120
#define Task2_Task_Prio 3
TaskHandle_t Task2_Task_Handler;
void Task2_Task(void *pvParamaters);

#define Key_Task_Size 120
#define Key_Task_Prio 2
TaskHandle_t Key_Task_Handler;
void Key_Task(void *pvParamaters);


int main(void)
{
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4	 
	delay_init();	    				//延时函数初始化	  
	uart_init(115200);					//初始化串口
	LED_Init();		  					//初始化LED
	Key_Init();
	EXTI_Key_Init();
	
	
	 xTaskCreate( (TaskFunction_t) 					Start_Task,
                (char *)  								"Start_Task", 
                (configSTACK_DEPTH_TYPE) 	Start_Task_Size,
                (void *)  								NULL,
                (UBaseType_t) 						Start_Task_Prio,
                (TaskHandle_t *)  				&Start_Task_Handler );
	
	
	vTaskStartScheduler();
}

void Start_Task(void *pvParamaters)
{
	xTaskCreate( (TaskFunction_t) 					Task1_Task,
                (char *)  								"Task1_Task", 
                (configSTACK_DEPTH_TYPE) 	Task1_Task_Size,
                (void *)  								NULL,
                (UBaseType_t) 						Task1_Task_Prio,
                (TaskHandle_t *)  				&Task1_Task_Handler );
								
	xTaskCreate( (TaskFunction_t) 					Task2_Task,
                (char *)  								"Task2_Task", 
                (configSTACK_DEPTH_TYPE) 	Task2_Task_Size,
                (void *)  								NULL,
                (UBaseType_t) 						Task2_Task_Prio,
                (TaskHandle_t *)  				&Task2_Task_Handler );
								
	xTaskCreate( (TaskFunction_t) 					Key_Task,
                (char *)  								"Key_Task", 
                (configSTACK_DEPTH_TYPE) 	Key_Task_Size,
                (void *)  								NULL,
                (UBaseType_t) 						Key_Task_Prio,
                (TaskHandle_t *)  				&Key_Task_Handler );
								
	vTaskDelete(Start_Task_Handler);
}

void Task1_Task(void *pvParamaters)
{
	uint8_t task1_num = 0;
	
	while(1)
	{
		task1_num++;
		vTaskDelay(1000);
		printf("Task1 is running %d\r\n",task1_num);
	}
}

void Task2_Task(void *pvParamaters)
{
	uint8_t task2_num = 0;
	
	while(1)
	{
		task2_num++;
		vTaskDelay(1000);
		printf("Task2 is running %d\r\n",task2_num);
	}
}

void Key_Task(void *pvParamaters)
{
	while(1)
	{
		if( GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0) == 0)
		{
			vTaskDelay(1000);
			vTaskSuspend(Task1_Task_Handler );
			printf("Task is suspend\r\n");
		}
		
//		if( GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_13) == 0)
//		{
//			vTaskDelay(1000);
//			vTaskResume(Task1_Task_Handler );
//			printf("Task is resume\r\n");
//		}
	}
}

注:使用外部中断,要打开AFIO时钟,而且要在GPIO_EXTILineConfig()函数之前打开!!

函数执行流程

// main函数中的执行顺序:

  1. 硬件初始化(串口、GPIO等)

  2. 创建Start_Task(优先级1)

  3. vTaskStartScheduler(); // 启动调度器

└── 调度器开始工作

└── 选择就绪态中优先级最高的任务执行
时间轴:

t0: Start_Task创建(优先级1,进入就绪态)

t1: vTaskStartScheduler()调用

t2: 调度器发现就绪态任务:[Start_Task]

t3: 执行Start_Task(因为它是唯一就绪的任务)

t4: Start_Task创建其他3个任务

t5: Start_Task删除自己

t6: 调度器重新调度,从就绪态任务中选择

相关推荐
不能跑的代码不是好代码2 小时前
STM32 标准外设库中关于 GPIO(通用输入输出) 模块的函数声明
stm32·单片机·嵌入式硬件
仰泳之鹅2 小时前
【天气时钟】第一课:工程模板的搭建
单片机·嵌入式硬件
Moonquakes5402 小时前
嵌入式开发基础学习笔记(LED实验C语言实现、蜂鸣器实验、SDK裸机驱动、链接脚本、BSP工程管理)
stm32·单片机·嵌入式硬件
思茂信息2 小时前
CST仿真实例:手机Type-C接口ESD仿真
c语言·开发语言·单片机·嵌入式硬件·智能手机·cst·电磁仿真
梁洪飞2 小时前
armv7 cache机制
linux·arm开发·嵌入式硬件·arm·memcache
我是海飞2 小时前
杰理 AC792N 使用 WebSocket 连接百度语音大模型,实现 AI 对话
c语言·单片机·嵌入式·ai对话·杰理·websockey
别掩2 小时前
光耦选型指南
单片机·嵌入式硬件
2023自学中2 小时前
嵌入式系统中的非易失性存储设备
linux·嵌入式硬件
czhaii14 小时前
MP3音乐播放器【FatFs+SD/TF卡+I2S-DAC】@STC32G144K246,实时解码MP3
单片机·硬件工程