1. 简介
@6 Y1 t7 F; X/ s, ^' T( F: _) r 我们已经了解了FreeRTOS,接下来我们就把FreeRTOS移植到我们所使用的平台上,我们使用的板子是STM32F407。+ a0 w5 o7 ]/ ?$ `5 }5 L: c8 C1 o, w
2. 预备工作
" ]( F) _, V# X8 Q% v2 Q 要移植FreeRTOS,肯定需要一个基础工程,基础工程越简单越好,我们就用之前的跑马灯实验作为基础工程。
* n8 k$ I3 I, A# Y) k7 k9 H/ Z8 s h+ N% W) I. M+ A
3. FreeRTOS移植: g, M7 Z6 s9 |/ L+ ^: B
3.1 创建FreeRTOS文件夹
( ?6 @& W+ R, h% |# `& _! O/ R& z' w- M# c0 [
6 j& F1 `: z9 h% X0 @+ w
+ K8 k- r/ M$ T: a% C$ R. k3.2 将FreeRTOS的源码添加到FreeRTOS目录中8 h% _" w6 ?, W3 D# w5 J4 ~6 U
- S+ o8 S1 `" y
FreeRTOSv10.4.1\FreeRTOS\Source. v5 u% F% {4 K) I8 ]5 t
* l+ N* S! k i2 c" B9 Y$ f: Q4 T+ I
! |1 ]5 O' q3 n" Y; w+ U* `# M! E. s" W8 p! E$ G7 ?% ^
3.3 删除portable文件夹中相关的文件和目录/ r _# T% c0 y4 b a
0 ~8 U% v/ h! D- Z7 {+ a我们只需要留下keil、MemMang和RVDS这三个文件夹,其余的都可以删除的。
/ {: M; c \) k& Z0 a4 g0 L, b" \% N3 y4 Z
( o' |/ Y$ O A3 a+ l
H4 _3 Z% a7 A/ b# k0 H, i
3.4 向工程分组中添加文件
- H: j6 b* \( R- t6 G7 g* H. G
( p1 R4 p9 y5 x( d打开基础工程,新建分组FreeRTOS_CORE和FreeRTOS_PORTABLE,然后向这两个分组中添加文件。
6 k, Q' E0 @. i$ z/ l# g) C0 o
# f5 s5 O+ d+ @5 W! t% f
( B( H. d2 I7 x+ e1 y) a9 Q% o7 C5 _: `3 P' c n Q! X
FreeRTOS_CORE中的文件就在FreeRTOS目录中。FreeRTOS_PORTABLE分组中的port.c和heap_4.c是怎么来的呢?port.c是RVDS文件夹下的ARM_CM4F中的文件,因为STM32F407是Cortex-M4内核并且带有FPU,因此要选择ARM_CM4F中的port.c文件。heap_4.c是MemMang文件夹中的,里面有5个c文件:heap_1.c,heap_2.c,heap_3.c,heap_4.c,heap_5.c。这5个c文件是五种不同的内存管理方法。' {. w# C, ?. b" v. u
" _- h' l& n9 O2 m/ E9 C' C这5个文件都可以用来作为FreeRTOS的内存管理文件,只是它们的实现原理不同,各有利弊。后面我们再来讨论FreeRTOS的内存管理。, U) I; I( z' _( I! N3 Y: J1 [$ H$ E$ o3 w
* q, f6 m/ @7 h6 R" B& g r7 a3.5 添加响应的头文件路径+ I' _/ ]' H( w8 b& C8 w
- B# o; M2 s1 g" y5 S
7 {; K* I# m: b- t
2 U" t6 B8 C& Y
3.6 找不到头文件的错误5 G3 s( X, B# R% D# m' V" t
- ..\FreeRTOS\croutine.c(27): error: #5: cannot open source input file "FreeRTOS.h": No such file or directory
复制代码 6 @2 ]8 `7 \: p# Z2 r! z6 t
解决办法
, z2 k3 m& C! n* o1 b' M. j; v$ j( y2 }, q3 g& z5 L; k8 i
FreeRTOS.h头文件在FreeRTOS\include目录中。6 y2 i9 x( W; }# O. x
) a$ d/ ~" H I) }- R
/ H0 C! _( }5 Y
4 d7 x! F0 T. @ ?. ^
再次编译发现又有头文件找不到FreeRTOSConfig.h文件
3 ~3 b4 `, e$ F0 L7 A1 ^& L! M, G+ f1 ?9 E' L3 j' m
- ..\FreeRTOS\include\FreeRTOS.h(57): error: #5: cannot open source input file "FreeRTOSConfig.h": No such file or directory
复制代码
, j7 k. q6 a% C在项目文件中搜索该头文件发现找不到,这个时候我们可以找找FreeRTOS的官方移植工程汇总会不会有这个文件,打开FreeRTOS针对STM32F407的移植工程文件,文件夹是H:\02_stm32\其它资料\FreeRTOS\FreeRTOSv10.4.1\FreeRTOS\Demo\CORTEX_M4F_STM32F407ZG-SK。
0 Y L J5 g- ~( N( x
7 d( ^; q: d! a
' Q3 H7 F4 z/ r. B
+ P/ Y1 I3 X: ~: i0 t0 W找到该文件之后,我们直接将它复制到FreeRTOS源码中的include文件夹下。FreeRTOSConfig.h文件是配置文件,一般的操作系统都有裁剪、配置功能,而这些裁剪及配置都是通过一个文件来完成的,基本都是通过宏定义来完成对系统的配置和裁剪的。 [ U: Z+ z0 _$ ?( K
1 c1 c( r3 S/ h- H3.7 SystemCoreClock没有定义的错误, V- J# m5 Y/ K3 Z, c
7 t! y4 N# X! M; y ]+ D- e- ..\FreeRTOS\portable\RVDS\ARM_CM4F\port.c(732): error: #20: identifier "SystemCoreClock" is undefined
复制代码 SystemCoreClock未定义,因为在FreeRTOSConfig.h中使用了SystemCoreClock来标记MCU的频率。, i8 I) H3 k9 C
& J% w5 T1 v3 d5 w% d2 L9 j9 @6 h, B
+ }4 _3 _, T# S% T/ Y0 ?
' G/ d. z: H: @这是一个条件编译,只有定义了__ICCARM__以后下边的代码才有效。+ x1 |# W ?+ M4 e. w0 X* O
5 C; _( ^" H! j- M1 g
- /* Ensure stdint is only used by the compiler, and not the assembler. */8 W! ~( X7 {7 y5 \1 Y7 l
- #ifdef __ICCARM__
+ g; j9 M6 C- [1 A) X: j - #include <stdint.h>
& L! F. @0 V- P& Q! p/ _ - extern uint32_t SystemCoreClock;0 b$ m8 A5 K8 E C$ l4 r
- #endif
复制代码
& J! B$ G& @1 x7 x( h$ ]修改这个条件编译,修改后的代码如下:5 m! z5 |3 c8 Q- K2 W0 x( D
- /* Ensure stdint is only used by the compiler, and not the assembler. */3 z( i, q5 p8 ?) |
- #if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__)3 s' i$ M; F. P( A: ], N
- #include <stdint.h>
/ B6 D1 {9 ^1 k - extern uint32_t SystemCoreClock;
4 M; w0 v! Z! m - #endif
复制代码 a' r5 j( d- ]: A v; \& |, r
3.8 重复定义的错误, G! O/ v( |* F( f( S4 _3 Z
4 {' c, J0 ^3 t- ..\OBJ\01Test.axf: Error: L6200E: Symbol PendSV_Handler multiply defined (by port.o and stm32f4xx_it.o)." R, |8 d4 d" E3 D
- ..\OBJ\01Test.axf: Error: L6200E: Symbol SVC_Handler multiply defined (by port.o and stm32f4xx_it.o).
0 I2 V0 [% u2 q, q: i% E$ L - ..\OBJ\01Test.axf: Error: L6200E: Symbol SysTick_Handler multiply defined (by port.o and stm32f4xx_it.o).
复制代码 * p) O" Z" \: ~( w$ R7 I. _. [
port.c和stm32f4xx_it.c两个文件中有重复定义的函数:PendSV_Handler(), SVC_Handler(), SysTick_Handler()。屏蔽掉stm32f4xx_it.c中的PendSV_Handler(), SVC_Handler(), SysTick_Handler()三个函数。再次编译,发现如下未定义错误。
6 A2 x8 \# h% E! X2 }8 i
1 E7 ]( l6 D+ t& }* U3 K8 R! J/ {3.9 未定义错误) E ~( O8 U! m6 l; K5 k
( h) ?% { Z' Z8 [9 P1 s- Build started: Project: 01Test: U' n& D* r' j1 w! U/ y- D
- *** Using Compiler 'V5.06 update 6 (build 750)', folder: 'D:\Keil_v5\ARM\ARMCC\Bin'( n" K! X( ^- t. b o- s
- Build target '01Test'; K& }! L# B" u2 R p
- compiling stm32f4xx_it.c... y: \4 C$ F; f: Z) s* R
- linking...
1 T V9 T4 v! E% U! X - ..\OBJ\01Test.axf: Error: L6218E: Undefined symbol vApplicationIdleHook (referred from tasks.o).
+ ?: T1 F( y7 K5 h - ..\OBJ\01Test.axf: Error: L6218E: Undefined symbol vApplicationStackOverflowHook (referred from tasks.o).
6 a( H) W4 R/ ~7 J0 R7 I! T - ..\OBJ\01Test.axf: Error: L6218E: Undefined symbol vApplicationTickHook (referred from tasks.o).
# _9 P0 \8 }9 v0 l' J - ..\OBJ\01Test.axf: Error: L6218E: Undefined symbol vApplicationMallocFailedHook (referred from heap_4.o).7 f. @# `; N1 X5 N I4 a
- Not enough information to list image symbols.& _/ T) s9 e) k1 d4 V R7 ]
- Not enough information to list load addresses in the image map.
. x1 L$ l# }; H- {# t' D* y - Finished: 2 information, 0 warning and 4 error messages.$ @( W: L" J; v7 @( c" @6 L; n0 |
- "..\OBJ\01Test.axf" - 4 Error(s), 0 Warning(s).
2 [7 k! i* S- e8 `, W8 R# ~ - Target not created.. G& ?& s5 m9 h: y0 o( Y
- Build Time Elapsed: 00:00:05
. f& ~' I0 `& S1 u, w
复制代码 3 r( |9 \8 f! N$ n; r
发现这些未定义的函数,它们都是Hook结尾的,这些函数有个共同的名称:钩子函数,这是因为在FreeRTOSConfig.h中开启了这些钩子函数,但是没有定义这些钩子函数导致的。我们在FreeRTOSConfig.h中关闭这些钩子函数就行了,关闭的方法很简单,将相应的宏定义改为0即可。这里将宏configUSE_IDLE_HOOK、configUSE_TICK_HOOK、configUSE_MALLOC_FAILED_HOOK和configCHECK_FOR_STACK_OVERFLOW定义为0。
) C" ~+ g: j' f! N6 u5 p" e& t e# _( |" E1 I- F* A
最后编译一下,应该就没有错误了,如果还有错误的话大家自行根据错误类型查找和修改错误。$ F. ^! Y! g8 S6 v; P
' ]& g- d4 u7 P1 Z# q% F
4. SYSTEM文件修改1 e5 R$ t# A5 _2 S% k# t- u/ u% n
4.1 修改sys.h文件
; J1 Y& z1 _1 `/ X3 b% |9 f使用FreeRTOS,我们应该将宏SYSTEM_SUPPORT_OS改为1。- //0,不支持ucos
" ]$ A3 J+ c, c% d! w - //1,支持ucos
! G$ z5 R: p7 O5 A% F% R- ?# L& |8 Q% \ - #define SYSTEM_SUPPORT_OS 1 //定义系统文件夹是否支持OS
复制代码
D3 u0 D1 s* o9 F4.2 修改usart.c文件
0 c7 f9 w' N, I0 @usart.c文件修改也很简单,usart.c文件有两部分要修改,一个是添加FreeRTOS.h头文件,默认是添加的UCOS中的includes.h头文件。修改之后内容如下:
+ ?6 X4 `8 E3 Y6 W1 \ q- //如果使用ucos,则包括下面的头文件即可.) o/ k' Q9 J# F1 x2 S& N
- #if SYSTEM_SUPPORT_OS7 G% N; f9 {8 m
- #include "FreeRTOS.h" //os使用
7 S# {2 i9 R5 y! A6 x* ` - #endif
) Q3 A, K0 T9 B* s
复制代码
7 J: m% Y: K9 B( {& G修改USART1中的中断服务函数,在使用UCOS的时候需要进出中断的时候添加OSIntEnter()和OSIntExit()。使用FreeRTOS的话就不需要了,所以将这两行代码删除即可。
9 {' x- P+ Z: Z9 Q4 | H3 ^3 E
3 N5 K. }- N" o* O1 @5 u$ S/ C# T- void USART1_IRQHandler(void) //串口1中断服务程序
9 s. z6 w* E/ y, u* R" u; ?" U - {0 X# W" I6 _* n- \* P
- u8 Res;
5 F5 O$ \& v. {9 s2 P, b1 X5 x - 2 s8 m' e/ T6 y) @
- if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中断(接收到的数据必须是0x0d 0x0a结尾)
/ A7 e. ?1 @# N# R - { h% G3 ^ [1 i( O/ E+ r3 q) q
- Res =USART_ReceiveData(USART1);//(USART1->DR); //读取接收到的数据
4 u$ r* Q, N& i5 y |$ Y - * L) t7 y( U5 v
- if((USART_RX_STA&0x8000)==0)//接收未完成
1 I6 l; e3 |( w" r6 j - {% }! p( e9 k2 O( z( e0 m
- if(USART_RX_STA&0x4000)//接收到了0x0d7 B* g2 B( z" Q! t+ E, N
- {. i' ]# A/ @" `
- if(Res!=0x0a)USART_RX_STA=0;//接收错误,重新开始* y S$ S( N/ L* F4 T
- else USART_RX_STA|=0x8000; //接收完成了 + g+ T/ e% W e
- }; J1 X" B4 w; T2 J% l
- else //还没收到0X0D
5 G; _/ M+ F+ m, N - {
, H% X% h J* d8 V# Z - if(Res==0x0d)USART_RX_STA|=0x4000;
7 K5 i3 k( p; T - else8 n( ?& r" O7 g
- {- m/ G: K* C: D# E) _" i" o5 M
- USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;
, f8 T) N" ~- D4 O" u4 l7 Z - USART_RX_STA++;, Q+ _, V, b" H7 e: C! u
- if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收数据错误,重新开始接收 7 g2 k" |, j& N5 h
- }
6 @; |5 h( t' u; \! E9 } - }
9 {7 y$ m& _! m j8 |' R! a& X - }
$ G1 B. V* M% h/ O - }: M0 p7 q) A, Y1 T7 [' V
- }
复制代码
$ }* g" ?* A4 I6 I3 z$ T1 b: ?2 t4.3 修改delay.c文件
0 B6 g: j2 [ r8 O7 I% M3 Z5 ^/ `, L$ F) j+ k3 \2 s9 M `
delay.c文件修改的就比较大了,因为涉及到FreeRTOS的系统时钟,delay.c文件里面有4个函数。9 ]% X6 |0 h. l* ^" z: s2 s
- h S8 `6 V9 Q; ]5 M2 q
首先来看看SysTick_Handler(),次函数是滴答定时器的中断服务函数,代码如下:# A$ r8 U! d) ]5 S7 Q+ y( H
+ _8 S: U; M# n; G- extern void xPortSysTickHandler(void);# D/ x: R# _) E( n; P
- 2 n- O2 N, r: o* I6 J
- //systick中断服务函数,使用OS时用到. f: s0 ~4 ?; ~: i8 `1 N! S/ w$ A
- void SysTick_Handler(void); p) M/ R m$ J
- {/ A" @) x* O" \+ D- k" Q
- if(xTaskGetSchedulerState()!=taskSCHEDULER_NOT_STARTED)//系统已经运行$ {4 A& Z! |" z( U9 { d
- {
& |1 t7 `- c; @( d- A! ~ - xPortSysTickHandler();2 @# }* I: P( s
- }
6 s- G+ f- Y5 }3 e$ ]. i - }
复制代码 : S5 `* j0 p7 V! G( _% p2 D
delay_init()是用来初始化滴答定时器和延时函数,代码如下:
7 z+ o4 {3 o2 Y k; n4 G, u1 v( e' F( x$ o0 i7 ^/ C. \
- //初始化延迟函数" T5 h: O8 Z2 s0 L" ~( J
- //SYSTICK的时钟固定为AHB时钟,基础例程里面SYSTICK时钟频率为AHB/8! X0 _' S; {/ U4 D+ L9 `# ?/ z
- //这里为了兼容FreeRTOS,所以将SYSTICK的时钟频率改为AHB的频率!: ?1 H1 ]/ C N! w3 l5 M2 g; k' b [
- //SYSCLK:系统时钟频率
' _2 Y& y6 H: s% M - void delay_init(u8 SYSCLK)
0 @$ u- M) I5 G/ [* \' F) S, c - {
7 L2 C4 b/ s, l) c+ X/ l0 |* V - u32 reload;+ _% f; k$ G1 ^& J5 w( P6 E
- SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK);
& A3 N) ~8 x: u" k& c% p. T& ^ - fac_us=SYSCLK; //不论是否使用OS,fac_us都需要使用6 N( `" f: H/ ^- x+ x% ]0 H/ n
- reload=SYSCLK; //每秒钟的计数次数 单位为M* y; e+ Z8 h: P1 @% J
- reload*=1000000/configTICK_RATE_HZ; //根据configTICK_RATE_HZ设定溢出时间, o5 w' ?" d3 O! [8 Q! b8 A& L+ i
- //reload为24位寄存器,最大值:16777216,在168M下,约合0.0998s左右8 J' G* O5 v- `' Y% \
- fac_ms=1000/configTICK_RATE_HZ; //代表OS可以延时的最少单位
, j5 ^' X+ F! F4 l. C V1 U4 m" P - SysTick->CTRL|=SysTick_CTRL_TICKINT_Msk;//开启SYSTICK中断
0 d% g O9 c: g+ [: D& S - SysTick->LOAD=reload; //每1/configTICK_RATE_HZ断一次
6 J# ^' p3 G+ q7 s - SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk; //开启SYSTICK4 h+ p& _2 t3 k V! I
- }
复制代码 8 h/ O! C# v! l* `3 y( w, M }
延时函数定义如下:3 ]0 d, l2 X3 ~
2 q" T0 c# j( O+ e
- //延时nus
4 g) o0 t& f1 Z6 z - //nus:要延时的us数.
6 Z8 ^3 ]) |% x7 q# o! m: y' v - //nus:0~204522252(最大值即2^32/fac_us@fac_us=168)
9 `: u! `, E2 l! K4 F$ Y - void delay_us(u32 nus)
0 B! j0 m' m2 |5 r. m - { 3 y8 E3 u# b8 D) F& U0 r, H# J
- u32 ticks;
|4 r7 D1 H0 @: m6 Q - u32 told,tnow,tcnt=0;' G$ S( M" E: [3 B, V- e+ G8 ^" c
- u32 reload=SysTick->LOAD; //LOAD的值, Q9 R+ r5 W) f7 |
- ticks=nus*fac_us; //需要的节拍数
* W7 U6 k3 E2 Y& p/ d: N& \, O- I9 D - told=SysTick->VAL; //刚进入时的计数器值; s, f, w. k5 J0 F
- while(1)
' K' W$ [, ?! r# r% i2 W - {/ j) p8 r2 C, Y' K' x- Q W' `
- tnow=SysTick->VAL;
) q8 J& _* N g- {6 @ - if(tnow!=told)
3 S1 Y+ Y5 x2 n - {
# V# M. w2 U& v - if(tnow<told)tcnt+=told-tnow; //这里注意一下SYSTICK是一个递减的计数器就可以了.! j6 V3 s* X; E! w! f8 x
- else tcnt+=reload-tnow+told;
8 C6 ^( E! K x/ l/ S* v( ?# M - told=tnow;
y- P5 {: @ Q8 D5 X+ X - if(tcnt>=ticks)break; //时间超过/等于要延迟的时间,则退出.
+ J8 ?# w4 ^; C$ g; `/ q - }
1 T& l5 ?! N2 P! A" B - };. f1 ?. Y( j# h! s* A0 H
- }! f( m1 _) y2 Z2 _
- //延时nms" z( x' c+ O6 K' W* J
- //nms:要延时的ms数# Z N* m" F% J' K" y
- //nms:0~65535
& s) A8 C( q( H5 s4 l - void delay_ms(u32 nms)
: H5 r. J( i. h0 g* D - {* x- E# E L4 Q7 |8 C0 r+ a
- if(xTaskGetSchedulerState()!=taskSCHEDULER_NOT_STARTED)//系统已经运行
: ?9 u, M# m7 o/ t - { ) u( Z5 @* e; M' b3 G2 s
- if(nms>=fac_ms) //延时的时间大于OS的最少时间周期
l, P, x6 u$ K# j) J - {
; M# x4 z7 }( j - vTaskDelay(nms/fac_ms); //FreeRTOS延时
+ v* t" G; D1 l! i - }
+ e8 q- N7 k) l+ K0 E - nms%=fac_ms; //OS已经无法提供这么小的延时了,采用普通方式延时
8 @" G. t9 r0 C" N4 q }6 _" u7 f - }; t) i+ E; W& z# c. b& Y+ e
- delay_us((u32)(nms*1000)); //普通方式延时 p* S3 j1 _, V5 ]
- }4 e/ S4 V9 h4 t! x( ]
$ f# O; q' S" _# ?: `5 I- //延时nms,不会引起任务调度
7 O1 b [) F5 H4 u- b - //nms:要延时的ms数
/ N2 H* C% ~( K1 o: o9 s4 O& T( y - void delay_xms(u32 nms)" D0 x y& x: B) v: S. [% B5 Y
- {8 o8 O) e# X* m" s# z
- u32 i;
" Z% k* V2 w5 s6 d, x! i - for(i=0;i<nms;i++) delay_us(1000);9 a' N, W9 C, b) u& r
- }
复制代码 , g4 G3 B1 T7 Y A" E
编译之后出现如下错误9 \2 C/ p; ~8 `$ T/ Q0 U
9 y$ @0 q: w3 ] e& \
- ..\OBJ\01Test.axf: Error: L6200E: Symbol SysTick_Handler multiply defined (by port.o and delay.o).
复制代码
' \+ u' Z: f9 n _; j0 V$ `; V0 P在port.c和delay.c中有重复定义的函数,SysTick_Handler只能二选一,很明显delay.c中的SysTick_Handler()保留下来,打开FreeRTOSConfig.h文件,找到如下宏定义:! q& z% D9 N, o+ [( r0 ^8 m
- #define xPortSysTickHandler SysTick_Handler
复制代码
1 d! N6 K" u% a9 s注释上面的宏定义。
& d+ z L: W& S0 L) v
) n* x: S8 h, i# p4 [& B/ b- E/ _2 w i5. 测试程序设计& X; ~) p/ R, T" j
main.c文件( _9 j" U& K# j+ G2 h8 Y" Q+ e
# ?! U* Q* L4 k2 n
- #include "sys.h"
8 z$ s s9 T; N0 o+ ] - #include "delay.h"8 `" ~2 {6 Y$ p" _, \; V8 u
- #include "usart.h"% \+ a* ~7 J" M$ O; m
- #include "led.h"/ p" I5 ]5 K( R& @( ?6 } I/ z8 H
- #include "FreeRTOS.h"4 k* F! f' a; i$ f* U2 ^. l+ b
- #include "task.h"
! L7 f% C E, Q- C- u: | - & G: b9 Y, w5 ^2 S# a
- //任务优先级
V3 ^6 K5 L8 M/ V9 y4 O9 X8 j - #define START_TASK_PRIO 1. I8 A$ l E; a; A
- //任务堆栈大小; b+ k# s, X* }" A. E
- #define START_STK_SIZE 128
7 x2 r+ k# \" N4 F( J: |3 ~$ b - //任务句柄
% e. ^3 x& n3 q7 R - TaskHandle_t StartTask_Handler;
! w7 Q+ F2 L3 B" k9 R O; n - //任务函数
& H8 W% r, q* D) b0 \2 G1 z - void start_task(void *pvParameters);4 I$ T# W9 G) z4 r" x
- 1 R7 V3 Z$ N( J
- //任务优先级
. t6 S+ y, Q: U* J - #define LED0_TASK_PRIO 2
5 }/ t5 a8 R4 T - //任务堆栈大小9 p# }7 B' J' D9 S
- #define LED0_STK_SIZE 50
# N, e6 o% z) H! Q) ^+ Q - //任务句柄
. u) ]5 `3 C- ^, y8 G - TaskHandle_t LED0Task_Handler;" r' Y) ]2 Z# `' u* W
- //任务函数
P! z8 X- ~( @. b - void led0_task(void *pvParameters);
$ g4 `) Q" l8 I# e2 r - " l7 ?2 V: q8 }) s+ z1 ~
- //任务优先级$ \' j* s# P3 e3 h
- #define LED1_TASK_PRIO 3
T% k) W0 P% W9 O; ~# B - //任务堆栈大小
8 q" i8 ~( Y* n7 M S) w - #define LED1_STK_SIZE 503 T" A6 Z2 h1 Y$ s
- //任务句柄
# E+ |$ q5 U, Z5 `( `( C1 H- } - TaskHandle_t LED1Task_Handler;1 p6 e5 M, p( V, F
- //任务函数" N2 c/ E9 W# I) M; w) l' z
- void led1_task(void *pvParameters);
- T2 n& N, M# k* |
) F3 J6 ]- v1 @% T% M) D& Z, }/ F- //任务优先级' R3 {) ^7 V3 t& T1 Y; v$ H
- #define FLOAT_TASK_PRIO 4
' v' G8 S1 \. B2 t - //任务堆栈大小
$ F$ R ^% ?+ {! l" M6 H* Q* j - #define FLOAT_STK_SIZE 1284 G, {$ g7 {* N" {
- //任务句柄9 p& _! w9 O! _( V+ U0 r
- TaskHandle_t FLOATTask_Handler;) k4 d* S5 U8 l
- //任务函数
* r. X6 @1 r! d) L- |, H - void float_task(void *pvParameters);
" T# q3 b! A6 s - 0 a% M& C7 H4 i c
- int main(void)/ o0 F* ~; Y% e8 X$ ~
- {
2 k; o7 h1 A9 p7 m e - NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4
5 R5 ~$ n7 a) o2 } - delay_init(168); //初始化延时函数
! Y/ z( F ? X" g/ q) ^: G6 r - uart_init(115200); //初始化串口
F6 B' U0 Z7 x - LED_Init(); //初始化LED端口
4 w3 {9 j) W. e5 |; Y - , p) Y" B+ @2 m7 f3 t8 r
- //创建开始任务; P/ i2 y" @; j* F3 ^+ c, Y, r
- xTaskCreate((TaskFunction_t )start_task, //任务函数
$ r. M, @ s; U0 Q& U! @1 O8 k$ x! a& N" E - (const char* )"start_task", //任务名称! ^; k1 X' k1 D
- (uint16_t )START_STK_SIZE, //任务堆栈大小9 H# U$ X3 o$ k( B9 c
- (void* )NULL, //传递给任务函数的参数
& \7 j' J: l, R - (UBaseType_t )START_TASK_PRIO, //任务优先级
0 \) p, @0 D4 I' L- @ - (TaskHandle_t* )&StartTask_Handler); //任务句柄 ! x8 M. ]5 m! g( [
- vTaskStartScheduler(); //开启任务调度1 t7 N3 _/ i4 S1 K7 D
- }
& b' f# H$ }5 c+ b8 b3 Z5 B! }
/ ]/ e% l( X% ?$ f4 O. i- ^. O0 a- //开始任务任务函数& S9 a: J+ A" l( M' a: D: |
- void start_task(void *pvParameters)9 } j% N: _" D0 F, t8 a
- {( ^4 R2 c1 b- w) r
- taskENTER_CRITICAL(); //进入临界区
: ? B2 q- a! R7 A$ a# J - //创建LED0任务
* [' M% n2 Q1 s( b, }/ X, n - xTaskCreate((TaskFunction_t )led0_task, ; s. ?/ x' L4 \7 x
- (const char* )"led0_task",
2 H: }4 Q- U! Z2 Z8 G; c - (uint16_t )LED0_STK_SIZE,7 U2 w C$ i& f
- (void* )NULL,
" c/ M8 k1 \/ @- N- H - (UBaseType_t )LED0_TASK_PRIO,
+ E% y" E# C: V- O C9 h+ e% a - (TaskHandle_t* )&LED0Task_Handler);5 Q( p s2 a; M
- //创建LED1任务) Q0 Y v! I( l2 B+ ] O
- xTaskCreate((TaskFunction_t )led1_task,
- Z, \4 l1 p0 F; j# } - (const char* )"led1_task",' z& A2 H: j! q9 x* b2 ]) E. O
- (uint16_t )LED1_STK_SIZE,- \0 x' i- ~) r9 r! U" z* j
- (void* )NULL,
$ ?! C6 v0 W0 {; G - (UBaseType_t )LED1_TASK_PRIO,
; x1 s, ^0 y5 s5 `# U - (TaskHandle_t* )&LED1Task_Handler);) Y- C' i7 o9 q' j: m
- //浮点测试任务
5 C8 g+ c+ f7 ^3 k# | - xTaskCreate((TaskFunction_t )float_task,
0 v# U/ d* X, a6 l4 V+ Y" b - (const char* )"float_task",
7 K: W3 r( R" E/ [% y - (uint16_t )FLOAT_STK_SIZE,5 H- _( t: K U, Z* n! y
- (void* )NULL,' M+ h2 f" C3 p9 W# q+ p4 O6 F
- (UBaseType_t )FLOAT_TASK_PRIO,
: z: l! q; P3 Z) c. k - (TaskHandle_t* )&FLOATTask_Handler);
& v7 b, }+ Q4 |) N) P) z - vTaskDelete(StartTask_Handler); //删除开始任务' [: E) } g3 G0 W( Q: _6 m
- taskEXIT_CRITICAL(); //退出临界区
9 t( \$ x& ~2 S9 h! o9 q7 B. | - }
+ X3 g; j- T4 b: n2 N* W - , A& E/ F9 z8 w9 A. Q! J' x
- //LED0任务函数
, \. I6 h) ? D o+ I7 R - void led0_task(void *pvParameters)- @1 |' R3 v/ Z
- {
) S2 A) i& S& r, }& x8 E/ v3 D0 P - while(1)& d0 H# r- q. E3 \
- {9 K0 f0 g6 U: J+ C" ^; B+ U; U
- LED0=~LED0;4 Q# w' x8 s4 U$ J# W+ a
- vTaskDelay(500);
6 u$ y5 f1 B" s1 p, C1 ^4 \, a - }
/ J7 o) d9 \' h# I, F" z$ n - }
+ @) B' n3 P8 v( C: A% W% a) X4 {
% h4 E! H# T. X) n4 Q- //LED1任务函数
- T2 q+ c$ i. m+ [, V/ n3 m - void led1_task(void *pvParameters)
$ x5 p' N e; c M3 o$ ~. G. f7 f - {3 M6 s3 { \4 i8 W$ p7 |# k
- while(1)
2 @( _- n2 f J1 h - {
6 ^, T! s, A$ d: q5 g6 A+ v - LED1=0;5 L o: f' w+ y$ k- [+ M
- vTaskDelay(200);/ w% } _9 k3 V8 b: h
- LED1=1;
2 |9 Q& u: c" q6 b- h - vTaskDelay(800);) y9 B* q& O! |" n
- }/ s6 E- }$ V' b$ K
- }
- W+ i2 u$ S6 I! V - - E* S9 r3 ~% `$ c% C# c4 ]6 A
- //浮点测试任务
2 O( e! i5 G; o. t8 U; h* H0 J- ^ - void float_task(void *pvParameters) p5 P( p ]9 z! R8 T6 X
- {
; G: u. N1 m& L2 K7 Q# ] - static float float_num=0.00;9 Y1 s4 M8 L) ]4 e, F5 V- q
- while(1)
5 g2 ]) [, c( D3 R! L - {% ^1 u/ G. G7 i8 }6 Y3 o, P
- float_num+=0.01f;8 B! |4 y6 j1 H9 H- W- g
- printf("float_num的值为: %.4f\r\n",float_num);
/ G) D+ p7 V# m8 U; u - vTaskDelay(1000);
. M& k. Z" x6 a - }
7 e! _5 @2 b2 \ - }$ @+ q- N* {8 G r
复制代码
9 v2 b4 ~+ @: f( A3 K# p4 Y实验结果:
4 t3 [: i( p) p! n. t0 {! L/ R6 b
" C; A1 p p2 ]+ d0 S) B) g" RLED0和LED1开始闪烁,LED0均匀闪烁,LED1亮的时间短,灭的时间长。然后串口不断有数据输出。) I# b0 x6 U4 N
$ R- g @9 s2 r( V. Y
. m" b6 ^ M: B5 y# _* O4 a7 l( M3 Q, P: u6 F& k+ Y
|