极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 5349|回复: 2

CoOS(For Cortex MCU 的实时操作系统)

[复制链接]
发表于 2012-9-19 16:29:57 | 显示全部楼层 |阅读模式
ooCox CoOS是专门针对于ARM Cortex-M系列设计和优化的一款可剪裁的多任务实时内核。CooCox CoOS支持时间片轮询和优先级抢占两种不同的任务调度机制,支持软件定时器,并提供多种同步通信方式,如:信号量、邮箱、队列、事件标志、互斥体等。它符合CMSIS(Cortex Microcontroller Software Interface Standard)。

以下都可以在coocox官方网址下载: www.coocox.org/CN
n
CoOS特征
Ø
免费、开源的实时操作系统;
Ø
针对Cortex-M系列处理器设计;
Ø
高度可裁剪性,最小系统内核仅974Byte;
Ø
自适应任务调度算法;
Ø
支持优先级和时间片轮转两种调度算法;
Ø
零中断调度时间;
Ø
能进行堆栈溢出检查;
Ø
支持信号量,互斥体,事件标志,邮箱和队列五种同步与通信方式;
Ø
符合CMSIS规范;
Ø
支持多种编译器:ICCARM,ARMCC,GCC。
n
CoOS 的技术参数
CooCox CoOS的时间技术参数如表C-1所列,空间技术参数如表C-2所列。

coos.png

C.3.2.        移植
可从如下网站下载CooCox CoOS 的源代码:www.coocox.org,该源代码包是完全开放和免费的,目前的最新版本是1.13,本节应用实例也使用此版本。源码下载之后,将其加入到工程中去即可。
对于CoOS源码,还应根据处理器及应用需求进行相关的配置,需要修改的内容非常简单,主要是修改OsConfig.h文件。以下是根据NUC140处理器及本节应用实例所做的修改:
/* 配置处理器核的类型,cortex-m3(1),cortex-m0(2) */
#define CFG_CHIP_TYPE           (2)

/* 定义可以分配的最低优先级 */
#define CFG_LOWEST_PRIO         (64)

/* 最多能够运行的任务,根据实际应用选择,这里选择5以节省空间 */            
#define CFG_MAX_USER_TASKS     (5)      

/* 空闲任务堆栈大小(字) */   
#define CFG_IDLE_STACK_SIZE    (25)   

/* 系统时钟频率,12000000表示12MHz */   
#define CFG_CPU_FREQ            (12000000)

/* 系统节拍频率(Hz),100表示10ms,100Hz的系统节拍 */
#define CFG_SYSTICK_FREQ       (100)     

/* ISR 中最大系统API调用数 */
#define CFG_MAX_SERVICE_REQUEST (3)

/*任务调度方式选择,1为时间片轮转方式,0为优先级抢占方式 */
#define CFG_ROBIN_EN            (0)         
关于CoOS的详细介绍,可以参考《Coocox CoOS User's Guide》,该手册可以在http://www.coocox.com/CoOS.htm下载, 在http://www.coocox.com/CN/CoOS.htm中也有相应的中文手册。


C.3.3.        CoOS应用程序设计
设计任务:使用CoOS操作系统;建立4个任务,分别用于初始化,打印RTC时间,打印ADC转换值,控制开发板的LED5-LED8闪烁。
硬件设计:本次设计用到NUC140VE3CN开发板,用到的外设有ADC,RTC,GPIO,LCD等。其相关外设可查开发板资料。
软件设计与实现:
1)        建立工程
在CoIDE下面建立工程,勾选相应的COX组件以及驱动,按C.1.1小节描述修改OsConfig.h文件。工程结构如图C-11所示。


图C-11 CoOS_Exp工程结构
2)        编写应用代码
在基于OS 的应用开发中,一个应用程序通常由若干个任务组成。在CoOS中,任务通常是一个内部无限循环的C函数,同样有返回值和参数,由于任务永远不会返回,所以任务的返回类型必须定义为void。下面是一个典型的任务体:
void myTask (void* pdata)
{
  for(;;)
    {
    }
}
与普通的C 函数不同,任务退出是通过调用系统退出的API函数来实现的。若只是通过代码执行结束来表示任务退出,这样将会导致系统崩溃。在CooCox CoOS 中,可以调用ExitTask()和DelTask(taskID)来删除一个任务。
ExitTask()删除当前正在运行的任务;DelTask(taskID)可以删除其他任务,若参数为当前任务ID,则同ExitTask()一样删除当前任务。具体用法可参考《Coocox CoOS User's Guide》。
        包含CoOS头文件
加入CoOS源代码并完成相关配置之后,使用CoOS只需要在main.c中添加如下语句:
#include
        编写任务代码
任务在创建的时候要为它指定堆栈空间,对于CoOS,任务的堆栈指针是用户指定的,所以先要定义四个数组用于四个任务的堆栈:
/*define arrays used for the stack of the tasks    */
OS_STK     taskA_stk[STACK_SIZE_TASKA];
OS_STK     taskB_stk[STACK_SIZE_TASKB];
OS_STK     taskC_stk[STACK_SIZE_TASKC];
OS_STK     task_init_Stk[TASK_STK_SIZE];
taskA用于打印输出当前时间,taskB用于打印ADC转换值,taskE用于控制LED5-LED8闪烁,task_init用于初始化所有外设,创建标志,互斥量等。例如,taskC任务对应的taskC函数如下:

/********************************************************************//**
  * @brief  TaskC is for led blinky.
  * @param  None.
  * @retval None.
***********************************************************************/
void taskC (void* pdata)
{
    for(;;)
    {
        //
        // Output high level.
        //
        xGPIOPinWrite( xGPIO_PORTC_BASE, xGPIO_PIN_12 | xGPIO_PIN_13 |
                                         xGPIO_PIN_14 | xGPIO_PIN_15, 1);

        CoTickDelay(100);

           //
        // Output low level.
        //
        xGPIOPinWrite( xGPIO_PORTC_BASE, xGPIO_PIN_12 | xGPIO_PIN_13 |
                                         xGPIO_PIN_14 | xGPIO_PIN_15, 0);

        CoTickDelay(100);
    }
}
        优先级及任务调度方式
需要为每个任务设定优先级:
/*set the priority of the task*/
#define PRIORITY_TASKA        2
#define PRIORITY_TASKB        3
#define PRIORITY_TASKC        1
#define PRIORITY_TASK_INIT    0
其中,值越小优先级越高,因此首先会执行task_init,然后依次是taskC、taskB、taskA。
这里使用优先级抢占的任务调度方式,前面已在OsConfig.h中做了选择。需要根据应用选择信号量、互斥体、事件标志、邮箱和队列等同步方式之一,并在任务中作同步处理,详细内容可参考《Coocox CoOS User's Guide》。
        创建任务,启动多任务
当所有的任务代码已经完成之后,接下来应该初始化OS,创建任务,起始多任务调度。在使用CoOS 之前,也就是调用任何OS的API之前,必须首先通过CoOsInit()函数对CoOS 进行初始化,之后就可以调用所有CoOS的API了。
创建任务使用函数CoCreateTask,例如创建任务task_init:
CoCreateTask(task_init,(void*)0,PRIORITY_TASK_INIT,
               &task_init_Stk[SIZE_TASK-1], SIZE_TASK);
最后,通过CoOsStart()函数,系统进行第一次调度,系统正式启动。CoOsStart()之后的代码不会得到执行,因为OS 在第一次调度之后不会返回。
到此,就完成了一个简单的基于CoOS的多任务调度应用——CoOS_Exp 的设计。
整个CoIDE工程包括启动代码、C库文件、COX文件、CoOS源码等,User文件下CoOS_Exp.c是主程序文件,其参考内容如下:
/********************************************************************//**
* @title   CoOS Exp
* @author  UPTeam, Coocox
* @date    20/06/2012
* @brief   A simple exmple shows how to use CoOS on nuc140-LB board.
* First,we will see "CoOS example.." on LCD.Four leds will blink.We can see   
* time on  hyperterminal and every  5 seconds adc conversion value will show.
************************************************************************/
#include

#include

#include "uc1601.h"
#include "hw_uc1601.h"

#include "xhw_memmap.h"
#include "xhw_types.h"
#include "xhw_ints.h"
#include "xhw_nvic.h"
#include "xcore.h"
#include "xsysctl.h"
#include "xhw_sysctl.h"
#include "xgpio.h"
#include "xhw_gpio.h"
#include "xhw_uart.h"
#include "xuart.h"
#include "xrtc.h"
#include "xhw_rtc.h"
#include "xhw_adc.h"
#include "xadc.h"
   
/*-------------- Private define ---------------------------------------*/
#define SIZE_TASK 128
/*set the priority of the task*/
#define PRIORITY_TASKA         2
#define PRIORITY_TASKB         3
#define PRIORITY_TASKC         1
#define PRIORITY_TASK_INIT    0
/*-------------- Private variables ------------------------------------*/
/*define arrays used for the stack of the tasks    */
OS_STK     taskA_stk[SIZE_TASK];
OS_STK     taskB_stk[SIZE_TASK];
OS_STK     taskC_stk[SIZE_TASK];
OS_STK     task_init_Stk[SIZE_TASK];

OS_FlagID  adc_flag;
OS_MutexID mut_terminal;


tTime  Current_Time ={00, 20, 10, 18, 6, 2012, RTC_TIME_24H}, Show_Time;
unsigned long  ulRTCTickIntFlag = 1, ulcount = 0, ulconversionData;
/*----------------Private functions -----------------------------------*/
void GPIOSet(void);
void UARTSet(void);
void RTCSet(void);
void ADCSet(void);
unsigned long xRTCCallback(void *pvCBData, unsigned long ulEvent,
                           unsigned long ulMsgParam, void *pvMsgData);


/********************************************************************//**
  * @brief  TaskA is used to show rtc time.
  * @param  None.
  * @retval None.
************************************************************************/
void taskA (void* pdata)
{
    for(;;)
    {
        if(ulRTCTickIntFlag == 1)
        {
            //
            // Use Show_Time to store time.
            //
            RTCTimeRead(&Show_Time, RTC_TIME_CURRENT);

            CoEnterMutexSection(mut_terminal);
            //
            // Display time.
            //
            printf("Time: %02u:%02u:%02u\r",(unsigned int)Show_Time.ulHour,
                                              (unsigned int)Show_Time.ulMinute,
                                               (unsigned int)Show_Time.ulSecond);
            CoLeaveMutexSection(mut_terminal);

            ulRTCTickIntFlag = 0;

        }
        if(ulcount == 5)
        {
            CoEnterMutexSection(mut_terminal);
               printf("\n\r");
            CoLeaveMutexSection(mut_terminal);

            //
            // Set adc_flag.
            //
               CoSetFlag(adc_flag);
               CoTickDelay(10);
        }
    }
}

/********************************************************************//**
  * @brief  TaskB is used to get ADC conversion value.
  * @param  None.
  * @retval None.
************************************************************************/
void taskB (void* pdata)
{
    for(;;)
    {
        //
        // Wait adc_flag.
        //
           CoWaitForSingleFlag(adc_flag, 0);

        //
        // Enable ADC and start conversion.
        //
        ADCEnable(ADC_BASE);
        ADCProcessorTrigger(ADC_BASE);

        //
        // Wait for conversion complete.
        //
        while(ADCDataStatus(ADC_BASE, 7) !=ADC_DATA_VALID);
        ulconversionData = ADCDataGet(ADC_BASE, 7);

        CoEnterMutexSection(mut_terminal);
        //
        // Show conversion data.
        //
        printf("ADC conversion result:%02u\r\n",
               (unsigned int)ulconversionData);
        CoLeaveMutexSection(mut_terminal);

        ulcount = 0;

        //
        // Clear adc_flag.
        //
        CoClearFlag(adc_flag);
    }
}

/********************************************************************//**
  * @brief  TaskC is for led blinky.
  * @param  None.
  * @retval None.
************************************************************************/
void taskC (void* pdata)
{
    for(;;)
    {
        //
        // Output high level.
        //
        xGPIOPinWrite(xGPIO_PORTC_BASE,xGPIO_PIN_12 | xGPIO_PIN_13 |
                                             xGPIO_PIN_14 | xGPIO_PIN_15, 1);

        CoTickDelay(100);

        //
        // Output low level.
        //
        xGPIOPinWrite(xGPIO_PORTC_BASE,xGPIO_PIN_12 | xGPIO_PIN_13 |
                                                xGPIO_PIN_14 | xGPIO_PIN_15, 0);

        CoTickDelay(100);
    }
}

/********************************************************************//**
  * @brief  Initialization all the task in this application.
  * @param  None.
  * @retval None.
  * @details    Initialize all the hardware ,Create all the flag and mutex in
  * this application.
************************************************************************/
void task_init (void* pdata)
{
    //
    // Related hardware set.
    //
    GPIOSet();
    UARTSet();
    RTCSet();
    ADCSet();

    //
    // Create a CoOS flag.
    //
    adc_flag = CoCreateFlag(1,0);

    //
    // Create a CoOS flag.
    //
    mut_terminal = CoCreateMutex();

    //
    // LCD configuration and show messages.
    //
    UC1601Init(1500000);
    UC1601Clear();
    UC1601CharDispaly(0, 0, "CoOS example.");
    UC1601CharDispaly(1, 0, "Use terminal to");
    UC1601CharDispaly(2, 0, "show result.");
    UC1601CharDispaly(3, 0, "4 LEDs blinky.");

    CoCreateTask (taskA,0,PRIORITY_TASKA,
                     &taskA_stk[SIZE_TASK-1],SIZE_TASK);
    CoCreateTask (taskB,0,PRIORITY_TASKB,
                     &taskB_stk[SIZE_TASK-1],SIZE_TASK);
CoCreateTask (taskC,0,PRIORITY_TASKC,
                 &taskC_stk[SIZE_TASK-1],SIZE_TASK);

    //
    // Delete 'task_init' task.
    //
    CoExitTask();
}


/********************************************************************//**
  * @brief  CoOS_Exp is used to start CoOS.
  * @param  None.
  * @retval None.
************************************************************************/
int main()
{
    xSysCtlClockSet(12000000, xSYSCTL_OSC_MAIN);

    //
    // Initial CooCox CoOS
    //
    CoInitOS ();

    //
    // Create init tasks
    //

    CoCreateTask(task_init, (void *)0, PRIORITY_TASK_INIT,
                   &task_init_Stk[SIZE_TASK-1], SIZE_TASK);

    //
    // Start multitask
    //
    CoStartOS ();

    while (1);
}

/********************************************************************//**
  * @brief  Configs 4 LEDS GPIO pin.
  * @param  None.
  * @retval None.
************************************************************************/
void GPIOSet(void)
{
    //
    // Set GPIO port c pin 12, 13, 14, 15 output mode.
    //
    xGPIODirModeSet(xGPIO_PORTC_BASE, xGPIO_PIN_12, xGPIO_DIR_MODE_OUT);
    xGPIODirModeSet(xGPIO_PORTC_BASE, xGPIO_PIN_13, xGPIO_DIR_MODE_OUT);
    xGPIODirModeSet(xGPIO_PORTC_BASE, xGPIO_PIN_14, xGPIO_DIR_MODE_OUT);
    xGPIODirModeSet(xGPIO_PORTC_BASE, xGPIO_PIN_15, xGPIO_DIR_MODE_OUT);
}

/********************************************************************//**
  * @brief  Configs UART for print.
  * @param  None.
  * @retval None.
************************************************************************/
void UARTSet(void)
{
    //
    //  Set UART pins.
    //
    xSPinTypeUART(UART0RX, PB0);
    xSPinTypeUART(UART0TX, PB1);

    //
    //  Enable UART and its clock.
    //
    xSysCtlPeripheralEnable(xSYSCTL_PERIPH_UART0);
    SysCtlPeripheralClockSourceSet(SYSCTL_PERIPH_UART_S_EXT12M);

    //
    //  UART configuration.
    //
    UARTConfigSetExpClk(UART0_BASE, 115200, (UART_CONFIG_WLEN_8 |
                                                     UART_CONFIG_STOP_ONE |
                                                     UART_CONFIG_PAR_NONE));
}

/********************************************************************//**
  * @brief  Configs RTC for showing time.
  * @param  None.
  * @retval None.
************************************************************************/
void RTCSet(void)
{
    RTCTimeInit();

    //
    // Write current time to corresponding register.
    //
    RTCTimeWrite(&Current_Time, RTC_TIME_CURRENT);

    //
    // Set Tick interrupt.
    //
    RTCTickModeSet(RTC_TIME_TICK_1);


    RTCIntCallbackInit(xRTCCallback);

    //
    // Enable tick interrupt.
    //
    RTCIntEnable(RTC_INT_TIME_TICK);
    xIntEnable(INT_RTC);
}

/********************************************************************//**
  * @brief  Configs ADC.
  * @param  None.
  * @retval None.
************************************************************************/
void ADCSet(void)
{
    xSPinTypeADC(ADC7, PA7);

    //
    //  Enable ADC and its clock.
    //
    xSysCtlPeripheralEnable(xSYSCTL_PERIPH_ADC0);
    SysCtlPeripheralClockSourceSet(SYSCTL_PERIPH_ADC_S_EXT12M);

    //
    //  ADC configuration.
    //
ADCConfigure(ADC_BASE, ADC_INPUT_SINGLE,
               ADC_OP_SINGLE, ADC_TRIGGER_PROCESSOR);

    //
    //  Enables ADC channel 7.
    //
    ADCChannelEnable(ADC_BASE, 7);
}

/********************************************************************//**
  * @brief  RTC tick interrupt callback function.
  * @param  pvCBData is the callback pointer associated with the instance
  * generating the callback.  This is a value provided by the client during
  * initialization of the instance making the callback.
  * @param  ulEvent is the identifier of the asynchronous event which is being
  * notified to the client.
  * @param ulMsgParam is an event-specific parameter.
  * @param pvMsgData is an event-specific data pointer.
  * @retval Returns an event-dependent value.
************************************************************************/
unsigned long xRTCCallback(void *pvCBData,
                                unsigned long ulEvent,
                                unsigned long ulMsgParam,
                                void *pvMsgData)
{
    ulRTCTickIntFlag = 1;
    ulcount++;
    return 0;
}
运行过程:
(1)使用USB线连接PC机与NUC140VE3CN开发套件,并将开发板的uart0和PC机的串口连接起来;
(2)打开例程包中CoOS_Exp目录下的工程,编译连接工程并下载到开发板中;
(3)按开发板的Reset按键,可以看到NUC140VE3CN开发板上四个LED灯LED5-LED8闪烁,并可以看到LCD显示“CoOS example.....”。通过超级终端,可以看到RTC时间,每隔5秒,ADC转换值将打印到超级终端上。

CoOS开源而且免费(学习和商业均免费),获得CoOS的方式:http://www.coocox.com/CN/CoOS.htm
回复

使用道具 举报

发表于 2012-9-19 17:22:48 | 显示全部楼层
{:soso_e103:} 这么快就已经用操作系统了。。。。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2012-9-19 18:03:57 | 显示全部楼层
弘毅 发表于 2012-9-19 17:22
这么快就已经用操作系统了。。。。

渐渐的好东西都拿出来分享下
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|联系我们|极客工坊 ( 浙ICP备09023225号 )

GMT+8, 2019-6-26 04:27 , Processed in 0.052712 second(s), 27 queries .

Powered by Discuz! X3.4 Licensed

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表