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.有两个函数未定义
- vApplicationGetIdleTaskMemory 给空闲任务分配内存
- 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函数中的执行顺序:
硬件初始化(串口、GPIO等)
创建Start_Task(优先级1)
vTaskStartScheduler(); // 启动调度器
└── 调度器开始工作
└── 选择就绪态中优先级最高的任务执行
时间轴:t0: Start_Task创建(优先级1,进入就绪态)
t1: vTaskStartScheduler()调用
t2: 调度器发现就绪态任务:[Start_Task]
t3: 执行Start_Task(因为它是唯一就绪的任务)
t4: Start_Task创建其他3个任务
t5: Start_Task删除自己
t6: 调度器重新调度,从就绪态任务中选择