首页 » PHP教程 » phpurlmod技巧_教你编写最简单的CM3操作系统160行实现责任创建与切换

phpurlmod技巧_教你编写最简单的CM3操作系统160行实现责任创建与切换

访客 2024-12-10 0

扫一扫用手机浏览

文章目录 [+]

关于RTOS的理论性知识,实在是无力多讲,资料太多了,请自行探求吧!

关于Cortex-M3,它实在是太精良了,它的很多特性便是为了RTOS而生的

phpurlmod技巧_教你编写最简单的CM3操作系统160行实现责任创建与切换

你可以下载代码,在keil下实行软件仿真调试即可,区区160行代码(不算注释),相信你能搞明白的

phpurlmod技巧_教你编写最简单的CM3操作系统160行实现责任创建与切换
(图片来自网络侵删)

本例固定4个任务,main函数是第一个任务,在main函数再创建2个任务,大略轮转调度,任务管理不在本文谈论内容,请见谅

注释偏少,不懂叨教!

直接上代码:

OS核心部分

#include \公众os.h\"大众

typedef struct TCB{

int reserve[3];

void stack; // 任务栈顶地址 汇编利用,offset 0x0C

int deleteFlag;

//...

}TCB;

struct _OS{

TCB run; // 正在运行的任务 汇编利用,offset 0x00

TCB rdy; // 就绪的任务 汇编利用,offset 0x04

// ...

}os;

__asm void SVC_Handler (void){

PRESERVE8

THUMB

PUSH {LR}

MRS R0,PSP // Read PSP

LDM R0,{R0-R3,R12} // Read R0-R3,R12 from stack

BLX R12 // Call SVC Function

MRS R1,PSP // Read PSP

STR R0,[R1,#0x0] // set return values

POP {PC}

ALIGN

}

__asm void PendSV_Handler (void){

PRESERVE8

THUMB

IMPORT os

IMPORT OS_Sched

PUSH {LR}

MRS R0,PSP

STMFD R0!,{R4-R11}

MSR PSP,R0

BL OS_Sched // C措辞任务调度

// 切换任务,看C示意代码

// os.run->stack = PSP;

LDR R2,=os

LDR R1,[R2,#0x0]

MRS R3,PSP

STR R3,[R1,#0xC]

// os.run = os.rdy;

LDR R0,[R2,#0x4]

STR R0,[R2,#0x0]

// PSP = os.rdy->stack

LDR R1,[R2,#0x4]

LDR R0,[R1,#0xC]

MSR PSP,R0

MRS R0,PSP

LDMFD R0!,{R4-R11}

MSR PSP,R0

POP {PC}

ALIGN

}

/

[url=home.php?mod=space&uid=159083]@brief[/url] 悬起PendSV,由于此中断优先级最低,以是若是在SVC_Handler或更高等别中断函数中设置的,

PendSV_Handler函数不会立即实行, [url=home.php?mod=space&uid=418085]@see[/url] <Cortex-M3威信指南>

/

__asm void OS_PendSV (void){

PRESERVE8

THUMB

NVIC_INT_CTRL EQU 0xE000ED04

NVIC_PENDSVSET EQU 0x10000000

LDR R0, =NVIC_INT_CTRL

LDR R1, =NVIC_PENDSVSET

STR R1, [R0]

BX LR

ALIGN

}

void _OS_TaskDeleteSelf(void){

// 本例没有实现 ...

// 一样平常做法是将该TCB从链表中移除

os.run->deleteFlag = 1;

OS_PendSV();

}

/

@brief 当任务函数实行返回时,跳转到此函数, @see OS_TaskStackInit

/

__asm void ASM_TaskDelete(void){

PRESERVE8

THUMB

IMPORT _OS_TaskDeleteSelf

LDR R12,=_OS_TaskDeleteSelf

SVC 0

ALIGN

}

/

@brief 堆栈初始化

/

__asm void OS_TaskStackInit(void (taskFun)(void),void stk,void argv){

PRESERVE8

THUMB

MOV R3,#0x01000000 // 初始化PSR的值

STMFD R1!, {R3} // push xPSR

STMFD R1!, {R0} // push PC = taskFun

LDR R0,=ASM_TaskDelete

STMFD R1!,{R0} // push LR = 删除任务函数的地址

MOV R0,#0x0

STMFD R1!,{R0} // push R12

STMFD R1!,{R0} // push R3

STMFD R1!,{R0} // push R2

STMFD R1!,{R0} // push R1

STMFD R1!,{R2} // push R0 = argv

STMFD R1!,{R0} // push R11

STMFD R1!,{R0} // push R10

STMFD R1!,{R0} // push R9

STMFD R1!,{R0} // push R8

STMFD R1!,{R0} // push R7

STMFD R1!,{R0} // push R6

STMFD R1!,{R0} // push R5

STMFD R1!,{R0} // push R4

// 返回新栈顶

MOV R0, R1

BX LR

ALIGN

}

/

@brief 变动CPU模式,并设置PendSV的优先级为最低

/

__asm void OS_ChangeCpuMode (void stk){

PRESERVE8

THUMB

NVIC_SYSPRI2 EQU 0xE000ED20 // 系统优先级寄存器(2)

NVIC_PENDSV_PRI EQU 0xFFFF0000 // PendSV中断和系统节拍中断 (都为最低,0xff).

MSR PSP,R0

// 设置中断优先级,将PendSV设为最低

LDR R0, =NVIC_SYSPRI2

LDR R1, =NVIC_PENDSV_PRI

STR R1, [R0]

// 改换CPU模式,使线程模式运行在特权级,#0x3则运行在用户级

MOV R0,#0x2

MSR CONTROL,R0

// 开中断

CPSIE I

BX LR

ALIGN

}

/

@brief 切换到下一个任务

/

void _OS_TaskPass(void){

OS_PendSV();

}

/// 引用配置文件中的定义,os是一个模块,是要被编译成lib文件的,以是这里只要声明即可

extern int const IDLE_TASK_TACK_SIZE;

extern uint64_t IdleTaskTackBuff[];

extern int const FIRST_TASK_TACK_SIZE;

extern uint64_t FirstTaskTackBuff[];

/// 本例固定定义4个TCB,实际编写时应采取声明,由os配置文件做详细定义,同上

/// 这样在编译OS时不依赖任何运用干系的配置

TCB tcbArray[2+2];

int tcbIndex = 0;

int osSchedIndex;

// 这是一个大略实现函数

void OS_Sched(void){

// 查找一个没有被删除的任务

do{

osSchedIndex++;

if(osSchedIndex >= 4){

osSchedIndex = 0;

}

}while(tcbArray[osSchedIndex].deleteFlag == 1);

os.rdy = &tcbArray[osSchedIndex];

}

/

@brief 这是一个大略实现函数,一样平常要做链表的插入操作

/

int _OS_TaskCreate(void (taskFun)(void),void stk,int prio_stkSize,void argv){

if(tcbIndex >= 4){

return -1;

}

// 取优先级参数,此例暂不该用

//int prio = (prio_stkSize & 0xff);

// 取堆栈size

prio_stkSize = prio_stkSize>>8;

// 初始化任务堆栈

stk = (void)((int)stk + prio_stkSize);

stk = OS_TaskStackInit(taskFun,stk,argv);

// 初始化TCB,此例没有任务管理功能,仅设置栈顶即可

tcbArray[tcbIndex].stack = stk;

tcbArray[tcbIndex].deleteFlag = 0;

// 返回任务ID

return tcbIndex++;

}

// 这是一个大略实现函数

void OS_Start(void (taskFun)(void)){

extern void OS_IdleTask(void);

// 初始化空闲任务,默认利用tcbArray[0]

// 空闲任务的堆栈不须要初始化,多单步运行几次你就会明白的

tcbArray[0].stack = (void)((int)IdleTaskTackBuff + IDLE_TASK_TACK_SIZE);

tcbArray[0].deleteFlag = 0;

// 创建第一个任务

tcbIndex = 1;

_OS_TaskCreate(taskFun,FirstTaskTackBuff,0|(FIRST_TASK_TACK_SIZE<<8),0);

// os.run指向空闲任务

osSchedIndex = 0;

os.run = &tcbArray[0];

// 启动任务

OS_ChangeCpuMode(os.run->stack);

_OS_TaskPass();

OS_IdleTask();

}

__weak void OS_IdleTask(void){

// 把稳:本列没有实现定时器,以是要主动切换任务,不然就一贯运行在这里

// 若要实现定时器,只须要在处理完韶光事务后调用OS_PendSV()函数即可切换任务

while(1)

os_pass();

}

复制代码

头文件部分

#include \公众stdint.h\公众

// 把稳:不能直策应用这个函数,要经由SVC才可以,参考下面的例子,其它函数也一样,请自行举一反三

extern int _OS_TaskCreate(void (taskFun)(void),void stk,int prio_stkSize,void argv);

extern void _OS_TaskPass(void);

/

@brief 堆栈定义宏

/

#define TACK_DEF(pool,size) unsigned long long pool[((size)+7)/8]

#define __SVC_0 __svc_indirect(0)

extern int _os_tsk_create (uint32_t p,void (task)(void ),void stk,int prio_stkSize,void argv) __SVC_0;

extern int _os_tsk_create_ex(uint32_t p,void (task)(void),void stk,int prio_stkSize,void argv) __SVC_0;

#define os_tsk_create(taskFun,prio,stk,stkSize) \

_os_tsk_create((uint32_t)_OS_TaskCreate,taskFun,stk,prio|(stkSize<<8),(void)0)

#define os_tsk_create_ex(taskFun,prio,stk,stkSize,argv) \

_os_tsk_create_ex((uint32_t)_OS_TaskCreate,taskFun,stk,prio|(stkSize<<8),argv)

extern void _os_pass (uint32_t p) __SVC_0;

#define os_pass() _os_pass((uint32_t)_OS_TaskPass) // 把稳:这只是一个SVC调用的例子,实际上此函数不须要经由SVC

复制代码

运用部分

#include \"大众os.h\"大众

// 配置空闲任务堆栈与第一个任务堆栈的例子,请利用Configuration Wizard窗口,不过此功能仅keil才有

//-------- <<< Use Configuration Wizard in Context Menu >>> -----------------

// <o>Idle Task stack size [bytes] <128-4096:128><#/4>

// <i> Default: 512

#ifndef OS_STKSIZE

#define OS_STKSIZE 64

#endif

// <o>First Task stack size [bytes] <128-4096:128><#/4>

// <i> Default: 512

#ifndef MAIN_TASK_STKSIZE

#define MAIN_TASK_STKSIZE 256

#endif

//------------- <<< end of configuration section >>> -----------------------

int const IDLE_TASK_TACK_SIZE = OS_STKSIZE4;

int const FIRST_TASK_TACK_SIZE = MAIN_TASK_STKSIZE4;

TACK_DEF(IdleTaskTackBuff,IDLE_TASK_TACK_SIZE);

TACK_DEF(FirstTaskTackBuff,FIRST_TASK_TACK_SIZE);

// 以上代码应专门放在一个配置文件里面,随项目一起,

// 以下为运用代码,仅能再创建2个任务,加上空闲任务与第一个任务共4个任务

TACK_DEF(Task1Stk,256);

TACK_DEF(Task2Stk,256);

void Task2(void argv){

int x = 0;

if((int)argv == 1){

// ...

}else{

// ...

}

while(1){

x++;

os_pass();

}

}

void Task1(void){

int x = 0;

while(1){

x++;

os_pass();

}

}

int main(void){

os_tsk_create(Task1,0,Task1Stk,sizeof(Task1Stk));

os_tsk_create_ex(Task2,0,Task2Stk,sizeof(Task2Stk),(void)0);

// 此函数退出后,这个任务将会被删除...

}

/

@brief 修正lib启动过程,在实行分散加载后由os接管,main函数作为第一个任务

/

#ifdef __MICROLIB

void _main_init (void) __attribute__((section(\"大众.ARM.Collect$00000007\"大众)));

__asm void _main_init (void) {

#else

__asm void __rt_entry (void) {

#endif

PRESERVE8

IMPORT main

IMPORT OS_Start

IMPORT __heap_base

IMPORT __heap_limit

#ifdef __MICROLIB

#else

IMPORT __rt_lib_init

LDR R0,=__heap_base

LDR R1,=__heap_limit

BL __rt_lib_init

#endif

LDR R0,=main

BL OS_Start

ALIGN

}

复制代码

以上图文内容均是EEWORLD论坛网友:samos2011 原创,在此感谢。

如有疑问可到EEWORLD论坛或通过微博、微信提出。

欢迎微博@EEWORLD

如果你也写过此类原创干货请关注微信"大众号:EEWORLD(电子工程天下)回答“投稿”,也可将你的原创发至:bbs_service@eeworld.com.cn,一经入选,我们将帮你登上头条!

与更多行业内网友进行互换请上岸EEWORLD论坛。

标签:

相关文章

大数据赋能制鞋行业,引领智能制造新时代

随着互联网、大数据、人工智能等新兴技术的飞速发展,我国制鞋行业迎来了前所未有的变革。大数据技术作为新时代的驱动力,为制鞋行业提供了...

PHP教程 2024-12-16 阅读0 评论0

大数据环绕,未来世界的核心驱动力

在21世纪的今天,随着科技的飞速发展,大数据已成为全球范围内最具影响力的关键词之一。大数据环绕,已成为未来世界发展的核心驱动力。本...

PHP教程 2024-12-16 阅读0 评论0