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