2011年9月4日 星期日

簡單多工2版

用在PIC18、PIC33時發現一些問題,做了修改,同時加入windows平台下的模擬程式。

主程式:
#define TASK_NUM    4
extern void SimInit(void);
extern void Task1(void);
extern void Task2(void);
extern void OS_ENTER_CRITICAL(void);
extern void OS_EXIT_CRITICAL(void);

#define INIT_DEVICE()        SimInit()
#define DIS_INTR()            OS_ENTER_CRITICAL()
#define ENA_INTR()            OS_EXIT_CRITICAL()
// O.S function declaim
void Dummy(void);
unsigned char FuncID;
unsigned int Task_Delay_Count[TASK_NUM];
unsigned int Task_Skip_Count[TASK_NUM];
void (*TaskFunc[TASK_NUM])(void);
void (*TaskResumeFunc[TASK_NUM])(void);

// O.S functions
void InitSystem(void)
{
    unsigned char i;

    FuncID = 0;
    for ( i= 0; i< TASK_NUM ; i++)
    {
        Task_Delay_Count[i] = Task_Skip_Count[i] = 0;
        TaskFunc[i] = TaskResumeFunc[i] = Dummy;
    }
    TaskFunc[1] = Task1;
    TaskFunc[2] = Task2;
}

void Dummy(void)
{
    return;
}

void Task_Set_Next(void (*p_func)(void))
{
    TaskFunc[FuncID]=p_func;
}

void Task_Set_Other_Task(unsigned char id, void (*p_func)(void))
{
    DIS_INTR();
    TaskFunc[id]=p_func;
    ENA_INTR();
}

void Task_Delay_Ms_Next(unsigned int n, void (*p_func)(void))
{
    if (! n ) n = 1;
    TaskResumeFunc[FuncID]=p_func;
    TaskFunc[FuncID] = Dummy; // to sleep
    DIS_INTR();
    Task_Delay_Count[FuncID] = n;
    ENA_INTR();
}

static void Dummy_Skip(void)
{
    if ( Task_Skip_Count[FuncID] )
    {
        Task_Skip_Count[FuncID]--;
        if (! Task_Skip_Count[FuncID]) TaskFunc[FuncID]=TaskResumeFunc[FuncID];
    }
}

void Task_Set_Skip_Next(unsigned int n, void (*p_func)(void))
{
    if (! n ) n = 1;
    TaskResumeFunc[FuncID]=p_func;
    TaskFunc[FuncID] = Dummy_Skip; // to sleep
    Task_Skip_Count[FuncID] = n;
}

// O.S functions end

// main loop
void main(void)
{
    INIT_DEVICE();
    InitSystem();
    while (1)
    {
        register void (*Current_Func)(void);
        DIS_INTR();
        Current_Func = TaskFunc[FuncID]; // may break with interrupt
        ENA_INTR();
        // Trace System Code maybe add here
        Current_Func();
        if( ++FuncID >= TASK_NUM ) FuncID = 0;
    }
}

void TimeTick(void)  // This is timer interrupt
{
    unsigned char i;

    for ( i=0; i< TASK_NUM; i++)
    {
        if ( Task_Delay_Count[i] )
        {
            Task_Delay_Count[i]--;
            if (! Task_Delay_Count[i]) TaskFunc[i]=TaskResumeFunc[i]; // wake up function
        }
    }
}


給其他C檔案用的引入檔mt.h
extern void Task_Set_Next(void (*p_func)(void));
extern void Task_Set_Other_Task(unsigned char id, void (*p_func)(void));
extern void Task_Delay_Ms_Next(unsigned int n, void (*p_func)(void));
extern void Task_Set_Skip_Next(unsigned int n, void (*p_func)(void));


Windows下模擬用程式
#include <windows.h>
#include <winbase.h>

extern void TimeTick(void);

HANDLE              OSSemaphore;
DWORD WINAPI OSTickW32 ( LPVOID lpParameter );
HANDLE              OSTick32Handle;

void SimInit(void)
{
    DWORD  dwID;
   
    OSSemaphore = CreateSemaphore( NULL, 1, 1, NULL );
    OSTick32Handle = CreateThread( NULL, 0, OSTickW32, 0, 0, &dwID );
    SetPriorityClass(OSTick32Handle,THREAD_PRIORITY_HIGHEST);
    SetThreadPriority(OSTick32Handle,THREAD_PRIORITY_HIGHEST);
}

DWORD WINAPI OSTickW32( LPVOID lpParameter )
{
    while(1)
    {
        TimeTick();
        Sleep(1);
    }
    return 0;
}

void OS_SLEEP(unsigned int count)
{
    Sleep(count);
}

void OS_INIT_CRITICAL(void)
{
    return;
}

void OS_ENTER_CRITICAL(void)
{
    WaitForSingleObject( OSSemaphore, INFINITE );
}

void OS_EXIT_CRITICAL(void)
{
    ReleaseSemaphore( OSSemaphore, 1, NULL );
}


測試用程式
#include <stdio.h>
#include "mt.h"
void Task1(void)
{
    printf("G");
    Task_Delay_Ms_Next(100,Task1);
}

void Task2(void)
{
    printf("z");
    Task_Delay_Ms_Next(33,Task2);
}


測試畫面

要記得請使用多核心下去跑,因為本來就不是給Windows用的,所以會用掉一個核心。