具体移植步骤,请参照如上所述的移植开发文档,这次我们使用的开发环境是 Keil MDK-ARM
此处我们认为开发环境已经搭建完毕,我们通过一些简单的例程,具体介绍一下实时操作系统TINIUX在Cortex-M0芯片下的应用。
我们这次使用的芯片是Navota纳瓦特的 NV32F100FL64E,时钟信号使用的是芯片内部时钟,根据芯片相关信息,我们首先通过头文件OSPreset.h对TINIUX系统进行相关配置/裁剪,配置/裁剪信息如下:
// !!!注:应用程序可以根据需要调整Tiniux系统API接口函数及相关功能模块的开关 !!!
#ifndef __OS_PRESET_H_
#define __OS_PRESET_H_
/*-----------------------------------------------------------
* Application specific definitions.
*
* These definitions should be adjusted for your particular hardware and
* application requirements.
*
*----------------------------------------------------------*/
/* Ensure stdint is only used by the compiler, and not the assembler. */
#if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__)
#include <stdint.h>
extern uint32_t SystemCoreClock;
#endif
#define SETOS_CPU_CLOCK_HZ ( SystemCoreClock ) //定义CPU运行主频 (如72000000)
#define SETOS_TICK_RATE_HZ ( 1000 ) //定义TINIUX系统中ticks频率
#define SETOS_MINIMAL_STACK_SIZE ( 48 ) //定义任务占用的最小Stack空间
#define SETOS_TOTAL_HEAP_SIZE ( 1024*2 ) //定义系统占用的Heap空间
#define SETOS_ENABLE_MEMFREE ( 0 ) //是否允许释放内存,允许后可以在系统运行时删除Task MsgQ Semaphone Mutex Timer等
#define SETOS_LOWPOWER_MODE ( 0 ) //是否开启低功耗模式
#define SETOS_MAX_NAME_LEN ( 8 ) //定义任务、信号量、消息队列等变量中的名称长度
#define SETOS_MAX_PRIORITIES ( 4 ) //定义任务最大优先级
#define SETOS_TASK_SIGNAL_ON ( 1 ) //是否启动轻量级的任务同步信号,功能类似Semaphore MsgQ,内存占用要小于Semaphore MsgQ
#define SETOS_USE_SEMAPHORE ( 1 ) //是否启用系统信号量功能 0关闭 1启用
#define SETOS_USE_MUTEX ( 1 ) //是否启用互斥信号量功能 0关闭 1启用
#define SETOS_USE_MSGQ ( 1 ) //是否启用系统消息队列功能 0关闭 1启用
#define SETOS_MSGQ_MAX_MSGNUM ( 5 ) //定义消息队列中消息的门限值
#define SETOS_USE_TIMER ( 1 ) //是否使用系统软件定时器
#define SETOS_USE_QUICK_SCHEDULE ( 1 ) //是否启动快速调度算法
#define SETOS_TIME_SLICE_ON ( 1 ) //是否启用时间片轮转(time slice)调度机制
#define SETOS_PEND_FOREVER_VALUE ( 0xFFFFFFFFUL )//定义信号量及消息队列中永久等待的数值
/* Cortex-M specific definitions. */
#ifdef __NVIC_PRIO_BITS
/* __BVIC_PRIO_BITS will be specified when CMSIS is being used. */
#define SETHW_PRIO_BITS __NVIC_PRIO_BITS
#else
#define SETHW_PRIO_BITS ( 4 ) /* 15 priority levels */
#endif
/* The highest interrupt priority that can be used by any interrupt service
routine that makes calls to interrupt safe TINIUX API functions. DO NOT CALL
INTERRUPT SAFE TINIUX API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER
PRIORITY THAN THIS! (higher priorities are lower numeric values. */
/* !!!! OSMAX_HWINT_PRI must not be set to zero !!!!*/
#define OSMAX_HWINT_PRI ( 0x5 << (8 - SETHW_PRIO_BITS) ) /* equivalent to 0x50, or priority 5. */
/* This is the value being used as per the ST library which permits 16
priority values, 0 to 15. This must correspond to the OSMIN_HWINT_PRI
setting. Here 15 corresponds to the lowest NVIC value of 255. */
#define OSMIN_HWINT_PRI ( 0xF << (8 - SETHW_PRIO_BITS) ) /* equivalent to 0xF0, or priority 15. */
#define FitSVCHandler SVC_Handler
#define FitPendSVHandler PendSV_Handler
#define FitOSTickISR SysTick_Handler
#endif /* __OS_PRESET_H_ */
通过上面的代码,我们看到为TINIUX系统配置的Ticks频率为1000Hz,即每个时钟滴答(Tick)为1毫秒。对于内核频率不高芯片,在应用时可适当降低Ticks频率,这样会提高系统的调度效率。
通过TINIUX轻量级同步信号控制LED灯
创建两个任务,一个为LedTask任务,一个为CtrlTask任务,两个任务之间通过轻量级同步信号进行同步交互操作。此例程主要演示了TINIUX系统中接口函数OSTaskSignalWait()与OSTaskSignalEmit()的使用方式。
相关实现代码如下所示:
// 包含芯片相关的头文件。
#include "system_nv32f100.h"
#include "nv32f100.h"
#include "NV32_config.h"
// 包含嵌入式实时操作系统TINIUX相关的头文件TINIUX.h,在使用TINIUX操作系统时,必须包含此头文件。
#include "TINIUX.h"
// 定义空指针
#ifndef NULL
#define NULL ( OS_NULL )
#endif
// 定义LED任务的句柄,便于对LED任务的具体操作
OSTaskHandle_t LedTaskHandle = NULL;
// 定义控制任务的句柄,与LED任务通过轻量级同步信号进行同步交互操作
OSTaskHandle_t CtrlTaskHandle = NULL;
// LED任务函数的声明
static void LedTask( void *pvParameters );
// Ctrl控制任务函数的声明
static void CtrlTask( void *pvParameters );
// LED任务的具体实现函数
static void LedTask( void *pvParameters )
{
// 我们暂时没有用到任务函数的参数pvParameters
( void )pvParameters;
// 任务函数体内一般都是一个死循环,不能通过return语句返回,若任务函数执行完毕后没有必要再继续执行,
// 则需要调用OSTaskDelete函数进行任务删除操作,便于系统调度,同时把分配给该任务的堆栈空间回收,以供系统再次使用。
for( ;; )
{
// 调用TINIUX的接口函数,让此任务等待接收轻量级的同步信号,等待时间为OSPEND_FOREVER_VALUE,此数值代表永久等待,直至接收到有效的信号为止。
// 也可以通过参数指定一个具体的数值,代表等待具体的时间,单位为Ticks。若在指定的时间内没有接收到有效信号,则也返回,只是返回值为OS_FALSE;
// 若在指定的等待时间内接收到有效的信号后,则返回OS_TRUE。此函数与OSTaskSignalEmit()对应使用;
OSTaskSignalWait( OSPEND_FOREVER_VALUE);
// 接收到同步信号后,转换LED灯的状态
// 控制LED等的亮或熄灭,请参照你的板卡进行控制实验。
LED0_Toggle();
LED1_Toggle();
LED2_Toggle();
}
}
// 控制任务的具体实现函数
static void CtrlTask( void *pvParameters )
{
// 我们暂时没有用到任务函数的参数pvParameters
( void )pvParameters;
// 任务函数体内一般都是一个死循环,不能通过return语句返回。
for( ;; )
{
// 调用TINIUX的接口函数,让此任务休眠500毫秒,这里调用OSM2T函数,
// 将500毫秒数值转换为OSTaskSleep函数需要的Ticks数值
OSTaskSleep( OSM2T(500) );
//通过任务句柄LedTaskHandle,向LedTask任务发射同步信号。此接口函数与LedTask任务中的OSTaskSignalWait()函数相对应;
OSTaskSignalEmit(LedTaskHandle);
}
}
static void GPIO_Configuration(void)
{
LED0_Init();
LED1_Init();
LED2_Init();
}
static void SetupHardware( void )
{
/* HAL library initialization: Low Level Initialization */
SystemInit();
GPIO_Configuration();
}
int main(void)
{
// 对硬件进行配置,包括时钟及Led等.
SetupHardware();
// 在使用TINIUX之前,首先对TINIUX相关参数进行初始化
OSInit();
// 创建控制LED灯的任务,第一个参数指定具体的任务函数LedTask,第二个参数为LedTask用到的参数,此处我们暂时不用,填写NULL
// 第三个参数为任务使用的堆栈空间,因为LedTask任务函数中使用的变量较少,我们直接填写OSMINIMAL_STACK_SIZE,
// 第四个参数填写为LedTask任务分配的优先级,在此例程中,我们使用的任务不多,此处填写比空闲任务大1个的优先级,
// 第五个参数为任务的名称,任务的名称主要便于调试时分辨任务,此处我们根据任务的功能填写Led
// 任务创建完毕后,返回任务句柄,保存到LedTaskHandle中,便于后面对此任务进行操作
LedTaskHandle = OSTaskCreate(LedTask, NULL, OSMINIMAL_STACK_SIZE, OSLOWEAST_PRIORITY+1, "Led");
// 创建控制任务,参数含义参照main函数中创建LedTask任务时的注释,优先级与LedTask相同,也是OSLOWEAST_PRIORITY+1;
CtrlTaskHandle = OSTaskCreate(CtrlTask, NULL, OSMINIMAL_STACK_SIZE, OSLOWEAST_PRIORITY+1, "Ctrl");
// 启动TINIUX操作系统
OSStart();
// 如果TINIUX启动正常,则不会执行到这里。
// 一旦运行到此处,有可能是分配给TINIUX的堆栈空间太小,TINIUX直接退出运行了。
for( ;; );
}
本例程对应的软件工程如下:
通过TINIUX轻量级同步信号控制LED灯_NV32F100FL64E.rar
(564.18 KB)
|