worldsing 发表于 2015-5-13 10:33:24

借傻孩子老师的地盘发个小小调度器

/*!
*************************************************************************************
*\file    switch.h
*\brief   简易的调度器
*         1、轮番调度
*         2、可以主动释放CPU
*         3、用户的栈大小可自定义
*         4、任务数可自定义
*      
*\authorworldsing
*\version V0.01
*\date    2015/04/24
*
*\b       1、去除C文件, 实现单个头文件代码结构
*         2、目前仅在ST系列的Cortex-M3平台测试过
*\li      2015/04/24
*         SWITCH_EN 宏须在创建任务的文件里定义
*************************************************************************************
*/
#ifndef __SWITCH_H__
#define __SWITCH_H__


//------------------------------------------------------------------------------------
//                                    Include File
//------------------------------------------------------------------------------------

#include <stm32f10x.h>
#include <core_cm3.h>
#include <stdint.h>
#include <stdbool.h>

//------------------------------------------------------------------------------------
//                                    Function declare
//------------------------------------------------------------------------------------

void switchDelayMs(uint16_t nTick);   


//------------------------------------------------------------------------------------
//                                    Switch code
//------------------------------------------------------------------------------------
#ifdefSWITCH_EN

__asm void setPSP(uint32_t topOfProcStack)
{
msr psp, r0
bx lr
}
                                                      
__asm void taskSwitch(void)                                    
{                                                            
    LDR   R0, =0xE000ED22                                    
    LDR   R1, =0xFF                                          
    STRB    R1,                                           
    LDR   R0, =0xE000ED04                                    
    LDR   R1, =0x10000000                                    
    STR   R1,                                           
    BX      LR                                                
    ALIGN
}                                                            
__asm void PendSV_Handler(void)                              
{                                                            
    IMPORTtaskRuning
    IMPORTtaskNew
    CPSID   I                                                
    MRS   R0, PSP                                          
    CBZ   R0, NoSave                                       
    SUBS    R0, R0, #0x20                                 
    STM   R0, {R4-R11}                                 
    LDR   R1, =taskRuning                                    
    LDR   R1,                                           
    STR   R0,                                           
                                                               
NoSave                                                   
    LDR   R0, =taskRuning                                    
    LDR   R1, =taskNew                                       
    LDR   R2,                                           
    STR   R2,                                        
    LDR   R0,                                           
    LDM   R0, {R4-R11}                                       
    ADDS    R0, R0, #0x20                                 
    MSR   PSP, R0                                          
    ORR   LR, LR, #0x04                                 
    CPSIE   I                                                
    BX      LR                                                
    ALIGN                                                      
}                                                            


#define SWITCH_CONFIG(MAX_TASK, N_TICK_IN_SECOND, SYSTEM_CLK_NMHZ,    \
                      SYS_TICK_HOOK, IDLE_HOOK);                      \
                                                                      \
typedef struct {                                                      \
uint32_t *pTaskStack;                                             \
uint16_t delay;                                                   \
}TCB;                                                               \
                                                                      \
TCB taskTCB = {0};                                    \
                                                                      \
TCB *taskNew, *taskRuning;                                          \
                                                                      \
uint8_ttaskCnt = 0;                                                 \
uint8_tnTask;                                                       \
                                                                      \
void taskIdle(void) {                                                 \
while(1){                                                         \
    IDLE_HOOK();                                                      \
    __nop();                                                          \
}                                                                   \
}                                                                     \
voidSysTick_Handler (void) {                                        \
    uint8_t i;                                                      \
    bool bOneSwitch;                                                \
    SYS_TICK_HOOK();                                                \
    bOneSwitch = false;                                             \
    for(i = 0; i < nTask; i++){                                       \
      if(taskTCB.delay != 0){                                    \
      taskTCB.delay--;                                           \
      }                                                               \
      if(bOneSwitch == false){                                        \
      taskCnt %= nTask;                                             \
      if(0 == taskTCB.delay){                              \
          bOneSwitch = true;                                          \
          taskNew = &taskTCB;                              \
          }                                                         \
      taskCnt++;                                                    \
      }                                                             \
    }                                                               \
    if(bOneSwitch == false)                                           \
      taskNew = &taskTCB;                                    \
    taskSwitch();                                                   \
}                                                                     \
                                                                      \
                                                                      \
void switchDelayMs(uint16_t nTick) {                                  \
    uint8_t i;                                                      \
    if(0 == nTick)                                                    \
      return;                                                         \
                                                                      \
    taskRuning->delay = nTick;                                        \
    for(i = 0; i < nTask; i++){                                       \

      if(0 == taskTCB.delay){                              \
         taskNew = &taskTCB;                               \
         break;                                                       \
      }else taskCnt++;                                                \
    }                                                               \
    if(taskRuning == taskNew)                                       \
      taskNew = &taskTCB;                                    \
    taskSwitch();                                                   \
}                                                                     \
                                                                      \
                                                                      \
void switchTaskInt(void (*task)(void), uint32_t *ptos) {            \
    if(MAX_TASK + 1 <= taskCnt){                                    \
      taskCnt = 0;                                                    \
      return;                                                         \
    }                                                               \
    *(ptos)    = (uint32_t)0x01000000L;                               \
    *(--ptos)= (uint32_t)task;                                    \
    taskTCB. pTaskStack =ptos -14;                     \
}                                                                     \
                                                                      \
                                                                      \
void switchStart(void){                                             \
switchTaskCreate(taskIdle, 256);                                    \
if(taskCnt < (MAX_TASK + 1))                                        \
    nTask = taskCnt;                                                \
else                                                                \
    nTask = MAX_TASK;                                                 \
setPSP(0);                                                          \
SysTick_Config((SYSTEM_CLK_NMHZ / N_TICK_IN_SECOND) - 1);         \
while(1);                                                         \
}

#define switchTaskCreate(task, stackSize) {__align(8) static uint32_t task##Stack; \
                                           switchTaskInt(task, &task##Stack[(stackSize/4)-1]);    \
                                          }

#endif

//------------------------------------------------------------------------------------
//                                    Demo code
//------------------------------------------------------------------------------------
#if(0)

#define   SWITCH_EN
#include"switch.h"

void tickHook(void)
{
        //不得放入阻塞\复杂\死循环代码       
}
       
void idleHook(void)
{
       
}       

//配置参数:最大任务数1秒Tick数 系统时钟时钟钩子空闲钩子
SWITCH_CONFIG(2, 100, 72000000, tickHook, idleHook);

       
void task0(void){                         //任务0
   for(;;){
   //这放入您的代码
   switchDelayMs(200);                  //可用delay()释放CPU
   }
}

void task1(void){                         //任务1
for(;;){
//这放入您的代码
switchDelayMs(1);                     //可用delay()释放CPU
}
}

       

int main(void){
switchTaskCreate(task0, 60);            //在调度前建立任务
switchTaskCreate(task1, 30);            //在调度前建立任务
switchStart();                        //开始调度
}
#endif

#endif

//------------------------------------------------------------------------------------
//                                    End of file
//------------------------------------------------------------------------------------

   

worldsing 发表于 2015-5-13 20:31:29

本帖最后由 worldsing 于 2015-5-13 20:33 编辑

/*!
*************************************************************************************
*\file    switch.h
*\brief   简易的调度器
*         1、轮番调度
*         2、可以主动释放CPU
*         3、用户的栈大小可自定义
*         4、任务数可自定义
*      
*\authorworldsing
*\version V0.01
*\date    2015/04/24
*
*\b       1、去除C文件, 实现单个头文件代码结构
*         2、目前仅在ST系列的Cortex-M3平台测试过
*\li      2015/04/24
*         SWITCH_EN 宏须在创建任务的文件里定义
*************************************************************************************
*/
#ifndef __SWITCH_H__
#define __SWITCH_H__


//------------------------------------------------------------------------------------
//                                    Include File
//------------------------------------------------------------------------------------

#include <stm32f10x.h>
#include <core_cm3.h>
#include <stdint.h>
#include <stdbool.h>

//------------------------------------------------------------------------------------
//                                    Function declare
//------------------------------------------------------------------------------------

void switchDelayMs(uint16_t nTick);   


//------------------------------------------------------------------------------------
//                                    Switch code
//------------------------------------------------------------------------------------
#ifdefSWITCH_EN

__asm void setPSP(uint32_t topOfProcStack)
{
msr psp, r0
bx lr
}
                                                      
__asm void taskSwitch(void)                                    
{                                                            
    LDR   R0, =0xE000ED22                                    
    LDR   R1, =0xFF                                          
    STRB    R1,                                           
    LDR   R0, =0xE000ED04                                    
    LDR   R1, =0x10000000                                    
    STR   R1,                                           
    BX      LR                                                
    ALIGN
}                                                            
__asm void PendSV_Handler(void)                              
{                                                            
    IMPORTtaskRuning
    IMPORTtaskNew
    CPSID   I                                                
    MRS   R0, PSP                                          
    CBZ   R0, NoSave                                       
    SUBS    R0, R0, #0x20                                 
    STM   R0, {R4-R11}                                 
    LDR   R1, =taskRuning                                    
    LDR   R1,                                           
    STR   R0,                                           
                                                               
NoSave                                                   
    LDR   R0, =taskRuning                                    
    LDR   R1, =taskNew                                       
    LDR   R2,                                           
    STR   R2,                                        
    LDR   R0,                                           
    LDM   R0, {R4-R11}                                       
    ADDS    R0, R0, #0x20                                 
    MSR   PSP, R0                                          
    ORR   LR, LR, #0x04                                 
    CPSIE   I                                                
    BX      LR                                                
    ALIGN                                                      
}                                                            


#define SWITCH_CONFIG(MAX_TASK, N_TICK_IN_SECOND, SYSTEM_CLK_NMHZ,    \
                      SYS_TICK_HOOK, IDLE_HOOK);                      \
                                                                      \
typedef struct {                                                      \
uint32_t *pTaskStack;                                             \
uint16_t delay;                                                   \
}TCB;                                                               \
                                                                      \
TCB taskTCB = {0};                                    \
                                                                      \
TCB *taskNew, *taskRuning;                                          \
                                                                      \
uint8_ttaskCnt = 0;                                                 \
uint8_tnTask;                                                       \
                                                                      \
void taskIdle(void) {                                                 \
while(1){                                                         \
    IDLE_HOOK();                                                      \
    __nop();                                                          \
}                                                                   \
}                                                                     \
voidSysTick_Handler (void) {                                        \
    uint8_t i;                                                      \
    bool bOneSwitch;                                                \
    SYS_TICK_HOOK();                                                \
    bOneSwitch = false;                                             \
    for(i = 0; i < nTask; i++){                                       \
      if(taskTCB.delay != 0){                                    \
      taskTCB.delay--;                                           \
      }                                                               \
      if(bOneSwitch == false){                                        \
      taskCnt %= nTask;                                             \
      if(0 == taskTCB.delay){                              \
          bOneSwitch = true;                                          \
          taskNew = &taskTCB;                              \
          }                                                         \
      taskCnt++;                                                    \
      }                                                             \
    }                                                               \
    if(bOneSwitch == false)                                           \
      taskNew = &taskTCB;                                    \
    taskSwitch();                                                   \
}                                                                     \
                                                                      \
                                                                      \
void switchDelayMs(uint16_t nTick) {                                  \
    uint8_t i;                                                      \
    if(0 == nTick)                                                    \
      return;                                                         \
                                                                      \
    taskRuning->delay = nTick;                                        \
    for(i = 0; i < nTask; i++){                                       \
                                                                               \
      if(0 == taskTCB.delay){                              \
         taskNew = &taskTCB;                               \
         break;                                                       \
      }else taskCnt++;                                                \
    }                                                               \
    if(taskRuning == taskNew)                                       \
      taskNew = &taskTCB;                                    \
    taskSwitch();                                                   \
}                                                                     \
                                                                      \
                                                                      \
void switchTaskInt(void (*task)(void), uint32_t *ptos) {            \
    if(MAX_TASK + 1 <= taskCnt){                                    \
      taskCnt = 0;                                                    \
      return;                                                         \
    }                                                               \
    *(ptos)    = (uint32_t)0x01000000L;                               \
    *(--ptos)= (uint32_t)task;                                    \
    taskTCB. pTaskStack =ptos -14;                     \
}                                                                     \
                                                                      \
                                                                      \
void switchStart(void){                                             \
switchTaskCreate(taskIdle, 256);                                    \
if(taskCnt < (MAX_TASK + 1))                                        \
    nTask = taskCnt;                                                \
else                                                                \
    nTask = MAX_TASK;                                                 \
setPSP(0);                                                          \
SysTick_Config((SYSTEM_CLK_NMHZ / N_TICK_IN_SECOND) - 1);         \
while(1);                                                         \
}

#define switchTaskCreate(task, stackSize) {__align(8) static uint32_t task##Stack; \
                                           switchTaskInt(task, &task##Stack[(stackSize/4)-1]);    \
                                          }

#endif

//------------------------------------------------------------------------------------
//                                    Demo code
//------------------------------------------------------------------------------------
#if(0)

#define   SWITCH_EN
#include"switch.h"

void tickHook(void)
{
        //不得放入阻塞\复杂\死循环代码       
}
       
void idleHook(void)
{
       
}       

//配置参数:最大任务数1秒Tick数 系统时钟时钟钩子空闲钩子
SWITCH_CONFIG(2, 100, 72000000, tickHook, idleHook);

       
void task0(void){                         //任务0
   for(;;){
   //这放入您的代码
   switchDelayMs(200);                  //可用delay()释放CPU
   }
}

void task1(void){                         //任务1
for(;;){
//这放入您的代码
switchDelayMs(1);                     //可用delay()释放CPU
}
}

       

int main(void){
switchTaskCreate(task0, 60);            //在调度前建立任务
switchTaskCreate(task1, 30);            //在调度前建立任务
switchStart();                        //开始调度
}
#endif

#endif

//------------------------------------------------------------------------------------
//                                    End of file
//------------------------------------------------------------------------------------

   

沉默胜过白金 发表于 2015-5-13 10:48:11

STM32可用?

motodefy 发表于 2015-5-13 10:51:16

码一个,改天试试

creep 发表于 2015-5-13 11:22:41

来个压缩文件分享一下,谢谢!

Excellence 发表于 2015-5-13 13:14:36

MARK.看看。。。。

embeddev_1 发表于 2015-5-13 14:09:36

楼主把汇编部分讲解下吧,汇编看起来太累!{:biggrin:}

Robin_King 发表于 2015-5-13 14:27:32

MARK之。。。坐等傻孩子点评!!!

蓝蓝的恋 发表于 2015-5-13 14:37:52

果断小白鼠一下,帮顶~

yongxiangu 发表于 2015-5-13 17:11:24

有空仔细研究一下

wader 发表于 2015-5-13 17:14:19

mark试试看

byrin219 发表于 2015-5-13 17:25:08

有时间试试,貌似不错。

机器人天空 发表于 2015-5-13 19:12:29

楼主汇编看不懂啊,{:sweat:}

worldsing 发表于 2015-5-13 20:34:42

沉默胜过白金 发表于 2015-5-13 10:48
STM32可用?

可用{:smile:}

xad74 发表于 2015-5-13 20:34:53

LZ是转过来的吗{:lol:}

worldsing 发表于 2015-5-13 20:36:09

xad74 发表于 2015-5-13 20:34
LZ是转过来的吗

欢迎找原文,找到有奖励。哈哈

worldsing 发表于 2015-5-13 20:37:54

embeddev_1 发表于 2015-5-13 14:09
楼主把汇编部分讲解下吧,汇编看起来太累!

大概的意思就是产生个软件异常中断,再切换任务栈。

worldsing 发表于 2015-5-13 20:42:08

creep 发表于 2015-5-13 11:22
来个压缩文件分享一下,谢谢!

没有细看帖子啊,整个调度器就一个头文件,还带demo还有什么好说的?

flyfox8 发表于 2015-5-15 14:29:44

LZ高人!虽然不懂汇编,还是要拿来玩一下。
页: [1]
查看完整版本: 借傻孩子老师的地盘发个小小调度器