Linux教程:微型嵌入式实时操作系统SmallRTOS常用接口函数
微型嵌入式实时操作系统SmallRTOS是一个源代码开放的、易于移植的、面向深度嵌入式应用的微内核实时操作系统,主要应用领域为工业控制,智能传感器开发,智能终端,物联网等。任何人在遵循SmallRTOS许可协议的前提下均可免费使用该嵌入式实时操作系统。最新版本源代码及示例工程的发布网站为: http://www.smallrtos.org
下载到SmallRTOS的源代码压缩包后,进行解压,可以看到SmallRTOS的目录结构如下:
Kernel: 存放SmallRTOS的内核文件OS及和CPU相关的移植文件;
Demo: 存放SmallRTOS提供的示例文件;
Doc: 存放SmallRTOS相关说明/教程文档;
License:存放SmallRTOS使用许可;
微型嵌入式实时操作系统SmallRTOS在设计时,其文件命名、函数名及变量命名由专用的前缀进行区分:前缀为OS,表示为SmallRTOS的内核,这些是与平台无关的内核部分,在进行跨平台移植时,无需更改;前缀为Fit,表示为硬件(芯片类型等)相关的部分,在进行移植时,这一部分的文件、函数及变量需要根据硬件平台(芯片类型等)进行适当的调整;
微型嵌入式实时操作系统SmallRTOS是多任务抢占式操作系统,高优先级任务可以抢先执行,体现了操作系统的实时性。在SmallRTOS系统中,优先级0为最低优先级,该优先级为SmallRTOS系统的保留优先级,作为空闲任务OSIdleTask的专用优先级,用户创建的任务无法使用。除此之外的优先级,用户可以根据任务的重要程度自行分配使用。优先级高的任务会抢先执行。
为了突显嵌入式操作系统配置的灵活性,在SmallRTOS系统设计之初就进行了全面的考量,部分参数采用了宏定义的方式进行配置。每个任务均有自己的名称及优先级,任务名称长度最大为OSNAME_MAX_LEN, 该变量是一个宏定义,超出该最大长度的名称会自动舍弃,默认为10个字符。任务优先级的定义为OSTASK_MAX_PRIORITY, 这是一个非常重要的参数,系统默认值为10。
Ticks经常被称为时钟滴答,是SmallRTOS系统中最小的时间单位,这个参数可以根据硬件平台的性能进行设置。在SmallRTOS系统中,该参数采用宏定义configTICK_RATE_HZ进行配置。在SmallRTOS提供的大部分示例工程中,均配置的为1000Hz,即每个时钟滴答间隔是1毫秒,该参数会影响SmallRTOS系统对任务的控制精度。系统调度器启动后,会按照任务的优先级进行执行,直至该任务让出执行权或者被更高级的任务抢断。如果没有符合条件的任务需要执行,则运行系统中预留的OSIdleTask(空闲任务)。
在SmallRTOS系统中,除了相关参数采用宏定义进行配置之外,功能模块也采用宏定义进行配置。其中宏定义OS_SEMAPHORE_ON表示是否启用信号量(Semaphore,又称作旗语)功能模块,若定义为1,则表示启用信号量(Semaphore,又称作旗语)功能模块,若定义为0,则该功能模块不被启用;宏定义OS_MSGQ_ON表示是否启用消息队列,用法同OS_SEMAPHORE_ON;宏定义OS_MUTEX_ON表示是否启用互斥信号量,用法同OS_SEMAPHORE_ON;
下面是微型嵌入式实时操作系统SmallRTOS中经常用到的接口函数,供大家使用时参考;
一、系统中任务相关的API函数
OSTaskHandle_t OSTaskCreate(OSTaskFunction_t pxTaskFunction,
void* pvParameter,
const uOS16_t usStackDepth,
uOSBase_t uxPriority,
sOS8_t* pcTaskName);
OSTaskCreate为微型嵌入式实时操作系统SmallRTOS的任务创建函数,其中参数OSTaskFunction_t pxTaskFunction为任务函数,该任务函数类型定义为void TaskFunction( void *pParameters );任务函数中的参数void *pParameters 亦即OSTaskCreate的第二个参数;第三个参数为任务的栈空间usStackDepth,栈空间需要根据任务占用的空间多少进行调整;第四个参数为任务的优先级,除最低优先级0为系统保留外,均可使用。第五个参数为任务名字,任务名字也就是任务的标签,主要方便在调试时区分不同的任务。
函数OSTaskCreate的返回值为OSTaskHandle_t类型的任务句柄,该句柄可以被其它系统函数调用,以设置或控制任务的状态;
void OSTaskSleep(uOS32_t uxWatiTicks);
OSTaskSleep为微型嵌入式实时操作系统SmallRTOS系统中任务延迟执行设置函数,通过此函数,可以把当前任务休眠若干毫秒的时间。参数uOS32_t uxWatiTicks代表休眠的时间长短,单位为Ticks,用户可以通过OSTICKS_PER_MS把毫秒转换为Ticks计数;
void OSTaskYield()
OSTaskYield函数为SmallRTOS中的任务控制类函数,在任务中调用,用于让出当前任务的执行权,并切换到下一个处于 eTaskStateReady状态的任务;函数OSTaskYield并不改变任务的状态,只是把当前正在执行的任务排列到状态为 eTaskStateReady的任务队列的队尾,若只有当前任务处于eTaskStateReady状态,则仍然执行当前任务;
uOS16_t OSStart( void )
函数OSStart为OSStartScheduler()函数的宏定义,OSStartScheduler()函数是SmallRTOS中的任务调度启动函数;在该函数中,系统会设置空闲任务OSIdleTask及时钟中断;OSIdleTask任务为系统空闲任务,若系统当前没有需要执行的任务,则会调用该空闲任务,空闲任务可以用于统计当前系统的利用率,及释放处于待删除状态任务的资源;时钟中断则为系统的ticks配置,整个系统的运行即依赖此ticks驱动运行;
二、任务同步信号量相关的API函数
OSSemHandle_t OSSemCreate()
函数OSSemCreate为信号量(Semaphore)创建函数,用于创建任务间同步操作的信号量。信号量创建后,默认有效信号量计数值为0,表示该信号量无有效信号,对应的OSSemPend函数处于阻塞状态,等待有效信号;其返回值为OSSemHandle_t类型的句柄,方便用于对该信号量的操控;
sOSBase_t OSSemPend( OSSemHandle_t SemHandle, uOSTick_t xTicksToWait)
函数OSSemPend为信号量等待函数,在任务执行函数中调用,用于等待相关同步的信号量;参数OSSemHandle_t SemHandle为信号量句柄,参数uOSTick_t xTicksToWait为任务阻塞时间,单位为Tick数,若设置为OSPEND_FORVER_VALUE,则会永远阻塞,直至指定信号量 SemHandle获取到有效信号;
sOSBase_t OSSemPost( OSSemHandle_t SemHandle)
函数OSSemPost用于向指定信号量发送有效信号,使处于等待该信号量的任务获取同步信号,以便恢复执行。注:此函数不能在中断服务函数中调用。
sOSBase_t OSSemPostFromISR( OSSemHandle_t SemHandle )
函数OSSemPostFromISR用于向指定信号量发送有效信号,使处于等待该信号量的任务获取同步信号,以便恢复执行。注:此函数只能在中断服务函数中调用。
三、任务同步消息相关的API函数
OSMsgQHandle_t OSMsgQCreate( const uOSBase_t uxQueueLength, const uOSBase_t uxItemSize)
函数OSMsgQCreate为消息队列的创建函数,用于创建任务间同步操作的消息队列,参数uxQueueLength为消息队列中的消息数的容量(消息数目超过此容量,则发送任务挂起,直到消息队列有空闲位置),第二个参数uxItemSize为单个消息的长度。其返回值为 OSMsgQHandle_t类型的消息队列句柄,方便对消息队列的操控;
sOSBase_t OSMsgQReceive( OSMsgQHandle_t MsgQHandle, void * const pvBuffer, uOSTick_t xTicksToWait)
函数OSMsgQReceive用于在任务中接收指定消息队列的消息,在任务执行函数中调用;该函数为任务阻塞函数。参数MsgQHandle为消息队列句柄, 参数pvBuffer表示消息的指针,参数xTicksToWait为消息队列等待接收时间,单位为Tick,若设置为 OSPEND_FORVER_VALUE,则会永远等待,直至指定消息队列MsgQHandle获取到有效消息为止。函数返回值代表消息接收状态,若为 FALSE则未接收到有效消息,若为TRUE则接收到有效消息;
sOSBase_t OSMsgQReceiveFromISR( OSMsgQHandle_t MsgQHandle, void * const pvBuffer)
函数OSMsgQReceiveFromISR用于在中断函数中接收指定消息队列的消息;参数MsgQHandle为消息队列句柄, 参数pvBuffer表示消息的指针,该函数不会阻塞。函数返回值代表消息接收状态,若为FALSE则未接收到有效消息,若为TRUE则接收到有效消息;注:此函数只能在中断服务函数中调用。
sOSBase_t OSMsgQSend( OSMsgQHandle_t MsgQHandle, const void * const pvItemToQueue, uOSTick_t xTicksToWait)
函数OSMsgQSend用于向指定的消息队列发送消息,使处于等待该消息的任务获取同步消息,并恢复执行,其中参数MsgQHandle表示消息队列,参数pvItemToQueue表示消息地址(指针),参数xTicksToWait为消息发送等待接收时间,单位为Tick,若设置为 OSPEND_FORVER_VALUE,则会永远等待,直至指定消息队列MsgQHandle有空闲位置。函数返回值代表消息发送状态,若为FALSE 则消息发送失败,若为TRUE则消息发送成功;注:此函数不能在中断服务函数中调用。
sOSBase_t OSMsgQSendFromISR( OSMsgQHandle_t MsgQHandle, const void * const pvItemToQueue)
函数OSMsgQSendFromISR用于向指定的消息队列发送消息,使处于等待该消息的任务获取同步消息,并恢复执行,其中参数 MsgQHandle表示消息队列,参数pvItemToQueue表示消息地址(指针),如果消息队列已满,则函数不会阻塞,直接返回发送失败信息。注:此函数只能在中断服务函数中调用。
四、定时器相关的API函数
OSTimerHandle_t OSTimerCreate(OSTimerFunction_t Function, void* pvParameter, uOSBase_t uxPeriodicTimeMS, sOS8_t* pcName)
接口函数OSTimerCreate用于创建定时器。其中参数Function为定时器的服务函数,用于响应定时器,函数 OSTimerFunction_t的定义类型为void TimerFunction(void *pParameters )。pvParameter为定时器服务函数的参数,不用时可以设置为NULL。参数uxPeriodicTimeMS为定时器的周期,单位为毫秒。参数 pcName为定时器的名称,方便区分不同的定时器;注意:定时器服务函数中禁止添加信号量等待、消息队列等待等用于阻塞的函数,为不影响整个系统的性能,定时器服务函数耗时越少越好。
uOSBase_t OSTimerStart(OSTimerHandle_t const TimerHandle)
定时器创建完毕后并不会自动启动,需要用户显示的调用启动函数OSTimerStart(),之后定时器才会生效。参数TimerHandle为定时器句柄,为定时器创建函数OSTimerCreate()的返回值;
uOSBase_t OSTimerStop(OSTimerHandle_t const TimerHandle)
定时启动后,用户可以通过接口函数OSTimerStop()停止定时。参数TimerHandle为定时器句柄,为定时器创建函数OSTimerCreate()的返回值;
简单示例程序
下面是采用实时嵌入式操作系统SmallRTOS实现的多任务处理演示示例,主要包括任务创建、信号量创建、任务延时等功能。代码如下:
OSTaskHandle_t HWTaskHandle = NULL;
OSTaskHandle_t GBTaskHandle = NULL;
OSSemHandle_t GBSemaphoreHandle = NULL;
void TaskHelloWorld( void *pvParameters );
void TaskGoodBye( void *pvParameters );
int main( void )
{
GBSemaphoreHandle = OSSemCreate();
// configure and start tasks
HWTaskHandle = OSTaskCreate(TaskHelloWorld, NULL, OSMINIMAL_STACK_SIZE, OSLOWEAST_PRIORITY+1, "HW");
GBTaskHandle = OSTaskCreate(TaskGoodBye, NULL, OSMINIMAL_STACK_SIZE, OSLOWEAST_PRIORITY+2, "GB");
/* Start the tasks and timer running. */
OSStart();
for( ;; );
return 0;
}
void TaskHelloWorld( void *pvParameters )
{
/* Remove compiler warning about unused parameter. */
( void ) pvParameters;
for( ;; )
{
OSSemPost(GBSemaphoreHandle);
OSTaskSleep(200*OSTICKS_PER_MS);
}
}
void TaskGoodBye( void *pvParameters )
{
/* Remove compiler warning about unused parameter. */
( void ) pvParameters;
for( ;; )
{
OSSemPend(GBSemaphoreHandle, OSPEND_FOREVER_VALUE);
}
}