【专题1:电子工程师】 之 【27.基于STM32从0到1写操作系统 - 【6.任务定义】】

  笔者在嵌入式领域深耕6年,对嵌入式项目构建,BLDC电机控制,产品上位机开发以及产品量产和产品售后维护有多年工作经验。经验分享,从0到1, 让我带你从实际工作的角度走进嵌入式成长之路。

  原创不易欢迎大家关注我的微信公众号嵌入式工程师成长之路扫下面二维码
                     在这里插入图片描述
所有文章总目录:【电子工程师 qt工程师】

原创视频总目录:【电子工程师 qt工程师】

1.任务概述

1.1.任务的外观

  一个永远不会返回的函数。
【专题1:电子工程师】 之 【27.基于STM32从0到1写操作系统 - 【6.任务定义】】_第1张图片

1.2.任务的内在

  一个函数有四部分组成:栈、堆(这两部分可以由我们来指定起始地址)、数据区(全局变量)和代码区(代码)。
【专题1:电子工程师】 之 【27.基于STM32从0到1写操作系统 - 【6.任务定义】】_第2张图片

2.任务切换原理

 保存前一个任务的当前运行状态,恢复后一任务之前的运行状态。
 运行状态包含以下数据:
① 代码和数据区:由编译器自动分配,各个任务相互独立,并不冲突。
② 堆:不适用。
③ 栈:硬件只支持两个栈空间,不同的任务需要有自己独立的栈。
④ 内核寄存器:编译器会在某些时间保存到栈中,譬如函数调用或异常处理。对于CPU会自动保存的寄存器,我们可以不用管;但CPU未保存的需要我们自己处理。
⑤ 其他的状态数据:也可能需要处理。

 为每个任务配置独立的栈,用于保存该任务的所有状态数据。
【专题1:电子工程师】 之 【27.基于STM32从0到1写操作系统 - 【6.任务定义】】_第3张图片

3.代码实现

3.1.main.c

#include "zpowerOS.h"

/*触发PendSV异常*/
#define NVIC_INT_CTRL		 	0xE000ED04 /*地址*/
#define	NVIC_PENDSVSET		0x10000000	/**/
#define	NVIC_SYSPRI2			0xE000E022
#define	NVIC_PENDSV_PRI		0x000000FF

#define MEM32(addr)				*(volatile unsigned long*)(addr)
#define MEM8(addr)				*(volatile unsigned char*)(addr)
	
/*PendSV异常是专门用来做任务切换的*/
void triggerPendSVC(void)
{
	/*设置pendSV异常为最低优先级*/
	MEM8(NVIC_SYSPRI2) = NVIC_PENDSV_PRI;
	/*触发PendSV异常*/
	MEM32(NVIC_INT_CTRL) = NVIC_PENDSVSET;
}

typedef struct _BlockType_t
{
	unsigned long* stackPtr;
}BlockType_t;

BlockType_t* blockPtr;
int flag;

unsigned long stackBuffer[1024];
BlockType_t block;

void delay(int count)
{
	while (--count > 0);
}

void tTaskInit(tTask* task, void (*entry)(void*), void* param, tTaskStack* stack)
{
	task->stack = stack;
}

tTask tTask1;
tTask tTask2;

tTaskStack task1Env[1024];
tTaskStack task2Env[1024];

void task1 (void* param)
{
	for (;;)
	{
	
	}
}

void task2 (void* param)
{
	for (;;)
	{
	
	}
}

int main (void)
{
	tTaskInit(&tTask1, task1, (void*)0x11111111, &task1Env[1024]);
	
	tTaskInit(&tTask2, task2, (void*)0x22222222, &task2Env[1024]);
	
	block.stackPtr = &stackBuffer[1024];
	blockPtr = █
	for (;;)
	{
		flag = 0;
		delay(100);
		flag = 1;
		delay(100);
		/*触发PendSV异常*/
		triggerPendSVC();
	}
}

3.2.异常处理函数

/*PendSV异常处理函数*/
/*内嵌汇编保存R4-R11的值*/
__asm void PendSV_Handler(void)
{
	/*导入blockPtr变量,IMPORT和C语言中的extern类似*/
	IMPORT blockPtr
	LDR R0, = blockPtr
	LDR R0, [R0]
	LDR R0, [R0]
	
	/*将寄存器批量的保存到内存中*/
	STMDB	R0!, {R4-R11}
	
	LDR R1, = blockPtr
	LDR R1, [R1]
	STR R0,	[R1]
	
	ADD R4, R4, #1
	ADD R5, R5, #1
	
	/*恢复*/
	LDMIA R0!, {R4-R11}
	
	/*退出异常*/
	BX LR
	NOP
}

3.3.任务栈

#ifndef ZPOWEROS_H
#define ZPOWEROS_H

#include 

typedef uint32_t tTaskStack;

typedef struct _tTask{
	tTaskStack* stack;
}tTask;

#endif

你可能感兴趣的:(专题1:电子工程师)