回复 沙发 hansonhe 的帖子
uCOS-II的测试代码在http://micrium.com/page/downloads/ports/ti/msp430 下载
FreeRTOS的在http://sourceforge.net/projects/freertos/files/ 下载(已经更新到7.2了)
关于代码,先比较下内核中的任务调度部份,由于涉及到对堆栈指针sp的操作,该部份代码是采用汇编语言编写的。
uCOS-II的TICK ISR函数(位于os_cpu_a.s43文件):
WDT_ISR ; wd timer ISR
PUSHM.A #12, R15
BIC.W #0x01, SFRIE1 ; disable wd timer interrupt
CMP.B #0, &OSIntNesting ; if (OSIntNesting == 0)
JNE WDT_ISR_1
MOVX.A &OSTCBCur, R13 ; save task stack
MOVX.A SP, 0(R13)
MOVX.A &OSISRStkPtr, SP ; load interrupt stack
WDT_ISR_1
INC.B &OSIntNesting ; increase OSIntNesting
BIS.W #0x01, SFRIE1 ; enable wd timer interrupt
EINT ; enable general interrupt to allow for interrupt nesting
CALLA #OSTimeTick ; call ticks routine
DINT ; IMPORTANT: disable general interrupt BEFORE calling OSIntExit()
CALLA #OSIntExit
CMP.B #0, &OSIntNesting ; if (OSIntNesting == 0)
JNE WDT_ISR_2
MOVX.A &OSTCBHighRdy, R13 ; restore task stack SP
MOVX.A @R13, SP
WDT_ISR_2
POPM.A #12, R15
RETI ; return from interrupt
FreeRTOS 7.1.1中的vPortTickISR函数(位于portext.s43文件)
vPortTickISR:
/* The sr is not saved in portSAVE_CONTEXT() because vPortYield() needs
to save it manually before it gets modified (interrupts get disabled). */
push.w sr
portSAVE_CONTEXT
calla #vTaskIncrementTick
#if configUSE_PREEMPTION == 1
calla #vTaskSwitchContext
#endif
portRESTORE_CONTEXT
FreeRTOS代码中含有宏定义且功能略少,因此显得比较精简。两内核的任务调度原理是一致的:
1.当某个任务正在运行时产生了systick中断(即某个定时器中断),此时堆栈指针(SP)是指向该任务自身堆栈区的
2.进入中断后将对状态寄存器(SR)、程序指针(PC)、以及通用寄存器(R4~R15)进行入栈操作,该任务的运行状态就被保存到自身的堆栈区了
3.进行任务调度算法。内核对系统时间进行更新,在就绪任务中选择一个作为下一个时间片要执行的任务,并将该任务的堆栈地址赋给堆栈指针(SP)
4.此时的堆栈指针已经指向需要执行的任务了,将堆栈中存储的寄存器值逐个读取到各个寄存器中,中断返回时,程序指针(PC)从堆栈中读取了当前任务的地址,单片机便开始运行该任务的代码。
个人感觉两个内核的任务调度原理是一致的,不同之处在于各自的调度算法。
关于两个系统的比较可以参考FreeRTOS 和uCOS II的简单比较
在内核的应用上两个系统的差别不大,我举个很简单的例子:建立两个任务并开始任务调度。
uCOS-II:
#include
static OS_STK AppTask1Stk[APP_TASK1_STK_SIZE];
static OS_STK AppTask2Stk[APP_TASK2_STK_SIZE];
static void AppTask1 (void *p_arg);
static void AppTask2 (void *p_arg);
void main (void)
{
OSInit(); /* Initialize "uC/OS-II, The Real-Time Kernel" */
OSTaskCreateExt(AppTask1, /* Create start task 1 */
(void *)0,
(OS_STK *)&AppTask1Stk[APP_TASK1_STK_SIZE - 1],
APP_START_TASK1_PRIO,
APP_START_TASK1_PRIO,
(OS_STK *)&AppTask1Stk[0],
APP_TASK1_STK_SIZE,
(void *)0,
OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR);
OSTaskCreateExt(AppTask2, /* Create start task 2 */
(void *)0,
(OS_STK *)&AppTask2Stk[APP_TASK2_STK_SIZE - 1],
APP_START_TASK2_PRIO,
APP_START_TASK2_PRIO,
(OS_STK *)&AppTask2Stk[0],
APP_TASK2_STK_SIZE,
(void *)0,
OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR);
OSStart(); /* Start multitasking (i.e. give control to uC/OS-II) */
}
FreeRTOS:
#include "FreeRTOS.h"
#include "task.h"
#include "FreeRTOSConfig.h"
int main( void )
{
/* Setup the hardware ready for the demo. */
prvSetupHardware();
xTaskCreate(task1, "task1", 50, NULL, 2, NULL );
xTaskCreate( task2, "task2", 50, NULL, 2, NULL );
/* Start the scheduler. */
vTaskStartScheduler();
return 0;
}
可见两个内核在应用时都是先创建任务,然后开始任务调度的,不同之处在于uCOS-II是显示分配堆栈空间,FreeRTOS是系统自动分配。在其它内核服务(如消息队列、信号量等)的应用上只是函数名称不同,功能上是十分相似的。
个人认为uCOS和FreeRTOS在应用上各有利弊,uCOS功能强大(相对FreeRTOS),而FreeRTOS代码精简,内存占用量很小。本人就是因为想学习一下多任务系统的开发(在MSP430平台)才开始接精简的触嵌入式内核的,由于强大的uCOS为开源收费且不支持相同优先级任务(uCOS-III已经没有这个限制了),综合考虑之下还是选择了FreeRTOS,本想上来问问有没有人做过FreeRTOS的项目及其运行效果,结果没人回答。
以上是本人对两个系统内核的理解,如有不妥之处还望大家多多指正。如果有人做过FreeRTOS的项目,望不吝赐教,为小弟指点一二