上QQ阅读APP看书,第一时间看更新
3.6 main()函数
main()函数在文件app.c中编写,app.c文件的完整代码参见代码清单3-29。
代码清单3-29 app.c文件
1 /* 2 ******************************************************************* 3 * 包含的头文件 4 ******************************************************************* 5 */ 6 #include "os.h" 7 #include "ARMCM3.h" 8 9 /* 10 ******************************************************************* 11 * 宏定义 12 ******************************************************************* 13 */ 14 15 16 /* 17 ******************************************************************* 18 * 全局变量 19 ******************************************************************* 20 */ 21 22 uint32_t flag1; 23 uint32_t flag2; 24 25 /* 26 ******************************************************************* 27 * TCB & STACK &任务声明 28 ******************************************************************* 29 */ 30 #define TASK1_STK_SIZE 20 31 #define TASK2_STK_SIZE 20 32 33 static CPU_STK Task1Stk[TASK1_STK_SIZE]; 34 static CPU_STK Task2Stk[TASK2_STK_SIZE]; 35 36 static OS_TCB Task1TCB; 37 static OS_TCB Task2TCB; 38 39 void Task1( void *p_arg ); 40 void Task2( void *p_arg ); 41 42 /* 43 ******************************************************************* 44 * 函数声明 45 ******************************************************************* 46 */ 47 void delay(uint32_t count); 48 49 /* 50 ******************************************************************* 51 * main()函数 52 ******************************************************************* 53 */ 54 /* 55 * 注意事项:1)该工程使用软件仿真,debug需要选择为Ude Simulator 56 * 2)在Target选项卡中把晶振Xtal(MHz)的值改为25,默认是12, 57 * 改成25是为了与system_ARMCM3.c中定义的__SYSTEM_CLOCK相同, 58 * 3)确保仿真时时钟一致 59 */ 60 int main(void) 61 { 62 OS_ERR err; 63 64 65 66 /* 初始化相关的全局变量 */ 67 OSInit(&err); 68 69 /* 创建任务 */ 70 OSTaskCreate ((OS_TCB*) &Task1TCB, 71 (OS_TASK_PTR ) Task1, 72 (void *) 0, 73 (CPU_STK*) &Task1Stk[0], 74 (CPU_STK_SIZE) TASK1_STK_SIZE, 75 (OS_ERR *) &err); 76 77 OSTaskCreate ((OS_TCB*) &Task2TCB, 78 (OS_TASK_PTR ) Task2, 79 (void *) 0, 80 (CPU_STK*) &Task2Stk[0], 81 (CPU_STK_SIZE) TASK2_STK_SIZE, 82 (OS_ERR *) &err); 83 84 /* 将任务加入就绪列表 */ 85 OSRdyList[0].HeadPtr = &Task1TCB; 86 OSRdyList[1].HeadPtr = &Task2TCB; 87 88 /* 启动操作系统,将不再返回 */ 89 OSStart(&err); 90 } 91 92 /* 93 ******************************************************************* 94 * 函数实现 95 ******************************************************************* 96 */ 97 /* 软件延时 */ 98 void delay (uint32_t count) 99 { 100 for (; count!=0; count--); 101 } 102 103 104 105 /* 任务1 */ 106 void Task1( void *p_arg ) 107 { 108 for ( ;; ) { 109 flag1 = 1; 110 delay( 100 ); 111 flag1 = 0; 112 delay( 100 ); 113 114 /* 任务切换,这里是手动切换 */ 115 OSSched(); 116 } 117 } 118 119 /* 任务2 */ 120 void Task2( void *p_arg ) 121 { 122 for ( ;; ) { 123 flag2 = 1; 124 delay( 100 ); 125 flag2 = 0; 126 delay( 100 ); 127 128 /* 任务切换,这里是手动切换 */ 129 OSSched(); 130 } 131 }
代码清单3-29中的所有代码在本小节之前都有循序渐进的讲解,这里只是融合在一起放在main()函数中。Task1和Task2并不会真正自动切换,而是在各自的函数体中加入了OSSched()函数来实现手动切换。OSSched()函数的实现具体参见代码清单3-30。
代码清单3-30 OSSched()函数
1 /* 任务切换,实际就是触发PendSV异常,然后在PendSV异常中进行上下文切换 */ 2 void OSSched (void) 3 { 4 if ( OSTCBCurPtr == OSRdyList[0].HeadPtr ) { 5 OSTCBHighRdyPtr = OSRdyList[1].HeadPtr; 6 } else { 7 OSTCBHighRdyPtr = OSRdyList[0].HeadPtr; 8 } 9 10 OS_TASK_SW(); 11 }
OSSched()函数的调度算法很简单,即如果当前任务是任务1,那么下一个任务就是任务2,如果当前任务是任务2,那么下一个任务就是任务1,然后调用OS_TASK_SW()函数触发PendSV异常,再在PendSV异常中实现任务的切换。在此后的章节中,我们将继续完善,加入SysTick中断,从而实现系统调度的自动切换。OS_TASK_SW()函数其实是一个宏定义,具体是往中断及状态控制寄存器SCB_ICSR的位28(PendSV异常启用位)写入1,从而触发PendSV异常。OS_TASK_SW()函数在os_cpu.h文件中实现(第一次使用os_cpu.h时需要自行在文件夹C-CPU中新建并添加到工程的C/CPU组),文件的内容具体参见代码清单3-31。
代码清单3-31 os_cpu.h文件
1 #ifndef OS_CPU_H 2 #define OS_CPU_H 3 4 /* 5 ******************************************************************* 6 * 宏定义 7 ******************************************************************* 8 */ 9 10 #ifndef NVIC_INT_CTRL 11 /* 中断控制及状态寄存器 SCB_ICSR */ 12 #define NVIC_INT_CTRL *((CPU_REG32 *)0xE000ED04) 13 #endif 14 15 #ifndef NVIC_PENDSVSET 16 /* 触发PendSV异常的值 Bit28:PENDSVSET */ 17 #define NVIC_PENDSVSET 0x10000000 18 #endif 19 20 /* 触发PendSV异常 */ 21 #define OS_TASK_SW() NVIC_INT_CTRL = NVIC_PENDSVSET 22 /* 触发PendSV异常 */ 23 #define OSIntCtxSw() NVIC_INT_CTRL = NVIC_PENDSVSET 24 /* 25 ******************************************************************* 26 * 函数声明 27 ******************************************************************* 28 */ 29 void OSStartHighRdy(void);/* 在os_cpu_a.s中实现 */ 30 void PendSV_Handler(void);/* 在os_cpu_a.s中实现 */ 31 32 33 #endif/* OS_CPU_H */