uC/OS-II(又名Micro C/OS)是基于嵌入式系统的完整的,可移植、可固化、可裁剪的可剥夺型实时内核,其已经广泛应用在航空飞行器、医疗设备、工业控制等可靠性和稳定性要求较高的场合。该内核的代码也是完全开源的,如果不做商业用途,完全免费。因此对于广大的嵌入式爱好者与工程师们而言,了解OS从uC/OS-II开始不失为一个很好的选择。
Qsys组件添加 在一个工程实例基础上,添加一个Interval Timer外设,设置该Timer的定时Period为10ms,用于作为uC/OS-II的时钟节拍(Clock tick),如图1所示。
图1 修改该Timer外设名称为ucosii_timer。将它的clk和reset信号分别连接到clk组件的clk和clk_reset信号上,将它的Avalon从机接口s1连接到nios_qsys_0的data_master上,并将它的irq连接到nios_qsys_0的d_irq上。
图2 自动分配地址,点击SystemàAssign Base Addresses。自动分配中断向量号,点击SystemàAssign Interrupt Numbers,接着点击Generate生成新的系统。 完成Qsys新系统的Generate,接着重新编译Quartus II的project。自此,硬件的修改已经就绪。 软件工程创建 如图3所示,打开EDS后,点击FileàNewàNios II Application and BSP from Template新建模板工程。
图3 如图4所示,在新建工程向导中,选择SOPC Information File name为当前工程目录下的sopcinfo文件。Project name命名为ucosii_swprj,选择Project template为Hello MicroC/OS II。最后点击Finish创建工程。
图4 新建工程出现在工程管理窗口后,右键单击ucosii_swprj文件夹,选择NIOS IIàBSP Editor,如图5所示。
图5 如图6所示,确定Main页面中Common里面的stderr/stdin/stdout均为jtag_uart,ucosii_timer为sys_clk_timer即可。点击Generate更新设置。
图6 右键点击应用工程,选择Build Project进行软件工程编译。完成后Console窗口打印如图7所示的信息,可见这个uC/OS-II内核以及软件的HAL占用了大约94KB的存储空间,uC/OS-II其实还是很小的,只不过NIOS II各种外设的HAL比较大,不过也都是可以裁剪的。
图7 uC/OS-II运行调试 首先将Quartus II工程产生的sof硬件配置文件烧录到FPGA中。 接着应用工程上点击右键弹出菜单选择Run asàNios II Hardware,在线运行uC/OS-II实例工程。 这个uC/OS-II工程的实验目的只是创建两个task分别打印一串字符,正如readme所描述: Readme - Hello MicroC/OS-II Hello Software Example Hello_uosii is a simple hello world program running MicroC/OS-II. The purpose of the design is to be a very simple application that just demonstrates MicroC/OS-II running on NIOS II. The design doesn't account for issues such as checking system call return codes. etc. 在NIOS II Console中,我们可以看到最终运行的效果,如图8所示,两个任务所打印的字符串”Hello from task1”和”Hello from task2”循环出现。
图8 主要实例源码如下: #include #include "includes.h" /* Definition of Task Stacks */ #define TASK_STACKSIZE 2048 OS_STK task1_stk[TASK_STACKSIZE]; OS_STK task2_stk[TASK_STACKSIZE]; /* Definition of Task Priorities */ #define TASK1_PRIORITY 1 #define TASK2_PRIORITY 2 /* Prints "Hello World" and sleeps for three seconds */ void task1(void* pdata) { while (1) { printf("Hello from task1"); OSTimeDlyHMSM(0, 0, 3, 0); } } /* Prints "Hello World" and sleeps for three seconds */ void task2(void* pdata) { while (1) { printf("Hello from task2"); OSTimeDlyHMSM(0, 0, 3, 0); } } /* The main function creates two task and starts multi-tasking */ int main(void) { OSTaskCreateExt(task1, NULL, (void *)&task1_stk[TASK_STACKSIZE-1], TASK1_PRIORITY, TASK1_PRIORITY, task1_stk, TASK_STACKSIZE, NULL, 0); OSTaskCreateExt(task2, NULL, (void *)&task2_stk[TASK_STACKSIZE-1], TASK2_PRIORITY, TASK2_PRIORITY, task2_stk, TASK_STACKSIZE, NULL, 0); OSStart(); return 0; } 源码中,一个标准的uC/OS-II工程,如图9所示,初始化时调用OSInit();函数;接着调用OSTaskCreate();或OSTaskCreateExt();函数创建用户任务;最后调用OSStart();函数运行任务。这里的main函数里虽然没有出现OSInit();函数,但实际上在HAL后台外设初始化时候肯定调用了。中间是任务的创建,这里创建两个任务task1和task2,优先级分别为1和2,并且分配了相应的堆栈空间。在两个任务中,分别打印字符串”Hello from task1”和”Hello from task2”,字符串打印后调用OSTimeDlyHMSM(0, 0, 3, 0);函数做了3s的延时。如果修改这个延时时间,打印效果会发生改变,根据延时的情况,Console窗口出现的打印字样频率和速度会不一样。
图9
|