⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 uk_kernel.c

📁 非常简单的低端单片机内核, 有定时器,任务调度,状态机例子
💻 C
字号:
/*******************************************************************************
File: uK_Kernel.c

Description:
This file implements uK-Kernel RTOS

Creation
Date:	November 3, 2004
Author:	Benjamin M. Kacenas
*******************************************************************************/
#include "uK_Kernel.h"

/*******************************************************************************
Function: main()

Description:
Provide initialization and the main Main Loop Component

Creation
Date:	November 3, 2004
Author:	Benjamin M. Kacenas
*******************************************************************************/
main()
{
	// Disable all interrupts.
	IEN0 = 0x00;
	IEN1 = 0x00;
	IP   = 0x00;

	// Turn off timers
	TCON  = 0x00; 
	T2CON = 0x00;

	// Get the task queue ready
	by_QueMax      = 0; // For test purposes only
	by_TaskQueHead = 0; // Initialize the task queue head and tail pointers
	by_TaskQueTail = 0;
	b_TaskQueEmpty = 0; // Set the queue to empty status

	// Get the heartbeat and interval dispatcher ready
	by_RTX_Counter = 0; // Clear the 4 msec event counter
	ui_EventTask   = 0; // Initialize all task slots to DISABLED

	// Setup the heartbeat timer for 4.096 msec
	TL0  = 0;     // Preset timer 0 low byte to 0
	TH0  = 0;     // Preset timer 0 high byte to 0
	TMOD &= 0xF0; // Set timer 0 to mode 0, 13 bit with 5 bit prescaler
	PT0  = CLEAR; // Set timer 0 interrupt priority to low level
	TF0  = CLEAR; // Clear any pending Timer 0 interrupts
	ET0  = SET;   // Enable Timer 0 overflow interrupts

	// Start the heartbeat interrupt, let the kernel run
	EA   = SET;   // Set master interrupt enable
	TR0  = SET;   // Set timer 0 to run

	void (*fp)(void *);

	while (TRUE)
	{
		// Start of task dispatcher
		// Dispatch a task only if there is one pending
		if (b_TaskQueEmpty == NOT_EMPTY)
		{
			// Dispatch the next task in the queue
			fp = (void *)st_TaskQue[by_TaskQueTail].fp_Task;
			fp(st_TaskQue[by_TaskQueTail].p_TaskData);
			// If the tail is at the top of the queue set it back to 0
			if (by_TaskQueTail == (TASK_QUE_SIZE - 1))
			{            
				by_TaskQueTail = 0;
			}
			else    // Else increment the tail index
			{
				by_TaskQueTail++;
			}
			EA = DISABLE;	// Disable all interrupts
			// If the tail index has reached the head index, no pending
			if (by_TaskQueTail == by_TaskQueHead)
			{
				b_TaskQueEmpty = EMPTY;
			}
			EA = ENABLE;	// Enable all interrupts
		}
		// Check for any timed repetitive tasks
		sl_IntervalDispatcher();
		// Place processes to be run from the main loop in this area
		// ---------------------------------------------------------

		// ---------------------------------------------------------
	}
} // End of main()

/*******************************************************************************
Function: sl_RTX_Event()

Description:
Heartbeat interrupt service routine

Creation
Date:	November 3, 2004
Author:	Benjamin M. Kacenas
*******************************************************************************/
void sl_RTX_Event(void) interrupt 1
{
	// This function gets called every 4.096 msec; when Timer 0 
    // overflows
    byte by_Inx;	//Simple iterator

    // Loop through all delay timers
    for (by_Inx = 0; by_Inx < NUM_DELAY_TIMERS; by_Inx++)
    {
        // If the delay counter register for this timer is 0,
        // its not being used
        if (st_SysDelay[by_Inx].i_DelayCounter != 0)
        {
            // Decrement the counter being used
            st_SysDelay[by_Inx].i_DelayCounter--;
            // Now test again to see if it has gone to 0, timed out
            if (st_SysDelay[by_Inx].i_DelayCounter == 0)
            {
                // Queue that delay timer's task and test to see if the
                // Task Queue can except the task
                if (sl_QueTask(st_SysDelay[by_Inx].fp_Task,
                    st_SysDelay[by_Inx].p_TaskData) == TASK_QUE_FULL)
                {
                    // The Task Queue could not except the task,
                    // Set the delay to try again next tick
                    st_SysDelay[by_Inx].i_DelayCounter = 1;
                }
            }
        }
    }
    // Place code that will be executed every 4.096 msec in this area
    // ----------------------------------------------------------------
    // This stuff has no meaning, it just shows something in this slot
    b_ResultFlag = 0;
    if (b_TestFlag)
    {
        b_ResultFlag = 1;
    }
    // ----------------------------------------------------------------
    ui_EventTask |= FLAG_4MSEC;         // Set 4.096 msec event flag
    by_RTX_Counter++;
    if (by_RTX_Counter == 0)
    {
        return;
    }
    if (by_RTX_Counter % MSEC_40 == 0)
    {
        // Place code that will be executed every 40 msec in this area
        // ------------------------------------------------------------

        // ------------------------------------------------------------
        ui_EventTask |= FLAG_40MSEC;    // Set 40 msec event flag
    }
    if (by_RTX_Counter % MSEC_100 == 0)
    {
        // Place code that will be executed every 100 msec in this area
        // ------------------------------------------------------------
        sl_QueTask(sl_100msecTask, NULL);
        // ------------------------------------------------------------
        ui_EventTask |= FLAG_100MSEC;   // set 100 msec event flag
    }
    if (by_RTX_Counter % MSEC_200 == 0)
    {
        // Place codethat will be executed every 200 msec in this area
        // ------------------------------------------------------------

        // ------------------------------------------------------------
        ui_EventTask |= FLAG_200MSEC;   // set 200 msec event flag
    }
    if (by_RTX_Counter % MSEC_500 == 0)
    {
        // Place code that will be executed every 500 msec in this area
        // ------------------------------------------------------------

        // ------------------------------------------------------------
        ui_EventTask |= FLAG_500MSEC;   // set 500 msec event flag
    }
    if (by_RTX_Counter % MSEC_1000 == 0)
    {
        // Place code that will be executed every 1 sec in this area
        // ------------------------------------------------------------

        // ------------------------------------------------------------
        ui_EventTask |= FLAG_1000MSEC;  // set 1000 msec event flag
    }
    // Reset counter to zero here at 1024 ms
    if (by_RTX_Counter == RTX_COUNTER_LIMIT)
    {
        by_RTX_Counter = 0;
    }
    return;
} // End of sl_RTX_Event()

/*******************************************************************************
Function: sl_QueTask()

Description:
Task Queuing Service component

Creation
Date:	November 3, 2004
Author:	Benjamin M. Kacenas
*******************************************************************************/
byte sl_QueTask(FuncPoint fp_FunctionPointer, void *p_DataPointer) 
{
    EA = DISBALE;    // Disable all interrupts
    // Check to see if there is room for this request
    if ((b_TaskQueEmpty == NOT_EMPTY) &&
        by_TaskQueHead == by_TaskQueTail))
    {
        EA = ENABLE;           // Enable all interrupts
        return(TASK_QUE_FULL); // No room in the task queue
    }
    // Load the next location in the queue with the task pointer
    st_TaskQue[by_TaskQueHead].fp_Task = fp_FunctionPointer;
    // Load the next location in the queue with the task data pointer
    st_TaskQue[by_TaskQueHead].p_TaskData = p_DataPointer;
    // Increment the index head or wrap it back to zero
    if (by_TaskQueHead == (TASK_QUE_SIZE - 1))
    {
        by_TaskQueHead = 0;
    }
    else
    {
        by_TaskQueHead++;
    }
    // This is for debug purposes only QueMax
    if (by_TaskQueHead < by_TaskQueTail)
    {
        by_QueMax = MAX((TASK_QUE_SIZE - by_TaskQueTail + 
            by_TaskQueHead),by_QueMax);
    }
    else
    {
        by_QueMax = MAX((by_TaskQueHead - by_TaskQueTail), by_QueMax);
    }
    b_TaskQueEmpty = NOT_EMPTY; // Say that the queue is not empty
    EA = ENABLE;                // Enable all interrupts
    // Tell the calling function that we have queued the task
    return(NO_ERROR);
} // End of sl_QueTask()

/*******************************************************************************
Function: sl_IntervalDispatcher()

Description:
Interval Dispatcher component

Creation
Date:	November 3, 2004
Author:	Benjamin M. Kacenas
*******************************************************************************/
void sl_IntervalDispatcher(void)
{
    if (ui_EventTask & TASK_4MSEC)
    {
        // Place code that will be executed every 4 msec in this area
        // ------------------------------------------------------------
        //check for incoming characters on serial port
        SomeFunction();
        // ------------------------------------------------------------
        ui_EventTask &= ~TASK_4MSEC;
    }
    if (ui_EventTask & TASK_40MSEC)
    {
        // Place code that will be executed every 40 msec in this area
        // ------------------------------------------------------------

        // ------------------------------------------------------------
        ui_EventTask &= ~TASK_40MSEC;
    }
    if (ui_EventTask & TASK_100MSEC)
    {
        // Place code that will be executed every 100 msec in this area
        // ------------------------------------------------------------

        // ------------------------------------------------------------
        ui_EventTask &= ~TASK_100MSEC;
    }
    if (ui_EventTask & TASK_200MSEC)
    {
        // Place code that will be executed every 200 msec in this area
        // ------------------------------------------------------------

        // ------------------------------------------------------------
        ui_EventTask &= ~TASK_200MSEC;
    }
    if (ui_EventTask & TASK_500MSEC)
    {
        // Place code that will be executed every 500 sec in this area
        // ------------------------------------------------------------
        //process any waiting serial commands
        AnotherFunction();
        // ------------------------------------------------------------
        ui_EventTask &= ~TASK_500MSEC;
    }
    if (ui_EventTask & TASK_1000MSEC)
    {
        // Place code that will be executed every 1 sec in this area
        // ------------------------------------------------------------

        // ------------------------------------------------------------
        ui_EventTask &= ~TASK_1000MSEC;
    }
} // End of sl_IntervalDispatcher()

/*******************************************************************************
Function: sl_RequestDelay()

Description:
Delay Timer Request component

Creation
Date:	November 3, 2004
Author:	Benjamin M. Kacenas
*******************************************************************************/
byte sl_RequestDelay(unsigned int i_Delay, FuncPoint p_FunctionPointer,
    void *p_DataPointer)
{
    byte by_Inx;	// Simple iterator

    EA = DISABLE; // Disable all interrupts
    // Start the check for the first open Delay timer	
    for (by_Inx = 0; by_Inx < NUM_DELAY_TIMERS; by_Inx++)
    {
        // If the counter is 0, we have found an unused delay timer
        if (st_SysDelay[by_Inx].i_DelayCounter == 0)
        {
            break;
        }
    }
    // See if we have requested too many delay timers
    if (by_Inx == NUM_DELAY_TIMERS)
    {
        EA = ENABLE;             // Enable all interrupts
        return(NO_DELAY_TIMER);  // Return without assigning a timer
    }
    // Load up this delay timer structure with delay count, function
    // pointer and data pointer
    st_SysDelay[by_Inx].i_DelayCounter = i_Delay;
    st_SysDelay[by_Inx].fp_Task = fp_FunctionPointer;
    st_SysDelay[by_Inx].p_TaskData = p_DataPointer;
    // Record the number of delay timers used maximum
    if (by_Inx >= by_DelaysUsedMax)
    {
        by_DelaysUsedMax++;
    }
    EA = ENABLE;	      // Enable all interrupts
    return(NO_ERROR);	// Return with no error
} // End of sl_RequestDelay()

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -