一步步学习操作系统(1)——参照ucos,在STM32上实现一个简单的多任务(“精简版”)

相同的代码,另外还提供了讲解更详细的“啰里啰嗦版”,以供参考。

这里,我们将实现一个简单的多任务OS。其任务调度的机理如下:

1、 main函数创建任务,任务的数量上限由OS_MAX_TASKS宏指定(默认为16个);

2、所有任务轮流执行,每个任务执行相同的时间;

3、PendSV中断用来完成任务的切换与任务信息保存的工作;

4、SysTick中断规定次数后(由TASK_TIME_SLICE宏指定),触发PendSV中断,从而实现任务切换;

5、在OSStart之前,会创建一个“Idle Task”任务,当没有任务需要执行时,该任务独占CPU。

这里的代码创建的Task1与Task2都是与具体硬件相关的LED开关任务,注意对照着匹配自己的硬件,或使用USART任务来代替这些任务。

总共5个文件,给出如下:

1、main.c:

 1 #include "include.h"
 2 
 3 //#define LED1TURN() (GPIOA->ODR ^= 1<<8)
 4 //#define LED2TURN() (GPIOD->ODR ^= 1<<2)
 5 
 6 extern OS_TCB OSTCBTbl[OS_MAX_TASKS]; // (OS Task Control Block Table)
 7 extern OS_STK TASK_IDLE_STK[TASK_STACK_SIZE]; //("TaskIdle" Stack)
 8 extern OS_TCB *OSTCBCur; // Pointer to the current running task(OS Task Control Block Current)
 9 extern OS_TCB *OSTCBNext; // Pointer to the next running task(OS Task Control Block Next)
10 extern INT8U OSTaskNext; // Index of the next task
11 extern INT32U TaskTickLeft; // Refer to the time ticks left for the current task
12 extern INT32U TimeMS;       // For system time record                             
13 extern INT32U TaskTimeSlice; // For system time record
14 
15 OS_STK Task1Stk[TASK_STACK_SIZE];
16 OS_STK Task2Stk[TASK_STACK_SIZE];
17 OS_STK Task3Stk[TASK_STACK_SIZE];
18 
19 void Task1(void *p_arg);
20 void Task2(void *p_arg);
21 void Task3(void *p_arg);
22 //void LedInit(void);
23 
24 int main(void)
25 {
26     
27     
28     OSInit();
29     OSTaskCreate(Task1, (void*)0, (OS_STK*)&Task1Stk[TASK_STACK_SIZE-1]);
30     OSTaskCreate(Task2, (void*)0, (OS_STK*)&Task2Stk[TASK_STACK_SIZE-1]);
31     OSTaskCreate(Task3, (void*)0, (OS_STK*)&Task3Stk[TASK_STACK_SIZE-1]);
32     SysTickInit(5);
33     LedInit();
34     USART1_Configuration(8, 9600);
35 
36     //while(1);
37     OSStart();
38     
39     // while(1);
40     //while(1){
41     //    GPIOA->ODR &= ~(1<<8);
42     //    GPIOD->ODR |= 1<<2;
43     //}
44 }
45 
46 /*void LedInit(void)
47 {
48     RCC->APB2ENR |= 1<<2;
49     RCC->APB2ENR |= 1<<5;
50     //GPIOE->CRH&=0X0000FFFF;  
51     //GPIOE->CRH|=0X33330000;
52     
53     GPIOA->CRH &= 0xfffffff0;
54     GPIOA->CRH |= 0x00000003;
55     //GPIOA->ODR &= 0xfffffeff;
56     GPIOA->ODR |= 1<<8;
57 
58     GPIOD->CRL &= 0xfffff0ff;
59     GPIOD->CRL |= 0x00000300;
60     //GPIOD->ODR &= 0xfffffffd;    
61     GPIOD->ODR |= 1<<2;
62     
63     //LED1TURN();
64     LED2TURN();
65     
66 }*/
67 
68 void Task1(void *p_arg)
69 {
70     while(1) {
71         delayMs(100);
72         LED1TURN();
73     }
74 }
75 void Task2(void *p_arg)
76 {
77     while(1) {
78         delayMs(200);
79         LED2TURN();
80     }
81 }
82 
83 void Task3(void *p_arg)
84 {
85     while(1) {
86             USART1->DR = 'B';
87             while((USART1->SR & 0x40) == 0);
88             USART1->DR = '
';
89             while((USART1->SR & 0x40) == 0);
90             USART1->DR = '
';
91             while((USART1->SR & 0x40) == 0);
92             delayMs(50);
93     }
94 }

2、include.h:

 1 #ifndef INCLUDE_H
 2 #define INCLUDE_H
 3 
 4 #include <stdlib.h>
 5 
 6 #include "myos.h"
 7 
 8 #include "stm32f10x.h"
 9 
10 #endif

3、myos.h:

 1 #ifndef MYOS_H
 2 #define MYOS_H
 3 #include "stm32f10x.h"
 4 
 5 /**********CPU DEPENDENT************/
 6 #define TASK_TIME_SLICE     5         // 5ms for every task to run every time
 7 
 8 typedef unsigned char  INT8U;            // Unsigned  8 bit quantity  
 9 typedef unsigned short INT16U;            // Unsigned 16 bit quantity 
10 typedef unsigned int   INT32U;            // Unsigned 32 bit quantity
11 
12 typedef unsigned int   OS_STK;            // Each stack entry is 32-bit wide(OS Stack)
13 
14 // assembling functions
15 void OS_ENTER_CRITICAL(void);             // Enter Critical area, that is to disable interruptions
16 void OS_EXIT_CRITICAL(void);            // Exit Critical area, that is to enable interruptions
17 void OSCtxSw(void);                // Task Switching Function(OS Context Switch)
18 void OSStart(void);
19 
20 OS_STK* OSTaskStkInit(void (*task)(void *p_arg), // task function
21               void *p_arg, // (pointer of arguments)
22                 OS_STK *p_tos); // (pointer to the top of stack)
23 /**********CPU INDEPENDENT************/
24 
25 #define OS_MAX_TASKS    16
26 
27 #define TASK_STATE_CREATING     0
28 #define TASK_STATE_RUNNING    1
29 #define TASK_STATE_PAUSING    2
30 
31 #define TASK_STACK_SIZE     64
32               
33 #define LED1TURN() (GPIOA->ODR ^= 1<<8)
34 #define LED2TURN() (GPIOD->ODR ^= 1<<2)
35 
36 
37 typedef struct os_tcb {
38     OS_STK    *OSTCBStkPtr;     // (OS Task Control Block Stack Pointer)
39     INT8U     OSTCBStat;     // (OS Task Control Block Status)
40 } OS_TCB; // (OS Task Control Block)
41 
42 void OSInit(void);     // (OS Initialization)
43 void LedInit(void);
44 void USART1_Configuration(u32 pclk2, u32 bound);
45 void OS_TaskIdle(void *p_arg);
46 void OSInitTaskIdle(void); // (OS Initialization of "TaskIdle")
47 void OSTaskCreate(void (*task)(void *p_arg), // task function
48           void *p_arg,     // (pointer of arguments)
49           OS_STK *p_tos); // (pointer to the top of stack)
50 void OSTCBSet(OS_TCB *p_tcb, OS_STK *p_tos, INT8U task_state);
51 
52 
53 void SysTickInit(INT8U Nms); // (System Tick Initialization)
54 void SysTick_Handler(void); // The interrupt function 
55 
56 INT32U GetTime(void);
57 void delayMs(volatile INT32U ms); // The argument can't be too large
58 
59 #endif

4、myos.c:

  1 #include "myos.h"
  2 #include "stm32f10x.h"
  3 
  4 
  5 OS_TCB OSTCBTbl[OS_MAX_TASKS]; // (OS Task Control Block Table)
  6 OS_STK TASK_IDLE_STK[TASK_STACK_SIZE]; //("TaskIdle" Stack)
  7 OS_TCB *OSTCBCur; // Pointer to the current running task(OS Task Control Block Current)
  8 OS_TCB *OSTCBNext; // Pointer to the next running task(OS Task Control Block Next)
  9 INT8U OSTaskNext; // Index of the next task
 10 INT32U TaskTickLeft; // Refer to the time ticks left for the current task
 11 INT32U TimeMS;
 12 INT32U TaskTimeSlice;
 13 char * Systick_priority = (char *)0xe000ed23;
 14 // Initialize the stack of a task, it is of much relationship with the specific CPU
 15 OS_STK* OSTaskStkInit(void (*task)(void *p_arg),
 16           void *p_arg,
 17           OS_STK *p_tos)
 18 {
 19     OS_STK *stk;
 20     stk = p_tos;
 21 
 22     *(stk)    = (INT32U)0x01000000L;             // xPSR                                               
 23     *(--stk)  = (INT32U)task;                    // Entry Point  
 24 
 25     // Don't be serious with the value below. They are of random
 26     *(--stk)  = (INT32U)0xFFFFFFFEL;             // R14 (LR) 
 27     *(--stk)  = (INT32U)0x12121212L;             // R12                                                
 28     *(--stk)  = (INT32U)0x03030303L;             // R3                                                 
 29     *(--stk)  = (INT32U)0x02020202L;             // R2                                                 
 30     *(--stk)  = (INT32U)0x01010101L;             // R1                                                 
 31 
 32     // pointer of the argument
 33     *(--stk)  = (INT32U)p_arg;                   // R0
 34 
 35     // Don't be serious with the value below. They are of random
 36     *(--stk)  = (INT32U)0x11111111L;             // R11 
 37     *(--stk)  = (INT32U)0x10101010L;             // R10 
 38     *(--stk)  = (INT32U)0x09090909L;             // R9  
 39     *(--stk)  = (INT32U)0x08080808L;             // R8  
 40     *(--stk)  = (INT32U)0x07070707L;             // R7  
 41     *(--stk)  = (INT32U)0x06060606L;             // R6  
 42     *(--stk)  = (INT32U)0x05050505L;             // R5  
 43     *(--stk)  = (INT32U)0x04040404L;             // R4  
 44     return stk;
 45 }
 46 
 47 // Only to initialize the Task Control Block Table
 48 void OSInit(void)
 49 {
 50     INT8U i;
 51     OS_ENTER_CRITICAL();
 52     for(i = 0; i < OS_MAX_TASKS; i++) {
 53         OSTCBTbl[i].OSTCBStkPtr = (OS_STK*)0;
 54         OSTCBTbl[i].OSTCBStat = TASK_STATE_CREATING;
 55     }
 56     OSInitTaskIdle();
 57     OSTCBCur = &OSTCBTbl[0];
 58     OSTCBNext = &OSTCBTbl[0];
 59     OS_EXIT_CRITICAL();
 60 }
 61 
 62 void OSInitTaskIdle(void)
 63 {
 64     OS_ENTER_CRITICAL();
 65     OSTCBTbl[0].OSTCBStkPtr = OSTaskStkInit(OS_TaskIdle, (void *)0, (OS_STK*)&TASK_IDLE_STK[TASK_STACK_SIZE - 1]);
 66     OSTCBTbl[0].OSTCBStat = TASK_STATE_RUNNING;
 67     OS_EXIT_CRITICAL();
 68 }
 69 
 70 void OSTaskCreate(void (*task)(void *p_arg), 
 71           void *p_arg, 
 72           OS_STK *p_tos)
 73 {
 74     OS_STK * tmp;
 75     INT8U i = 1;
 76     OS_ENTER_CRITICAL();
 77     while(OSTCBTbl[i].OSTCBStkPtr != (OS_STK*)0) {
 78         i++;
 79     }
 80     tmp = OSTaskStkInit(task, p_arg, p_tos);
 81     OSTCBSet(&OSTCBTbl[i], tmp, TASK_STATE_CREATING);
 82     OS_EXIT_CRITICAL();
 83 }
 84 
 85 void OSTCBSet(OS_TCB *p_tcb, OS_STK *p_tos, INT8U task_state)
 86 {
 87     p_tcb->OSTCBStkPtr = p_tos;
 88     p_tcb->OSTCBStat = task_state;
 89 }
 90 
 91 void OS_TaskIdle(void *p_arg)
 92 {
 93     p_arg = p_arg; // No use of p_arg, only for avoiding "warning" here.
 94     for(;;) {
 95         // OS_ENTER_CRITICAL();
 96         // Nothing to do
 97         // OS_EXIT_CRITICAL();
 98     }
 99 }
100 
101 // void SysTick_Handler(void)
102 // {
103 //     // OS_ENTER_CRITICAL();
104 //     // OS_EXIT_CRITICAL();
105 // }
106 void SysTick_Handler(void)
107 {
108     OS_ENTER_CRITICAL();
109     if((--TaskTimeSlice) == 0){
110         TaskTimeSlice = TASK_TIME_SLICE;
111         OSTCBCur = OSTCBNext;
112         OSCtxSw();
113         OSTaskNext++;
114         while(OSTCBTbl[OSTaskNext].OSTCBStkPtr == (OS_STK*)0) { 
115             OSTaskNext++;
116             if(OSTaskNext >= OS_MAX_TASKS) {
117                 OSTaskNext = 0;
118             }
119         }
120         OSTCBNext = &OSTCBTbl[OSTaskNext];
121         TaskTimeSlice = TASK_TIME_SLICE;
122     }
123     TimeMS++;
124     OS_EXIT_CRITICAL();
125 }
126 
127 void SysTickInit(INT8U Nms)
128 {
129     
130     OS_ENTER_CRITICAL();
131     
132     TimeMS = 0;
133     TaskTimeSlice = TASK_TIME_SLICE;                             
134 
135     SysTick->LOAD  = 1000 * Nms - 1; 
136     *Systick_priority = 0x00;
137     SysTick->VAL   = 0;  
138     SysTick->CTRL = 0x3;
139     OS_EXIT_CRITICAL();
140 }
141 
142 INT32U GetTime(void)
143 {
144     return TimeMS;
145 }
146 
147 void delayMs(volatile INT32U ms)
148 {
149     INT32U tmp;
150     tmp = GetTime() + ms;
151     while(1){
152         if(tmp < GetTime()) break;
153     }
154 }
155 
156 void LedInit(void)
157 {
158     RCC->APB2ENR |= 1<<2;
159     RCC->APB2ENR |= 1<<5;
160     //GPIOE->CRH&=0X0000FFFF;  
161     //GPIOE->CRH|=0X33330000;
162     
163     GPIOA->CRH &= 0xfffffff0;
164     GPIOA->CRH |= 0x00000003;
165     //GPIOA->ODR &= 0xfffffeff;
166     GPIOA->ODR |= 1<<8;
167 
168     GPIOD->CRL &= 0xfffff0ff;
169     GPIOD->CRL |= 0x00000300;
170     //GPIOD->ODR &= 0xfffffffd;    
171     GPIOD->ODR |= 1<<2;
172     
173     //LED1TURN();
174     LED2TURN();
175     
176 }
177 
178 void USART1_Configuration(u32 pclk2, u32 bound)
179 {
180     float tmp;
181     u16 mantissa;
182     u16 fraction;
183     tmp = (float)(pclk2 * 1000000)/(bound * 16);
184     mantissa = tmp;
185     fraction = (tmp - mantissa) * 16;
186     mantissa <<= 4;
187     mantissa += fraction;
188     RCC->APB2ENR |= 1 << 2;
189     RCC->APB2ENR |= 1 << 14;
190     GPIOA->CRH &= 0xFFFFF00F;
191     GPIOA->CRH |= 0x000008b0;
192     RCC->APB2RSTR |= 1 << 14;
193     RCC->APB2RSTR &= ~(1<<14);
194     USART1->BRR = mantissa;
195     USART1->CR1 |= 0x2008; // enable usart1, TE
196     USART1->CR2 &= ~(0x3000); // stop 1 bit
197 }

5、os_cpu_a.asm:

  1     IMPORT     OSTCBCur
  2     IMPORT    OSTCBNext
  3     
  4     EXPORT    OS_ENTER_CRITICAL
  5     EXPORT     OS_EXIT_CRITICAL
  6     EXPORT    OSStart
  7     EXPORT    PendSV_Handler
  8     EXPORT     OSCtxSw
  9     
 10 NVIC_INT_CTRL    EQU            0xE000ED04    ; Address of NVIC Interruptions Control Register
 11 NVIC_PENDSVSET    EQU            0x10000000    ; Enable PendSV
 12 NVIC_SYSPRI14   EQU         0xE000ED22  ; System priority register (priority 14).
 13 NVIC_PENDSV_PRI EQU         0xFF        ; PendSV priority value (lowest).
 14     
 15     PRESERVE8 ; align 8
 16 
 17     AREA    |.text|, CODE, READONLY 
 18     THUMB 
 19 
 20 ;/******************OS_ENTER_CRITICAL************/
 21 OS_ENTER_CRITICAL
 22     CPSID    I    ; Enable interruptions(Change Processor States: Interrupts Disable)
 23     BX    LR    ; Return
 24 
 25 ;/******************OS_EXIT_CRITICAL************/
 26 OS_EXIT_CRITICAL
 27     CPSIE    I    ; Disable interruptions
 28     BX    LR     ; Return
 29 
 30 ;/******************OSStart************/
 31 OSStart
 32     ; disable interruptions
 33     CPSID    I                            ; OS_ENTER_CRITICAL();
 34     ; initialize PendSV
 35     ; Set the PendSV exception priority
 36     LDR     R0, =NVIC_SYSPRI14              ; R0 = NVIC_SYSPRI14;
 37     LDR     R1, =NVIC_PENDSV_PRI            ; R1 = NVIC_PENDSV_PRI;
 38     STRB    R1, [R0]                        ; *R0 = R1;
 39     
 40     ; initialize PSP as 0
 41     ; MOV    R4, #0
 42     LDR R4,  =0x0                        ; R4 = 0;
 43     MSR    PSP, R4                            ; PSP = R4;
 44     
 45     ; trigger PendSV
 46     LDR    R4, =NVIC_INT_CTRL                ; R4 = NVIC_INT_CTRL;
 47     LDR    R5, =NVIC_PENDSVSET                ; R5 = NVIC_PENDSVSET;
 48     STR    R5, [R4]                        ; *R4 = R5;
 49     
 50     ; enable interruptions
 51     CPSIE    I                            ; OS_EXIT_CRITICAL();
 52 
 53 ; should never get here
 54 ; a endless loop
 55 OSStartHang                                    
 56     B    OSStartHang
 57 
 58 ;/******************PendSV_Handler************/
 59 PendSV_Handler
 60     CPSID    I                            ; OS_ENTER_CRITICAL();
 61     ; judge if PSP is 0 which means the task is first invoked
 62     MRS     R0, PSP                        ; R0 = PSP;
 63     CBZ     R0, PendSV_Handler_NoSave    ; if(R0 == 0) goto PendSV_Handler_NoSave;
 64     
 65     ;     R12, R3, R2, R1
 66     SUB     R0, R0, #0x20                ; R0 = R0 - 0x20;
 67     
 68     ; store R4 
 69     STR     R4 , [R0]                ; *R0 = R4;
 70     ADD     R0, R0, #0x4            ; R0 = R0 + 0x4;
 71     ; store R5 
 72     STR     R5 , [R0]                ; *R0 = R5;
 73     ADD     R0, R0, #0x4            ; R0 = R0 + 0x4;
 74     ; store R6 
 75     STR     R6 , [R0]                ; *R0 = R6;
 76     ADD     R0, R0, #0x4            ; R0 = R0 + 0x4;
 77     ; store R7 
 78     STR     R7 , [R0]                ; *R0 = R7;
 79     ADD     R0, R0, #0x4            ; R0 = R0 + 0x4;
 80     ; store R8 
 81     STR     R8 , [R0]                ; *R0 = R8;
 82     ADD     R0, R0, #0x4            ; R0 = R0 + 0x4;
 83     ; store R9
 84     STR     R9, [R0]                ; *R0 = R4;
 85     ADD     R0, R0, #0x4            ; R0 = R0 + 0x4;
 86     ; store R10 
 87     STR     R10, [R0]                ; *R0 = R10;
 88     ADD     R0, R0, #0x4            ; R0 = R0 + 0x4;
 89     ; store R11 
 90     STR     R11, [R0]                ; *R0 = R11;
 91     ADD     R0, R0, #0x4            ; R0 = R0 + 0x4;
 92 
 93     SUB     R0, R0, #0x20             ; R0 = R0 - 0x20;
 94     
 95     ; easy method
 96     ;SUB     R0, R0, #0x20
 97     ;STM     R0, {R4-R11}
 98     
 99     LDR     R1, =OSTCBCur            ; R1 = OSTCBCur;
100     LDR     R1, [R1]                 ; R1 = *R1;(R1 = OSTCBCur->OSTCBStkPtr)
101     STR     R0, [R1]                 ; *R1 = R0;(*(OSTCBCur->OSTCBStkPrt) = R0)
102 
103 PendSV_Handler_NoSave
104     LDR     R0, =OSTCBCur             ; R0 = OSTCBCur;
105     LDR     R1, =OSTCBNext            ; R1 = OSTCBNext;
106     LDR     R2, [R1]                 ; R2 = OSTCBNext->OSTCBStkPtr;
107     STR     R2, [R0]                ; *R0 = R2;(OSTCBCur->OSTCBStkPtr = OSTCBNext->OSTCBStkPtr)
108     
109     LDR     R0, [R2]                 ; R0 = *R2;(R0 = OSTCBNext->OSTCBStkPtr)
110     ; LDM     R0, {R4-R11}
111     ; load R4 
112     LDR     R4, [R0]                  ; R4 = *R0;(R4 = *(OSTCBNext->OSTCBStkPtr))
113     ADD     R0, R0, #0x4             ; R0 = R0 + 0x4;(OSTCBNext->OSTCBStkPtr++)
114     ; load R5 
115     LDR     R5, [R0]                ; R5 = *R0;(R5 = *(OSTCBNext->OSTCBStkPtr))
116     ADD     R0, R0, #0x4             ; R0 = R0 + 0x4;(OSTCBNext->OSTCBStkPtr++)
117     ; load R6
118     LDR     R6, [R0]                ; R6 = *R0;(R6 = *(OSTCBNext->OSTCBStkPtr))
119     ADD     R0, R0, #0x4             ; R0 = R0 + 0x4;(OSTCBNext->OSTCBStkPtr++)
120     ; load R7 
121     LDR     R7 , [R0]                ; R7 = *R0;(R7 = *(OSTCBNext->OSTCBStkPtr))
122     ADD     R0, R0, #0x4             ; R0 = R0 + 0x4;(OSTCBNext->OSTCBStkPtr++)
123     ; load R8 
124     LDR     R8 , [R0]                ; R8 = *R0;(R8 = *(OSTCBNext->OSTCBStkPtr))
125     ADD     R0, R0, #0x4             ; R0 = R0 + 0x4;(OSTCBNext->OSTCBStkPtr++)
126     ; load R9 
127     LDR     R9 , [R0]                ; R9 = *R0;(R9 = *(OSTCBNext->OSTCBStkPtr))
128     ADD     R0, R0, #0x4             ; R0 = R0 + 0x4;(OSTCBNext->OSTCBStkPtr++)
129     ; load R10 
130     LDR     R10 , [R0]                ; R10 = *R0;(R10 = *(OSTCBNext->OSTCBStkPtr))
131     ADD     R0, R0, #0x4             ; R0 = R0 + 0x4;(OSTCBNext->OSTCBStkPtr++)
132     ; load R11 
133     LDR     R11 , [R0]                ; R11 = *R0;(R11 = *(OSTCBNext->OSTCBStkPtr))
134     ADD     R0, R0, #0x4             ; R0 = R0 + 0x4;(OSTCBNext->OSTCBStkPtr++)
135     
136     MSR     PSP, R0                 ; PSP = R0;(PSP = OSTCBNext->OSTCBStkPtr)
137     ; P42
138     ; P139 (key word: EXC_RETURN)
139     ; use PSP
140     ORR     LR, LR, #0x04         ; LR = LR | 0x04;
141     CPSIE     I                     ; OS_EXIT_CRITICAL();
142     BX    LR                         ; return;
143 
144 OSCtxSw ;OS context switch
145     PUSH    {R4, R5}                
146     LDR     R4, =NVIC_INT_CTRL             ; R4 = NVIC_INT_CTRL
147     LDR     R5, =NVIC_PENDSVSET            ; R5 = NVIC_PENDSVSET
148     STR     R5, [R4]                     ; *R4 = R5
149     POP     {R4, R5}
150     BX     LR                                 ; return;
151     
152     align 4
153     end
原文地址:https://www.cnblogs.com/ansersion/p/4396766.html