在嵌入式系统中,需要同时处理多个任务的需求非常普遍。
本文将介绍如何在STM32芯片上实现多任务处理,通过合理的任务调度和管理,充分发挥芯片的性能,提高系统的灵活性和效率。
下面介绍两种多任务处理的实现方法
1. 时间片轮转调度机制
⏩ 定义不同的任务:定义任务的优先级、堆栈大小、维护一个任务列表,通过编写调度器代码,在合适的时机选择下一个任务来执行。
#include "stm32fxxx.h"
// 定义任务的优先级
#define TASK1_PRIORITY 1
#define TASK2_PRIORITY 2
// 定义任务的堆栈大小
#define TASK_STACK_SIZE 128
// 定义任务堆栈空间
uint32_t task1_stack[TASK_STACK_SIZE];
uint32_t task2_stack[TASK_STACK_SIZE];
// 定义任务函数
void task1(void);
void task2(void);
// 定义任务控制块结构
typedef struct {
uint32_t* stack_ptr;
} TaskControlBlock;
// 定义任务控制块实例
TaskControlBlock tcb1;
TaskControlBlock tcb2;
// 定义当前任务指针
TaskControlBlock* current_task;
// 任务1的函数
void task1(void) {
while (1) {
// 任务1的处理逻辑
// 切换任务
__asm volatile("yield");
}
}
// 任务2的函数
void task2(void) {
while (1) {
// 任务2的处理逻辑
// 切换任务
__asm volatile("yield");
}
}
⏩ 定时器中断:在中断处理函数中切换任务,并保存当前任务的上下文(包括寄存器、堆栈等),然后加载下一个任务的上下文,使其开始执行。
// 定义定时器中断处理函数
void TIM_IRQHandler(void) {
// 切换到下一个任务
if (current_task == &tcb1) {
current_task = &tcb2;
} else {
current_task = &tcb1;
}
// 加载下一个任务的堆栈指针
__asm volatile("mov sp, %0" ::"r"(current_task->stack_ptr));
}
int main() {
// 初始化任务控制块
tcb1.stack_ptr = task1_stack + TASK_STACK_SIZE - 1;
tcb2.stack_ptr = task2_stack + TASK_STACK_SIZE - 1;
// 初始化定时器,设置定时器中断
// 这里使用TIM3作为定时器,具体配置请根据实际情况进行修改
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
TIM_TimeBaseInitTypeDef TIM_InitStruct;
TIM_InitStruct.TIM_Prescaler = 1000;
TIM_InitStruct.TIM_Period = 1000;
TIM_InitStruct.TIM_CounterMode = TIM_CounterMode_Up;
TIM_InitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInit(TIM3, &TIM_InitStruct);
TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);
NVIC_EnableIRQ(TIM3_IRQn);
TIM_Cmd(TIM3, ENABLE);
// 初始化当前任务指针
current_task = &tcb1;
// 启动任务1
task1();
while (1) {
// 主循环,任务在定时器中断中切换
}
}
这种简单的多任务处理方式适用于较简单的应用场景,但对于复杂的多任务应用,建议使用RTOS来提供更好的任务管理和调度机制。
2. 使用RTOS(实时操作系统)
RTOS是一种常用的多任务处理解决方案,它提供了任务调度和管理机制,简化了多任务应用的开发。
对于STM32芯片,常见的RTOS有FreeRTOS、uC/OS等。以下是实现多任务处理的基本步骤:
⏩ 创建任务:使用RTOS的API,在应用程序中创建多个任务。每个任务都有自己的代码和优先级
void Task1(void* pvParameters)
{
while (1)
{
// Task1处理代码
}
}
void Task2(void* pvParameters)
{
while (1)
{
// Task2处理代码
}
}
int main()
{
// 硬件初始化和其他配置
// 创建任务
xTaskCreate(Task1, "Task1", configMINIMAL_STACK_SIZE, NULL, 1, NULL);
xTaskCreate(Task2, "Task2", configMINIMAL_STACK_SIZE, NULL, 2, NULL);
// 启动调度器
vTaskStartScheduler();
// 代码永远不会执行到这里
while (1)
{
}
}
int main()
{
// 硬件初始化和其他配置
// 配置FreeRTOS内核
// 设置时钟节拍
TickType_t tickRate = 1000 / configTICK_RATE_HZ;
TickTypeSet(tickRate);
// 配置优先级分组
NVIC_SetPriorityGrouping(0);
// 创建任务和启动调度器
// ...
// 代码永远不会执行到这里
while (1)
{
}
}
void Task1(void* pvParameters)
{
while (1)
{
// Task1处理代码
// 任务挂起一段时间,以便给其他任务执行机会
vTaskDelay(pdMS_TO_TICKS(100));
}
}
void Task2(void* pvParameters)
{
while (1)
{
// Task2处理代码
// 任务挂起一段时间,以便给其他任务执行机会
vTaskDelay(pdMS_TO_TICKS(50));
}
}
来自zsky 一起学嵌入式公众号