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.h>
编写任务代码
任务在创建的时候要为它指定堆栈空间,对于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 <CoOS.h>
#include <stdio.h>
#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转换值将打印到超级终端上。 |