1、源码准备6 W8 H* ?: s. `6 f) r# f" a
首先准备好我们下载好的FreeRTOS源码以及STM32F407的工程模板(这里以原子的F4跑马灯工程为例,可去原子的开源论坛自行下载),源码下载及参考请参考我的上一篇博客。+ f! w9 H+ o/ g( q
7 ~9 `3 O* E. F$ Y/ S2、创建FreeRTOS文件夹3 A5 m0 W+ b* @" o$ ~7 M5 n
在工程中创建FreeRTOS文件夹,将FreeRTOS源码全部复制到该文件夹下
8 C1 _/ r0 w& I* E1 Y- q2 P: P$ E+ ~8 ?
/ D7 D$ A+ D' m" {5 V, M4 @5 p% ]* k3 d# n5 ~
打开portable文件夹,删除没用的文件,留下如下文件即可* O6 |9 E( ~$ B+ G6 K
+ |( j9 \* m9 ~2 F
/ z/ V6 T# P& @- l6 r
: T- b& a, X6 X$ O& Z6 x
3、在工程中添加FreeRTOS源码
8 } D; B+ ]% f打开工程,在工程中新建FreeRTOS_CORE和FreeRTOS_PORTABLE,然后向着两个组中添加对应的文件,如下图所示:
; W2 |: t1 ?5 }% `- I* l
% S9 R6 N2 u1 C# C
6 P. L8 w! U8 u
& D+ D+ m' p. b2 g FreeRTOS_CORE的文件打开FreeRTOS就可看到,port.c是RVDS文件夹下的ARM_CM4F中的,因为STM32F407是Cortex-M4内核并且带FPU。Heap_4.c是MemMang文件夹中,这里有5个文件,是5个不同的内存管理方法,为什么选择第4个,因为FreeRTOS内存管理所决定。1 l4 J8 @& S) h9 G$ y
3 b# Q1 s2 x- W7 U# z4、添加对应的头文件路径3 y, v: }8 j$ I7 i. i8 h3 q; I
( ]; S: e0 D/ W: k' q
, }) ?/ A% [/ ~% v3 }7 }) I7 S' |7 H
5、编译及错误解决$ z4 k: t' J# c
5.1 找不到FreeRTOSConfig.h文件
7 p9 ?8 |2 f8 m! `7 D4 ?完成后编译一下,会出现如下错误3 M9 }1 I& t/ C1 r6 f( T+ N
( g1 i! b3 b+ g9 g& q6 B- S
; M, X7 s% r" F1 ]1 v3 G
+ q o" A# ~1 } 很明显是没有FreeRTOSConfig.h这个文件,那我们就把它添加进去,具体位置在FreeRTOS的DEMO中找到CORTEX_M4F_STM32F407ZG-SK文件,如下图所示
7 b2 B9 b1 F7 r! T- _; Z$ d1 _1 C. a' Q. P" P( G
- Q7 R" ?. s4 `1 l/ D
4 |4 _; b, H8 a 至于放到哪个位置自己随意,一般是放在FreeRTOS的include里面,而这个文件是FreeRTOS的配置文件,一般操作系统都有裁剪、配置功能,而这些都是通过一个文件内的宏定义来完成。: W ^) L% q. ~$ Z9 a/ A3 I* |+ O
2 x; n+ s" O1 J& N5.2 SystemCoreClock未定义3 K( W: r* R& d7 `/ S7 K
接着上面的步骤再编译一次,还会出现以下错误,意思是SystemCoreClock未定义
+ s8 j* O/ O: d; g1 i
9 H7 Q( q; D, H" p! E( S
1 ?8 H7 v5 ^+ h+ |+ j t; T2 k解决办法:修改条件编译
5 g* f& A M: n2 v8 r T( V" D& E6 ]' E8 y
6 A" g. W, ?% G# Y. ?, d, B7 E3 ^9 ?& `: f+ P6 S% o6 g
5.3 重复定义 W6 w; v0 w* c& T! r
接着再编译一下,发现还有错误,这次的错误是重复定义1 ^+ N! h8 M; M) a. |+ m: d
4 o8 B+ J; h$ U6 |7 b4 n- A
' e9 E( f" p+ Y) w: p" W t( o0 Z$ g/ h. }2 w; W- b
解决办法:
% x! c# t o& n3 B* H z G7 C# q8 s2 I" Y
屏蔽掉stm32f4xx_it.c中的PendSV_Handler(),SVC_Handler(),SysTick_Handler()这三个函数,4 r, q' ~0 G' p8 N: d. F F
( f4 Z6 ^1 M7 q% O% J6 a
" [ s& K, S' e: n/ j ] I. |. v+ P, Q* E0 J
5.4 钩子函数未定义
* [3 y. e* m" T; @4 k 继续编译一次,还是会有错,这次的错是函数未定义,他们都是Hook结尾的,称为钩子函数。4 ~6 ?) C7 P! _1 m
+ E/ j! G; i0 B) D" B4 x9 V# I
3 s2 G( D8 v# Y8 J
+ ?. P5 y" x4 ^9 F( Z" r( W) G解决办法:4 r# J2 v4 o) r8 u2 U2 F( i
5 @" z1 {7 M# l 去FreeRTOSConfig.h中关闭这些钩子函数,他们都是宏定义决定,这里将configUSE_IDLE_HOOK、configUSE_TICK_HOOK、configUSE_MALLOC_FAILED_HOOK和configUSE_FOR_STACK_OVERFLOW定义为0.
" u. v. x5 b9 `* l, ~
8 n7 d/ T {: D, D; ^$ y
2 H5 m$ B4 F0 c5 J* c- ?8 C6 Y5 U! \. A& p5 _& |3 k. J, Z
再编译一下应该就没错了。( E3 w, s+ o) p; q
7 g- Q" _/ ~- m' s% J5 s
6、修改SYSTEM文件4 j1 {. |7 s$ t& |# R6 p. x' a
因为原子的SYSTEM文件夹是针对UCOS编写的,所以要进行对应的修改
4 M( ~, Q. k3 P- b D" A8 V" s: D, N1 B9 S" F( _
6.1 修改sys.h文件8 a4 N0 y# i, Q' O
把宏定义改为1即可,要支持OS,UCOS也一样的4 [; e/ s' a, l+ V# G) T
3 I% `' K. i- y0 B
/ c1 `+ _4 C' O2 k5 B0 d
; }, {( S( S& h! t) U1 R6.2 修改usart.c文件. q) o7 p$ H* R! E I
修改头文件为& s, J5 w2 k5 u7 x; F/ W( B& q
! n- h$ j" n, j
/ ~! P8 \; k3 C/ @7 p
* f; h0 {' A& u4 J9 P修改串口中断服务函数为:7 d- E `6 F; p$ m* C
, Y. W8 T7 m4 o+ G' l/ a, U; ~
$ ` x3 |* m, k
4 d) C$ {' c" G7 A6.3 修改delay.c文件
1 C8 A' t5 F) `( A$ N同样先修改宏定义的头文件
# q- o1 b" G7 c# w9 A( e# x5 G/ z+ j& r
* k2 o. g- S) B0 z5 A
6 J% a. ]$ f! R( u5 A, i接着修改systick中断服务函数为
, o& M, @- H+ e( T! P# o: c/ h/ [& }! j6 P9 C
! O3 e$ w7 r/ P- x% \. j' m$ u- }) ]3 {7 J0 o) Q, `5 h% d0 D, }
在滴答定时器中断服务函数中调用FreeRTOS的API函数xPortSysTickHandler();( b/ I+ I2 m p }( C% m+ d
( _/ i" q% I" h8 ]7 ^/ j( l/ E在修改delay_init()函数,如下:) c" a @, w: M8 x. p5 z/ y" b0 R
5 y% }" [# k, m- B) q, ?0 Z4 ?
5 h* v# k& ~' T! H& j
" N' X- U0 v+ B: H3 f; o+ G
接下来就是延时函数的修改
5 s+ j% v+ c5 Y; I
# B) S8 D0 i/ ^ i" [3 k
1 R, G4 n d, B# n9 r8 N) q1 \$ |2 y
9 [! x- b( u; \8 l1 i; U修改完后再编译一下,会出现重复定义的错误,如下图:
* ^2 H& J. W- C$ |9 l ?! j& l1 v" o
. e. [" d# S3 C% N/ T7 _
/ k. G3 b* ?% ?# _
. }; n6 i5 C, r) x解决办法:屏蔽FreeRTOSConfig.h掉底部的#define xPortSysTickHandler SysTick_Handler
9 O( T( q3 j8 G: ` l9 a% u; ?. H
; m4 |* K) v6 C& J2 S, Q
# s1 G( c" T: _% v
: h2 V; M: R- Y# ~& i- p
7、修改main.c进行功能验证
/ [; e% N: u" g主函数主要是实现实时系统多任务的创建,具体如下
! V: k: {9 a1 B% M Y
: M5 I Q+ w! y! n" m% w% | O- #include "sys.h"0 c" g( o6 J$ j" C! b( S
- #include "delay.h". M3 n% J: i b4 I
- #include "usart.h". p) [6 |4 c9 E6 R7 D
- #include "led.h"
: L8 T# r+ c [* i' C - #include "FreeRTOS.h"6 u( o$ a* v: F$ o- i1 p
- #include "task.h"
2 v' ^# c" ^9 m/ I" L - " ?: }$ X0 q* H9 A3 @
- #define START_TASK_PRIO 1& [1 B( ?' F5 S
- #define START_STK_SIZE 120& ` b. z$ k' H
- void start_task(void * pvParameters); //任务函数
4 m$ P/ M j h3 f, J% ?) A - TaskHandle_t StartTask_Handler; //任务句柄
2 Y* E9 _$ P1 U+ ?+ t - 4 S v/ O, a6 d' c9 V3 I8 I
( g3 C) g3 O1 R& u8 Y' V- #define TASK1_TASK_PRIO 2
# b9 q. ^3 E) R( _: X: f - #define TASK1_STK_SIZE 120
: C% s1 ^3 y5 E+ F( j - void task1_task(void * pvParameters);
6 @/ ~1 I, {- x8 ~. Z0 [ - TaskHandle_t Task1Task_Handler; //任务句柄 . `( V4 n# O6 ?2 A
9 ~. F, U- T, y* t9 G5 s7 D% s, Z6 w- #define TASK2_TASK_PRIO 3
1 C+ c! k& ?+ H5 [8 j/ W1 |2 X - #define TASK2_STK_SIZE 120 8 G9 {6 K0 J0 l
- void task2_task(void * pvParameters);
* F# `& K c' R. U2 a0 P - TaskHandle_t Task2Task_Handler; //任务句柄 + s! j' @! b* t/ R4 L# [. D' j
( [& x0 e) o1 M) x; b' [- int main(void)
; ?/ X# n X) _4 D$ Y - {; {+ S$ a. u+ n: M6 h! O
- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
4 j {5 R: I+ V3 I5 Y# _$ d" j - delay_init(168); //初始化延时函数
0 H4 u! Y- z0 v# H# ` - LED_Init(); //初始化LED " s& a5 h9 ~' K) c8 I: i" K# U+ C
- uart_init(115200); //初始化串口& Q9 U6 `# Y- ]
- 1 `& H& a2 \" \$ U; O
- xTaskCreate((TaskFunction_t ) start_task,
9 s2 y6 |8 ~8 | - (char* ) "start_task",* |& h P. m( R0 I6 @- u
- (uint16_t ) START_STK_SIZE,2 `* z7 [1 ^4 f7 H a: E8 F& a3 B
- (void * ) NULL,. C+ O% Q n( S, g) ~& C: A" ?% f
- (UBaseType_t ) START_TASK_PRIO,, \. g, j+ Y# p" [/ e. C5 w/ H* c
- (TaskHandle_t* ) &StartTask_Handler);3 R; o/ i! S' g. t) d
- vTaskStartScheduler(); //开启任务调度. j7 W- f+ D( T
- } W1 t2 W# y2 [; D' [6 J5 z
2 u% j$ m; r" F& V) A) }- void start_task(void * pvParameters)0 C0 ~9 s( V1 k" L8 f X; a" T8 ?! H
- {* x8 [$ U" K' E
- //创建Task1+ @) ^/ u4 T8 C( n1 r7 _
- xTaskCreate((TaskFunction_t ) task1_task,
0 A4 U. n/ f- L - (char* ) "task1_task",
9 s6 Z3 N3 }7 c5 Q) E* Z. S - (uint16_t ) TASK1_STK_SIZE,/ h/ h( g* k2 F# C; k9 l
- (void * ) NULL,
1 u9 F3 X! w; E! S/ p# _# _ - (UBaseType_t ) TASK1_TASK_PRIO,6 S8 ~1 A! J& t$ V8 x
- (TaskHandle_t* ) &Task1Task_Handler);/ u9 V9 I( ~) S
-
# T$ I" V, U! @' ]& V8 ~- m1 b - //创建Task2; X, F1 a9 z3 L' O7 ^/ X: U7 q
- xTaskCreate((TaskFunction_t ) task2_task,
0 [; h. x' G) ?4 a - (char* ) "task2_task",
3 a+ a+ T& Z0 F) D [6 R) q" ~ - (uint16_t ) TASK1_STK_SIZE," e! `; |4 I9 r% e: z# c. A
- (void * ) NULL,
. r/ Z4 u5 G1 D1 k1 j% T( j7 W2 f - (UBaseType_t ) TASK2_TASK_PRIO,4 P" d9 B& `' n
- (TaskHandle_t* ) &Task2Task_Handler);
) m: i* j& W7 X' b" _" O - vTaskDelete(StartTask_Handler); //NULL1 K9 Z0 h% Z& q+ L9 m+ g( R# a
- }
- c- R) C/ G1 q1 \: M
$ @, |7 x+ a+ P- void task1_task(void * pvParameters)2 n ?' v, x8 r5 h; F7 F* d i
- {$ s, n) x, m# Z% m+ Q0 B. S$ T" {
- char task1_num=0;
8 {2 A, C# B/ a; G+ b* p3 P - . C) z) ?! b1 u3 i- l4 ]; v
- while(1)1 h/ g7 ?/ k" w, s4 ?9 Y
- {0 d+ p/ `9 | Q/ E
- task1_num++;
! H6 K6 [2 {4 T4 y1 j5 | - ' e/ ?5 ^% m5 x5 T, P( N
- LED0 = ~LED0;
, r. D& c+ F6 U0 H6 E$ a" a' _0 Z, F - printf("Task1 Runing %d !\r\n",task1_num);1 d2 a9 G0 K% n4 R2 i% i9 U
-
& w1 M+ a2 X/ A; } - vTaskDelay(1000);+ ^+ `0 n) D8 Y8 m, F1 t% G
- }2 N9 g5 b# ^1 z% A. O5 ]
- }9 a1 m4 N, ~2 C/ r7 u5 ]& O/ a
- # X) d& o4 E' F/ p
- void task2_task(void * pvParameters)0 z1 T( [4 l6 P# J% ~, F
- {' z' n) Y c3 k% x$ D/ w* n5 k/ w
- char task2_num=0;
: ~% V7 {9 ~4 D - while(1); O& B% v' T- c% w
- {
: N5 K1 E8 q1 \& R( B7 C - task2_num++;" h6 M1 ^( o) I- }- L8 `
-
; n1 N: I; e j" y: F - LED1 = ~LED1;) ?# H- a/ X9 w
- printf("Task2 Runing %d!\r\n",task2_num);
4 w6 o7 @0 W& Z% Z& N3 l - vTaskDelay(500);
+ _$ b: }1 e7 f3 _ - }
9 _7 i0 Q, G/ Q2 C$ P% E0 T2 S; M2 c - }
复制代码 , Z) E! e) F8 z5 U! H4 S- @
实验现象;
( f$ E" M G$ p5 L8 V! b! v8 d. q. a& l7 h! z2 Q/ I$ C2 e7 u% {
开发板上LED0和LED1进行不同状态的闪烁,串口也会打印任务执行次数,很明显任务二的速度是任务一的两倍。
# A. {: M; {# f; A; f8 h3 `6 M& C/ e1 |. I# u5 A
) Q, Q" E( P- I1 `) ]! I0 |
0 @; w/ o9 @: [$ V
5 p; g8 ^8 ^% p* H
. `6 q S- b$ { J: \5 e
我这里使用的是STM32F407VET6,原理都差不多,用那块板子都一样。至此,FreeRTOS移植和任务创建成功。5 z& K. {1 K Q2 u
5 t) G" r! I; r" F5 ^' N
: I' i9 n! ~" h2 T) i
% E& V' C7 {/ _" w
|