登录 免费注册 首页 | 行业黑名单 | 帮助
维库电子市场网
技术交流 | 电路欣赏 | 工控天地 | 数字广电 | 通信技术 | 电源技术 | 测控之家 | EMC技术 | ARM技术 | EDA技术 | PCB技术 | 嵌入式系统
驱动编程 | 集成电路 | 器件替换 | 模拟技术 | 新手园地 | 单 片 机 | DSP技术 | MCU技术 | IC 设计 | IC 产业 | CAN-bus/DeviceNe

看看ARM菜鸟在ARM7上写的操作系统——ARM圈圈操作系统

作者:computer00 栏目:ARM技术
看看ARM菜鸟在ARM7上写的操作系统——ARM圈圈操作系统
 
最近在ADUC7027上写了一个ARM_00_OS,头都写晕了,发上来给大家一起来看看。

任务按优先级调度,如果处于就绪态且优先级最高的任务有两个或更多,则按时间片轮循调度。

支持任务创建、任务删除、内存分配、简单的消息、简单的设备管理、CPU及内存等使用统计等功能。

任务可处于ARM模式或THUMB模式,在创建任务时,要指定任务所处于的模式。

从这里下载整个文件包:http://blog.21ic.com/more.asp?NAME=computer00&id=16341





















 

* - 本贴最后修改时间:2006-6-1 1:17:28 修改者:computer00

2楼: >>参与讨论
computer00
ARM_00_OS_TaskSwitch.c file
/**********************************************************************************************
本程序只供学习使用,不得用于其它任何用途,否则后果自负。

  ARM_00_OS_TaskSwitch.c file
  
  注意:该文件必须设置为ARM模式。
  
  作者:Computer-lov
  建立日期:2006-5-1
  修改日期:2006-5-16
  版本:V1.0
  版权所有,盗版必究。
  任何技术问题可到我的博客上留言:    http://computer00.21ic.org
  COPYRIGHT(C) Computer-lov 2006-2016
  All rights reserved
**********************************************************************************************/

#include <ADuC7027.H>
#include "My_type.h"
#include "LED.H"
#include "UART.H"
#include "KEYS.H"
#include "interrupt.h"
#include "ARM_00_OS_Core.H"
#include "ARM_00_OS_TaskSwitch.H"

/**********************************************************************************************
功能:禁止中断。
入口参数1:DisEnabledBit。即CPSR中对应的I位和Q位。
           头文件中有定义,#define OS_I_Bit 0x80 #define OS_F_Bit 0x40
           关IRQ中断时,使用OS_I_Bit,关FIQ中断时,使用OS_F_Bit。
           两个都关时,将两者按位或,即 OS_I_Bit | OS_F_Bit
返回:无。
使用资源:使用软中断号0。
备注:使用了内嵌的ARM指令,该函数所在的文件必须设置为ARM模式。
**********************************************************************************************/
void DisEnableInterrupt(uint32 DisEnableBit) __swi(0)
{
__asm LDMIA SP!,{R8}     //堆栈中保存的是SPSR寄存器(参看SWI_VEC.s文件),将其弹出至R8中。
__asm ORR R8,R8,R0,LSL #0  //R8中的值,跟传递进来的DisEnableBit(被放在R0中)相或。{}
__asm STMDB SP!,{R8}        //将设置好的SPSR寄存器,压回堆栈

DisEnableBit=0;            //防止编译器警告。请不要删除该语句。如果删除该语句,编译器可能会删除某些语句
                            //从而导致程序运行错误
}
//////////////////////////////////End of function//////////////////////////////////////////////



/**********************************************************************************************
功能:使能中断。
入口参数1:EnabledBit。即CPSR中对应的I位和Q位。
           头文件中有定义,#define OS_I_Bit 0x80 #define OS_F_Bit 0x40
           关IRQ中断时,使用OS_I_Bit,关FIQ中断时,使用OS_F_Bit。
           两个都关时,将两者按位或,即 OS_I_Bit | OS_F_Bit
返回:无。
使用资源:使用软中断号1。
备注:使用了内嵌的ARM指令,该函数所在的文件必须设置为ARM模式。
**********************************************************************************************/
void EnableInterrupt(uint32 EnableBit) __swi(1)
{
__asm LDMIA SP!,{R8}  //堆栈中保存的是SPSR寄存器(参看SWI_VEC.s文件),将其弹出至R8中
__asm MVN R0,R0       //EnableBit(被放在R0中)取反
__asm AND R8,R8,R0    //R8中的值,跟R0相与{}
__asm STMDB SP!,{R8}  //将设置好的SPSR寄存器,压回堆栈


EnableBit=0;            //防止编译器警告。请不要删除该语句

}
//////////////////////////////////End of function//////////////////////////////////////////////



/**********************************************************************************************
功能:启动操作系统。
入口参数1:AddrOfSystemIdle。必须设置为系统空闲任务的入口地址。系统启动后,从系统空闲任务开始运行。
入口参数2:Mode。系统空闲任务代码的模式。可以选择ARM_MODE或者THUMB_MODE。
返回:无。
使用资源:使用软中断号2。
备注:使用了内嵌的ARM指令,该函数所在的文件必须设置为ARM模式。系统启动后,进入系统空闲任务。
**********************************************************************************************/
void OSStart(uint32 AddrOfSystemIdle,uint32 Mode) __swi(2)
{
__asm ADD SP,SP,#20     //{}调整SP,使其指向返回地址的前一个字
__asm STMDB SP,{R0}    //将入口地址压入堆栈中的返回地址处

__asm SUB SP,SP,#20    //{}将堆栈指针调回

__asm LDMIA SP!,{R8}   //将SPSR弹出,放入R8中

Mode|=~(0x20);         //将传递进来的Mode其它位设置为1,只保留T位

__asm ORR R8,R8,#0x20  //将SPSR中的T位设置为1{}
__asm AND R8,R8,R1     //将SPSR的值与Mode相与。从而T位跟Mode的T位相同{}

__asm STMDB SP!,{R8}   //将SPSR压回栈中


OSCurrentPcb=&OSSystemIdlePcb;   //当前任务为系统空闲任务

AddrOfSystemIdle=0;              //防止编译器警告。请不要删除该语句

}
//////////////////////////////////End of function//////////////////////////////////////////////


/**********************************************************************************************
功能:保存堆栈指针。堆栈指针被保存在当前任务的TaskSP成员中。
入口参数1:sp。当前任务堆栈指针的地址值。
返回:无。
备注:sp由R0寄存器传入。
**********************************************************************************************/
void OSSaveSP(uint32 sp)
{
OSCurrentPcb->TaskSP=sp;  //保存当前堆栈指针
}
//////////////////////////////////End of function//////////////////////////////////////////////


/**********************************************************************************************
功能:恢复堆栈指针。将当前任务的堆栈指针恢复。
入口参数1:无。
返回:堆栈指针的地址值。被保存在R0中。
备注:无。
**********************************************************************************************/
uint32 OSResumeSP(void)
{
return OSCurrentPcb->TaskSP;    //将堆栈指针的地址值返回
}
//////////////////////////////////End of function//////////////////////////////////////////////

/**********************************************************************************************
功能:设置堆栈。任务创建时,要设置好其堆栈,使其看起来,就像任务刚被切换的任务一样。
入口参数1:StackAddr。32位的堆栈入口地址值,堆栈是往下生长的,所以入口地址应该是堆栈区的最高地址。
入口参数2:TaskEntryAddr。32位的任务入口地址值。
入口参数3:Mode。被创建任务代码的模式。可选择为OS_ARM_MODE或者OS_THUMB_MODE。
返回:32位的堆栈地址。被压入堆栈后,堆栈指针会更新。
使用资源:使用软中断号4。
备注:无。
**********************************************************************************************/
uint32 OSSetStack(uint32 StackAddr,uint32 TaskEntryAddr,uint32 Mode) __swi(4)
{
#define PushedBytes (16*4)    //压入了16个字,共64字节
//R0中保存的是堆栈入口地址
__asm MOV R12,R0        //{}StackAddr传进时,被放在了R0中。将R0转存至R12中。
__asm STMDB R12!,{R3}    //入口地址被TaskEntryAddr被编译器转移至R3中。将R3压栈
__asm MOV R8,#0         //{}R8清零
__asm STMDB R12!,{R8}   //该位置保存的是R3。将其清0。
__asm STMDB R1
3楼: >>参与讨论
computer00
ARM_00_OS_TaskSwitch.H  file
/**********************************************************************************************
ARM_00_OS_TaskSwitch.H  file

作者:Computer-lov
建立日期:2006-5-1
修改日期:2006-5-15
版本:V1.0
版权所有,盗版必究。
任何技术问题可到我的博客上留言:    http://computer00.21ic.org
COPYRIGHT(C) Computer-lov 2006-2016
All rights reserved
**********************************************************************************************/

#ifndef __ARM_00_OS_TASKSWITCH_H__
#define __ARM_00_OS_TASKSWITCH_H__

#include "My_type.h"

void DisEnableInterrupt(uint32 DisEnableBit) __swi(0);    //关中断
void EnableInterrupt(uint32 EnableBit) __swi(1);          //开中断
void OSStart(uint32 AddrOfSystemIdle,uint32 Mode) __swi(2);   //操作系统开始运行
void OSTaskSwitch(void)__swi(3);                            //任务切换
uint32 OSSetStack(uint32 StackAddr,uint32 TaskEntryAddr,uint32 Mode)__swi(4);  //设置堆栈指针

#endif



4楼: >>参与讨论
computer00
ARM_00_OS_Core.c file (PART I)
/**********************************************************************************************
本程序只供学习使用,不得用于其它任何用途,否则后果自负。

  ARM_00_OS_Core.c file
   
  作者:Computer-lov
  建立日期:2006-5-1
  修改日期:2006-5-15
  版本:V1.0
  版权所有,盗版必究。
  任何技术问题可到我的博客上留言:    http://computer00.21ic.org
  COPYRIGHT(C) Computer-lov 2006-2016
  All rights reserved
**********************************************************************************************/

#include <ADuC7027.H>

#include "interrupt.h"
#include "LED.H"
#include "ARM_00_OS_TaskSwitch.H"
#include "my_type.h"
#include "ARM_00_OS_Core.H"
#include "UART.H"
#include "KEYS.H"
#include "Task.h"

OSpcb * OSReadyList;    //就绪态任务表表头
OSpcb * OSSuspendList;  //挂起态任务表表头
OSpcb * OSDelayList;    //延时态任务表表头
OSpcb * OSCurrentPcb;   //当前运行的任务


OSpcb OSSystemIdlePcb;  //系统空闲任务
OSShortPcb OSSuspendListBottom;    //挂起态列表表底
OSShortPcb OSDelayListBottom;      //延时态列表表底


OSdevice OSDeviceBottom;       //设备列表的底部
OSdevice * OSDeviceList;       //设备列表


volatile uint32 CopyOfIRQEN;    //用来备份IRQEN的状态
volatile uint32 CopyOfFIQEN;    //用来备份FIQEN的状态
volatile uint32 OSEnCrCount;    //用来统计进入临界代码段次数


volatile uint32 TaskAmount;    //用来统计共有多少个任务


volatile uint32 TimeOfTaskStart;  //用来保存一个任务刚被切换到运行态的时刻

#define OSMemoryLack       0x0000000100000000  /*错误号:内存资源不足*/

/**********************************************************************************************
功能:内存管理。
入口参数1:Operation。操作方式。可以设置为MEMORY_ALLOCATION(分配)、MEMORY_FREE(释放)、统计使用量(MEMORY_STATISTIC)
入口参数2:StartAddr。起始地址,释放内存时使用。
入口参数3:Length。申请内存或释放内存时的长度,单位为字节。但实际分配时,是按块分配的,所以分配时,
           实际分配到的数量可能会比指定的多,所以分配时,最好按块的整数倍大小来指定分配长度。
           
返回:32无符号型整数。
      当操作为分配内存时,返回32位的内存首地址,返回0表示无足够多的可以用内存。
      当操作为释放内存时,返回1表示释放成功。返回0表示释放出错。
      当操作为统计内存使用量时,返回的是内存被使用的字节数。
      当操作为获取缓冲池大小时,返回的是内存缓冲池大小。

备注:缓冲池大小由OSSizeOfMemoryPool指定。每块的大小由OSSizePerBlock指定             
**********************************************************************************************/
uint32 OSMemoryManage(uint32 Operation,uint32 StartAddr,uint32 Length)
{
  //内存分配表
  //内存分配表是32位整数的一维数组。用每一位来表示一块是否被使用。当某位设置为1时,表示那一块被使用。
  //当某位为0时,表示那一块可用。
static uint32  OSMemoryTable[OSSizeOfMemoryPool/OSSizePerBlock/32];
                                                                      
static uint32 OSMemoryPool[OSSizeOfMemoryPool/4]; //内存缓冲池。内存缓冲池为一个大是数组

uint32 BlankCount;    //统计空块的计数器
uint32 Mask;          //分配内存时用的掩码
volatile uint32 i,j;  //循环用的变量

OSEnterCritical();   //进入临界段

SWITCH(Operation)     //根据操作码,选择不同的操作
  {
   case MEMORY_INIT:   //如果是内存初始化
    {
     for(i=0;i<OSSizeOfMemoryPool/OSSizePerBlock/32;i++)
      {
       OSMemoryTable[i]=0;  //则将整张内存分配表清0
      }
     OSExitCritical();  //退出临界段
     return 1;   //返回1
    }

   case MEMORY_ALLOCATION:  //如果是内存分配,则
    {
     BlankCount=0;   //先将内存空块的数量清0
     for(i=0;i<(OSSizeOfMemoryPool/OSSizePerBlock/32);i++)  //扫描整个内存分配表
      {
       Mask=1;   //掩码被设置为1,即最低位为1,其它位为0。
       if(OSMemoryTable[i]==0xFFFFFFFF)  //如果该字中的所以位都为1,表示该字节对应的所有块都被占用
        {
         BlankCount=0;  //空块计数器置0
         continue;      //退出本次循环,查找下一个字
        }
       for(j=0;j<32;j++)  //扫描一个字的32个bit是否有空闲的RAM
        {
         if((Mask & OSMemoryTable[i])==0)  //如果该位为0,表示该块空闲
          {
           BlankCount++;   //空块计数器加1。
          }
         else
          {
           BlankCount=0;  //如果遇到非空块,则空块计数器置0。
          }
         if((BlankCount*OSSizePerBlock)>=Length)  //如果空闲的RAM,大于或者等于需要的长度,那么分配成功
          {
           //计算被分配到的内存的起始地址,并将其保存在StartAddr中。
           StartAddr=((uint32)OSMemoryPool)+(i*32+j+1)*OSSizePerBlock-OSSizePerBlock*BlankCount;
           while(1)  //设置被使用的块为1
            {
             OSMemoryTable[i] |=Mask;  //将已经被分配的标志为1
   &n
5楼: >>参与讨论
computer00
ARM_00_OS_Core.c file (PART II)
/**********************************************************************************************
功能:将一个任务挂起。
入口参数:pcb。要挂起的任务的pcb。
返回:是否成功挂起。0:成功挂起。错误代码 NO_SUCH_A_TASK:没有这个任务;CAN_NOT_BE_SUSPENDED:指定的任务不能挂起
备注:无。
/*********************************************************************************************/
uint32 OSTaskSuspend(OSpcb * pcb)
{
OSpcb * TempPcb;

if(pcb==&OSReadyListBottom)  //如果要挂起系统空闲任务,
  {
   return CAN_NOT_BE_SUSPENDED;  //则返回 该任务不能被挂起
  }

OSEnterCritical();  //进入临界段
TempPcb=OSReadyList;   //从就绪表表头开始查找
while(TempPcb->Next)   //直到结束
  {
   if(TempPcb==pcb)  //如果找到,
    {
     DeleteFromReadyList(pcb);  //将其从就绪表中删除
     InsertToSuspendList(pcb);  //插入挂起列表
     OSExitCritical();         //退出临界段
     if(pcb==OSCurrentPcb)   //如果要挂起的是自己
      {
       OSTaskSwitch();    //则需要运行任务切换
      }
     return 0;         //返回0,表示成功
    }
   TempPcb=TempPcb->Next;
  }
return NO_SUCH_A_TASK;   //如果没找到,则返回错误
}
//////////////////////////////////End of function//////////////////////////////////////////////


/**********************************************************************************************
功能:发送一则消息
入口参数1:pcb。消息的接收者。指向任务的pcb的指针。
入口参数2:pMsg。消息指针。指向消息结构体的指针。
返回:消息是否发送成功。0:发送成功;错误代码 NO_SUCH_A_TASK:没有这个任务;
**********************************************************************************************/
uint32 OSSendMsg(OSpcb * pcb,OSMsg * pMsg)
{
OSpcb * TempPcb;

OSEnterCritical();    //进入临界段
pMsg->Sender=OSCurrentPcb;  //消息的发送者
SWITCH(pcb->Status)   //判断任务所处的状态
  {
   case OSInReadyStatus:  //如果任务处于就绪态
    {
     TempPcb=OSReadyList;   //在就绪表中查找
     while(TempPcb->Next)   //搜索整个就绪表
      {
       if(pcb==TempPcb)     //如果找到
        {
         pcb->Msg=pMsg;     //将消息放入任务的消息指针中
         OSExitCritical();  //退出临界段
         return 0;            //返回0,发送消息成功
        }
       TempPcb=TempPcb->Next;      //TempPcb移动到下一个
      }
     //如果在就绪表中找不到该任务,则
     OSExitCritical();       //退出临界段
     return NO_SUCH_A_TASK;  //返回错误代号:没有这样的任务。     
    }

   case OSInDelayStatus:  //如果任务处于延时态
    {
     TempPcb=OSDelayList;  //在延时态表中查找
     while(TempPcb->Next)  //搜索整个延时表
      {
       if(pcb==TempPcb)    //如果找到
        {
         pcb->Msg=pMsg;  //将消息放入任务的消息指针中
         pcb->Delay=0;   //取消任务的延时
         DeleteFromDelayList(pcb);  //将任务从延时列表中删除
         InsertToReadyList(pcb);    //将任务插入到就绪表中
         OSExitCritical();          //退出临界段
         OSTaskSwitch();            //有任务被唤醒,需要任务切换
         return 0;                  //返回0,表示发送消息成功
        }
       TempPcb=TempPcb->Next;      //TempPcb移动到下一个
      }
    //如果在延时表中找不到该任务,则
    OSExitCritical();   //退出临界段
    return NO_SUCH_A_TASK;  //返回错误代号:没有这样的任务。     
   }
    
   case OSInSuspendStatus:  //如果任务处于挂起态
    {
     TempPcb=OSSuspendList;      //在挂起态表中查找
     while(TempPcb->Next)        //搜索整个挂起态表
      {      
       if(pcb==TempPcb)         //如果找到
        {
         pcb->Msg=pMsg;   //将消息放入任务的消息指针中
         DeleteFromSuspendList(pcb);   //将任务从挂起态列表中删除
         InsertToReadyList(pcb);        //将任务插入到就绪表中
         OSExitCritical();     //退出临界段
         OSTaskSwitch();       //有任务被唤醒,需要任务切换
         return 0;             //返回0,表示消息发送成功
        }
       TempPcb=TempPcb->Next;      //TempPcb移动到下一个
      }
     //如果在挂起态表中找不到该任务,则
     OSExitCritical();   //退出临界段
     return NO_SUCH_A_TASK;  //返回错误代号:没有这样的任务。
    }
    
   
6楼: >>参与讨论
computer00
ARM_00_OS_Core.H file
/**********************************************************************************************
本程序只供学习使用,不得用于其它任何用途,否则后果自负。

  ARM_00_OS_Core.H file
  
  作者:Computer-lov
  建立日期:2006-5-1
  修改日期:2006-5-15
  版本:V1.0
  版权所有,盗版必究。
  任何技术问题可到我的博客上留言:    http://computer00.21ic.org
  COPYRIGHT(C) Computer-lov 2006-2016
  All rights reserved
**********************************************************************************************/

#ifndef __ARM_00_OS_CORE_H__
#define __ARM_00_OS_CORE_H__



//消息结构体
//用来保存一则消息
typedef struct OSMsg
{
volatile uint32 MsgType;      //消息的类型
volatile uint32 Length;       //本则消息的长度
struct OSpcb * Sender;       //消息的发送者
volatile uint32 * volatile pMsg;       //指向消息内容的指针
}OSMsg;


//OSpcb结构体——进程控制块
typedef struct OSpcb
{
struct OSpcb * Prior;    //指向前一个pcb
struct OSpcb * Next;     //指向后一个pcb
volatile uint32 PID;     //程序ID号。用的是申请到的内存块的首地址
volatile uint32 Delay;   //延迟时钟节拍数
volatile uint32 Priority; //任务的优先级。该值越小,优先级越高。操作系统保留0号及0xFFFFFFFF号优先级
volatile uint32 TaskSP;   //任务切换时,保存堆栈指针使用。
volatile uint32 StackLength; //任务创建时,申请的堆栈长度。单位为字节。
volatile uint32 Status;      //任务所处的状态。有OSInRunning、StatusOSInDelayStatus、OSInSuspendingStatus
volatile uint64 TotalRunTime;       //该任务总运行时间。时间单位由定时器0计数1的值决定。
volatile uint32 RunTimeInThisRefreshPeriod;   //该任务在一个刷新周期内,运行的时间,运行的时间。时间单位由定时器0计数1的值决定。
volatile uint32 WaitFor;           //任务等待的资源
struct OSMsg * Msg;                //消息指针
volatile uint8  Title[16];         //任务的标题
}OSpcb;

//OSSortPcb结构体。该结构体用来做一些pcb列表的底部,由于底部一些变量是无用的,因此建一个短表,可以节省RAM
//所有成员的意义同OSpcb结构体。
typedef struct OSShortPcb
{
struct OSpcb * Prior;
struct OSpcb * Next;
volatile uint32 PID;
volatile uint32 Delay;
volatile uint32 Priority;
}OSShortPcb;


extern OSpcb * OSReadyList;    //就绪态任务表表头
extern OSpcb * OSSuspendList;  //挂起态任务表表头
extern OSpcb * OSDelayList;    //延时态任务表表头
extern OSpcb * OSCurrentPcb;   //当前运行的任务

extern OSpcb OSSystemIdlePcb;  //系统空闲任务
#define OSReadyListBottom OSSystemIdlePcb  //就绪态列表的底部为系统空闲表
extern OSShortPcb OSSuspendListBottom;     //挂起态列表表底
extern OSShortPcb OSDelayListBottom;       //延时态列表表底


//设备
typedef struct OSdevice
{
struct OSdevice * Next;   //指向下一个设备
volatile OSpcb  * User;   //使用该设备的当前任务
volatile uint32 RequestCount;  //请求使用该设备的任务数
volatile uint32 DeviceID;      //该设备的ID号
}OSdevice;

extern OSdevice * OSDeviceList;  //设备列表


void OSInit(void);   //操作系统初始化


void OSTickInit(void);   //时钟节拍初始化


#define OS_I_Bit 0x00000080     /*IRQ中断控制位*/
#define OS_F_Bit 0x00000040     /*FIQ中断控制位*/

#define OS_ARM_MODE   0x00000000   /*选择任务为ARM代码*/
#define OS_THUMB_MODE 0x00000020   /*选择任务为THUMB代码*/

#define MaxOfTimer0 (163200/100-1)   /*定时器0计数的最大值。定时器0由最大开始减小,到0时,发生中断,产生时钟节拍。时钟节拍被设置为100Hz*/

#define RefreshPeriod 200    /*任务管理器的刷新周期。设置为200,表示200个时钟周期刷新一次,即2S刷新一次*/

#define TotalTime ((MaxOfTimer0+1)*RefreshPeriod)   /*任务管理器运行一次的总时间数*/


#define OSInReadyStatus      0x00000001   /*就绪状态*/
#define OSInDelayStatus      0x00000002   /*延时状态*/
#define OSInSuspendStatus    0x00000004   /*挂起状态*/


extern volatile uint32 CopyOfIRQEN;     //用来备份IRQEN的状态
extern volatile uint32 CopyOfFIQEN;     //用来备份FIQEN的状态
extern volatile uint32 OSEnCrCount;     //用来统计进入临界代码段次数
extern volatile uint32 TimeOfTaskStart;  //用来保存一个任务刚被切换到运行态的时刻

void OSTaskDelay(uint32 NumOfTick);  //延任务时NumOfTick个时钟节拍
uint32 OSTaskSuspend(OSpcb * pcb);      //将一个任务挂起

#define NO_SUCH_A_TASK       1           /*错误代号:该任务不存在*/
#define CAN_NOT_BE_SUSPENDED 2           /*错误代号:该任务不能被挂起*/


void OSSystemIdle(void);        //系统空闲任务
void OSTaskManager(void);       //任务管理器


void OSEnterCritical(void);           /*进入临界段*/
void OSExitCritical(void);            /*退出临界段*/


#define OSSizeOfMemoryPool (7*1024)    //缓冲池为7K字节
#define OSSizePerBlock     (4*4)       //每块大小为16字节

#define MEMORY_INIT          0
#define MEMORY_ALLOCATION    1  /*操作代码0,分配内存*/
#define MEMORY_FREE          2  /*操作代码1,释放内存*/
#define MEMORY_STATISTIC     4  /*操作代码2,统计内存*/
#define GET_MEMORY_POOL_SIZE 8  /*操作代码4,获取内存缓冲池大小*/
#define MEMORY_TEST          16  /*操作代码8,内存检测*/


uint32 OSMemoryManage(uint32 Operation,uint32 StartAddr,uint32 Length);  /*内存管理函数*/


#define OSMalloc(Length)          OSMemoryManage(MEMORY_ALLOCATION,0,(Length))  /*申请一块长度为Length字节的内存块*/
#define OSFree(StartAddr,Length)  OSMemoryManage(MEMORY_FREE,StartAddr,Length)  /*释放地址为StartAddr,长度为Length的一块内存*/
#define OSMemoryStatistic()       OSMemoryManage(MEMORY_STATISTIC,0,0)          /*统计内存使用量*/
#define OSGetMemoryPoolSize()     OSMemoryManage(GET_MEMORY_POOL_SIZE,0,0)      /*获取内存缓冲池的大小*/
#define OSMemo
7楼: >>参与讨论
computer00
ARM_00_OSSystemIdle.c file
/**********************************************************************************************
  ARM_00_OSSystemIdle.c file
  
  作者:Computer-lov
  建立日期:2006-5-13
  修改日期:2006-5-15
  版本:V1.0
  版权所有,盗版必究。
  任何技术问题可到我的博客上留言:    http://computer00.21ic.org
  COPYRIGHT(C) Computer-lov 2006-2016
  All rights reserved
**********************************************************************************************/

#include <ADuC7026.H>
#include "my_type.h"

#include "ARM_00_OS_TaskSwitch.H"
#include "ARM_00_OS_Core.H"
#include "UART.H"
#include "KEYS.H"
#include "Task.h"


/**********************************************************************************************
功能:系统空闲任务。
入口参数:无。
返回:无。
备注:操作系统必须从系统空闲任务开始运行。并且系统空闲任务永远不能挂起或者延时。
**********************************************************************************************/
void OSSystemIdle(void)
{
prints("",1);   //显示任务被启动
prints(OSCurrentPcb->Title,0);
prints(" Start.",1);

OSAddDevice(OS_PRINTER_DEVICE_ID);

OSTaskCreat((uint32)OSTaskManager,256,1,OS_THUMB_MODE,"TaskManager");   //创建任务管理器任务

OSTaskCreat((uint32)Task3,256,8,OS_THUMB_MODE,"Task3");  //创建任务3
OSTaskCreat((uint32)Task4,256,8,OS_THUMB_MODE,"Task4");  //创建任务4
OSTaskCreat((uint32)Task5,256,3,OS_THUMB_MODE,"Task5");

KEYBoardInit();     //初始化键盘

OSExitCritical();   //退出临界段

while(1)
  {
  }
}
//////////////////////////////////End of function//////////////////////////////////////////////








8楼: >>参与讨论
computer00
ARM_00_OSTaskManager.c file
/**********************************************************************************************
  ARM_00_OSTaskManager.c file
   
  作者:Computer-lov
  建立日期:2006-5-13
  修改日期:2006-5-15
  版本:V1.0
  版权所有,盗版必究。
  任何技术问题可到我的博客上留言:    http://computer00.21ic.org
  COPYRIGHT(C) Computer-lov 2006-2016
  All rights reserved
**********************************************************************************************/


#include <ADuC7026.H>
#include "my_type.h"

#include "ARM_00_OS_TaskSwitch.H"
#include "ARM_00_OS_Core.H"
#include "UART.H"
#include "KEYS.H"
#include "Task.h"
#include "ADC.H"

/**********************************************************************************************
功能:显示任务的PID号。
入口参数1:pcb。要显示的任务的进程控制块地址。
返回:无。
**********************************************************************************************/
void DisplayPID(OSpcb * pcb)
{
print_uint32(pcb->PID);  //显示任务ID号(PID)
send_a_byte(' ');
}
//////////////////////////////////End of function//////////////////////////////////////////////


/**********************************************************************************************
功能:显示任务的CPU使用率。
入口参数1:pcb。要显示的任务的进程控制块地址。
返回:无。
**********************************************************************************************/
void DisplayCPU(OSpcb * pcb)
{
uint32 CpuUsedRatio;

CpuUsedRatio=((pcb->RunTimeInThisRefreshPeriod)*100+TotalTime/2)/TotalTime;  //计算CPU使用率。加TotalTime/2是为了四舍无入
pcb->TotalRunTime+=pcb->RunTimeInThisRefreshPeriod;  //累加任务的CPU使用总时间
pcb->RunTimeInThisRefreshPeriod=0;   //清本次统计的时间
if(CpuUsedRatio>=100)  //如果统计的结果大于100
  {
   CpuUsedRatio=99;  //结果为99
  }
send_a_byte((CpuUsedRatio/10)+'0');  //显示结果
send_a_byte((CpuUsedRatio%10)+'0');
send_a_byte('%');
send_a_byte(' ');
send_a_byte(' ');
}
//////////////////////////////////End of function//////////////////////////////////////////////


/**********************************************************************************************
功能:显示任务使用CPU的总时间。
入口参数1:pcb。要显示的任务的进程控制块地址。
返回:无。
**********************************************************************************************/
void DisplayCPUTime(OSpcb * pcb)
{
uint32 Time;   //用来保存时间
uint8 H,M,S;   //用来保存时,分,秒

Time=(uint32)((pcb->TotalRunTime)/((MaxOfTimer0+1)*100));  //计算总时间。结果为多少秒。
S=Time%60;   //计算秒
Time/=60;
M=Time%(60);  //计算分
Time/=60;
H=Time%(24);  //计算时

send_a_byte((H/10)+'0'); //显示时
send_a_byte((H%10)+'0');
send_a_byte(':');
send_a_byte((M/10)+'0'); //显示分
send_a_byte((M%10)+'0');
send_a_byte(':');
send_a_byte((S/10)+'0'); //显示秒
send_a_byte((S%10)+'0');
send_a_byte(' ');
send_a_byte(' ');
}
//////////////////////////////////End of function//////////////////////////////////////////////


/**********************************************************************************************
功能:显示内存使用量
入口参数1:pcb。要显示的任务的进程控制块地址。
返回:无。
**********************************************************************************************/
void DispalyMemroyUsed(OSpcb * pcb)
{
print_uint32(pcb->StackLength);   //显示内存使用量
send_a_byte('B');               //显示单位
send_a_byte(' ');
send_a_byte(' ');
}
//////////////////////////////////End of function//////////////////////////////////////////////


/**********************************************************************************************
功能:显示任务所处的状态。
入口参数1:pcb。要显示的任务的进程控制块地址。
返回:无。
**********************************************************************************************/
void DispalyStatus(OSpcb * pcb)
{
SWITCH(pcb->Status)    //根据状态来显示
  {
   case OSInReadyStatus:      prints("Ready  ",0);break;  //就绪态
   case OSInDelayStatus:      prints("Delay  ",0);break;  //延时态
   case OSInSuspendStatus:    prints("Suspend",0);break;  //挂起态
   default:break;
  }
}
//////////////////////////////////End of function//////////////////////////////////////////////



#define REF_VOL  2.5

//////////////////////////////显示内核电压////////////////////////////////////
void DisplayCoreVoltage(void)
{
uint16 VALUE;
uint32 result;
uint8 s_result[10];

prints("Core voltage: ",0);
VALUE=2*read_ADC(0x13);      //通道号为0x13的电压为1/2电源电压
result=REF_VOL*10000;          //换算成电压,结果为多少mV的10倍
result=result*VALUE/4095;
s_result[9]=0;                  //将结果转换成字符串
s_result[8]=' ';
s_result[7]='V';
s_result[6]='m';
s_result[5]='0'+result%10;
result/=10;
s_result[4]='.';
s_result[3]='0'+result%10;
result/=10;
s_result[2]='0'+result%10;
result/=10;
s_result[1]='0'+result%10;
result/=10;
s_result[0]='0'+result%10;
prints("    ",0);
prints(s_result,0);         //显示电压
prints("  ",0);
}
//////////////////////////////////////////////////////////////////////////////

//////////////////////////////////显示内核温度////////////////////////////////
void DisplayCoreTemperature(void)
{
uint16 VALUE;
sint32 result;
uint8 s_result[10];

prints("Core temperature: ",0);
VALUE=read_ADC(0x10);           //通道号为0x10的是温度传感器电压
result=REF_VOL*10000;           //换算成电压,结果为多少mV的10倍
result=result*VALUE/4095;
result=((7800-result)*10/13)+250;     //温度是25℃时,输出电压为780mV,每升高1℃,输出电压降低1.3mV
                                     //计算结果为多少度的10倍
if(result<0)                   //如果温度小于0度
  {
   s_result[0]='-';            //显示负号
   result*=-1;                //将结果换成正的
  }
else
  {
   s_result[0]=' ';  
9楼: >>参与讨论
computer00
Task.c file
/**********************************************************************************************
本程序只供学习使用,不得用于其它任何用途,否则后果自负。

  Task.c file

  作者:Computer-lov
  建立日期:2006-5-8
  修改日期:2006-5-15
  版本:V1.0
  版权所有,盗版必究。
  任何技术问题可到我的博客上留言:    http://computer00.21ic.org
  COPYRIGHT(C) Computer-lov 2006-2016
  All rights reserved
**********************************************************************************************/


#include <ADuC7026.H>

#include "interrupt.h"
#include "LED.H"
#include "ARM_00_OS_TaskSwitch.H"
#include "my_type.h"
#include "ARM_00_OS_Core.H"
#include "UART.H"
#include "KEYS.H"
#include "Task.h"

/**********************************************************************************************
任务1。处于挂起状态,等待一条消息。系统空闲任务会扫描按键,当按键按下后,系统空闲任务会将
键值通过消息发送给任务1。任务1接到消息后,显示消息的发送者以及消息的信息等。然后控制LED4的亮灭。
**********************************************************************************************/
void Task1(void)
{
uint32 PrinterDeviceAddr;   //保存打印机设备的地址

PrinterDeviceAddr=OSGetDeviceAddr(OS_PRINTER_DEVICE_ID);   //获取打印机设备地址
OSRequestDevice(PrinterDeviceAddr,0);    //申请使用打印机

prints("",1);
prints(OSCurrentPcb->Title,0);   //显示任务启动
prints(" Start.",1);

OSFreeDevice(PrinterDeviceAddr);   //释放打印机

EN_LED4();  //使能LED4

while(1)
  {
   OSTaskSuspend(OSCurrentPcb);  //任务挂起
   if(OSCurrentPcb->Msg)        //如果收到消息
    {
     OSRequestDevice(PrinterDeviceAddr,0);  //申请打印机
     
     prints("",1);
     prints("",1);
     prints(OSCurrentPcb->Title,0);  //显示任务标题
     prints(":",1);
     prints("Haha,I have got a message from: ",0);  //显示相关信息
     prints(OSCurrentPcb->Msg->Sender->Title,1);    //显示发送者的标题
     prints("The sender's PID is: ",0);
     print_uint32(OSCurrentPcb->Msg->Sender->PID);  //显示发送者的PID
     prints("",1);
     prints("The message type is:",0);             //消息类型
     print_uint32(OSCurrentPcb->Msg->MsgType);
     prints("",1);
     prints("The message VALUE is",0);             //消息的值
     print_uint32(*(OSCurrentPcb->Msg->pMsg));
     prints("",1);
     prints("",1);
     
     OSFreeDevice(PrinterDeviceAddr);  //释放打印机
     
     SWITCH(*(OSCurrentPcb->Msg->pMsg))    //键值散转
      {
       case KEY1: ON_LED4();break;    //如果是按键1按下,则点亮LED4
       case KEY2: OFF_LED4();break;   //如果是按键2按下,则熄灭LED4
       default: break;
      }
     OSCurrentPcb->Msg=0;           //消息处理完毕
    }
  }
}
//////////////////////////////////End of function//////////////////////////////////////////////


/**********************************************************************************************
任务2。延迟1S,等待一条消息。系统空闲任务会扫描按键,当按键按下后,系统空闲任务会将
键值通过消息发送给任务1。任务1接到消息后,显示消息的发送者以及消息的信息等。然后控制LED4的亮灭。
如果1S过后,还未收到消息,则显示接收超时。
/*********************************************************************************************/
void Task2(void)
{
uint32 PrinterDeviceAddr;    //保存打印机设备的地址

PrinterDeviceAddr=OSGetDeviceAddr(OS_PRINTER_DEVICE_ID);     //获取打印机设备地址
OSRequestDevice(PrinterDeviceAddr,0);                   //申请使用打印机

prints("",1);
prints(OSCurrentPcb->Title,0);  //显示任务启动
prints(" Start.",1);
OSFreeDevice(PrinterDeviceAddr);   //释放打印机

EN_LED5();
while(1)
  {
   OSTaskDelay(100);       //延时等待消息的到来
   if(OSCurrentPcb->Msg)   //如果收到了消息
    {
     OSRequestDevice(PrinterDeviceAddr,0);   //申请使用打印机
     prints("",1);
     prints("",1);
     prints(OSCurrentPcb->Title,0);   //显示任务的标题
     prints(":",1);
     prints("Haha,I have got a message from: ",0);
     prints(OSCurrentPcb->Msg->Sender->Title,1);     //显示消息发送者的标题
     prints("The sender's PID is: ",0);
     print_uint32(OSCurrentPcb->Msg->Sender->PID);  //显示消息发送者的PID
     prints("",1);
     prints("The message type is:",0);
     print_uint32(OSCurrentPcb->Msg->MsgType);    //显示消息的类型
     prints("",1);
     prints("The message VALUE is",0);
     print_uint32(*(OSCurrentPcb->Msg->pMsg));   //显示消息
     prints("",1);
     prints("",1);
     OSFreeDevice(PrinterDeviceAddr);    //释放打印机
     SWITCH(*(OSCurrentPcb->Msg->pMsg))     //键值散转
      {
       case KEY3: ON_LED5();break;    //如果是按键3按下,则点亮LED5
       case KEY4: OFF_LED5();break;   //如果是按键4按下,则熄灭LED5
       default: break;
      }
     OSCurrentPcb-&g
10楼: >>参与讨论
computer00
ARM_00_OS_main.c file
/**********************************************************************************************
本程序只供学习使用,不得用于其它任何用途,否则后果自负。

  ARM_00_OS_main.c file

  ADuC702x上的操作系统——ARM_00_OS

  作者:Computer-lov
  建立日期:2006-5-1
  修改日期:2006-5-15
  版本:V1.0
  版权所有,盗版必究。
  任何技术问题可到我的博客上留言:    http://computer00.21ic.org
  COPYRIGHT(C) Computer-lov 2006-2016
  All rights reserved
**********************************************************************************************/

#include <ADuC7027.H>
#include "My_type.h"
#include "LED.H"
#include "interrupt.h"
#include "ARM_00_OS_TaskSwitch.H"
#include "ARM_00_OS_Core.H"
#include "UART.H"
#include "KEYS.H"

/*********************************************************************************************/
void SysClkInit(void)
{
PLLKEY1=0xAA;
PLLCON=0x01;   //PLL配置  
PLLKEY2=0x55;
POWKEY1=0x01;
POWCON=0x00;  //CPU时钟配置为41.78MHz
POWKEY2=0xF4;
}
///////////////////////////////////////////////////////////////////////////////////////////////

/**********************************************************************************************
main函数
**********************************************************************************************/
void main(void)
{

DisEnableInterrupt(OS_I_Bit | OS_F_Bit);  //关中断

SysClkInit();  //系统时钟初始化

UART_init();   //串口初始化

DelayXms(100);  //延迟100MS

cls();         //清屏

prints("SystemStart",1);  //显示开机信息

OSInit();   //操作系统初始化

DelayXms(2000);   //延时2S

OSEnterCritical();  //进入临界段

EnableInterrupt(OS_I_Bit | OS_F_Bit);  //开中断

OSTickInit();  //系统时钟节拍初始化

OSStart((uint32)OSSystemIdle,OS_THUMB_MODE);  //系统开始运行

}
//////////////////////////////////End of function//////////////////////////////////////////////


11楼: >>参与讨论
computer00
估计大家看了会有些头晕,因为我自己头都晕了…………
准备先休息一段时间,好好看看书,然后再慢慢补充内容吧。

12楼: >>参与讨论
kingpoo
恭喜恭喜!00又有大作了,下来看看!
恭喜恭喜!00又有大作了,下来看看!

13楼: >>参与讨论
eleven11
每句都有注释,非常好
 
14楼: >>参与讨论
hjf8031
好!
 
15楼: >>参与讨论
wangkj
继续努力,终有大成
 
16楼: >>参与讨论
lpcfans
牛就一个字。。。。。
 
17楼: >>参与讨论
iversonma
圈圈太牛了~敬仰~
 
18楼: >>参与讨论
sfofyyy
无限敬仰!啥时候俺也~~~~
 
19楼: >>参与讨论
阿南
青年人有冲劲,好样的。。。
 
20楼: >>参与讨论
computer00
多谢斑竹鼓励~~~~~~再补充一个文件,软中断进入时的汇编部分
/***********************************************************************/
/*  This file is PART of the CA ARM C Compiler PACKAGE                 */
/*  COPYRIGHT KEIL ELEKTRONIK GmbH 2002 - 2004                         */
/***********************************************************************/
/*                                                                     */
/*  SWI_VEC.S:  Pre-defined vectored interrupt handler SWI interrupt   */
/*                                                                     */
/***********************************************************************/

/*
修改日期:2006-5-16
修改者:computer00
*/

AREA ?C?SWI, CODE, READONLY, ALIGN=2

PUBLIC SWI_Handler?A, ?SWI?Table, ?SWI?Empty

SWI_Handler?A    PROC CODE32
        STMFD   SP!,{R3,R8,R12,LR} ; Store R3,R8,R12,LR register
        MRS     R8,SPSR            ; 将SPSR放入R8中
        STMFD   SP!,{R8}           ; 将R8压栈
        TST     R8,#0x20           ; SWI call from
        LDRNEH  R8,[LR,#-2]        ; Thumb: Load halfword instruction
        ANDNE   R8,R8,#0xFF        ;        extract SWI NUMBER
        LDREQ   R8,[LR,#-4]        ; ARM:   Load word     instruction
        BICEQ   R8,R8,#0xFF000000  ;        extract SWI NUMBER
                                   ; R4 now contains SWI NUMBER
; SWI Handler
;       LDR     R12,[PC,#(?SWI?Table-$-8)] ; Maximum NUMBER of interrupts
;       LDR     R12,[PC,#0x24]     ; Maximum NUMBER of interrupts
        ADR     R12,?SWI?Table
        LDR     R12,[R12]          ; load last SWI-Function-NUMBER

        CMP     R8,R12                                             
        BGT     ?SWI?Empty         ; overflow
        ADR     R12,?SWI?Table+4
        LDR     R12,[R12,R8,LSL #2]; SWI function address
        MOV     LR,PC              ; Return address
        BX      R12                ; Call SWI function
         
        LDMFD   SP!,{R8}           ;R8出栈
        MSR     SPSR_fsxc,R8       ;设置SPSR寄存器
        LDMFD   SP!,{R3,R8,R12,PC}^  ; Return

?SWI?Empty:
        B       $                  ; no existing SWI

; *** DO NOT MODIFY THIS PORTION OF THE FILE ***
?SWI?Table:                        ; Marker for LA Linker                       
;
; The LA Linker inserts at this label
;       DD      0                  ; <last SWI function NUMBER>
;       DD      ?SWI?Empty         ; <entry for SWI function 0>
;       DD      <SWI entry 1>
;       DD      <SWI entry 2>
;       DD           :
; For non-existing SWI functions DD ?SWI?Empty is inserted

        ENDP

        END


21楼: >>参与讨论
3极管
感叹~~圈圈深不可测~~~~
 
22楼: >>参与讨论
liuxinghy
很好
不错,楼猪辛苦啦

23楼: >>参与讨论
minr1982
顶!顶!!!
顶!顶!!!

问一下
我下来后运行不了

缺少 my_tpye.h

24楼: >>参与讨论
wgeg722
谦虚~!
呵呵,你还说你自己是菜鸟.

这样的话,那什么年代我才能成为菜鸟啊.

25楼: >>参与讨论
computer00
哦,不好意思,有两个地方忘记改过来了,
现在已经改好并重新上传了。

如果软件仿真的话,将主函数中的延时2秒去掉,仿真会快些。

此外,keil自带的头文件也有点问题,在KEIL自带的DAC.H头文件有点问题,在DAC.H文件中找到


typedef struct s_DAC {
   s_DAC_Channel Channel[DAC_COUNT]; /* @0 */
} s_DAC;


并将其改成下面的样子:

#if DAC_COUNT > 0
typedef struct s_DAC {
   s_DAC_Channel Channel[DAC_COUNT]; /* @0 */
} s_DAC;
#endif



26楼: >>参与讨论
hotpower
高,实在是高~~~不愧是"空军一号"
有空投入汽油桶让我"烟酒烟酒"...

高~~~佩服~~~这次汇编再忘不了了...

27楼: >>参与讨论
testcode
佩服...
 
28楼: >>参与讨论
南方的老树
俺给圈圈出个主意,你就专心做arm-00-os商业化的操作系统好了
做好了卖license,不比帮别人赚钱强?


* - 本贴最后修改时间:2006-5-17 0:41:27 修改者:南方的老树

29楼: >>参与讨论
computer00
这个…………离商业化恐怕还差了很大的距离……
现在对操作系统的学习和理解还处于起步阶段,以后做得像模像样时,或许可以考虑考虑~~~~~~~

30楼: >>参与讨论
南方的老树
所以我让你专心嘛,要那么多的本事干啥,一样做好就行了
 
31楼: >>参与讨论
computer00
说的也是,也许以后工作了,就会变得比较专一吧,
趁现在还有些时间,多学几样吧……到时老了,就不想动了…………

32楼: >>参与讨论
fushaobing
祝贺“圈圈”!!!
 
33楼: >>参与讨论
computer00
谢谢!
 
34楼: >>参与讨论
gw1428jk

 
35楼: >>参与讨论
dionry
强烈支持圈圈!
顺便介绍一下圈圈,华南理工电信学院学生,今天七月将本科毕业,保送为电信学院的研究生。十足的牛人,敬佩!

36楼: >>参与讨论
computer00
今天测试了一下,定时器中断切换任务要12uS左右,
任务主动放弃CPU使用切换任务需要10uS左右。

由于定时器中断需要给延迟的任务时间减一并判断任务是否需要唤醒,所以时间就需要多点。

* - 本贴最后修改时间:2006-5-21 13:19:47 修改者:computer00

37楼: >>参与讨论
devicegate
:)
无论如何,起码这种钻研精神值得提倡,咱们老中太少这些人了。。。。

广州联智arm9学习板,开发板

38楼: >>参与讨论
solo8
学习圈圈好榜样
我是ARM的初学者哦,向你学习

39楼: >>参与讨论
jxc827
厉害!
人和人的差距砸就这么大呢?

40楼: >>参与讨论
ysg2894
牛,学习中……
 
41楼: >>参与讨论
hqgboy
00:直接在KEIL中打开提示不能运行A51.EXE?
现在的压缩包不缺文件吧?
谢谢.

42楼: >>参与讨论
wuhanmcu

 
43楼: >>参与讨论
computer00
to hqgboy:你的keil是什么版本的?Keil UV3才可以的。
我用的是Keil UV3 2.5版本的,就在我blog的这个帖子中,给出了下载连接。

44楼: >>参与讨论
小浪
楼主真强呀~~~
真是由衷的佩服楼主的研发能力,向你学习了!!!

45楼: >>参与讨论
computer00
呵呵,其实这算不上真正的操作系统吧,只是为了练习一下ARM编程
做一回ARM菜鸟~~~~~~~~~~~

46楼: >>参与讨论
hqgboy
谢谢00..可能我的版本低...
希望00有时间写的更好...呵呵.
串口之类的能用中断尽量用中断...
支持....

47楼: >>参与讨论
poly_lou
强啊
 
48楼: >>参与讨论
LPCfAnS
不错....呵呵.
 
49楼: >>参与讨论
fzhiyu
看到了00,看到了希望..
我是ARM初学者,现在遇到问题了。.想请教一下........
我会在你博客上留言的...

50楼: >>参与讨论
robshine
OO ni 你比牛还牛!
 
51楼: >>参与讨论
heros
牛人&好人
搂住真牛人啊!感谢共享!

52楼: >>参与讨论
Computer00
关于ARM_00_OS的CPU使用率统计的算法
我是利用时钟节拍发生器的定时器的值来计算每个任务的运行时间的。每个任务的PCB里都有两个时间累加器,
一个是当前统计时间(例如2s)内运行时间t1,另一个是总运行时间t2。另外还有一个变量用来保存任务发生
切换后,定时器当前的值。首先,将所有时间累计清0,在任务发生切换时,读出定时器中的值,跟上一次
发生任务切换时,保存的定时器的值比较,即可计算出在两次任务切换之间定时器值之差,这就是上一个
任务所运行的CPU时间,将它累加到任务PCB的t1中。当统计时间到时,计算t1在整个2s内所占的比例,
就是该任务的CPU使用率。在计算完成后,将t1累加到t2中,t1清0。t2即是任务运行的总时间,换算
成时间显示即可。最后总的cpu使用率,用100%减掉空闲任务占用的cpu资源即可。我的空闲任务
就是一个while(1),你可以将其改成让CPU进入空闲模式的指令,由中断唤醒,这可以降低功耗。

    由于定时器的计数速度很快,很容易是us级的,例如在我的系统中,时钟节拍是10ms,需要计数1632次,
即每一次计数间隔为6us左右,因而最终的统计结果将会很准确。但是由于在最后显示时,我只需要精确到1%,
所以用了四舍五入的方法,这样一下来,就可能会有多个小于1%的cpu被舍去,从而最后的cpu累加不是100%,
不过总体感觉上还是很不错的。

由于最近比较忙,所以一直没写它的结构以及调度算法等,以后有空了,再补上吧,不过似乎对这个感兴趣的人不多,所以我也一直没什么动力去搞^_^。


53楼: >>参与讨论
eleven11
lz的d12我看了
写的很简洁啊,一定花了不少时间,很多人的d12程序一看就是抄的

* - 本贴最后修改时间:2006-6-3 11:10:22 修改者:eleven11

54楼: >>参与讨论
3h5h

我是搞硬件的,看到这些就发晕。
现在还没理清 头绪-----头文件和自己程序有什么联系??
不知哪位大侠能够指点一下迷津?
谢咯!!!

55楼: >>参与讨论
Computer00
头文件跟其它.c文件一样,只是一个文本文件。
只是大家都约定叫做.h文件而已。

关键在于#include语句,通过该语句引用头文件。相当于把头文件中的所有内容,复制到了被include的位置。

这样,你就可以将一些重复性的代码,例如宏定义,函数及变量的声明等,放在头文件中,
然后使用include语句引用该头文件。这样看起来就简洁得多,也不用每个.c文件前面
都跑去复制一堆代码过来。想象一下,你的某c文件,要使用一个处理器的寄存器,
那么你首先得定义这些寄存器,如果每次都将这一堆相同的定义写在c文件的开头,看到头都晕了…………

56楼: >>参与讨论
zhych71
有点头晕,先收藏,学习中...
 
57楼: >>参与讨论
terrence
向圈圈学习!
 
58楼: >>参与讨论
tengfeihk
什么时候我才跟得上圈圈呢?
努力+努力!

59楼: >>参与讨论
黄二

 
60楼: >>参与讨论
eleven11
牛b的楼主
 
61楼: >>参与讨论
ft2006095
高手啊。。。牛。。。。。
 
62楼: >>参与讨论
ft2006095
高手就是高手
 
63楼: >>参与讨论
hgchenkv
向00学习!
 
64楼: >>参与讨论
forbbs21ic
楼主真的很牛……
佩服

65楼: >>参与讨论
hotpower
哈哈~~~
 
66楼: >>参与讨论
computer00
等我有空了,再把它完善一下~~~~~并弄到不同公司的ARM芯片上~~
 
67楼: >>参与讨论
cpld163
re
楼住就一牛人啊,呵呵!

68楼: >>参与讨论
mike_le

 
69楼: >>参与讨论
guohaidao
圈圈操作系统
圈圈操作系统真是不错:)非常适合入门,谢谢,支持一下

70楼: >>参与讨论
aceice
贴个规范上来^_^
看你的代码看到我头晕:)
形而上学的东西还是要掌握点的~
支持圈圈

http://bbs.21ic.com/upfiles/img/200661593117771.rar

71楼: >>参与讨论
nioyz
辛苦
RT

72楼: >>参与讨论
computer00
to ACEICE:俺这叫有个性~~~~~~~~~个性代码~~
如果大家都一样了,那多死板呀,一点生气都没有,会很枯燥的~~~~~~~

73楼: >>参与讨论
linqing171
路过,留名以后观看.
 
74楼: >>参与讨论
yingzqy
路过
路过
收藏!

75楼: >>参与讨论
将军令
干劲不错,可是没有什么用
uclinux不是已经很好了吗???

76楼: >>参与讨论
computer00
写来玩玩而已^_^
这就像流水灯一样,别人写来玩了,你也可以写来玩的。

77楼: >>参与讨论
海天一色
高山仰止,佩服。
 
78楼: >>参与讨论
win2000_li
太强啊!!!!
 
79楼: >>参与讨论
pianomail
佩服
厉害啊!向楼主学习!

80楼: >>参与讨论
哈佛大学
晕,唉...搞技术这么烦.还是跑业务好
哦,原来00是华工的学生,怪不得这么厉害!

81楼: >>参与讨论
HWM
看来中国也要出盖茨了,因为美国的盖茨就是这样玩出来的.
 
82楼: >>参与讨论
fen_mo
顶一下表示支持
 
83楼: >>参与讨论
r_jw
值的我学习!
顶!!!

84楼: >>参与讨论
lihaichuan
怎一个牛字了得!
怎一个牛字了得!
敬仰00

85楼: >>参与讨论
tonydesign
佩服佩服
也好想成为这样的人才:)

86楼: >>参与讨论
stonewater
学习ing……
 
87楼: >>参与讨论
高慧婷
hehe```
偶也来列```00```

88楼: >>参与讨论
yuqijia
不服不行啊
佩服啊,自己写OS
人跟人的差距咱这么大涅

89楼: >>参与讨论
林泉明
真强人也
 
90楼: >>参与讨论
ljxh401
想起了灌水区的一个谜语
母牛追着公牛

91楼: >>参与讨论
luan_dahai
好晕
51的还比较好看,这个好累阿 。看两天了。呵呵圈圈 我要向你学习阿!有不会的还要请教阿 。

92楼: >>参与讨论
joy晴天

 
参与讨论
昵称:
讨论内容:
 
 
相关帖子
有兴趣看看我的操作系统:RT-Thread
想看linux的源代码,大家推荐一下哪个版本注释比较好看懂?
求教数据通信问题
请教桢内预测,的VHDL/VERILOG代码
想运行带GUI的LINUX,请推荐一款ARM9
免费注册为维库电子开发网会员,参与电子工程师社区讨论,点此进入


Copyright © 1998-2006 www.dzsc.com 浙ICP证030469号