1、源码准备) j/ ]" f% ~2 X6 x
首先准备好我们下载好的FreeRTOS源码以及STM32F407的工程模板(这里以原子的F4跑马灯工程为例,可去原子的开源论坛自行下载),源码下载及参考请参考我的上一篇博客。
4 N7 P4 R6 }, U. _& o: c" T! u( p1 L5 n) y
2、创建FreeRTOS文件夹1 a/ n, I, a: Y, Y
在工程中创建FreeRTOS文件夹,将FreeRTOS源码全部复制到该文件夹下
$ ]. v6 b6 W; L2 h* e! n* |9 V1 z
9 f' R3 _( |- C% B
6 e+ l+ I) n. ?5 u' J
$ y) y. R$ a! i2 }0 q打开portable文件夹,删除没用的文件,留下如下文件即可8 Y* Q) u" x+ i
8 M& D9 Y- t7 m+ r+ l. @
$ U4 W; ?7 a/ e w: m
, Y* }1 L8 J% v! _/ A
3、在工程中添加FreeRTOS源码: S# J" o2 E' R8 B) e
打开工程,在工程中新建FreeRTOS_CORE和FreeRTOS_PORTABLE,然后向着两个组中添加对应的文件,如下图所示:
' X8 ]& W* |8 L2 q* I: I3 }/ P" }( O$ x$ O# z: Z
' z- t* _3 l3 v! p
! ]/ j5 H, h% ? FreeRTOS_CORE的文件打开FreeRTOS就可看到,port.c是RVDS文件夹下的ARM_CM4F中的,因为STM32F407是Cortex-M4内核并且带FPU。Heap_4.c是MemMang文件夹中,这里有5个文件,是5个不同的内存管理方法,为什么选择第4个,因为FreeRTOS内存管理所决定。
8 e3 Y* ^* a& s- i% a8 e9 t4 ]$ w- N1 q2 ` M2 _; H+ n
4、添加对应的头文件路径- Y$ |+ W' ] {8 F
1 u; f# ?% t7 `! O9 B
G2 }' `' m9 o
; u+ \, G4 Q) q3 j# w5、编译及错误解决
8 w0 D2 _' q: F( y( K8 b5.1 找不到FreeRTOSConfig.h文件
! {1 P- F$ A I* K/ {5 R% Q完成后编译一下,会出现如下错误
( C2 b2 s* W9 I5 G/ f# C, m
. O7 x9 \ ^$ V
& d" z @ W3 h8 J6 B) d- W
1 S9 c! {8 q4 D 很明显是没有FreeRTOSConfig.h这个文件,那我们就把它添加进去,具体位置在FreeRTOS的DEMO中找到CORTEX_M4F_STM32F407ZG-SK文件,如下图所示6 D" J/ B9 ?( V+ O; j" B* |( N
; X! K/ Q3 z( y1 u S
$ b, e4 |3 }' E' A0 x* \$ B
# E1 g0 n( J3 a$ l4 y" T+ @3 ` 至于放到哪个位置自己随意,一般是放在FreeRTOS的include里面,而这个文件是FreeRTOS的配置文件,一般操作系统都有裁剪、配置功能,而这些都是通过一个文件内的宏定义来完成。% {; w' g* U/ [" L
( H7 q4 `: @+ \' P! R# A8 E" w( [5.2 SystemCoreClock未定义
9 o" C4 n# J2 ~4 {: A接着上面的步骤再编译一次,还会出现以下错误,意思是SystemCoreClock未定义$ w! \( c/ G( A( p- k) l4 E
% V/ U) G! ~9 f" i y5 Q4 y
( h& R. K* S+ Z解决办法:修改条件编译. Y7 O2 m' d+ N9 L
5 a! K |- N; O9 Z% `
: }- K1 ~/ ]; Q/ w# X
p" N# p$ y/ F2 @* {& |1 e9 w5.3 重复定义- ~& h! o0 h2 x! T
接着再编译一下,发现还有错误,这次的错误是重复定义6 _( M# Y; S4 V0 G& s. [
. Y- I7 j8 C6 W) [4 n
1 q8 q! M/ U0 j& k
( o+ c2 n# X, M ~解决办法:/ D0 G$ Z4 k# O
+ S+ d; K7 ]5 _ O
屏蔽掉stm32f4xx_it.c中的PendSV_Handler(),SVC_Handler(),SysTick_Handler()这三个函数,& Y) g2 w. t" d( m& Q$ f
, i2 G) G) t/ |( Y2 ]5 n
2 T: V! T; M( M
5 @+ i* q3 Z4 X, U1 _6 v
5.4 钩子函数未定义
! L7 R( L2 F9 f% N5 b 继续编译一次,还是会有错,这次的错是函数未定义,他们都是Hook结尾的,称为钩子函数。3 ]6 Y( r1 d0 C8 q: }3 I+ W b
1 R0 Y1 @2 j9 P
+ D e# F( h9 @9 X. i* u
, X1 t6 _7 H$ G0 Q+ c8 @ ?解决办法:
2 [: T P! G) v4 d+ D
6 D7 @7 G8 X" X% K, {9 k 去FreeRTOSConfig.h中关闭这些钩子函数,他们都是宏定义决定,这里将configUSE_IDLE_HOOK、configUSE_TICK_HOOK、configUSE_MALLOC_FAILED_HOOK和configUSE_FOR_STACK_OVERFLOW定义为0.5 J* {" k" H! M9 [9 j; `
. h0 A- P, d7 D/ D# x6 O; `
& F" Q0 |1 r6 Q3 s8 J, K l; E4 ~: z$ G! @8 e8 u; I$ P
再编译一下应该就没错了。
6 n! f+ [9 _( r0 y6 f2 v8 U- c. q8 k6 ?3 G2 [
6、修改SYSTEM文件
( M1 _$ J7 E T( t$ \因为原子的SYSTEM文件夹是针对UCOS编写的,所以要进行对应的修改0 w% R3 A! H% m/ |" k2 u
6 d- `3 W# y1 d9 n( R
6.1 修改sys.h文件: \) k$ t. f5 D5 N8 N- T0 N4 c4 |
把宏定义改为1即可,要支持OS,UCOS也一样的' |" J9 S5 I o
% E; t3 d% _2 r$ \+ O
8 `' b' G, c* h o5 u u
; Z/ G' [& g) u, ]$ L8 c9 Z6.2 修改usart.c文件1 _ W" C+ m5 T3 X8 E+ T, i
修改头文件为$ L+ x8 D# o' x& A
$ f: c; q- N7 T. o' A
& e0 \! b1 d g! m) b ^" J+ V
6 ]8 i& ?0 D# Z9 R修改串口中断服务函数为:/ w) V+ f* Y7 j# x E$ c
$ L2 g+ }2 p7 ^. }9 H. O
2 c5 z: e2 s8 I o1 v# U5 H$ P! @8 G
& h% D' x' N, L5 i6.3 修改delay.c文件
u( {6 D, i& z' x L同样先修改宏定义的头文件# y* w0 S$ z8 s$ @- r8 r
! U( b9 y( V4 }/ z
0 e1 X0 B3 n! a2 v% K1 W( U; c8 h Y! X- I
接着修改systick中断服务函数为
' u5 a$ o2 G0 B S1 h3 D+ N6 K
" l0 c) ^$ [6 ` ] Z, C. @
# W+ }1 ] G/ L$ l
; V7 }8 x$ k. A, \9 J在滴答定时器中断服务函数中调用FreeRTOS的API函数xPortSysTickHandler();7 W$ m9 [# A+ F; i& a% N
* t7 r u6 \; V% J% X+ ]3 R$ i
在修改delay_init()函数,如下:2 {8 m8 p; @6 ^) l: S$ ?, j
$ s1 B% G! t6 q& n5 x
1 y3 i! i: I) L, s" _8 ~; b D0 b$ P& @
' f' v G2 V( S' h
接下来就是延时函数的修改" [- l% a. _. I9 ?2 a
( \/ a" l, V1 W) a2 Q4 Y
& B# j* t- s7 x! {' C# d u) r0 e0 O1 M& U4 f( T
修改完后再编译一下,会出现重复定义的错误,如下图:
* F" {. o. T" B( [. d6 K! I' c; \/ S" I/ R; t
. `1 |" A% X# |
- i) d7 z1 R5 q' P解决办法:屏蔽FreeRTOSConfig.h掉底部的#define xPortSysTickHandler SysTick_Handler7 |& _" c+ V5 m) I! l
; U, F" ]( F1 T* N7 a* s( i
7 ^9 u9 p/ f( S$ @$ Z; D
$ v1 t; z( U( V
7、修改main.c进行功能验证
% c' W& c9 e7 R主函数主要是实现实时系统多任务的创建,具体如下
U/ ^$ d& }/ e2 P
% K& q* P, V5 \- #include "sys.h"5 f3 V; R) I: Y& O+ g& r1 n
- #include "delay.h"
: v+ L2 I; P; |" F2 b - #include "usart.h"
' [4 |# { O: s0 A; @( b - #include "led.h"' H1 K$ k' J3 p
- #include "FreeRTOS.h". y5 y$ o) M# c" a& ^$ u. I
- #include "task.h") p! }0 K4 G( M2 V/ ~! W7 M
- % X9 K$ T$ _! ^
- #define START_TASK_PRIO 1
! K S5 P7 h# L. ]: R) j" N8 r - #define START_STK_SIZE 120: f. r: M/ s7 K% {& t& w0 c! R
- void start_task(void * pvParameters); //任务函数
E4 D7 `% d* g- ^% Q5 s% f - TaskHandle_t StartTask_Handler; //任务句柄 : W% w( g7 _& w8 q! V
- ; Q1 t w6 E+ _/ a
. Q* l8 y! g2 _2 Z" s4 \# W- #define TASK1_TASK_PRIO 2
2 d! a! `- s1 ^" c0 ?( J - #define TASK1_STK_SIZE 1205 `7 f9 W7 M3 @ |
- void task1_task(void * pvParameters);; j$ j2 G6 s8 G7 L! n
- TaskHandle_t Task1Task_Handler; //任务句柄
# P, r8 G5 [5 p+ F: g: Y1 F% Y+ J, e - 2 U& C2 c5 _. V2 U
- #define TASK2_TASK_PRIO 3' H, A5 F, }; a9 M
- #define TASK2_STK_SIZE 120
, z( k9 ^" {0 B6 J. O) | - void task2_task(void * pvParameters);
0 }' c+ O; g% ~5 b' r - TaskHandle_t Task2Task_Handler; //任务句柄
7 K! }" r) L4 _, p b7 | - 1 S" K4 j+ F; F
- int main(void)
) @( `9 i9 k# |5 p# D9 n( Q, G# u - {: ^3 Z+ p/ _# y* Y, x P
- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);( `3 n5 U8 L9 t! R
- delay_init(168); //初始化延时函数% S" T' T* P2 S. o
- LED_Init(); //初始化LED ( l- V! Z( K. Y2 Q$ S# |7 I. ~
- uart_init(115200); //初始化串口
" w- w2 ~8 b* a# Y/ S, e - 6 j5 G( N9 X) s8 M
- xTaskCreate((TaskFunction_t ) start_task,3 ^7 ~* h( D# j q
- (char* ) "start_task",
) }$ x. w9 ]: P0 N' H - (uint16_t ) START_STK_SIZE,, W' N' Q3 a; w8 f9 i
- (void * ) NULL,- P- n: v# Q0 [1 A% N$ ]
- (UBaseType_t ) START_TASK_PRIO,
& k# Y/ N/ p& v/ b - (TaskHandle_t* ) &StartTask_Handler);
( I9 U; \) n0 R3 t - vTaskStartScheduler(); //开启任务调度 E& |6 _+ |, A2 n. P
- }& e! z% R+ d6 |8 B) T
- l4 ? P* a) Y- void start_task(void * pvParameters)9 |# Z! P; Q( k8 p/ O
- {* k7 K# d }+ G" M; ~0 L7 b9 W
- //创建Task1
5 p: [2 [1 D* } - xTaskCreate((TaskFunction_t ) task1_task,
8 h" B/ S( |4 x- P4 B3 f3 A, e - (char* ) "task1_task",; \: E! X0 G" [% K, ~! N3 e
- (uint16_t ) TASK1_STK_SIZE,
3 g% j% Z; Q0 K# J1 k% R - (void * ) NULL,+ l( W u! _7 W! \$ t
- (UBaseType_t ) TASK1_TASK_PRIO,
6 _# m, C8 l1 Q: n3 S+ r - (TaskHandle_t* ) &Task1Task_Handler);
9 O) w3 @2 a" F - * p N2 B. v/ N2 ? b
- //创建Task2
7 L5 ?) P& C5 U. m - xTaskCreate((TaskFunction_t ) task2_task,
! g i0 L0 F6 i! P9 F! v1 A8 M - (char* ) "task2_task",! o; O, m' l$ Z; D7 ` R+ W. `4 t
- (uint16_t ) TASK1_STK_SIZE,5 a( R( J5 A; l
- (void * ) NULL,
" e0 j" G: J' L Z! n - (UBaseType_t ) TASK2_TASK_PRIO,; E6 ~; _4 F3 R! G% Y" W1 j
- (TaskHandle_t* ) &Task2Task_Handler);
- x2 x5 U' H8 ? - vTaskDelete(StartTask_Handler); //NULL
9 [4 U8 N4 {/ u/ f2 e - }
" Y- E+ i: {; n. _, j
- Y4 D+ X2 c% M( T- void task1_task(void * pvParameters)
; S1 Z+ s: E6 V% T# L9 e - {
' a2 ?, }- C8 I1 u2 u - char task1_num=0;/ g; `/ o8 m8 V1 t9 X5 q
- ) K* A. q+ t( g( u e G* J- m. r' z
- while(1)
; C% B$ j8 D7 u% O - {
9 g" @% c7 I$ h% f, F: J' U- m - task1_num++;
! t9 N; D; E* P I0 O4 c - - i1 n* z$ Y5 `$ Y
- LED0 = ~LED0;
+ b0 q) j% V; I) _ - printf("Task1 Runing %d !\r\n",task1_num);7 y0 P0 G5 f$ J9 i
-
& e$ F% _( O5 k- U0 q - vTaskDelay(1000);
5 @. O* d/ l# h) o9 c. M! B - }
) l; K/ J0 I7 ^ \. I& O4 i - }' V# `: y; _) A7 ` }& s8 j
) `2 r& E4 N/ ^5 \- void task2_task(void * pvParameters)$ }% a4 K; O* Z, x' k6 R6 ^
- {
& u+ h/ b! O+ i% x$ E5 z - char task2_num=0;! ~0 g* x5 y$ B' X+ R
- while(1)
4 y# P, E9 B9 C+ s - {
0 S/ g Y. E' N3 n2 W - task2_num++;
. q. M. D9 c5 {9 M -
0 y! g) ^" D0 q% G6 D/ c$ ?; b - LED1 = ~LED1;- p! _0 c2 {. p( B0 J. {! u* j
- printf("Task2 Runing %d!\r\n",task2_num);+ d; P9 b( [6 Q: ]
- vTaskDelay(500);
7 ?5 ^5 I7 c0 ^ ` - }
; @2 R& p/ ~9 L v; w4 v- C - }
复制代码 ) ^9 O' v/ a1 u
实验现象;
% D9 ?- p3 B( P3 w; a# b; j" h
1 O! s& P- Q1 ]& u% X 开发板上LED0和LED1进行不同状态的闪烁,串口也会打印任务执行次数,很明显任务二的速度是任务一的两倍。2 _6 |3 ?) k3 d
/ U. T T y7 }% s# D
- D' O, x0 c L# {* ~2 n+ j4 @* ~% `* o( h7 {
6 v% i+ h5 Y7 I* G6 V8 }
! `8 T/ T' e: H" E4 r我这里使用的是STM32F407VET6,原理都差不多,用那块板子都一样。至此,FreeRTOS移植和任务创建成功。: H7 M- w, b6 M/ }
$ [+ ]- J# y6 A' f) g2 l
- g( i2 [7 _ I) D9 B* e% Z% k& `: C' @
|