Demo entry 6691647

c

   

Submitted by c on Jan 12, 2018 at 03:24
Language: C. Code size: 15.0 kB.

#include "os.h"
#include "mymalloc.h"
#include "usart.h"

unsigned int CPU_ExceptStk[OS_EXCEPT_STK_SIZE];  //主任务堆栈
unsigned int* CPU_ExceptStkBase;       //指向的是数组最后一个元素
unsigned int IDLE_STK[IDLE_STK_SIZE];  //空闲任务堆栈

unsigned int criticalDeep = 0;  //记录进入critical的深度 0时允许退出critical
TCB Taskarray[MAXJOB + 1];  //初始化调度表内存空间,数组实现。留一个哨兵
unsigned int Taskarray_stat = 0x0;          // TCB内存块空闲指示寄存器
TCB* PriLeaderTable[PRINUM] = {NULL};       // 优先级领头任务地址表
unsigned char PriReadyTable[PRINUM] = {0};  //优先级任务就绪数表
TCB* TaskCurrent = NULL;                    //当前任务指针
TCB* TaskNext = NULL;                       //下一个任务指针
TCB* Head;                                  //任务表头
unsigned char HighestPri = 0;               //调度器中当前最高优先级
PriReadyTable_OBJ PriReady = {getPriReadyTable,
                              setPriReadyTable,  //实例化PriReady 对象
                              addPriReadyTable, subPriReadyTable};
unsigned char getPriReadyTable(unsigned char pri) {
    if (pri < PRINUM)
        return PriReadyTable[pri];
    else
        return 0;
}
void setPriReadyTable(unsigned char pri, unsigned char num) {
    if (0 < pri && pri < PRINUM) PriReadyTable[pri] = num;
}
void addPriReadyTable(unsigned char pri) {
    if (0 < pri && pri < PRINUM) {
        if (PriReadyTable[pri] == 0 && pri > HighestPri) {
            HighestPri = pri;
        }
        PriReadyTable[pri]++;
    }
}
void subPriReadyTable(unsigned char pri) {
    if (0 < pri && pri < PRINUM) {
        if (PriReadyTable[pri] > 0) {
            PriReadyTable[pri]--;
            if (PriReadyTable[pri] == 0 && pri == HighestPri) {
                HighestPri = FindNextValidPri(pri);
            }
        }
    }
}
TCB* jobmalloc(void) {  //分配一个任务TCB内存块
    int i;
    for (i = 0; (Taskarray_stat & (1 << i)) && i < MAXJOB + 1; i++)
        ;
#if DEBUGING
    printf("finded a space at:%d\r\n", i);
#endif
    if (i != MAXJOB) {
        Taskarray_stat |= 1 << i;
        return (TCB*)Taskarray + i;
    }

    else {
#if DEBUGING
        printf("Task full\r\n");
#endif
        return NULL;
    }
}
void jobfree(TCB* job) {  //释放TCB内存块
    Taskarray_stat &= ~(1 << (job - Taskarray));
}
unsigned char FindNextValidPri(unsigned char thispri) {  //得到下一个有效优先级
    unsigned char i;
    if (thispri) thispri--;
    for (i = thispri; !PriLeaderTable[i] && i > 0; i--)
        ;
    return i;
}
void IDLE(void) {
    unsigned char static flag = 1;
    if (flag) {
        OSCtxSw();
        flag = 0;
    }
#if SLEEPWHENIDLE
    __ASM volatile("wfi");  //进入休眠,等待下一次systick或中断唤醒
#endif
    while (1)
        ;
}
void CreatIDLE(void) {  //创建系统空闲任务
    unsigned int* p_stk;
    TCB* p = jobmalloc();
    p->pid = 0;
    p->Pri = 0;
    p->StkPtr = IDLE_STK;
    p->DLy = 0;
    p->next = NULL;
    PriLeaderTable[0] = p;
    //接下来预先压栈
    p_stk = &IDLE_STK[IDLE_STK_SIZE - 1];
    p_stk = (unsigned int*)((unsigned int)(p_stk)&0xFFFFFFF8u);  // 8字节对齐
    //以下寄存器顺序和PendSV退出时寄存器恢复顺序一致
    *(--p_stk) =
        (unsigned int)0x01000000uL;  // xPSR状态寄存器、第24位THUMB模式必须置位一
    *(--p_stk) = (unsigned int)IDLE;          // entry point//函数入口
    *(--p_stk) = (unsigned int)Task_End;      // R14(LR);
    *(--p_stk) = (unsigned int)0x12121212uL;  // R12
    *(--p_stk) = (unsigned int)0x03030303uL;  // R3
    *(--p_stk) = (unsigned int)0x02020202uL;  // R2
    *(--p_stk) = (unsigned int)0x01010101uL;  // R1
    *(--p_stk) = (unsigned int)0x00000000uL;  // R0
    // PendSV发生时未自动保存的内核寄存器:R4~R11 值随意
    *(--p_stk) = (unsigned int)0x11111111uL;  // R11
    *(--p_stk) = (unsigned int)0x10101010uL;  // R10
    *(--p_stk) = (unsigned int)0x09090909uL;  // R9
    *(--p_stk) = (unsigned int)0x08080808uL;  // R8
    *(--p_stk) = (unsigned int)0x07070707uL;  // R7
    *(--p_stk) = (unsigned int)0x06060606uL;  // R6
    *(--p_stk) = (unsigned int)0x05050505uL;  // R5
    *(--p_stk) = (unsigned int)0x04040404uL;  // R4
    //将该任务控制块中应当指向栈顶的指针,指向了该任务的新栈顶
    p->StkPtr = p_stk;
}

void Task_End(void) {  //用于挂到task的LR寄存器上,正常不会被执行
    while (1)
        ;  //不应该执行到这里
}
int CreateTask(void (*taskfun)(void), unsigned int* stk, unsigned char pid,
               unsigned char pri) {
    //注意c数组排列,传入的stk地址应该是做堆栈的数组最后一个元素地址,堆栈向下生长
    TCB* p = jobmalloc();  //获取TCB内存空间
    TCB* h;
    TCB* hp;
    unsigned int* p_stk;
    h = hp = Head;
    if (p) {  //如果获取内存成功,插入任务
        p->pid = pid;
        p->Pri = pri;
        p->StkPtr = stk;
        p->DLy = 0;
        //接下来预先压栈
        p_stk = stk;
        p_stk =
            (unsigned int*)((unsigned int)(p_stk)&0xFFFFFFF8u);  // 8字节对齐
        //以下寄存器顺序和PendSV退出时寄存器恢复顺序一致
        *(--p_stk) =
            (unsigned int)0x01000000uL;  // xPSR状态寄存器、第24位THUMB模式必须置位一
        *(--p_stk) = (unsigned int)taskfun;       // entry point//函数入口
        *(--p_stk) = (unsigned int)Task_End;      // R14(LR);
        *(--p_stk) = (unsigned int)0x12121212uL;  // R12
        *(--p_stk) = (unsigned int)0x03030303uL;  // R3
        *(--p_stk) = (unsigned int)0x02020202uL;  // R2
        *(--p_stk) = (unsigned int)0x01010101uL;  // R1
        *(--p_stk) = (unsigned int)0x00000000uL;  // R0
        // PendSV发生时未自动保存的内核寄存器:R4~R11 值随意
        *(--p_stk) = (unsigned int)0x11111111uL;  // R11
        *(--p_stk) = (unsigned int)0x10101010uL;  // R10
        *(--p_stk) = (unsigned int)0x09090909uL;  // R9
        *(--p_stk) = (unsigned int)0x08080808uL;  // R8
        *(--p_stk) = (unsigned int)0x07070707uL;  // R7
        *(--p_stk) = (unsigned int)0x06060606uL;  // R6
        *(--p_stk) = (unsigned int)0x05050505uL;  // R5
        *(--p_stk) = (unsigned int)0x04040404uL;  // R4
        //将该任务控制块中应当指向栈顶的指针,指向了该任务的新栈顶
        p->StkPtr = p_stk;
        while (pri < h->Pri) {  //寻找合适的插入位置
            hp = h;
            h = h->next;
        }
        if (h != hp) {  //不在头插入
            hp->next = p;
            p->next = h;
        } else {  //在头插入
            p->next = Head;
            Head = p;
        }
        PriReady.add(pri);        //对应优先级加一个就绪任务
        PriLeaderTable[pri] = p;  //更新此任务为其所在优先级头
        // FindNext();               //执行调度逻辑
        return 0;
    } else  //任务满了,创建失败
        return -1;
}
TCB* searchTask(unsigned char pid) {  //查找任务号pid的任务
    TCB* p;
    p = Head;
    while (p->next && p->pid != pid) {
        p = p->next;
    }
    if (p->next) {
#if DEBUGING
        printf("search succeed pid:%d,pri:%d\n", p->pid, p->Pri);
#endif
        return p;
    } else {  //此时均返回IDLE
#if DEBUGING
        printf("no this pid or is IDLE\n");
#endif
        return p;
    }
}
void printTCBtable(void) {
    TCB* p;
    unsigned char i;
    p = Head;
    while (p) {
        printf("pid=%d,pri=%d,Dly=%d\r\n", p->pid, p->Pri, p->DLy);
        p = p->next;
    }
    printf("Highest pri is %d\r\n", HighestPri);
    for (i = 0; i < PRINUM; i++)
        printf("pri %d has %d ready\r\n", i, PriReadyTable[i]);
}
int DeletTask(unsigned char pid) {  //删除为pid的任务
    TCB* per;
    TCB* this;
    per = Head;
    while (per->pid != pid && (per->next)->pid != pid && per->next) {
        per = per->next;
    }
    if (!per->next) return -1;

    if (per != Head) {  //不是第一个
        this = per->next;
        per->next = this->next;
    } else {
        Head = per->next;
        this = per;
    }
    //下面维护PriLeaderTable
    // 如果删除某一个优先级最后一个任务
    TaskCurrent = TaskNext =
        searchTask(0);  //直接引导到IDLE,其余逻辑有findnext执行
    if (this == PriLeaderTable[this->Pri]) {  //某优先级第一个
        if (this->next->Pri != this->Pri) {  //既是头也是尾,删了就全没了
            PriLeaderTable[this->Pri] = NULL;
        } else {
            PriLeaderTable[this->Pri] = this->next;
        }
    }
    //其他情况不需要维护
    if (this->DLy == 0) {  //如果删除了就绪任务
        PriReady.sub(this->Pri);
    }
    jobfree(this);  //释放内存块占用
    // FindNext();     //执行调度逻辑
    return 0;
}

void FindNext() {
    //调度逻辑核心,寻找下一个可执行任务, 写入TaskNext
    if (HighestPri > TaskCurrent->Pri && PriReady.get(HighestPri)) {  //发生抢占
        TaskNext = PriLeaderTable[HighestPri];
    } else
        TaskNext = TaskCurrent;
    while (1) {
        if ((TaskNext->DLy == 0 && TaskNext != TaskCurrent) ||
            (PriReady.get(HighestPri) == 1 &&
             TaskCurrent->DLy == 0))  //找到合适的了
            break;
        else {                                          //否则向下移动
            if (TaskNext->Pri > TaskNext->next->Pri &&  //回跳情况
                PriReady.get(TaskNext->Pri)) {
                TaskNext = PriLeaderTable[TaskNext->Pri];
            } else {
                TaskNext = TaskNext->next;
            }  //直接跳
        }
        if (TaskNext->pid == 0) break;
    }
    // printf("next will be %d\r\n",TaskNext->pid);
}
void handleDly(void) {  //在systick中断中执行
    TCB* p;
    p = Head;
    ENTER_CRITICAL();
    while (p->pid != 0) {  //在IDLE之前遍历维护DLy
        if (p->DLy > 0) {  //对休眠任务
            (p->DLy) = (p->DLy) - 1;
            if (p->DLy == 0) {
                PriReady.add(p->Pri);
            }
        }
        // printf("pid: %d DLy: %d\r\n",p->pid,p->DLy);
        p = p->next;
    }
    EXIT_CRITICAL();
}
void sleep(void) {  //要求 pid>0
    ENTER_CRITICAL();
    TaskCurrent->DLy = -1;
    PriReady.sub(TaskCurrent->Pri);
    EXIT_CRITICAL();
    OS_Sched();
}
void sleepPid(unsigned char pid) {  //要求 pid>0
    TCB* p;
    ENTER_CRITICAL();
    p = searchTask(pid);
    if (p->pid != 0) {
        p->DLy = -1;
        PriReady.sub(p->Pri);
    }
    EXIT_CRITICAL();
    OS_Sched();
}
void sleepDly(int DLy) {  //要求 Dly>=0,0意味着主动要求切换,并保持就绪
    ENTER_CRITICAL();
    (TaskCurrent->DLy) = (TaskCurrent->DLy) + DLy;
    if (DLy) PriReady.sub(TaskCurrent->Pri);
    EXIT_CRITICAL();
    OS_Sched();
}
void wakeup(unsigned char pid) {
    TCB* thispid;
    ENTER_CRITICAL();
    thispid = searchTask(pid);
    if (thispid->pid != 0) {
        thispid->DLy = 0;
        PriReady.add(thispid->Pri);
    }
    EXIT_CRITICAL();
    OS_Sched();
}
void pauseOS(void) {   //暂停系统调度
    ENTER_CRITICAL();  //关中断
    // SysTick->CTRL &= !SysTick_CTRL_ENABLE_Msk;//挂起systick
}
void resumeOS(void) {  //恢复系统调度
    EXIT_CRITICAL();   //开中断
    // SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;//恢复systick
}
unsigned char getNewPid(void) {  //返回一个pid值供创建任务时候传入
    static unsigned char i = 1;
    return i++;
}
//初始化队列对象
queueObj* creatQueue(unsigned int qsize, callbackType full,
                     callbackType empty) {
    queueObj* p;
    ENTER_CRITICAL();
    p = (queueObj*)malloc(sizeof(struct QUEUEOBJ));
    if (p) {
        p->head = 0;
        p->tail = 0;
        p->queuesize = qsize + 1;
        p->queue = (int*)malloc((qsize + 1) * sizeof(int));  //注意偏置
        p->emptyCallback = empty;
        p->fullCallback = full;
    } else {
        EXIT_CRITICAL();
        return NULL;
    }
    if (p->queue) {
        EXIT_CRITICAL();
        return p;
    } else {
        free(p);
        EXIT_CRITICAL();
        return NULL;
    }
}
//初始化队列对象通过static
void creatQueueStatic(queueObj* p, int* buf, unsigned int qsize,
                      callbackType full, callbackType empty) {
    ENTER_CRITICAL();
    p->head = 0;
    p->tail = 0;
    p->queuesize = qsize + 1;
    p->queue = buf;
    p->emptyCallback = empty;
    p->fullCallback = full;
    EXIT_CRITICAL();
}
//删除整个队列
void dropQueue(queueObj* p) {
    ENTER_CRITICAL();
    free(p->queue + p->queuesize - 1);  //注意偏置!
    free(p);
    p = NULL;
    EXIT_CRITICAL();
}
//进队列
void AddQueue(queueObj* p, int value) {
    ENTER_CRITICAL();
    //要先判断队列是否已满
    if ((p->tail + 1) % p->queuesize == p->head) {
        if (p->fullCallback) p->fullCallback();  //执行满回调
#if DEBUGING
        printf("queue full\n");
#endif
        EXIT_CRITICAL();

    } else {
        p->queue[p->tail] = value;
        p->tail = (p->tail + 1) % p->queuesize;
        EXIT_CRITICAL();
    }
}

//出队列
int DeleteQueue(queueObj* p) {
    int data;
    ENTER_CRITICAL();
    if (p->tail == p->head) {
        if (p->emptyCallback) p->emptyCallback();  //执行空回调
#if DEBUGING
        printf("queue empty\n");
#endif
        EXIT_CRITICAL();
        return 0;
    } else {
        data = p->queue[p->head];
        p->head = (p->head + 1) % p->queuesize;
    }
    EXIT_CRITICAL();
    return data;
}

//取出队列头,不出队列
int PeakQueue(queueObj* p) {
    int data;
    ENTER_CRITICAL();
    if (p->tail == p->head) {
#if DEBUGING
        printf("queue empty\n");
#endif
        EXIT_CRITICAL();
        return 0;
    } else {
        data = p->queue[p->head];
    }
    EXIT_CRITICAL();
    return data;
}

//判断队列是否为空
int IsQueueEmpty(queueObj* p) {
    if (p->head == p->tail) {
#if DEBUGING
        printf("queue empty\n");
#endif
        return 1;
    }
#if DEBUGING
    printf("queue is not empty\n");
#endif
    return 0;
}

//判断队列是否已满,用哨兵,牺牲一个存储空间

int IsQueueFull(queueObj* p) {
    if ((p->tail + 1) % p->queuesize == p->head) {
#if DEBUGING
        printf("queue full\n");
#endif
        return 1;
    }
#if DEBUGING
    printf("queue not full\n");
#endif
    return 0;
}

//遍历打印出队列元素
void PrintQueue(queueObj* p) {
    unsigned int i;
    for (i = p->head; i < p->tail; i++) {
        printf("%d ", p->queue[i]);
    }
    printf("\r\n");
}
void OS_Sched(void) {
    ENTER_CRITICAL();  //进入临界区
    FindNext();        //找出任务就绪表中优先级最高的任务
    if (TaskCurrent != TaskNext)  //如果不是当前运行任务,进行任务调度
    {
        // p_TCB_Cur=&TCB_Task[OS_PrioCur];
        OSCtxSw();  //调度任务,在汇编中引用
    }
    EXIT_CRITICAL();  //退出临界区
}
//系统(滴答)时钟初始化
void System_init(void) {
    //直接调用cm3.h提供的实现
    SysTick_Config(72000 * System_Ticks);
}

//系统(滴答)时钟中断,每1000/System_Ticks ms中断一次
void SysTick_Handler(void) {
    // OSIntNesting++;//对于Cortex-M3,任务切换是由pendsv中断实现的,而pendsv中断的优先级最低
    //即使中断嵌套发生了任务调度也没事,真正的任务切换也不会发生,只是触发了pendsv中断了而已
    // printf("#################systick...\r\n");
    ENTER_CRITICAL();
    handleDly();
    // printTCBtable();
    OS_Sched();  //都是由pendsv中断进行调度
    EXIT_CRITICAL();
}

void OS_init(void) {
    unsigned char i;
    CPU_ExceptStkBase =
        CPU_ExceptStk + OS_EXCEPT_STK_SIZE - 1;  // Cortex-M3栈向下增长
    for (i = 0; i < PRINUM; i++) {               //初始化优先级头表
        PriLeaderTable[i] = NULL;
        PriReadyTable[i] = 0;
    }
    PriReadyTable[0] = 1;  // IDLE永远就绪
    CreatIDLE();
    HighestPri = 0;  //当前最高设置为0级
    TaskCurrent = TaskNext =
        &Taskarray[0];  //初始IDLE一定在此位置
                        // OSGetHighRdy();//获得最高级的就绪任务
    PriLeaderTable[0] = TaskCurrent;
    Head = TaskCurrent;
}
void startScheduler(void) {
    System_init();     // 启动systick
    OSStartHighRdy();  // 重要,汇编的启动器
}

This snippet took 0.03 seconds to highlight.

Back to the Entry List or Home.

Delete this entry (admin only).