你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】FreeRTOS移植

[复制链接]
STMCU小助手 发布时间:2022-3-27 16:00
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 [
WE_]8WG(B]SX[2SKP_@6ZQ2.png
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
@3[$A2Y(0@2GXG_P2}XV2[I.png
! |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
KW@JN5TQ]4@3D6_3AHAM)JS.png ( 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 $X]UIM1K`TWXO[5Z6X8YMKB.png
( 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
7Z6AA}Y_AUGQN9S5CQOB%SV.png 7 {; K* I# m: b- t
2 U" t6 B8 C& Y
3.6 找不到头文件的错误5 G3 s( X, B# R% D# m' V" t
  1. ..\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
$JH~[U5%OOT}96{]]@[EQ(V.png / 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
  1. ..\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 YK}9`1[T(6EC)E}@~T~OZ)2.png ' 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
  1. ..\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
]ZSA_30S`DVKZEPGF{RP802.png
+ }4 _3 _, T# S% T/ Y0 ?
' G/ d. z: H: @这是一个条件编译,只有定义了__ICCARM__以后下边的代码才有效。+ x1 |# W  ?+ M4 e. w0 X* O
5 C; _( ^" H! j- M1 g
  1. /* Ensure stdint is only used by the compiler, and not the assembler. */8 W! ~( X7 {7 y5 \1 Y7 l
  2. #ifdef __ICCARM__
    + g; j9 M6 C- [1 A) X: j
  3. #include <stdint.h>
    & L! F. @0 V- P& Q! p/ _
  4. extern uint32_t SystemCoreClock;0 b$ m8 A5 K8 E  C$ l4 r
  5. #endif
复制代码

& J! B$ G& @1 x7 x( h$ ]修改这个条件编译,修改后的代码如下:5 m! z5 |3 c8 Q- K2 W0 x( D
  1. /* Ensure stdint is only used by the compiler, and not the assembler. */3 z( i, q5 p8 ?) |
  2. #if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__)3 s' i$ M; F. P( A: ], N
  3. #include <stdint.h>
    / B6 D1 {9 ^1 k
  4. extern uint32_t SystemCoreClock;
    4 M; w0 v! Z! m
  5. #endif
复制代码
  a' r5 j( d- ]: A  v; \& |, r
3.8 重复定义的错误, G! O/ v( |* F( f( S4 _3 Z

4 {' c, J0 ^3 t
  1. ..\OBJ\01Test.axf: Error: L6200E: Symbol PendSV_Handler multiply defined (by port.o and stm32f4xx_it.o)." R, |8 d4 d" E3 D
  2. ..\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
  3. ..\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
  1. Build started: Project: 01Test: U' n& D* r' j1 w! U/ y- D
  2. *** Using Compiler 'V5.06 update 6 (build 750)', folder: 'D:\Keil_v5\ARM\ARMCC\Bin'( n" K! X( ^- t. b  o- s
  3. Build target '01Test'; K& }! L# B" u2 R  p
  4. compiling stm32f4xx_it.c...  y: \4 C$ F; f: Z) s* R
  5. linking...
    1 T  V9 T4 v! E% U! X
  6. ..\OBJ\01Test.axf: Error: L6218E: Undefined symbol vApplicationIdleHook (referred from tasks.o).
    + ?: T1 F( y7 K5 h
  7. ..\OBJ\01Test.axf: Error: L6218E: Undefined symbol vApplicationStackOverflowHook (referred from tasks.o).
    6 a( H) W4 R/ ~7 J0 R7 I! T
  8. ..\OBJ\01Test.axf: Error: L6218E: Undefined symbol vApplicationTickHook (referred from tasks.o).
    # _9 P0 \8 }9 v0 l' J
  9. ..\OBJ\01Test.axf: Error: L6218E: Undefined symbol vApplicationMallocFailedHook (referred from heap_4.o).7 f. @# `; N1 X5 N  I4 a
  10. Not enough information to list image symbols.& _/ T) s9 e) k1 d4 V  R7 ]
  11. Not enough information to list load addresses in the image map.
    . x1 L$ l# }; H- {# t' D* y
  12. Finished: 2 information, 0 warning and 4 error messages.$ @( W: L" J; v7 @( c" @6 L; n0 |
  13. "..\OBJ\01Test.axf" - 4 Error(s), 0 Warning(s).
    2 [7 k! i* S- e8 `, W8 R# ~
  14. Target not created.. G& ?& s5 m9 h: y0 o( Y
  15. 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。
  1. //0,不支持ucos
    " ]$ A3 J+ c, c% d! w
  2. //1,支持ucos
    ! G$ z5 R: p7 O5 A% F% R- ?# L& |8 Q% \
  3. #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
  1. //如果使用ucos,则包括下面的头文件即可.) o/ k' Q9 J# F1 x2 S& N
  2. #if SYSTEM_SUPPORT_OS7 G% N; f9 {8 m
  3. #include "FreeRTOS.h"        //os使用
    7 S# {2 i9 R5 y! A6 x* `
  4. #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
  1. void USART1_IRQHandler(void)                        //串口1中断服务程序
    9 s. z6 w* E/ y, u* R" u; ?" U
  2. {0 X# W" I6 _* n- \* P
  3. u8 Res;
    5 F5 O$ \& v. {9 s2 P, b1 X5 x
  4. 2 s8 m' e/ T6 y) @
  5. if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //接收中断(接收到的数据必须是0x0d 0x0a结尾)
    / A7 e. ?1 @# N# R
  6. {  h% G3 ^  [1 i( O/ E+ r3 q) q
  7.         Res =USART_ReceiveData(USART1);//(USART1->DR);        //读取接收到的数据
    4 u$ r* Q, N& i5 y  |$ Y
  8. * L) t7 y( U5 v
  9.         if((USART_RX_STA&0x8000)==0)//接收未完成
    1 I6 l; e3 |( w" r6 j
  10.         {% }! p( e9 k2 O( z( e0 m
  11.                 if(USART_RX_STA&0x4000)//接收到了0x0d7 B* g2 B( z" Q! t+ E, N
  12.                 {. i' ]# A/ @" `
  13.                         if(Res!=0x0a)USART_RX_STA=0;//接收错误,重新开始* y  S$ S( N/ L* F4 T
  14.                         else USART_RX_STA|=0x8000;        //接收完成了 + g+ T/ e% W  e
  15.                 }; J1 X" B4 w; T2 J% l
  16.                 else //还没收到0X0D
    5 G; _/ M+ F+ m, N
  17.                 {
    , H% X% h  J* d8 V# Z
  18.                         if(Res==0x0d)USART_RX_STA|=0x4000;
    7 K5 i3 k( p; T
  19.                         else8 n( ?& r" O7 g
  20.                         {- m/ G: K* C: D# E) _" i" o5 M
  21.                                 USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;
    , f8 T) N" ~- D4 O" u4 l7 Z
  22.                                 USART_RX_STA++;, Q+ _, V, b" H7 e: C! u
  23.                                 if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收数据错误,重新开始接收          7 g2 k" |, j& N5 h
  24.                         }                 
    6 @; |5 h( t' u; \! E9 }
  25.                 }
    9 {7 y$ m& _! m  j8 |' R! a& X
  26.         }                    
    $ G1 B. V* M% h/ O
  27. }: M0 p7 q) A, Y1 T7 [' V
  28. }
复制代码

$ }* 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
  1. extern void xPortSysTickHandler(void);# D/ x: R# _) E( n; P
  2. 2 n- O2 N, r: o* I6 J
  3. //systick中断服务函数,使用OS时用到. f: s0 ~4 ?; ~: i8 `1 N! S/ w$ A
  4. void SysTick_Handler(void); p) M/ R  m$ J
  5. {/ A" @) x* O" \+ D- k" Q
  6. if(xTaskGetSchedulerState()!=taskSCHEDULER_NOT_STARTED)//系统已经运行$ {4 A& Z! |" z( U9 {  d
  7. {
    & |1 t7 `- c; @( d- A! ~
  8. xPortSysTickHandler();2 @# }* I: P( s
  9. }
    6 s- G+ f- Y5 }3 e$ ]. i
  10. }
复制代码
: 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. \
  1. //初始化延迟函数" T5 h: O8 Z2 s0 L" ~( J
  2. //SYSTICK的时钟固定为AHB时钟,基础例程里面SYSTICK时钟频率为AHB/8! X0 _' S; {/ U4 D+ L9 `# ?/ z
  3. //这里为了兼容FreeRTOS,所以将SYSTICK的时钟频率改为AHB的频率!: ?1 H1 ]/ C  N! w3 l5 M2 g; k' b  [
  4. //SYSCLK:系统时钟频率
    ' _2 Y& y6 H: s% M
  5. void delay_init(u8 SYSCLK)
    0 @$ u- M) I5 G/ [* \' F) S, c
  6. {
    7 L2 C4 b/ s, l) c+ X/ l0 |* V
  7. u32 reload;+ _% f; k$ G1 ^& J5 w( P6 E
  8. SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK);
    & A3 N) ~8 x: u" k& c% p. T& ^
  9. fac_us=SYSCLK;                                                        //不论是否使用OS,fac_us都需要使用6 N( `" f: H/ ^- x+ x% ]0 H/ n
  10. reload=SYSCLK;                                                        //每秒钟的计数次数 单位为M* y; e+ Z8 h: P1 @% J
  11. reload*=1000000/configTICK_RATE_HZ;                //根据configTICK_RATE_HZ设定溢出时间, o5 w' ?" d3 O! [8 Q! b8 A& L+ i
  12. //reload为24位寄存器,最大值:16777216,在168M下,约合0.0998s左右8 J' G* O5 v- `' Y% \
  13. fac_ms=1000/configTICK_RATE_HZ;                        //代表OS可以延时的最少单位
    , j5 ^' X+ F! F4 l. C  V1 U4 m" P
  14. SysTick->CTRL|=SysTick_CTRL_TICKINT_Msk;//开启SYSTICK中断
    0 d% g  O9 c: g+ [: D& S
  15. SysTick->LOAD=reload;                                         //每1/configTICK_RATE_HZ断一次
    6 J# ^' p3 G+ q7 s
  16. SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk; //开启SYSTICK4 h+ p& _2 t3 k  V! I
  17. }
复制代码
8 h/ O! C# v! l* `3 y( w, M  }
延时函数定义如下:3 ]0 d, l2 X3 ~
2 q" T0 c# j( O+ e
  1. //延时nus
    4 g) o0 t& f1 Z6 z
  2. //nus:要延时的us数.
    6 Z8 ^3 ]) |% x7 q# o! m: y' v
  3. //nus:0~204522252(最大值即2^32/fac_us@fac_us=168)
    9 `: u! `, E2 l! K4 F$ Y
  4. void delay_us(u32 nus)
    0 B! j0 m' m2 |5 r. m
  5. {        3 y8 E3 u# b8 D) F& U0 r, H# J
  6. u32 ticks;
      |4 r7 D1 H0 @: m6 Q
  7. u32 told,tnow,tcnt=0;' G$ S( M" E: [3 B, V- e+ G8 ^" c
  8. u32 reload=SysTick->LOAD;                                //LOAD的值, Q9 R+ r5 W) f7 |
  9. ticks=nus*fac_us;                                                 //需要的节拍数
    * W7 U6 k3 E2 Y& p/ d: N& \, O- I9 D
  10. told=SysTick->VAL;                                        //刚进入时的计数器值; s, f, w. k5 J0 F
  11. while(1)
    ' K' W$ [, ?! r# r% i2 W
  12. {/ j) p8 r2 C, Y' K' x- Q  W' `
  13. tnow=SysTick->VAL;
    ) q8 J& _* N  g- {6 @
  14. if(tnow!=told)
    3 S1 Y+ Y5 x2 n
  15. {
    # V# M. w2 U& v
  16. if(tnow<told)tcnt+=told-tnow;        //这里注意一下SYSTICK是一个递减的计数器就可以了.! j6 V3 s* X; E! w! f8 x
  17. else tcnt+=reload-tnow+told;
    8 C6 ^( E! K  x/ l/ S* v( ?# M
  18. told=tnow;
      y- P5 {: @  Q8 D5 X+ X
  19. if(tcnt>=ticks)break;                        //时间超过/等于要延迟的时间,则退出.
    + J8 ?# w4 ^; C$ g; `/ q
  20. }
    1 T& l5 ?! N2 P! A" B
  21. };. f1 ?. Y( j# h! s* A0 H
  22. }! f( m1 _) y2 Z2 _
  23. //延时nms" z( x' c+ O6 K' W* J
  24. //nms:要延时的ms数# Z  N* m" F% J' K" y
  25. //nms:0~65535
    & s) A8 C( q( H5 s4 l
  26. void delay_ms(u32 nms)
    : H5 r. J( i. h0 g* D
  27. {* x- E# E  L4 Q7 |8 C0 r+ a
  28. if(xTaskGetSchedulerState()!=taskSCHEDULER_NOT_STARTED)//系统已经运行
    : ?9 u, M# m7 o/ t
  29. {        ) u( Z5 @* e; M' b3 G2 s
  30. if(nms>=fac_ms)                                                //延时的时间大于OS的最少时间周期
      l, P, x6 u$ K# j) J
  31. {
    ; M# x4 z7 }( j
  32. vTaskDelay(nms/fac_ms);                         //FreeRTOS延时
    + v* t" G; D1 l! i
  33. }
    + e8 q- N7 k) l+ K0 E
  34. nms%=fac_ms;                                                //OS已经无法提供这么小的延时了,采用普通方式延时
    8 @" G. t9 r0 C" N4 q  }6 _" u7 f
  35. }; t) i+ E; W& z# c. b& Y+ e
  36. delay_us((u32)(nms*1000));                                //普通方式延时  p* S3 j1 _, V5 ]
  37. }4 e/ S4 V9 h4 t! x( ]

  38. $ f# O; q' S" _# ?: `5 I
  39. //延时nms,不会引起任务调度
    7 O1 b  [) F5 H4 u- b
  40. //nms:要延时的ms数
    / N2 H* C% ~( K1 o: o9 s4 O& T( y
  41. void delay_xms(u32 nms)" D0 x  y& x: B) v: S. [% B5 Y
  42. {8 o8 O) e# X* m" s# z
  43. u32 i;
    " Z% k* V2 w5 s6 d, x! i
  44. for(i=0;i<nms;i++) delay_us(1000);9 a' N, W9 C, b) u& r
  45. }
复制代码
, g4 G3 B1 T7 Y  A" E
编译之后出现如下错误9 \2 C/ p; ~8 `$ T/ Q0 U
9 y$ @0 q: w3 ]  e& \
  1. ..\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
  1. #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
  1. #include "sys.h"
    8 z$ s  s9 T; N0 o+ ]
  2. #include "delay.h"8 `" ~2 {6 Y$ p" _, \; V8 u
  3. #include "usart.h"% \+ a* ~7 J" M$ O; m
  4. #include "led.h"/ p" I5 ]5 K( R& @( ?6 }  I/ z8 H
  5. #include "FreeRTOS.h"4 k* F! f' a; i$ f* U2 ^. l+ b
  6. #include "task.h"
    ! L7 f% C  E, Q- C- u: |
  7. & G: b9 Y, w5 ^2 S# a
  8. //任务优先级
      V3 ^6 K5 L8 M/ V9 y4 O9 X8 j
  9. #define START_TASK_PRIO                1. I8 A$ l  E; a; A
  10. //任务堆栈大小; b+ k# s, X* }" A. E
  11. #define START_STK_SIZE                 128
    7 x2 r+ k# \" N4 F( J: |3 ~$ b
  12. //任务句柄
    % e. ^3 x& n3 q7 R
  13. TaskHandle_t StartTask_Handler;
    ! w7 Q+ F2 L3 B" k9 R  O; n
  14. //任务函数
    & H8 W% r, q* D) b0 \2 G1 z
  15. void start_task(void *pvParameters);4 I$ T# W9 G) z4 r" x
  16. 1 R7 V3 Z$ N( J
  17. //任务优先级
    . t6 S+ y, Q: U* J
  18. #define LED0_TASK_PRIO                2
    5 }/ t5 a8 R4 T
  19. //任务堆栈大小9 p# }7 B' J' D9 S
  20. #define LED0_STK_SIZE                 50
    # N, e6 o% z) H! Q) ^+ Q
  21. //任务句柄
    . u) ]5 `3 C- ^, y8 G
  22. TaskHandle_t LED0Task_Handler;" r' Y) ]2 Z# `' u* W
  23. //任务函数
      P! z8 X- ~( @. b
  24. void led0_task(void *pvParameters);
    $ g4 `) Q" l8 I# e2 r
  25. " l7 ?2 V: q8 }) s+ z1 ~
  26. //任务优先级$ \' j* s# P3 e3 h
  27. #define LED1_TASK_PRIO                3
      T% k) W0 P% W9 O; ~# B
  28. //任务堆栈大小
    8 q" i8 ~( Y* n7 M  S) w
  29. #define LED1_STK_SIZE                 503 T" A6 Z2 h1 Y$ s
  30. //任务句柄
    # E+ |$ q5 U, Z5 `( `( C1 H- }
  31. TaskHandle_t LED1Task_Handler;1 p6 e5 M, p( V, F
  32. //任务函数" N2 c/ E9 W# I) M; w) l' z
  33. void led1_task(void *pvParameters);
    - T2 n& N, M# k* |

  34. ) F3 J6 ]- v1 @% T% M) D& Z, }/ F
  35. //任务优先级' R3 {) ^7 V3 t& T1 Y; v$ H
  36. #define FLOAT_TASK_PRIO                4
    ' v' G8 S1 \. B2 t
  37. //任务堆栈大小
    $ F$ R  ^% ?+ {! l" M6 H* Q* j
  38. #define FLOAT_STK_SIZE                 1284 G, {$ g7 {* N" {
  39. //任务句柄9 p& _! w9 O! _( V+ U0 r
  40. TaskHandle_t FLOATTask_Handler;) k4 d* S5 U8 l
  41. //任务函数
    * r. X6 @1 r! d) L- |, H
  42. void float_task(void *pvParameters);
    " T# q3 b! A6 s
  43. 0 a% M& C7 H4 i  c
  44. int main(void)/ o0 F* ~; Y% e8 X$ ~
  45. {
    2 k; o7 h1 A9 p7 m  e
  46. NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4
    5 R5 ~$ n7 a) o2 }
  47. delay_init(168);                //初始化延时函数
    ! Y/ z( F  ?  X" g/ q) ^: G6 r
  48. uart_init(115200);             //初始化串口
      F6 B' U0 Z7 x
  49. LED_Init();                        //初始化LED端口
    4 w3 {9 j) W. e5 |; Y
  50. , p) Y" B+ @2 m7 f3 t8 r
  51. //创建开始任务; P/ i2 y" @; j* F3 ^+ c, Y, r
  52. xTaskCreate((TaskFunction_t )start_task,            //任务函数
    $ r. M, @  s; U0 Q& U! @1 O8 k$ x! a& N" E
  53.             (const char*    )"start_task",          //任务名称! ^; k1 X' k1 D
  54.             (uint16_t       )START_STK_SIZE,        //任务堆栈大小9 H# U$ X3 o$ k( B9 c
  55.             (void*          )NULL,                  //传递给任务函数的参数
    & \7 j' J: l, R
  56.             (UBaseType_t    )START_TASK_PRIO,       //任务优先级
    0 \) p, @0 D4 I' L- @
  57.             (TaskHandle_t*  )&StartTask_Handler);   //任务句柄            ! x8 M. ]5 m! g( [
  58. vTaskStartScheduler();          //开启任务调度1 t7 N3 _/ i4 S1 K7 D
  59. }
    & b' f# H$ }5 c+ b8 b3 Z5 B! }

  60. / ]/ e% l( X% ?$ f4 O. i- ^. O0 a
  61. //开始任务任务函数& S9 a: J+ A" l( M' a: D: |
  62. void start_task(void *pvParameters)9 }  j% N: _" D0 F, t8 a
  63. {( ^4 R2 c1 b- w) r
  64. taskENTER_CRITICAL();           //进入临界区
    : ?  B2 q- a! R7 A$ a# J
  65. //创建LED0任务
    * [' M% n2 Q1 s( b, }/ X, n
  66. xTaskCreate((TaskFunction_t )led0_task,   ; s. ?/ x' L4 \7 x
  67. (const char*    )"led0_task",   
    2 H: }4 Q- U! Z2 Z8 G; c
  68. (uint16_t       )LED0_STK_SIZE,7 U2 w  C$ i& f
  69. (void*          )NULL,                        
    " c/ M8 k1 \/ @- N- H
  70. (UBaseType_t    )LED0_TASK_PRIO,
    + E% y" E# C: V- O  C9 h+ e% a
  71. (TaskHandle_t*  )&LED0Task_Handler);5 Q( p  s2 a; M
  72. //创建LED1任务) Q0 Y  v! I( l2 B+ ]  O
  73. xTaskCreate((TaskFunction_t )led1_task,
    - Z, \4 l1 p0 F; j# }
  74. (const char*    )"led1_task",' z& A2 H: j! q9 x* b2 ]) E. O
  75. (uint16_t       )LED1_STK_SIZE,- \0 x' i- ~) r9 r! U" z* j
  76. (void*          )NULL,
    $ ?! C6 v0 W0 {; G
  77. (UBaseType_t    )LED1_TASK_PRIO,
    ; x1 s, ^0 y5 s5 `# U
  78. (TaskHandle_t*  )&LED1Task_Handler);) Y- C' i7 o9 q' j: m
  79. //浮点测试任务
    5 C8 g+ c+ f7 ^3 k# |
  80. xTaskCreate((TaskFunction_t )float_task,
    0 v# U/ d* X, a6 l4 V+ Y" b
  81. (const char*    )"float_task",
    7 K: W3 r( R" E/ [% y
  82. (uint16_t       )FLOAT_STK_SIZE,5 H- _( t: K  U, Z* n! y
  83. (void*          )NULL,' M+ h2 f" C3 p9 W# q+ p4 O6 F
  84. (UBaseType_t    )FLOAT_TASK_PRIO,
    : z: l! q; P3 Z) c. k
  85. (TaskHandle_t*  )&FLOATTask_Handler);
    & v7 b, }+ Q4 |) N) P) z
  86. vTaskDelete(StartTask_Handler); //删除开始任务' [: E) }  g3 G0 W( Q: _6 m
  87. taskEXIT_CRITICAL();            //退出临界区
    9 t( \$ x& ~2 S9 h! o9 q7 B. |
  88. }
    + X3 g; j- T4 b: n2 N* W
  89. , A& E/ F9 z8 w9 A. Q! J' x
  90. //LED0任务函数
    , \. I6 h) ?  D  o+ I7 R
  91. void led0_task(void *pvParameters)- @1 |' R3 v/ Z
  92. {
    ) S2 A) i& S& r, }& x8 E/ v3 D0 P
  93. while(1)& d0 H# r- q. E3 \
  94. {9 K0 f0 g6 U: J+ C" ^; B+ U; U
  95. LED0=~LED0;4 Q# w' x8 s4 U$ J# W+ a
  96. vTaskDelay(500);
    6 u$ y5 f1 B" s1 p, C1 ^4 \, a
  97. }
    / J7 o) d9 \' h# I, F" z$ n
  98. }
    + @) B' n3 P8 v( C: A% W% a) X4 {

  99. % h4 E! H# T. X) n4 Q
  100. //LED1任务函数
    - T2 q+ c$ i. m+ [, V/ n3 m
  101. void led1_task(void *pvParameters)
    $ x5 p' N  e; c  M3 o$ ~. G. f7 f
  102. {3 M6 s3 {  \4 i8 W$ p7 |# k
  103. while(1)
    2 @( _- n2 f  J1 h
  104. {
    6 ^, T! s, A$ d: q5 g6 A+ v
  105. LED1=0;5 L  o: f' w+ y$ k- [+ M
  106. vTaskDelay(200);/ w% }  _9 k3 V8 b: h
  107. LED1=1;
    2 |9 Q& u: c" q6 b- h
  108. vTaskDelay(800);) y9 B* q& O! |" n
  109. }/ s6 E- }$ V' b$ K
  110. }
    - W+ i2 u$ S6 I! V
  111. - E* S9 r3 ~% `$ c% C# c4 ]6 A
  112. //浮点测试任务
    2 O( e! i5 G; o. t8 U; h* H0 J- ^
  113. void float_task(void *pvParameters)  p5 P( p  ]9 z! R8 T6 X
  114. {
    ; G: u. N1 m& L2 K7 Q# ]
  115. static float float_num=0.00;9 Y1 s4 M8 L) ]4 e, F5 V- q
  116. while(1)
    5 g2 ]) [, c( D3 R! L
  117. {% ^1 u/ G. G7 i8 }6 Y3 o, P
  118. float_num+=0.01f;8 B! |4 y6 j1 H9 H- W- g
  119. printf("float_num的值为: %.4f\r\n",float_num);
    / G) D+ p7 V# m8 U; u
  120. vTaskDelay(1000);
    . M& k. Z" x6 a
  121. }
    7 e! _5 @2 b2 \
  122. }$ @+ 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
赞 收藏 评论0 发布时间:2022-3-27 16:00

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版