自己写的一个可以用在STM32F4的线程调度器

2021年12月7日23点52分:
目前这个调度器已成型
https://blog.csdn.net/qq_42907191/article/details/121772005.

写这个线程调度器的起因

学习单片机2年了,一直都是用的裸机开发。不过随着工程任务越来越复杂,觉得是时候上个系统了。

很多时候使用一个while(1)大循环+状态机就可以实现很多的功能,曾经我认为在单片机里加入系统,系统的任务切换会占用一定的cpu资源,感觉效率不如状态机来的高。 (好吧,当时我还没有意识到系统的强大)

不过在尝试使用了系统之后,发现很多事情方便了很多,状态机需要花费很多功夫来进行任务分布。例如我需要每个一段时间调用一个按键扫描程序,我的做法是在大循环里检查时间tick(在stm32的hal库中就使用HAL_GetTick()来获取时间),到时间了就执行按键扫描一次。

但是使用系统后只需要新建一个任务,里面加个循环直接用系统的延时函数就能实现相同功能。这个还不是系统最强大的地方,系统还可以通过对中断的响应,从一个任务切换到另一个任务(这是我觉得系统最强大的地方,也是系统能充分利用cpu的来源)。这个特性在代码中的体现就是中断对邮箱发送消息,然后中断结束之后系统就会立即吧任务切换到读取邮箱的任务中。(这个特性在我做的一个小玩意中让我省了一个定时器,原本裸机程序中这个定时器的中断是用来当作比while(1)优先级高,比USB中断优先级低的线程使用的,用来处理USB的数据)

不过我并不打算使用现成的操作系统,我打算尝试自己写一个,我最先从 Cortex-M3权威指南 来研究(先不管标题为什么是M4,先从简单的做起),这玩意有中文翻译版,学习起来比盯着满天英文舒服的很多,里面还要一些汇编指令的说明,为我写任务调度器提供了支持(任务调度内核还是离不开汇编的),然后我发现还有 ARM Cortex-M3与Cortex-M4权威指南 这个“葵花宝典”,这个也是中文的,因为M4多了FPU,内核编写需要注意浮点寄存器的处理(FPU这个鬼玩意个地方比较坑 FPU->FPCAR这个寄存器似乎于MSP有关联)。

实现参考

我先用STM32CubeMX生成了个带freertos的工程(不用自己移植简直不要太方便),先从freertos入手,研究freertos的源码。发现这个rtos临界区满天飞,而且区是由屏蔽全局中断来实现的(吐了一口老血),cortex强大的中断系统,中断这么一掐,心里总感觉不舒服,感觉这种系统用起来很不踏实(个人感觉)。然后我寻找有没有不掐中断的系统,结果还真找到了,它就是RTX,不过它凭什么不需要使用关中断来实现数据同步呢,在keil的目录中有RTX的源码,研究之后发现,其实,RTX在cortex中能实现不关中断又能实现数据同步,是因为它使用了LDREX/STREX这两个指令

自己写的一个可以用在STM32F4的线程调度器_第1张图片
RTX源码中有个宏定义 __USE_EXCLUSIVE_ACCESS 决定了使不使用这个特性

利用这两个指令的特性可以保证写入数据的原子特性,也可以得知,如果RTX用在没有类似于LDREX/STREX特性的平台上,它还是要乖乖关中断。

不过我实现的这个线程调度器并不想依赖这个特性(不想过多依赖硬件特性),当时我又不想屏蔽中断(中断是不可能掐的,这辈子都是不可能掐的),这使得我不得不将有关于中断的os功能削弱一点,在freertos中一个邮箱应该是能接收多个中断的发送请求的,但我的os的邮箱只能接收一个(没有关中断的支持也没办法啊)。 不过一般情况下邮箱只会有一个发送者,这个削弱影响不大。

虽然中断的邮箱发送只能单发送,但是邮箱的发送者都是线程的话,邮箱支持多发送者,这使得邮箱可以一种特殊的方法接收多个中断的邮箱,每个中断都有一个线程来接收中断的邮箱,这些线程再把消息转发到同一个线程的邮箱上,勉强实现了线程接收多个中断的邮箱(这个方法有点费内存啊 为了不关中断而费点内存,不亏 )。

这个线程调度器实现的功能

这个线程调度器的源码贴在后面,第一次写这玩意,是边学边写的,现学现卖,代码写的比较奔放(命名,结构混乱),后面再慢慢把代码整理了。不过得益于奔放的代码,源码才4个文件,加上内存管理,总共7个文件。

目前这个代码我在STM32F411和STM32H750使用过,未发现问题。F1系列的我没有测试,但用在上面的话只需要将FPU相关的现场保护,相关寄存器操作去掉应该就能用了。

调度器占用的资源有:
(1)内存 (废话)
(2)SysTick中断 (只需要在中断中调用一个函数就行不需要完全占用)
(3)PendSV中断 (在Cortex中 这个中断可是任务切换利器)

这个调度器没有使用到SVC中断(我终于可以用它干一些奇怪的事情了)

目前调度器实现的功能有:
(1)线程这个都不能实现还算什么线程调度器,线程可创建,可删除(仅支持线程删除自己本身)。
(2)线程休眠线程可以释放cpu,休眠一段时间在继续运行(不就是延时嘛,但好像不完全是)
(3)邮箱中断仅支持单发单收,线程中支持多发单收,支持限定时间的发送/接收操作,支持尝试发送/接收的操作,中断仅支持尝试发送(你说什么?多发多收!好像没有这么干的必要)。
(4)锁可用于保证资源互斥访问,一个线程获得锁之后,其他线程将不能获得这个锁,直到锁的拥有线程释放了锁,锁支持尝试获取,限时尝试获取,获取失败阻塞线程,锁仅用在线程之间
(5)CPU占用率统计如果使用,这个功能将占用一个高精度定时器(要求实现一个方法,返回上次调用这个方法于这次调用这个方法所过去的时间)

目前实现的功能不是很多,不过这些功能已经可以完成很多工作了,我认为线程调度器的核心功能就是于各种中断打交道,以实现任务调度,目前调度器于中断打交道的功能只有邮箱,邮箱似乎是万能的(这里的各种中断指的是除了PendSV SysTick之外的中断,例如USB,串口等)

如何把这个线程调度器加入自己的工程中

以STM32F4的HAL工程为例:
先修改stm32f4xx_it.c文件
自己写的一个可以用在STM32F4的线程调度器_第2张图片
里面构造了个全局变量SysTick_IRQ_Call,用于存放中断回调,线程调度器会在合适的时候调用SysTick_SetIrqCallback()来设置这个中断回调,以防止线程调度器的Systick处理被提前调用,线程调度器并不会完全占用systick中断,其内部依然可以加入用户的处理代码,例如HAL库的HAL_IncTick() (这样可以不影响HAL库的工作,至于图片里为什么不是HAL_IncTick()?是因为我把HAL库的延时部分修改了)

PendSV_Handler被注释掉了,因为它在H_task_port.s中被定义了,线程调度器将完全占用PendSV

一些头文件包含需要修改

头文件1
头文件2
stm32f4xx_hal.h可以替换为stm32f4xx.h 根据平台决定
Peripheral.h是用户头文件 编译的时候缺什么加什么就行。

H_task_test.c文件的开始调度方法需要修改
自己写的一个可以用在STM32F4的线程调度器_第3张图片
其实也不算什么修改 里面就是使能fpu 设置PendSV中断优先级为最低 不同平台可能方法不同,修改为对应平台的就可以。

最后保证其他中断的优先级不为最低即可(即不能让PendSV能够抢占其他中断),因为PendSV退出后必须是退出到线程模式的。

上面都是必须要的操作,下面还有一些不是必要操作,根据需求而定。

自己写的一个可以用在STM32F4的线程调度器_第4张图片
自己写的一个可以用在STM32F4的线程调度器_第5张图片
在H_task_test.c中可以配置内存大小,内存来源于Mem这个数组并且内存在H_taskInit()中进行初始化,可以根据需要修改

自己写的一个可以用在STM32F4的线程调度器_第6张图片
H_task_test.h中一个获取时间的方法,这个是用于CPU占有率统计的,如果不使用的话,直接返回0即可

现在这个线程调度器就可以使用了

调度器的使用

具体流程为:
(初始化调度器)->(创建信号量,锁)->(初始化外设,创建任务)->(开始调度)
创建信号量、锁在初始化外设之前,这是为了避免中断在邮箱创建之前就向邮箱发送消息。

自己写的一个可以用在STM32F4的线程调度器_第7张图片
这是一个示例,User_Init()是用来初始化外设的。建议main函数一开始就调用H_TaskInit()方法来初始化线程调度器。

线程/任务
所谓线程它的本体就是一个函数

void delegate_task(void* v){

  void* dv[2];
  void (*_Void_voidPtr)(void*);

  while(1){
    H_task_Msg_Read(v,dv);
    _Void_voidPtr=dv[0];
    _Void_voidPtr(dv[1]);
  }
}

这个是线程从邮箱里读数据,邮箱每个消息固定传2个指针,这个例子中这两个指针是一个方法和其传入的参数

在这个线程调度器中,线程的本体代码需要能传入一个指针,无返回参数(其实不需要严格遵守)

目前线程调度器仅支持线程结束自己的线程,如果想结束线程,只需要调用

//退出当前线程 并释放线程占用的资源
void TaskExit(void);

或者直接让线程函数返回

//让指针v指向的无符号整型数每毫秒加1,循环1000次后退出
void _add(void* v){
  int i;
  for (i = 0; i < 1000; i++)
  {
    ((unsigned int*)v)[0]++;
    TaskSleep(1);
  }
}

其实线程返回后就跳到TaskExit()方法里了。

调度器的初始化
线程调度器的初始化使用

void H_TaskInit(void* v,int StackSize)

v 是空闲任务传入参数(其实就是一个指针),这个指针现在对于空闲任务来说似乎并没有什么用(用户也基本碰不到空闲任务)
StackSize 空闲任务堆栈大小,单位:字节,如果传入大小不为4的倍数,会转换为大于它并且最接近它的4的倍数。

线程的创建

创建任务使用方法

void CreateTask(H_task_info_def** taskPtr,void (* Code)(void*),void* v,int StackSize,int Priority)

taskPtr 如果想获取任务句柄,此段就为容纳句柄的指针,如果不想获取,传入NULL即可
Code 线程运行的代码
v 线程传入参数
StackSize 线程堆栈大小
Priority 优先级 数字越小优先级越高 可设置为除0x7FFFFFFF(int的最大值,被空闲任务使用)外的所有数(int类型),除空闲任务外,其他任务的优先级可以设置为相同,但仅仅是传入的Priority相同了,内部还是会将Priority的优先级进行区分。但是Priority不同的任务之间的优先级大小是确定的 数字小的优先级大。

开始任务调度

void StartScheduler()

调用即可,无脑操作。它后面的代码不会执行到

线程休眠
调用

//线程休眠一段时间
void TaskSleep(int NumOfTick);

后触发线程调度,NumOfTick个SysTick中断后再将线程置为就绪态


我之前用c#做过上位机,发现锁是个好东西,我的这个线程调度器也要整一个。

这个锁仅支持线程之间使用

锁相关方法:

//新建一个锁
H_task_Lock_Def* new_H_task_Lock(void);

//锁定Lock 如果Lock已被其他线程占用 则阻塞当前线程并启动任务调度
void H_task_Lock(H_task_Lock_Def* lock);

//尝试锁定一个锁 返回0:成功
int H_task_tryLock(H_task_Lock_Def* lock);

//尝试锁定一个锁 超时检测
int H_task_tryLockTimeOut(H_task_Lock_Def* lock,int TimeOut);

//释放锁
void H_task_Unlock(H_task_Lock_Def* lock);

//删除锁
void H_task_Lock_Delete(H_task_Lock_Def* lock);

邮箱

邮箱有线程之间使用的邮箱(函数名不带irq),还有线程于中断之间使用的邮箱(函数名带irq),但邮箱的类型都是H_task_Msg_irq

邮箱相关方法:

//新建邮箱
H_task_Msg_irq* new_H_task_Msg_irq(int NumMsg);

//中断向邮箱发送消息 返回 0:成功 其他:失败
int H_task_Msg_irq_Send(H_task_Msg_irq* msg,void* v0,void* v1);

//尝试读取消息 不阻塞 返回 0:成功 其他:邮箱空
int H_task_Msg_irq_tryRead(H_task_Msg_irq* msg,void** dv);

//读取消息 如果消息为空则阻塞 直到获取到消息
void H_task_Msg_irq_Read(H_task_Msg_irq* msg,void** dv);

//删除邮箱
void H_task_Msg_irq_Delete(H_task_Msg_irq* msg);

//新建邮箱
H_task_Msg_irq* new_H_task_Msg(int NumMsg);

//邮箱发送消息
void H_task_Msg_Send(H_task_Msg_irq* msg,void* v0,void* v1);

//邮箱发送消息 返回 0:成功 其他:失败
int H_task_Msg_trySend(H_task_Msg_irq* msg,void* v0,void* v1);

//尝试向邮箱发送消息 超时失败 返回 0:成功 其他:失败 
int H_task_Msg_trySendtimeOut(H_task_Msg_irq* msg,void* v0,void* v1,int TimeOut);

//尝试读取消息 不阻塞 返回 0:成功 其他:邮箱空
int H_task_Msg_tryRead(H_task_Msg_irq* msg,void** dv);

//读取消息 如果消息为空则阻塞 直到获取到消息
void H_task_Msg_Read(H_task_Msg_irq* msg,void** dv);

//尝试读取消息 阻塞 超时返回失败 返回 0:成功 其他:失败
int H_task_Msg_tryReadtimeOut(H_task_Msg_irq* msg,void** dv,int TimeOut);

//删除邮箱
void H_task_Msg_Delete(H_task_Msg_irq* msg);

能在中断调用的方法只有H_task_Msg_irq_Send(),其他的方法只能在线程里调用(其实能被用户中断调用的方法在这个线程调度器中也只有这个)。H_task_Msg_irq_Send()是线程调度器与用户中断交互的唯一通道,信息只能从中断发送到线程,然后线程再操作外设。(要不然中断直接操作外设,但是这样就没线程调度器的事情了)

还有一些细节没有详尽的说明,例如邮箱的使用细节,但是如果使用过其他os,使用这个应该不麻烦,我相信源码能说明一切。

源码

每个代码段都是一个文件,复制粘贴保存为对应的文件名即可,每段代码段都有注明文件名。这些文件可放在同一个文件夹上

+++++++++++++++++++++++++++++++++++++++++++++++++++++
文件名:H_task_test.h

#ifndef __H_task_test_H_
#define __H_task_test_H_
#include "H_Malloc.h"








typedef struct _H_task_info_def
{
  void* parent;
  void* StackPointer;
  void* Stack;
  Hsize StackSize;
  struct _H_task_info_def* next;
  struct _H_task_info_def* DelayNext;//用于延时列表的指针
  

  int Priority;//优先级 仅影响线程在列表中的排列 值越小 在列表的位置就靠前 优先级高 若有两个线程优先级相同 实际优先级也是一高一低 取决于创建线程时线程加入列表的方式
  volatile int Status;//线程状态 0:就绪 -1:线程结束标记 -2:被邮箱阻塞 -3:被锁阻塞 -4:发送时被邮箱阻塞 大于0:因延时导致的阻塞 此段还表示为延时的tick数  其他:阻塞态
  volatile void* BlockObject;//阻塞对象 当Status为被中断邮箱阻塞时 此段为中断邮箱指针 当被锁阻塞时 此段为锁的指针

}H_task_info_def;

//锁
typedef struct
{
  volatile H_task_info_def* thread;
  volatile int isHighPriorityLockReq;//是否有更高优先级的锁请求
}H_task_Lock_Def;


//用于中断向线程发送消息的消息句柄
typedef struct
{
  H_task_info_def* thread;//正在尝试读取邮箱的线程

  struct{
    void** MsgArray;
    int I_Offset;
    int O_Offset;
    int MsgArrayNum;
  }Msgs;
}H_task_Msg_irq;

typedef struct
{
  H_task_info_def* root;
  H_task_info_def* DelayRoot;
  void*** RunThread;
  volatile int SchedulerSuspend;//当此段不为0时挂起线程调度
  volatile int SchedulerForIrq;//挂起线程调度时 中断产生了调度请求后 此段被置为非0
  

  int isDelete;//是否有待删除的任务 此段由删除任务函数设置 空闲任务清除
  
  int CPU_Utilization;//1000为百分百占用 负数表示cpu占有率获取未实现或者还未得到第一个占有率
  Huint32 idleTime;//线程空闲时间
  Huint32 runTime;//线程运行时间

  struct
  {
    void* (*Malloc)(Hsize);
    void (*Free)(void*);
  }Mem;
}H_task_test;




//初始化 传入空闲任务参数和空闲任务堆栈大小
void H_TaskInit(void* v,int StackSize);

//创建任务
void CreateTask(H_task_info_def** taskPtr,void (*Code)(void*),void* v,int StackSize,int Priority);

//线程休眠一段时间
void TaskSleep(int NumOfTick);

//退出当前线程 并释放线程占用的资源
void TaskExit(void);

//开始调度
void StartScheduler(void);

//新建邮箱
H_task_Msg_irq* new_H_task_Msg_irq(int NumMsg);

//中断向邮箱发送消息 返回 0:成功 其他:失败
int H_task_Msg_irq_Send(H_task_Msg_irq* msg,void* v0,void* v1);

//尝试读取消息 不阻塞 返回 0:成功 其他:邮箱空
int H_task_Msg_irq_tryRead(H_task_Msg_irq* msg,void** dv);

//读取消息 如果消息为空则阻塞 直到获取到消息
void H_task_Msg_irq_Read(H_task_Msg_irq* msg,void** dv);

//删除邮箱
void H_task_Msg_irq_Delete(H_task_Msg_irq* msg);

//新建邮箱
H_task_Msg_irq* new_H_task_Msg(int NumMsg);

//邮箱发送消息
void H_task_Msg_Send(H_task_Msg_irq* msg,void* v0,void* v1);

//邮箱发送消息 返回 0:成功 其他:失败
int H_task_Msg_trySend(H_task_Msg_irq* msg,void* v0,void* v1);

//尝试向邮箱发送消息 超时失败 返回 0:成功 其他:失败 
int H_task_Msg_trySendtimeOut(H_task_Msg_irq* msg,void* v0,void* v1,int TimeOut);

//尝试读取消息 不阻塞 返回 0:成功 其他:邮箱空
int H_task_Msg_tryRead(H_task_Msg_irq* msg,void** dv);

//读取消息 如果消息为空则阻塞 直到获取到消息
void H_task_Msg_Read(H_task_Msg_irq* msg,void** dv);

//尝试读取消息 阻塞 超时返回失败 返回 0:成功 其他:失败
int H_task_Msg_tryReadtimeOut(H_task_Msg_irq* msg,void** dv,int TimeOut);

//删除邮箱
void H_task_Msg_Delete(H_task_Msg_irq* msg);

//新建一个锁
H_task_Lock_Def* new_H_task_Lock(void);

//锁定Lock 如果Lock已被其他线程占用 则阻塞当前线程并启动任务调度
void H_task_Lock(H_task_Lock_Def* lock);

//尝试锁定一个锁 返回0:成功
int H_task_tryLock(H_task_Lock_Def* lock);

//尝试锁定一个锁 超时检测
int H_task_tryLockTimeOut(H_task_Lock_Def* lock,int TimeOut);

//释放锁
void H_task_Unlock(H_task_Lock_Def* lock);

//删除锁
void H_task_Lock_Delete(H_task_Lock_Def* lock);

//获取cpu占用率
int H_task_getCPU_Utilization(void);

#endif //__H_task_test_H_

+++++++++++++++++++++++++++++++++++++++++++++++++++++
文件名:H_task_test.c

#include "H_task_test.h"
#include "stm32f4xx_hal.h"


H_task_test* H_task_tcp;

__align(8) static Hbyte Mem[16*1024];


extern H_task_info_def* new_Task(void (*Code)(void*),void* v,int StackSize,int Priority);
extern void port_startFirstThread(void);

static void* Malloc(Hsize Size){
  void* r;
  r=H_Malloc(Mem,Size);
  if(r==NULL){
    for(;;)
    {
      //无效内存
    }
    
  }
  return r;
}
static void Free(void* p){
  H_Free(Mem,p);
}

int GetMemBfb(){
  H_Malloc_Info_Def info;

  H_task_tcp->SchedulerSuspend=-1;//挂起任务调度

  H_Malloc_GetInfo(Mem,&info);

  H_task_tcp->SchedulerSuspend=0;//允许任务调度
  if(H_task_tcp->SchedulerForIrq){
    H_task_tcp->SchedulerForIrq=0;
    SCB->ICSR|=SCB_ICSR_PENDSVSET_Msk;//触发调度
  }

  return 100*info.UseSize/(info.UseSize+info.FreeSize);
}





static void tryDeleteTask(){
  H_task_info_def* t;
  H_task_info_def* p;
  H_task_info_def* p_last;

  p=H_task_tcp->root;

  H_task_tcp->SchedulerSuspend=-1;//挂起任务调度

  while(p!=NULL){
    if(p->Status!=-1){
      break;
    }else{
      t=p;
      p=p->next;
      H_task_tcp->Mem.Free(t->StackPointer);
      H_task_tcp->Mem.Free(t->Stack);
      H_task_tcp->Mem.Free(t);
    }
  }
  H_task_tcp->root=p;

  if(H_task_tcp->root!=NULL){
    p_last=H_task_tcp->root;
    p=p_last->next;
    while(p!=NULL)
    {
      if(p->Status!=-1)
      {
        p_last=p;
        p=p->next;
      }else{
        p_last->next=p->next;
        t=p;
        p=p->next;
        H_task_tcp->Mem.Free(t->StackPointer);
        H_task_tcp->Mem.Free(t->Stack);
        H_task_tcp->Mem.Free(t);
      }
    }
  }else{
    for(;;){
      //根节点不可能为空
    }
  }

  H_task_tcp->SchedulerSuspend=0;//允许任务调度
  if(H_task_tcp->SchedulerForIrq){
    H_task_tcp->SchedulerForIrq=0;
    SCB->ICSR|=SCB_ICSR_PENDSVSET_Msk;//触发调度
  }
}

void EmptyTask(void* v){
  for(;;)
  {
    if(H_task_tcp->isDelete)
    {
      H_task_tcp->isDelete=0;
      tryDeleteTask();
    }
  }
}


//初始化 传入空闲任务参数和空闲任务堆栈大小
void H_TaskInit(void* v,int StackSize){
  H_task_info_def* t;

  H_Malloc_Init(Mem,16*1024);


  H_task_tcp=Malloc(sizeof(H_task_test));
  H_task_tcp->Mem.Malloc=Malloc;
  H_task_tcp->Mem.Free=Free;
  H_task_tcp->RunThread=NULL;
  H_task_tcp->DelayRoot=NULL;
  H_task_tcp->isDelete=0;
  H_task_tcp->SchedulerForIrq=0;
  H_task_tcp->CPU_Utilization=-1;
  H_task_tcp->idleTime=0;
  H_task_tcp->runTime=0;


  t=new_Task(EmptyTask,v,StackSize,0x7FFFFFFF);
  t->next=NULL;
  t->parent=H_task_tcp;

  H_task_tcp->root=t;

}

//创建任务
void CreateTask(H_task_info_def** taskPtr,void (*Code)(void*),void* v,int StackSize,int Priority){
  H_task_info_def* t;
  H_task_info_def* p;
  H_task_info_def* p_last;
  H_task_info_def* _this;

  if(Priority==0x7FFFFFFF){
    //不能使用这个优先级
    return;
  }

  H_task_tcp->SchedulerSuspend=-1;//挂起任务调度

  t=new_Task(Code,v,StackSize,Priority);
  t->next=NULL;
  t->parent=H_task_tcp;

  if (taskPtr!=NULL)
  {
    *taskPtr=t;
  }

  if(H_task_tcp->root->Priority>Priority){
    t->next=H_task_tcp->root;
    H_task_tcp->root=t;
  }else{
    p_last=H_task_tcp->root;
    p=p_last->next;

    while(p!=NULL){
      if(p->Priority>Priority){
        t->next=p;
        p_last->next=t;

        H_task_tcp->SchedulerSuspend=0;//允许任务调度
        if(H_task_tcp->SchedulerForIrq){
          H_task_tcp->SchedulerForIrq=0;
          SCB->ICSR|=SCB_ICSR_PENDSVSET_Msk;//触发调度
        }else{
          if(H_task_tcp->RunThread!=NULL){
            _this=(*H_task_tcp->RunThread)[1];
            if(_this->Priority>Priority){
              //新建的任务优先级比当前任务优先级更高 触发调度
              SCB->ICSR|=SCB_ICSR_PENDSVSET_Msk;//触发调度
            }
          }
        }
        return;
      }
      p_last=p;
      p=p->next;
    }
    t->next=NULL;
    p_last->next=t;
  }

  H_task_tcp->SchedulerSuspend=0;//允许任务调度
  if(H_task_tcp->SchedulerForIrq){
    H_task_tcp->SchedulerForIrq=0;
    SCB->ICSR|=SCB_ICSR_PENDSVSET_Msk;//触发调度
  }else{
    if(H_task_tcp->RunThread!=NULL){
      _this=(*H_task_tcp->RunThread)[1];
      if(_this->Priority>Priority){
        //新建的任务优先级比当前任务优先级更高 触发调度
        SCB->ICSR|=SCB_ICSR_PENDSVSET_Msk;//触发调度
      }
    }
  }


}


//线程休眠一段时间
void TaskSleep(int NumOfTick){
  H_task_info_def* _this;
  H_task_info_def* p;

  if(NumOfTick<=0){
    //进来个不大于0的家伙 是不是不想活了
    return;
  }

  _this=(*H_task_tcp->RunThread)[1];

  H_task_tcp->SchedulerSuspend=-1;//挂起任务调度
	

  _this->Status=NumOfTick;
  if(H_task_tcp->DelayRoot==NULL){
    _this->DelayNext=NULL;
    H_task_tcp->DelayRoot=_this;
  }else{
    p=H_task_tcp->DelayRoot;
    while (p->DelayNext!=NULL)
    {
      p=p->DelayNext;
    }
    _this->DelayNext=NULL;
    p->DelayNext=_this;
  }
  H_task_tcp->SchedulerSuspend=0;//允许任务调度
  if(H_task_tcp->SchedulerForIrq){
    H_task_tcp->SchedulerForIrq=0;
  }
  SCB->ICSR|=SCB_ICSR_PENDSVSET_Msk;//触发调度
  while(_this->Status){
    //等待阻塞结束
  }

}

//直接终止一个线程 并释放线程占用的资源 如果传入的为NULL 则为终止调用它的线程
void TaskAbort(H_task_info_def* Thread){
  H_task_info_def* _this;

  _this=(*H_task_tcp->RunThread)[1];
  if(Thread!=NULL){
    if(_this!=Thread){
      //终止的不是本线程

      H_task_tcp->SchedulerSuspend=-1;//挂起任务调度

      Thread->Status=-1;//线程结束标记
      H_task_tcp->isDelete=-1;

      H_task_tcp->SchedulerSuspend=0;//允许任务调度
      if(H_task_tcp->SchedulerForIrq){
        H_task_tcp->SchedulerForIrq=0;
        SCB->ICSR|=SCB_ICSR_PENDSVSET_Msk;//触发调度
      }

      return;
    }
  }

  //终止的是本线程

  H_task_tcp->SchedulerSuspend=-1;//挂起任务调度

  _this->Status=-1;//线程结束标记
  H_task_tcp->isDelete=-1;
  
  H_task_tcp->SchedulerSuspend=0;//允许任务调度
  if(H_task_tcp->SchedulerForIrq){
    H_task_tcp->SchedulerForIrq=0;
  }
  SCB->ICSR|=SCB_ICSR_PENDSVSET_Msk;//触发调度
  for(;;){
  }
}

//退出当前线程 并释放线程占用的资源
void TaskExit(){
  H_task_info_def* _this;

  _this=(*H_task_tcp->RunThread)[1];
  H_task_tcp->SchedulerSuspend=-1;//挂起任务调度

  _this->Status=-1;//线程结束标记
  H_task_tcp->isDelete=-1;
  
  H_task_tcp->SchedulerSuspend=0;//允许任务调度
  if(H_task_tcp->SchedulerForIrq){
    H_task_tcp->SchedulerForIrq=0;
  }
  SCB->ICSR|=SCB_ICSR_PENDSVSET_Msk;//触发调度
  for(;;){
  }
}

//开始调度
void StartScheduler(){
  FPU->FPCCR|=FPU_FPCCR_ASPEN_Msk|FPU_FPCCR_LSPEN_Msk;
  HAL_NVIC_SetPriority(PendSV_IRQn, 15U, 0U);
  port_startFirstThread();
}

//新建邮箱
H_task_Msg_irq* new_H_task_Msg_irq(int NumMsg){
  H_task_Msg_irq* r;

  H_task_tcp->SchedulerSuspend=-1;//挂起任务调度


  r=H_task_tcp->Mem.Malloc(sizeof(H_task_Msg_irq));
  r->Msgs.MsgArray=H_task_tcp->Mem.Malloc(sizeof(void*)*2*NumMsg);
  r->thread=NULL;
  r->Msgs.MsgArrayNum=NumMsg;
  r->Msgs.I_Offset=0;
  r->Msgs.O_Offset=0;


  H_task_tcp->SchedulerSuspend=0;//允许任务调度
  if(H_task_tcp->SchedulerForIrq){
    H_task_tcp->SchedulerForIrq=0;
    SCB->ICSR|=SCB_ICSR_PENDSVSET_Msk;//触发调度
  }

  return r;
} 

//中断向邮箱发送消息 返回 0:成功 其他:失败
int H_task_Msg_irq_Send(H_task_Msg_irq* msg,void* v0,void* v1){
  void** v;
  int EmptyNum;

  //判断是否有足够空间
	if(msg->Msgs.I_Offset < msg->Msgs.O_Offset){
		EmptyNum = msg->Msgs.O_Offset - msg->Msgs.I_Offset;
	}else{
		EmptyNum = msg->Msgs.MsgArrayNum - msg->Msgs.I_Offset + msg->Msgs.O_Offset;
	}
	//至少要空出一个容量
	if(EmptyNum<2){
		return -1;
	}


  v=&msg->Msgs.MsgArray[2*msg->Msgs.I_Offset];
  v[0]=v0;
  v[1]=v1;

  if(msg->Msgs.I_Offset==(msg->Msgs.MsgArrayNum-1)){
    msg->Msgs.I_Offset=0;
  }else{
    msg->Msgs.I_Offset++;
  }

  if(msg->thread!=NULL){
    if(msg->thread->Status==-2){
      //邮箱阻塞了线程

      if(H_task_tcp->SchedulerSuspend){
        H_task_tcp->SchedulerForIrq=1;
      }else{
        SCB->ICSR|=SCB_ICSR_PENDSVSET_Msk;//触发调度
      }
    }
  }
  return 0;
}

//尝试读取消息 不阻塞 返回 0:成功 其他:邮箱空
int H_task_Msg_irq_tryRead(H_task_Msg_irq* msg,void** dv){
  void** v;


  if(msg->Msgs.I_Offset!=msg->Msgs.O_Offset){
    v=&msg->Msgs.MsgArray[2*msg->Msgs.O_Offset];
    dv[0]=v[0];
    dv[1]=v[1];
    if(msg->Msgs.O_Offset==(msg->Msgs.MsgArrayNum-1)){
      msg->Msgs.O_Offset=0;
    }else{
      msg->Msgs.O_Offset++;
    }
    return 0;
  }

  return -1;
}

//读取消息 如果消息为空则阻塞 直到获取到消息
void H_task_Msg_irq_Read(H_task_Msg_irq* msg,void** dv){
  H_task_info_def* _this;

  _this=(*H_task_tcp->RunThread)[1];


  if(0!=H_task_Msg_irq_tryRead(msg,dv)){

    //阻塞
    _this->BlockObject=msg;
    _this->Status=-2;//被邮箱阻塞
    msg->thread=_this;
    SCB->ICSR|=SCB_ICSR_PENDSVSET_Msk;//触发调度

    while(0!=H_task_Msg_irq_tryRead(msg,dv)){
      //等待读取到数据
    }

  }
}

//删除邮箱
void H_task_Msg_irq_Delete(H_task_Msg_irq* msg){
  H_task_tcp->SchedulerSuspend=-1;//挂起任务调度

  H_task_tcp->Mem.Free(msg->Msgs.MsgArray);
  H_task_tcp->Mem.Free(msg);

  H_task_tcp->SchedulerSuspend=0;//允许任务调度
  if(H_task_tcp->SchedulerForIrq){
    H_task_tcp->SchedulerForIrq=0;
    SCB->ICSR|=SCB_ICSR_PENDSVSET_Msk;//触发调度
  }
}

//新建邮箱
H_task_Msg_irq* new_H_task_Msg(int NumMsg){
  return new_H_task_Msg_irq(NumMsg);
}

static int msgisNoEmpty(H_task_Msg_irq* msg){
  int EmptyNum;
  //判断是否有足够空间
	if(msg->Msgs.I_Offset < msg->Msgs.O_Offset){
		EmptyNum = msg->Msgs.O_Offset - msg->Msgs.I_Offset;
	}else{
		EmptyNum = msg->Msgs.MsgArrayNum - msg->Msgs.I_Offset + msg->Msgs.O_Offset;
	}
	//至少要空出一个容量
	if(EmptyNum<2){
    return -1;
  }

  return 0;
}

//邮箱发送消息
void H_task_Msg_Send(H_task_Msg_irq* msg,void* v0,void* v1){
  void** v;
  int EmptyNum;
  H_task_info_def* _this;

  _this=(*H_task_tcp->RunThread)[1];

  H_task_tcp->SchedulerSuspend=-1;//挂起任务调度

  //判断是否有足够空间
	if(msg->Msgs.I_Offset < msg->Msgs.O_Offset){
		EmptyNum = msg->Msgs.O_Offset - msg->Msgs.I_Offset;
	}else{
		EmptyNum = msg->Msgs.MsgArrayNum - msg->Msgs.I_Offset + msg->Msgs.O_Offset;
	}
	//至少要空出一个容量
	if(EmptyNum<2){

    //阻塞
    _this->BlockObject=msg;
    _this->Status=-4;//被邮箱阻塞
    msg->thread=_this;

    H_task_tcp->SchedulerSuspend=0;//允许任务调度
    if(H_task_tcp->SchedulerForIrq){
      H_task_tcp->SchedulerForIrq=0;
    }
    SCB->ICSR|=SCB_ICSR_PENDSVSET_Msk;//触发调度
		
    while(msg->thread!=_this){
    }

    H_task_tcp->SchedulerSuspend=-1;//挂起任务调度
	}


  v=&msg->Msgs.MsgArray[2*msg->Msgs.I_Offset];
  v[0]=v0;
  v[1]=v1;

  if(msg->Msgs.I_Offset==(msg->Msgs.MsgArrayNum-1)){
    msg->Msgs.I_Offset=0;
  }else{
    msg->Msgs.I_Offset++;
  }

  if(msg->thread!=NULL){

    if(msg->thread->Priority<_this->Priority){

      //读取线程优先级更高

      H_task_tcp->SchedulerSuspend=0;//允许任务调度
      if(H_task_tcp->SchedulerForIrq){
        H_task_tcp->SchedulerForIrq=0;
      }
      SCB->ICSR|=SCB_ICSR_PENDSVSET_Msk;//触发调度
      return;
    }
  }

  H_task_tcp->SchedulerSuspend=0;//允许任务调度
  if(H_task_tcp->SchedulerForIrq){
    H_task_tcp->SchedulerForIrq=0;
    SCB->ICSR|=SCB_ICSR_PENDSVSET_Msk;//触发调度
  }
	
	return;
}

//邮箱发送消息 返回 0:成功 其他:失败
int H_task_Msg_trySend(H_task_Msg_irq* msg,void* v0,void* v1){
  void** v;
  int EmptyNum;
  H_task_info_def* _this;

  _this=(*H_task_tcp->RunThread)[1];

  H_task_tcp->SchedulerSuspend=-1;//挂起任务调度

  //判断是否有足够空间
	if(msg->Msgs.I_Offset < msg->Msgs.O_Offset){
		EmptyNum = msg->Msgs.O_Offset - msg->Msgs.I_Offset;
	}else{
		EmptyNum = msg->Msgs.MsgArrayNum - msg->Msgs.I_Offset + msg->Msgs.O_Offset;
	}
	//至少要空出一个容量
	if(EmptyNum<2){
    
    H_task_tcp->SchedulerSuspend=0;//允许任务调度
    if(H_task_tcp->SchedulerForIrq){
      H_task_tcp->SchedulerForIrq=0;
      SCB->ICSR|=SCB_ICSR_PENDSVSET_Msk;//触发调度
    }
		return -1;
	}


  v=&msg->Msgs.MsgArray[2*msg->Msgs.I_Offset];
  v[0]=v0;
  v[1]=v1;

  if(msg->Msgs.I_Offset==(msg->Msgs.MsgArrayNum-1)){
    msg->Msgs.I_Offset=0;
  }else{
    msg->Msgs.I_Offset++;
  }

  if(msg->thread!=NULL){

    if(msg->thread->Priority<_this->Priority){

      //读取线程优先级更高

      H_task_tcp->SchedulerSuspend=0;//允许任务调度
      if(H_task_tcp->SchedulerForIrq){
        H_task_tcp->SchedulerForIrq=0;
      }
      SCB->ICSR|=SCB_ICSR_PENDSVSET_Msk;//触发调度
      return 0;
    }
  }

  H_task_tcp->SchedulerSuspend=0;//允许任务调度
  if(H_task_tcp->SchedulerForIrq){
    H_task_tcp->SchedulerForIrq=0;
    SCB->ICSR|=SCB_ICSR_PENDSVSET_Msk;//触发调度
  }
	
	return 0;
}


//尝试向邮箱发送消息 超时失败 返回 0:成功 其他:失败 
int H_task_Msg_trySendtimeOut(H_task_Msg_irq* msg,void* v0,void* v1,int TimeOut){

  int r;

  r=H_task_Msg_trySend(msg,v0,v1);
  if(r==0){
    return 0;
  }
  while(TimeOut){
    TimeOut--;

    TaskSleep(1);

    r=H_task_Msg_trySend(msg,v0,v1);
    if(r==0){
      return 0;
    }
  }

	return 0;
}

//尝试读取消息 不阻塞 返回 0:成功 其他:邮箱空
int H_task_Msg_tryRead(H_task_Msg_irq* msg,void** dv){
  return H_task_Msg_irq_tryRead(msg,dv);
}

//读取消息 如果消息为空则阻塞 直到获取到消息
void H_task_Msg_Read(H_task_Msg_irq* msg,void** dv){
  H_task_Msg_irq_Read(msg,dv);
  
}

//尝试读取消息 阻塞 超时返回失败 返回 0:成功 其他:失败
int H_task_Msg_tryReadtimeOut(H_task_Msg_irq* msg,void** dv,int TimeOut){
  int r;

  r=H_task_Msg_tryRead(msg,dv);
  if(r==0){
    return 0;
  }
  while(TimeOut){
    TimeOut--;

    TaskSleep(1);

    r=H_task_Msg_tryRead(msg,dv);
    if(r==0){
      return 0;
    }
  }

  return r;
}

//删除邮箱
void H_task_Msg_Delete(H_task_Msg_irq* msg){
  H_task_Msg_irq_Delete(msg);
}

//新建一个锁
H_task_Lock_Def* new_H_task_Lock(){
  H_task_Lock_Def* r;

  H_task_tcp->SchedulerSuspend=-1;//挂起任务调度

  r=H_task_tcp->Mem.Malloc(sizeof(H_task_Lock_Def));
  r->isHighPriorityLockReq=0;
  r->thread=NULL;

  H_task_tcp->SchedulerSuspend=0;//允许任务调度
  if(H_task_tcp->SchedulerForIrq){
    H_task_tcp->SchedulerForIrq=0;
    SCB->ICSR|=SCB_ICSR_PENDSVSET_Msk;//触发调度
  }

  return r;
}

//锁定Lock 如果Lock已被其他线程占用 则阻塞当前线程并启动任务调度
void H_task_Lock(H_task_Lock_Def* lock){
  H_task_info_def* _this;

  _this=(*H_task_tcp->RunThread)[1];

  
  H_task_tcp->SchedulerSuspend=-1;//挂起任务调度


  if((lock->thread!=NULL)&&(lock->thread!=_this)){
    //已有其他线程使用这个锁

    if(lock->thread->Priority>_this->Priority){
      //占用锁的优先级低
      lock->isHighPriorityLockReq=-1;//标记请求 已便于低优先级的线程释放锁时能触发任务调度
    }

    _this->BlockObject=lock;
    _this->Status=-3;//被锁阻塞

    H_task_tcp->SchedulerSuspend=0;//允许任务调度
    if(H_task_tcp->SchedulerForIrq){
      H_task_tcp->SchedulerForIrq=0;
    }
    SCB->ICSR|=SCB_ICSR_PENDSVSET_Msk;//触发调度
    while(lock->thread!=_this){
    }

    return;
  }else{
    lock->thread=_this;//锁定
  }  

  H_task_tcp->SchedulerSuspend=0;//允许任务调度
  if(H_task_tcp->SchedulerForIrq){
    H_task_tcp->SchedulerForIrq=0;
    SCB->ICSR|=SCB_ICSR_PENDSVSET_Msk;//触发调度
  }

}

//尝试锁定一个锁 返回0:成功
int H_task_tryLock(H_task_Lock_Def* lock){
  H_task_info_def* _this;

  _this=(*H_task_tcp->RunThread)[1];

  
  H_task_tcp->SchedulerSuspend=-1;//挂起任务调度

  if((lock->thread!=NULL)&&(lock->thread!=_this)){
    //已有其他线程使用这个锁

    H_task_tcp->SchedulerSuspend=0;//允许任务调度
    if(H_task_tcp->SchedulerForIrq){
      H_task_tcp->SchedulerForIrq=0;
      SCB->ICSR|=SCB_ICSR_PENDSVSET_Msk;//触发调度
    }
    
    return -1;
  }else{
    lock->thread=_this;//锁定
  }  

  H_task_tcp->SchedulerSuspend=0;//允许任务调度
  if(H_task_tcp->SchedulerForIrq){
    H_task_tcp->SchedulerForIrq=0;
    SCB->ICSR|=SCB_ICSR_PENDSVSET_Msk;//触发调度
  }

  return 0;
}

//尝试锁定一个锁 超时检测
int H_task_tryLockTimeOut(H_task_Lock_Def* lock,int TimeOut){
  int r;

  r=H_task_tryLock(lock);
  if(r==0){
    return 0;
  }
  while(TimeOut){
    TimeOut--;

    TaskSleep(1);

    r=H_task_tryLock(lock);
    if(r==0){
      return 0;
    }
  }

  return r;
}

//释放锁
void H_task_Unlock(H_task_Lock_Def* lock){
  H_task_info_def* _this;

  _this=(*H_task_tcp->RunThread)[1];

  H_task_tcp->SchedulerSuspend=-1;//挂起任务调度

  if(lock->thread==_this){
    lock->thread=NULL;
    if(lock->isHighPriorityLockReq){
      //存在更高优先级的线程尝试占用这个锁
      lock->isHighPriorityLockReq=0;

      H_task_tcp->SchedulerSuspend=0;//允许任务调度
      if(H_task_tcp->SchedulerForIrq){
        H_task_tcp->SchedulerForIrq=0;
      }
      SCB->ICSR|=SCB_ICSR_PENDSVSET_Msk;//触发调度
      return;
    }
  }

  H_task_tcp->SchedulerSuspend=0;//允许任务调度
  if(H_task_tcp->SchedulerForIrq){
    H_task_tcp->SchedulerForIrq=0;
    SCB->ICSR|=SCB_ICSR_PENDSVSET_Msk;//触发调度
  }
}

//删除锁
void H_task_Lock_Delete(H_task_Lock_Def* lock){
  H_task_tcp->SchedulerSuspend=-1;//挂起任务调度

  H_task_tcp->Mem.Free(lock);

  H_task_tcp->SchedulerSuspend=0;//允许任务调度
  if(H_task_tcp->SchedulerForIrq){
    H_task_tcp->SchedulerForIrq=0;
    SCB->ICSR|=SCB_ICSR_PENDSVSET_Msk;//触发调度
  }
}

//获取cpu占用率
int H_task_getCPU_Utilization(){
  return H_task_tcp->CPU_Utilization;
}

+++++++++++++++++++++++++++++++++++++++++++++++++++++
文件名:H_task_port.c

#include "H_task_test.h"
#include "Peripheral.h"


extern H_task_test* H_task_tcp;





void** H_Task;
void* PendSV_Call;
extern void* StartFirstThread;


//获取上次调用于本次调用之间的时间间隔
Hint32 port_GetDt(){
  static volatile Hint32 lastT=0;
  Hint32 nowT;
  Hint32 r;

  nowT=(Hint32)TIM5->CNT;

  r=nowT-lastT;
  lastT=nowT;

  return r;
}


//刷新H_Task 更新H_Task任务堆栈
void* H_Task_SP_Refresh(){
  H_task_info_def* p;
  Hint32 dt;
  int Status;
  int EmptyNum;
  void* BlockObject;

  if(H_task_tcp->SchedulerSuspend){
    return (void*)0;//调度已挂起
  }

  

  p=H_Task[1];

  if(p->Stack>H_Task[0]){
    while(1){
      //堆栈溢出
    }
  }

  dt=port_GetDt();
  H_task_tcp->runTime+=dt;
  if(p->next==NULL){
    //下一个为NULL 为空闲线程
    H_task_tcp->idleTime+=dt;
  }
  if(H_task_tcp->runTime>400000){
    H_task_tcp->CPU_Utilization=1000-(1000*H_task_tcp->idleTime/H_task_tcp->runTime);
    H_task_tcp->runTime=0;
    H_task_tcp->idleTime=0;
  }

  p=((H_task_test*)p->parent)->root;

  while(p!=NULL){
    Status=p->Status;
    if(Status==0){
      //就绪态
      if(H_Task==p->StackPointer){
        return (void*)0;
      }else{
        H_Task=p->StackPointer;
        return (void*)0xFFFFFFFF;
      }
    }else if(Status==-2){
      BlockObject=p->BlockObject;

      //是否就绪由消息管理
      if(((H_task_Msg_irq*)BlockObject)->Msgs.I_Offset!=((H_task_Msg_irq*)BlockObject)->Msgs.O_Offset){
        //不为空 就绪

        p->Status=0;
        ((H_task_Msg_irq*)BlockObject)->thread=NULL;

        if(H_Task==p->StackPointer){
          return (void*)0;
        }else{
          H_Task=p->StackPointer;
          return (void*)0xFFFFFFFF;
        }
      }
    }else if(Status==-3){
      BlockObject=p->BlockObject;

      //是否就绪由锁管理
      if(((H_task_Lock_Def*)BlockObject)->thread==NULL){
        //锁已释放 就绪

        p->Status=0;
        ((H_task_Lock_Def*)BlockObject)->thread=p;

        if(H_Task==p->StackPointer){
          return (void*)0;
        }else{
          H_Task=p->StackPointer;
          return (void*)0xFFFFFFFF;
        }
      }
    }else if(Status==-4){
      //是否就绪由消息管理
      BlockObject=p->BlockObject;

      //判断是否有足够空间
      if(((H_task_Msg_irq*)BlockObject)->Msgs.I_Offset < ((H_task_Msg_irq*)BlockObject)->Msgs.O_Offset){
        EmptyNum = ((H_task_Msg_irq*)BlockObject)->Msgs.O_Offset - ((H_task_Msg_irq*)BlockObject)->Msgs.I_Offset;
      }else{
        EmptyNum = ((H_task_Msg_irq*)BlockObject)->Msgs.MsgArrayNum - ((H_task_Msg_irq*)BlockObject)->Msgs.I_Offset + ((H_task_Msg_irq*)BlockObject)->Msgs.O_Offset;
      }
      //至少要空出一个容量
      if(EmptyNum<2){
        
      }else{

        p->Status=0;
        ((H_task_Msg_irq*)BlockObject)->thread=NULL;

        if(H_Task==p->StackPointer){
          return (void*)0;
        }else{
          H_Task=p->StackPointer;
          return (void*)0xFFFFFFFF;
        }
      }
    }
    p=p->next;
  }
  

  for(;;){
    //由于有空闲任务的存在 不可能存在没有就绪任务的情况
  }
  
}


void port_startFirstThread(){

  PendSV_Call=&StartFirstThread;
  H_Task=H_task_tcp->root->StackPointer;
  H_task_tcp->RunThread=&H_Task;
  //__ISB();
	//__DSB();


  extern void portSysTick(void* v);
  SysTick_SetIrqCallback(portSysTick,NULL);

  SCB->ICSR|=SCB_ICSR_PENDSVSET_Msk;
  
  for(;;){}
}

void portSysTick(void* v){
  H_task_info_def* p;
  H_task_info_def* p_last;
  int isScheduler;
  
  if(H_task_tcp->SchedulerSuspend){
    //调度已挂起
    return;
  }

  isScheduler=0;

  p=H_task_tcp->DelayRoot;
  while(p!=NULL){

    if(p->Status>0){
      p->Status--;
      if(p->Status==0){
        isScheduler=-1;
      }
    }

    p=p->DelayNext;
  }

  if(isScheduler){

    p=H_task_tcp->DelayRoot;

    while(p!=NULL){
      if(p->Status){
        break;
      }else{
        p=p->DelayNext;
      }
    }
    H_task_tcp->DelayRoot=p;

    if(H_task_tcp->DelayRoot!=NULL){
      p_last=H_task_tcp->DelayRoot;
      p=p_last->DelayNext;
      while(p!=NULL)
      {
        if(p->Status)
        {
          p_last=p;
          p=p->DelayNext;
        }else{
          p_last->DelayNext=p->DelayNext;
          p=p->DelayNext;
        }
      }
    }

    SCB->ICSR|=SCB_ICSR_PENDSVSET_Msk;
  }
}






H_task_info_def* new_Task(void (*Code)(void*),void* v,int StackSize,int Priority){
  H_task_info_def* t;
  void** r;
  unsigned int* Stack;
	int StackSize_div4;

  
  StackSize+=3;
  StackSize-=StackSize%4;
	
	StackSize_div4=StackSize/4;


  r=H_task_tcp->Mem.Malloc(sizeof(void*)*2);
  t=H_task_tcp->Mem.Malloc(sizeof(H_task_info_def));
  t->Priority=Priority;
  t->StackSize=StackSize;
  t->Status=0;
  t->BlockObject=NULL;
  t->Stack=H_task_tcp->Mem.Malloc(StackSize);

  r[1]=t;

  Stack=t->Stack;
  Stack[StackSize_div4-1]=0x01000000;//xPSR
  Stack[StackSize_div4-2]=((Huint32)Code);//&0xFFFFFFFE;//PC
  Stack[StackSize_div4-3]=(Huint32)TaskExit;//LR
  // Stack[StackSize_div4-4]=0x00000000;//R12
  // Stack[StackSize_div4-5]=0x00000000;//R3
  // Stack[StackSize_div4-6]=0x00000000;//R2
  // Stack[StackSize_div4-7]=0x00000000;//R1
  Stack[StackSize_div4-8]=(Huint32)v;//R0

  Stack[StackSize_div4-9]=0xFFFFFFFD;//LR 退回到线程模式 使用PSP
  Stack[StackSize_div4-10]=0;//R11
  Stack[StackSize_div4-11]=0;//R10
  Stack[StackSize_div4-12]=0;//R9
  Stack[StackSize_div4-13]=0;//R8
  Stack[StackSize_div4-14]=0;//R7
  Stack[StackSize_div4-15]=0;//R6
  Stack[StackSize_div4-16]=0;//R5
  Stack[StackSize_div4-17]=0;//R4

  r[0]=&Stack[StackSize_div4-17];

  t->StackPointer=r;

  return t;
}




+++++++++++++++++++++++++++++++++++++++++++++++++++++
注意这是.s的汇编文件
文件名:H_task_port.s

  
	AREA |.text|,CODE,READONLY
	THUMB
	PRESERVE8

	EXPORT PendSV_Handler
	EXPORT ThreadSwitch
	EXPORT StartFirstThread

	EXTERN H_Task
	EXTERN PendSV_Call
	EXTERN H_Task_SP_Refresh




ThreadSwitch PROC

	LDR       R0,=H_Task
	LDR       R12,[R0]            ;读取栈指针地址

	PUSH      {R12,LR}
	BL        H_Task_SP_Refresh  ;切换H_Task
	POP       {R12,LR}

	CMP       R0,#0              ;结果是否为0
	BXEQ      LR                 ;如果为0 返回 不做任务切换

	;开始任务切换 保存和释放堆栈
	MRS       R0,PSP             ;读线程栈指针到R0
	;ISB

	;判断线程是否使用了FPU 如果使用了 保存浮点寄存器
	TST       LR,#0x10
	VSTMDBEQ  R0!, {S16-S31}
	
	STMDB     R0!, {R4-R11,LR}   ;保存现场

	STR       R0,[R12]           ;保存栈指针

	LDR       R0,=H_Task
	LDR       R0,[R0]            ;读取栈指针地址
	LDR       R0,[R0]            ;读取栈指针

	LDMIA     R0!,{R4-R11,LR}    ;恢复现场

	;判断线程是否使用了FPU 如果使用了 恢复浮点寄存器
	TST       LR,#0x10
	VLDMIAEQ  R0!,{S16-S31}

	MSR       PSP,R0             ;恢复堆栈指针
	;ISB

	BX        LR
	
	ENDP

StartFirstThread PROC
	LDR       R0,=PendSV_Call
	LDR       R1,=ThreadSwitch
	STR       R1,[R0]
	
	;LDR       R0,=0xE000ED08     ;加载中断向量表寄存器地址(SCB->VTOR的地址)
	;LDR       R0,[R0]            ;读取栈初始指针的地址
	;LDR       R0,[R0]            ;读取栈初始指针
	;MSR       MSP,R0             ;设置主堆栈指针为初始指针
	;LDR       R1,=0xE000EF38     ;加载FPU上下文寄存器地址(FPU->FPCAR的地址)
	MOV       R0,#0
	;STR       R0,[R1]            ;FPU->FPCAR=0
	MSR       CONTROL,R0         ;设置CONTROL 特权级,使用MSP (主要是为了清除FPCA)
	;ISB

	LDR       R1,=H_Task         ;加载H_Task地址
	LDR       R1,[R1]            ;读取栈指针地址
	LDR       R0,[R1]            ;读取栈指针

	LDMIA     R0!,{R4-R11,LR}    ;恢复现场
	MSR       PSP,R0             ;恢复堆栈指针
	;ISB
	BX        LR
	ENDP


PendSV_Handler PROC
	LDR       R0,=PendSV_Call
	LDR       R0,[R0]
	BX        R0
	ENDP



	END

+++++++++++++++++++++++++++++++++++++++++++++++++++++
文件名:H_Type.c

#ifndef APP_INCLUDE_H_TYPE_H_
#define APP_INCLUDE_H_TYPE_H_



typedef unsigned char        Hbyte;

typedef int                  Hint;
typedef unsigned int         Huint;

typedef short                Hint16;
typedef unsigned short       Huint16;

typedef int                  Hint32;
typedef unsigned int         Huint32;

typedef long long            Hint64;
typedef unsigned long long   Huint64;


typedef unsigned char*       Hbyte_ptr;

typedef int*                 Hint_ptr;
typedef unsigned int*        Huint_ptr;

typedef short*               Hint16_ptr;
typedef unsigned short*      Huint16_ptr;

typedef int*                 Hint32_ptr;
typedef unsigned int*        Huint32_ptr;

typedef long long*           Hint64_ptr;
typedef unsigned long long*  Huint64_ptr;

//与(void*) 占用空间相同的整型
typedef int Hsize;

//与(void*) 占用空间相同的无符号整型
typedef unsigned int Husize;


#ifndef NULL
#define NULL ((void*)0)
#endif // !NULL



#endif /* APP_INCLUDE_H_TYPE_H_ */

+++++++++++++++++++++++++++++++++++++++++++++++++++++
文件名:H_Malloc.h

#ifndef __H_Malloc_H_
#define __H_Malloc_H_

#include "H_Type.h"




//长度使用的类型(与cpu位数相同可获得更高的效率)
#define H_Malloc_Size_Def Huint32

//对齐字节数 必须为2^n 并且不小于H_Malloc_Size_Def类型的储存字节数的两倍
#define H_Malloc_Align 8



typedef struct
{
  int Result;//结果 0:未发现问题 -1:头块不应有上一个块 -2:出现问题(长度数据被修改 尾部不对齐) -3:存在连续未分配的块 -4:上下块信息不匹配 -5:与下一块信息不匹配 -6:与上一块信息不匹配
  void* ErrPtr;//错误地址
  H_Malloc_Size_Def UseSize;//使用内存量
  H_Malloc_Size_Def FreeSize;//可申请重量
  H_Malloc_Size_Def OccupySize;//实际占用量
  H_Malloc_Size_Def NoOccupySize;//空闲量
}H_Malloc_Info_Def;




/**
 * @brief 初始化内存池
 * @param MemAddr 作为内存池数组的指针
 * @param MemSize 数组大小(字节)
 * @return 无
 */
void H_Malloc_Init(void* MemAddr,H_Malloc_Size_Def MemSize);

/**
 * @brief 向指定内存池申请内存
 * @param MemAddr 内存池地址
 * @param Size 要申请的内存大小
 * @return 申请到的内存指针 如果为NULL则为失败
 */
void* H_Malloc(void* MemAddr,H_Malloc_Size_Def Size);

/**
 * @brief 将内存释放回内存池
 * @param MemAddr 内存池地址
 * @param Ptr 要释放的内存指针
 * @return 无
 */
void H_Free(void* MemAddr,void* Ptr);

/**
 * @brief 获取内存池状态
 * @param MemAddr 内存池地址
 * @param info 用于存放信息的指针
 * @return 无
 */
void H_Malloc_GetInfo(void* MemAddr,H_Malloc_Info_Def* info);



#endif

+++++++++++++++++++++++++++++++++++++++++++++++++++++
文件名:H_Malloc.c

#include "H_Malloc.h"









typedef struct
{
  H_Malloc_Size_Def* StartSize_Ptr;//用于存放第一个内存池首地址
  H_Malloc_Size_Def* EntrySize_Ptr;//下次malloc时开始搜索的地址
  void* EndAddr;//边界地址 为(内存池首指针+内存池大小)
}H_Malloc_Header_Def;



/**
 * @brief 初始化内存池
 * @param MemAddr 作为内存池数组的指针
 * @param MemSize 数组大小(字节)
 * @return 无
 */
void H_Malloc_Init(void* MemAddr,H_Malloc_Size_Def MemSize){
	
  H_Malloc_Header_Def* Header;
  H_Malloc_Size_Def offset;
  Hbyte_ptr ptr;

  Header=(H_Malloc_Header_Def*)MemAddr;

  

  offset=sizeof(H_Malloc_Header_Def);
  while(((offset+H_Malloc_Align)%H_Malloc_Align)!=0){
    offset++;
  }
  ptr=(Hbyte_ptr)MemAddr;
  Header->StartSize_Ptr=(H_Malloc_Size_Def*)&ptr[offset];
  Header->EntrySize_Ptr=Header->StartSize_Ptr;
  Header->StartSize_Ptr[0]=MemSize-offset-H_Malloc_Align;
  Header->StartSize_Ptr[1]=0;
  Header->EndAddr=(void*)&ptr[MemSize];
}

/**
 * @brief 向指定内存池申请内存
 * @param MemAddr 内存池地址
 * @param Size 要申请的内存大小
 * @return 申请到的内存指针 如果为NULL则为失败
 */
void* H_Malloc(void* MemAddr,H_Malloc_Size_Def Size){
  H_Malloc_Header_Def* Header;
  H_Malloc_Size_Def tSize;
  H_Malloc_Size_Def* EntrySize_Ptr;
  H_Malloc_Size_Def* After_Ptr;
  H_Malloc_Size_Def* New_Ptr;
  H_Malloc_Size_Def Msk;
  Hbyte_ptr ptr;
  Hbyte_ptr r;


  if(Size==0)
  {
    return NULL;
  }

  Msk=((H_Malloc_Size_Def)0x1)<<(sizeof(H_Malloc_Size_Def)*8-1);
  Header=(H_Malloc_Header_Def*)MemAddr;
  EntrySize_Ptr=Header->EntrySize_Ptr;

  //将大小整和成H_Malloc_Align的倍数
  Size+=H_Malloc_Align-1;
  Size-=Size%H_Malloc_Align;
  
  do{
    tSize=EntrySize_Ptr[0];

    if(Msk&tSize){
      //已占用

    }else{
      //未占用

      if(tSize>Size){
        //大小不等

        if(tSize-Size<(H_Malloc_Align*2)){
          //不可分割

          *EntrySize_Ptr=tSize|Msk;
          ptr=(Hbyte_ptr)EntrySize_Ptr;
          r=&ptr[H_Malloc_Align];
          EntrySize_Ptr=(H_Malloc_Size_Def*)&ptr[tSize+H_Malloc_Align];
          if(Header->EndAddr==EntrySize_Ptr){
            EntrySize_Ptr=Header->StartSize_Ptr;
          }
          Header->EntrySize_Ptr=EntrySize_Ptr;
					return (void*)r;
        }else{
          //可分割

          ptr=(Hbyte_ptr)EntrySize_Ptr;
          After_Ptr=(H_Malloc_Size_Def*)&ptr[tSize+H_Malloc_Align];
          New_Ptr=(H_Malloc_Size_Def*)&ptr[Size+H_Malloc_Align];
          

          New_Ptr[0]=tSize-Size-H_Malloc_Align;
          New_Ptr[1]=Size;
          EntrySize_Ptr[0]=Size|Msk;

          if((void*)After_Ptr!=Header->EndAddr){
            //有下一个
            After_Ptr[1]=New_Ptr[0];
          }

          ptr=(Hbyte_ptr)EntrySize_Ptr;
          Header->EntrySize_Ptr=New_Ptr;
          return (void*)&ptr[H_Malloc_Align];
        }
      }else if(tSize==Size){
        //大小相同

        *EntrySize_Ptr=tSize|Msk;
        ptr=(Hbyte_ptr)EntrySize_Ptr;
        r=&ptr[H_Malloc_Align];
        EntrySize_Ptr=(H_Malloc_Size_Def*)&ptr[tSize+H_Malloc_Align];
        if(Header->EndAddr==EntrySize_Ptr){
          EntrySize_Ptr=Header->StartSize_Ptr;
        }
        Header->EntrySize_Ptr=EntrySize_Ptr;
        return (void*)r;
      }
    }

    ptr=(Hbyte_ptr)EntrySize_Ptr;
    EntrySize_Ptr=(H_Malloc_Size_Def*)&ptr[(tSize&(~Msk))+H_Malloc_Align];
    if(Header->EndAddr==EntrySize_Ptr){
      EntrySize_Ptr=Header->StartSize_Ptr;
    }

  }while(EntrySize_Ptr!=Header->EntrySize_Ptr);

  return NULL;
}

/**
 * @brief 将内存释放回内存池
 * @param MemAddr 内存池地址
 * @param Ptr 要释放的内存指针
 * @return 无
 */
void H_Free(void* MemAddr,void* Ptr){

  H_Malloc_Header_Def* Header;
  H_Malloc_Size_Def tSize;
  H_Malloc_Size_Def* Last_Ptr;
  H_Malloc_Size_Def* EntrySize_Ptr;
  H_Malloc_Size_Def* After_Ptr;
  H_Malloc_Size_Def* After_After_Ptr;
  H_Malloc_Size_Def Msk;
  Hbyte_ptr ptr;

  if(Ptr==NULL)
  {
    return;
  }
  

  Msk=((H_Malloc_Size_Def)0x1)<<(sizeof(H_Malloc_Size_Def)*8-1);
  Header=(H_Malloc_Header_Def*)MemAddr;
  EntrySize_Ptr=(H_Malloc_Size_Def*)((Hbyte_ptr)Ptr-(Hbyte_ptr)H_Malloc_Align);
  tSize=EntrySize_Ptr[0]&(~Msk);

  if(EntrySize_Ptr[1]==0){
    //没有上一块内存

    ptr=(Hbyte_ptr)EntrySize_Ptr;
    After_Ptr=(H_Malloc_Size_Def*)&ptr[tSize+H_Malloc_Align];

    if((void*)After_Ptr!=Header->EndAddr){
      //有下一个

      ptr=(Hbyte_ptr)After_Ptr;
      After_After_Ptr=(H_Malloc_Size_Def*)&ptr[(After_Ptr[0]&(~Msk))+H_Malloc_Align];

      if(After_Ptr[0]&Msk){
      //下一个被占用

        EntrySize_Ptr[0]&=(~Msk);//取消标记
      }else{
        //都无占用

        if(After_Ptr==Header->EntrySize_Ptr){
          //下次Malloc是即将要合并的位置

          Header->EntrySize_Ptr=EntrySize_Ptr;
        }
        EntrySize_Ptr[0]=tSize+After_Ptr[0]+H_Malloc_Align;//取消标记 并且更新大小
        if((void*)After_After_Ptr!=Header->EndAddr){
          After_After_Ptr[1]=EntrySize_Ptr[0];
        }
      }
    }else{
      //无下一个

      EntrySize_Ptr[0]&=(~Msk);//取消标记
    }
  }else{
    //有上一块内存

    Last_Ptr=(H_Malloc_Size_Def*)((Hbyte_ptr)EntrySize_Ptr-(Hbyte_ptr)(EntrySize_Ptr[1]+(H_Malloc_Size_Def)H_Malloc_Align));
    ptr=(Hbyte_ptr)EntrySize_Ptr;
    After_Ptr=(H_Malloc_Size_Def*)&ptr[tSize+H_Malloc_Align];

    if((void*)After_Ptr!=Header->EndAddr){
      //有下一个

      ptr=(Hbyte_ptr)After_Ptr;
      After_After_Ptr=(H_Malloc_Size_Def*)&ptr[(After_Ptr[0]&(~Msk))+H_Malloc_Align];

      if((Last_Ptr[0]&Msk)&&(After_Ptr[0]&Msk)){
        //都为已占用

        EntrySize_Ptr[0]&=(~Msk);//取消标记
      }else if(Last_Ptr[0]&Msk){
        //仅上一个占用 合并下一个

        if(After_Ptr==Header->EntrySize_Ptr){
          //下次Malloc是即将要合并的位置

          Header->EntrySize_Ptr=EntrySize_Ptr;
        }
        EntrySize_Ptr[0]=tSize+After_Ptr[0]+H_Malloc_Align;//取消标记 并且更新大小
        if((void*)After_After_Ptr!=Header->EndAddr){
          After_After_Ptr[1]=EntrySize_Ptr[0];
        }
      }else if(After_Ptr[0]&Msk){
        //仅下一个占用 合并到上一个

        if(EntrySize_Ptr==Header->EntrySize_Ptr){
          //下次Malloc是即将要合并的位置

          Header->EntrySize_Ptr=Last_Ptr;
        }
        Last_Ptr[0]=Last_Ptr[0]+tSize+H_Malloc_Align;//并且更新大小
        After_Ptr[1]=Last_Ptr[0];
      }else{
        //都无占用 全合并

        if((EntrySize_Ptr==Header->EntrySize_Ptr)||(After_Ptr==Header->EntrySize_Ptr)){
          //下次Malloc是即将要合并的位置

          Header->EntrySize_Ptr=Last_Ptr;
        }
        Last_Ptr[0]=Last_Ptr[0]+tSize+After_Ptr[0]+H_Malloc_Align*2;//并且更新大小
        if((void*)After_After_Ptr!=Header->EndAddr){
          After_After_Ptr[1]=Last_Ptr[0];
        }
      }
    }else{
      //无下一个

      if(Last_Ptr[0]&Msk){
        //上一个被占用

        EntrySize_Ptr[0]&=(~Msk);//取消标记
      }else{
        //都无占用

        if(EntrySize_Ptr==Header->EntrySize_Ptr){
          //下次Malloc是即将要合并的位置

          Header->EntrySize_Ptr=Last_Ptr;
        }
        Last_Ptr[0]=Last_Ptr[0]+tSize+H_Malloc_Align;//并且更新大小
      }
    }
  }
}

/**
 * @brief 获取内存池状态
 * @param MemAddr 内存池地址
 * @param info 用于存放信息的指针
 * @return 无
 */
void H_Malloc_GetInfo(void* MemAddr,H_Malloc_Info_Def* info){

  H_Malloc_Header_Def* Header;
  H_Malloc_Size_Def* EntrySize_Ptr;
  H_Malloc_Size_Def* After_Ptr;
  //H_Malloc_Size_Def* After_After_Ptr;
  H_Malloc_Size_Def* Last_Ptr;
  H_Malloc_Size_Def Msk;
  H_Malloc_Size_Def tSize;
  Hbyte_ptr ptr;

  Msk=((H_Malloc_Size_Def)0x1)<<(sizeof(H_Malloc_Size_Def)*8-1);
  Header=(H_Malloc_Header_Def*)MemAddr;


  info->UseSize=0;
  info->FreeSize=0;
  info->OccupySize=0;
  info->NoOccupySize=0;

  Last_Ptr=Header->StartSize_Ptr;

  tSize=Last_Ptr[0]&(~Msk);
  if(Last_Ptr[0]&Msk){
    info->UseSize+=tSize;
    info->OccupySize+=tSize+H_Malloc_Align;
  }else{
    info->FreeSize+=tSize;
    info->NoOccupySize+=tSize+H_Malloc_Align;
  }

  if(Last_Ptr[1]!=0){

    info->Result=-1;
    info->ErrPtr=Last_Ptr;
    return;
  }

  ptr=(Hbyte_ptr)Last_Ptr;
  EntrySize_Ptr=(H_Malloc_Size_Def*)&ptr[tSize+H_Malloc_Align];
	

  while(EntrySize_Ptr!=Header->EndAddr)
  {
    if((void*)EntrySize_Ptr > Header->EndAddr){
      info->Result=-2;
      info->ErrPtr=EntrySize_Ptr;
      return;
    }


    tSize=EntrySize_Ptr[0]&(~Msk);
		
		
		if(EntrySize_Ptr[1]==0){
			//没有上一块内存
			
			ptr=(Hbyte_ptr)EntrySize_Ptr;
			After_Ptr=(H_Malloc_Size_Def*)&ptr[tSize+H_Malloc_Align];
			
			if((void*)After_Ptr!=Header->EndAddr){
				//有下一个

				ptr=(Hbyte_ptr)After_Ptr;
				//After_After_Ptr=(H_Malloc_Size_Def*)&ptr[(After_Ptr[0]&(~Msk))+H_Malloc_Align];

				if(After_Ptr[1]!=tSize){
					info->Result=-5;
					info->ErrPtr=EntrySize_Ptr;
					return;
				}
			}else{
				//无下一个
			}
		}else{
			//有上一块内存
			
			
			Last_Ptr=(H_Malloc_Size_Def*)((Hbyte_ptr)EntrySize_Ptr-(Hbyte_ptr)(EntrySize_Ptr[1]+(H_Malloc_Size_Def)H_Malloc_Align));
			ptr=(Hbyte_ptr)EntrySize_Ptr;
			After_Ptr=(H_Malloc_Size_Def*)&ptr[tSize+H_Malloc_Align];

			if((void*)After_Ptr!=Header->EndAddr){
				//有下一个

				ptr=(Hbyte_ptr)After_Ptr;
				//After_After_Ptr=(H_Malloc_Size_Def*)&ptr[(After_Ptr[0]&(~Msk))+H_Malloc_Align];

				if(After_Ptr[1]!=tSize){
					info->Result=-5;
					info->ErrPtr=EntrySize_Ptr;
					return;
				}
				
				if((Last_Ptr[0]&(~Msk))!=EntrySize_Ptr[1]){
					info->Result=-6;
					info->ErrPtr=EntrySize_Ptr;
					return;
				}
				
			}else{
				//无下一个

				if((Last_Ptr[0]&(~Msk))!=EntrySize_Ptr[1]){
					info->Result=-6;
					info->ErrPtr=EntrySize_Ptr;
					return;
				}
			}
		
		}
		
    if(EntrySize_Ptr[0]&Msk){
      info->UseSize+=tSize;
      info->OccupySize+=tSize+H_Malloc_Align;
    }else{
      if((Last_Ptr[0]&Msk)==0){
        //都为未占用
        info->Result=-3;
        info->ErrPtr=Last_Ptr;
        return;
      }

      info->FreeSize+=tSize;
      info->NoOccupySize+=tSize+H_Malloc_Align;
    }

    if((Last_Ptr[0]&(~Msk))!=EntrySize_Ptr[1]){
      info->Result=-4;
      info->ErrPtr=Last_Ptr;
      return;
    }

    Last_Ptr=EntrySize_Ptr;

    ptr=(Hbyte_ptr)Last_Ptr;
    EntrySize_Ptr=(H_Malloc_Size_Def*)&ptr[tSize+H_Malloc_Align];
  }
	
	info->Result=0;
}



你可能感兴趣的:(RTOS,stm32,rtos,操作系统)