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

【经验分享】STM32使用HAL库手动移植FreeRTOS10.4.1

[复制链接]
STMCU小助手 发布时间:2022-4-10 19:56
(一)裸机工程创建  @' e; O5 z( W& j2 z6 F$ E, K& o) f/ p
使用STM32CubeMX创建裸机工程:
: \5 J. m% U' c% u  R- t( O% s' r4 R/ G
这里我是用的芯片是STM32F103RBT6,时钟主频为72MHz,配置时钟树:% m% T! J! h* \. i1 X

( e. R; x9 U) v! S [HJAIVR6Y8OGG98AS[H.png
. z9 X0 S, ~# p
- y& U# \9 M% q0 g: h配置调试串口1:" P% d, r6 X, l3 X" i

( A* j8 G+ T: P" g+ v M8_G2}7WA8CT@ZUVG}0@R`0.png
- F. F7 e1 r/ ?9 x! C
$ L; T- Y) s) w6 K6 Q! g配置两个LED灯:, Y  l. X6 x0 Q/ Y- H
3 \/ i% h' k: E2 t, N$ J% H
20201010162500610.png
  X4 F9 g8 @  u- t: i0 ]* z# J" x6 B7 ?) _" q+ E! P
由于FreeRTOS使用系统嘀嗒定时器当作心跳,HAL库也使用了这个定时器当作超时计数用,FreeRTOS和HAL库不能同时使用SysTick定时器,所在在这里将HAL库的定时器改为其他的定时器,我改成了定时器4:( y+ w9 d) F1 o! L6 Y

) Z0 H5 l( w" w* E' s ZW]AZRZ6{KK3FJ9V~Y{}D~Q.png
5 b" I, [+ S8 l: \/ ^1 _5 G2 k2 }
$ t$ `! Z! y/ B配置中断,注意这里一定要选择组4,也就是全部为抢占优先级:
8 H) c1 s! Z' ]% d# K0 ?  m8 x
2 g" V# V2 D  n2 j( u& V4 Q ANO~JLI_}E$E1]8B6U78I[X.png + ^( J; b' z! U7 o1 x
% Z( o, R6 W% i0 W9 L/ y
输出工程:
! o+ Y: a8 m( y  ^* I' ^. p) K. {* D- b% Y
20201010162753196.png / @6 e( l" J% y
20201010162833214.png
0 _; A/ Q1 v0 V+ [! {& p5 E6 f1 q0 Z; K. O7 V* w/ z

$ T$ Y' b+ V+ u" ^" n: d(二)移植FreeRTOS6 c$ Z8 C, Y$ ^# ?! f2 h
! `: X' Y* x3 V% X
解压FreeRTOS源码包有如下文件结构:) a1 M7 u# i4 r/ T. O

0 u2 W' z1 U7 T) y% i3 z) l/ Y+ X 7L$%8]J0YCQ2N2IE`HG1PJN.png
, h6 \9 y) r* ]; \8 {
8 }, o  r. Z8 x0 c) x+ k. ?- h在Keil工程目录下新建FreeRTOS文件夹用于存放freertos的源码。/ J7 [1 I7 X7 Z" m( Z$ x
4 J$ p6 D" W2 }. C6 }
拷贝FreeRTOS/Source/文件夹内的以下文件,放入keil工程目录FreeRTOS文件夹内,效果如下图:
8 x' G7 L8 k: T# W$ L: H* t1 @# R2 |- I. e! @4 Y% H3 Z- H
2~65A5@GXSM$QGGM2S885GU.png
6 e% R5 g6 e/ R! ?. ]/ h& j, n
0 D, s$ X# A" X在Keil中将FreeRTOS源码加入到工程内:
0 b  u8 j6 T; ]  q& I
6 L7 T( i) p' q/ e" U! h 0]DPJOU3QX3U0ZAN46OSQ04.png ; J  @8 V5 Y# U9 ~! y8 c
; k* O+ h1 u+ y6 V: M
打开stm32f1xx_it.c文件,在头部添加FreeRTOS的三个函数导入:
  1. extern void xPortPendSVHandler(void);
    ; W( J/ a  A' q$ s. o* p6 }
  2. extern void xPortSysTickHandler(void);+ y) T9 i' X. T' E( B: `
  3. extern void vPortSVCHandler(void);
复制代码

$ {: D3 v8 F, q$ l- G0 ?* r 3DC746)588]2)A%~F[L%ERS.png 4 T/ i, J# c2 e2 o2 t5 E6 ?

1 N& k, B- v( [& E: o. @; L; }) d在函数SVC_Handler中添加函数调用:
0 T  Y, e# }( y' F
) O2 J( Y; y1 H; O/ z5 Z 20201010165147723.png 1 p! ?5 i% f$ b& q) L+ B
# p  j& }  w! f' m- c
在函数PendSV_Handler中添加函数调用:
$ U* v2 \) T& [' H- |- N+ _8 f
# U4 u7 Y; y! ^# D+ y 20201010165237842.png ( _# Z" o& ?: u
, j) t# R6 ]9 v+ W/ x
在函数SysTick_Handler中添加函数调用:
4 ~4 D( m, _: R( n7 T# Y
: C: f" l% J  x6 V, h( [ O[VQ{YF9{KZOLWVE[9O(OGN.png * Y" G$ [# S/ s2 @& T% m+ ]
9 y1 m4 \  \0 r/ V3 D7 I/ V* p  R
新建一个名为FreeRTOSConfig.h的文件,这是FreeRTOS的配置文件,这里我贴一个我配置的:
% k' X) p' ]$ A9 a- P$ u) f, w: l2 x& ?  D% F, V
  1. #ifndef FREERTOS_CONFIG_H__
    7 _( B$ v- ]/ M( L+ x
  2. #define FREERTOS_CONFIG_H__3 `1 \6 H; Q" ?. W# s- n8 w
  3. # f2 W" V6 V- [, k
  4. /*
    ) E" X* q, H8 _* k

  5. 9 o' a; D3 j, n8 J1 Y' T: q
  6. */1 d% m- D% w/ Q# l5 O

  7. # u4 r# ^" @3 j# s
  8. // 设置为1使用抢占式,为0使用时间片轮转调度。
    7 R( D) Q3 W' _# d9 M
  9. #define configUSE_PREEMPTION                    1
    8 V) T: ]5 P9 Y) P! I9 T

  10.   Q: O" W; U# j) V' P- L
  11. // 设置为1使能低功耗tickless模式,为0保持系统节拍(tick)中断一直运行。; t, y) z" B1 K! L
  12. #define configUSE_TICKLESS_IDLE                 0  ^* c1 D+ U& b6 v8 ^/ F) C

  13. 0 b) D* C) }/ A% T5 u) P
  14. // 系统时钟主频
    % q$ @. d1 g# z$ b% M9 H
  15. #define configCPU_CLOCK_HZ                      72000000* H* B: t  m& _
  16. # V) f  L7 B; x
  17. // 系统节拍中断的频率,即1s进中断的次数,配置为1000就是一秒进1000次中断,系统节拍就是1s。
    1 K, H* ^% B2 S4 i- h% e' ~
  18. #define configTICK_RATE_HZ                      1000
    ! J! o% @2 p% f2 W" d$ T
  19.   r, z. r' }8 e* u
  20. // 任务最大优先级,对于STM32来说最大不要超过32
    5 J# u& M; {. u4 e1 V$ Y
  21. #define configMAX_PRIORITIES                    32
    + e% t/ |+ p. u2 W& Q+ N% O3 a
  22. - R5 t7 m# R/ `: [/ r# [
  23. // 任务最小栈大小( h& c$ c  r+ t# v
  24. #define configMINIMAL_STACK_SIZE                64/ N# V3 \; i) g

  25. 0 _! E% C: `! X! }4 V  P! e
  26. // FreeRTOR堆空间大小: i8 P: V/ j- |7 J/ Q9 d! G  n5 X
  27. #define configTOTAL_HEAP_SIZE                   8192: g* Z4 X( }0 x. h) J
  28. 1 h: y9 M; f" z- M7 @
  29. // 任务名称最大长度8 i2 o( L% I( \# Z' @: a/ h% J% M
  30. #define configMAX_TASK_NAME_LEN                 16( G: o" i# _" x1 A, E" u; K: z$ J
  31. . k+ E7 a  y. x
  32. // 系统节拍计数器的变量类型,即定义portTickType是表示16位变量还是32位变量。
    + l; |8 W2 A; v* Y# t) E
  33. #define configUSE_16_BIT_TICKS                  0
    ; j0 }+ w& `$ ~6 e$ u, ]% u3 Y8 Q
  34. + F; U0 j1 d) Q# k% y% R& V9 Q
  35. // 设置为1允许任务调度,为0不允许(时间片耗尽才让出CPU使用权),该参数抢占式方式下才生效
    / N0 S7 H+ S+ y8 H# q) o
  36. #define configIDLE_SHOULD_YIELD                 14 c5 _! ?1 K& [3 z

  37. 3 [5 G- Z6 o- @6 I' h
  38. // 设置是否使用互斥量2 ^! K. a, J" x( c. d6 g, Q9 l" v
  39. #define configUSE_MUTEXES                       1
    * Z( t8 E7 H3 ~. J1 ]$ O0 e. H

  40. , k$ q. b5 S5 G/ E- J
  41. // 设置是否使用递归互斥量$ K! Y) h* X" r
  42. #define configUSE_RECURSIVE_MUTEXES             0' V3 I* h; m, T: m6 W! c; p
  43. + y9 X& K( L) E- _, v
  44. // 设置是否使用计数信号量
    6 }" t* n# W8 i5 _, j: G
  45. #define configUSE_COUNTING_SEMAPHORES           0
    2 F& @+ t* C1 {5 y: W+ s
  46. * P! [8 c0 A1 v9 P9 z" N* G4 T
  47. // 设置可以记录的队列和信号量的最大数目
    8 C4 M3 o5 u& b" M
  48. #define configQUEUE_REGISTRY_SIZE               10
    / C/ s2 E) {/ |, w  t# v

  49. : k- Y0 ^  O# w- y9 L2 |! a- e
  50. // 是否使用空闲钩子函数
    : }" u/ W7 E: L3 }" y4 o
  51. #define configUSE_IDLE_HOOK                     0
    1 A1 e% ]) e9 c6 o1 T

  52. 3 l+ W: u, }/ [/ P
  53. // 是否使用TICK嘀嗒钩子函数  \8 {7 m8 _* H2 v
  54. #define configUSE_TICK_HOOK                     0& {% Q6 o0 ^( w: S

  55. 8 X0 y4 d0 }2 q! H- H2 W" I9 j2 r
  56. // 是否使用栈溢出检查  U' w; i; M+ U$ w
  57. #define configCHECK_FOR_STACK_OVERFLOW          0
    % M5 b7 `8 d* d+ ?" ]/ s$ _; n  V

  58. * N, t& T9 [$ v' O
  59. // 是否使用内存申请失败钩子函数
      i7 `5 S' j' m8 O! M% R
  60. #define configUSE_MALLOC_FAILED_HOOK            0
    ( z! a( G  o3 X- [5 g3 k- @- y& d
  61.   Q* |; I5 S. V" N) {
  62. // 是否使用软件定时器
    - s3 D, r! C2 r# ^: p5 u  e
  63. #define configUSE_TIMERS                        1
    0 p6 k! D+ _" P* d# z; n! v
  64. 4 [. U" g! \4 h
  65. // 设置软件定时器服务/守护进程的优先级4 F) p& X' _9 {" \6 q
  66. #define configTIMER_TASK_PRIORITY               3
    & p6 o  [6 ]+ p( {/ {- y
  67. 8 Q! X; _# `, B& q7 V; X
  68. // 设置软件定时器命令队列的长度
    / g% Q- G$ N$ k9 {' r# S0 e
  69. #define configTIMER_QUEUE_LENGTH                10
    ' s. N% l/ V9 e. H. s- L

  70. 0 D  o1 Y8 d- w+ H+ f3 [, z: ^4 r
  71. // 设置软件定时器服务/守护进程任务的堆栈深度
    - r" ^! p4 L. u( v( s  x
  72. #define configTIMER_TASK_STACK_DEPTH            configMINIMAL_STACK_SIZE4 y. T% s2 G# V1 n) e

  73. 9 @' V1 G# H8 \0 C: B# @
  74. // STM32的最低优先级/ i  z3 j: q+ j6 y( Y/ ?; m! p. D
  75. #define configLIBRARY_LOWEST_INTERRUPT_PRIORITY   15
    - w9 {- k# U. r( [; u$ L- ~6 I8 P

  76. 7 ]. n: S9 S8 K! V* d" _$ h
  77. // 能够在中断服务函数中安全调用FreeRTOS API的中断最低优先级, }  \* Z8 _! k% ~  @$ ^$ n* W0 P9 J
  78. #define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 1& G+ i' ]. ~( K6 v% N# b

  79. 2 k9 d9 Q& N: E$ S6 p
  80. #define configKERNEL_INTERRUPT_PRIORITY                 ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << 4 )
    - U% R. F- y8 y4 p# j& E9 Z+ P
  81. #define configMAX_SYSCALL_INTERRUPT_PRIORITY         ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << 4 )  L" G6 T+ N% n) A" S0 R
  82. + z8 d8 f6 r$ B1 c& L

  83. 7 E) ^6 [5 X& P2 D' j: y- j5 s
  84. // 将以下定义设置为1以包含API函数,或设置为0排除API函数
    8 R* X' B+ D5 C  ^) C  M; x: Y
  85. #define INCLUDE_vTaskPrioritySet                1" ^+ b) \1 Z+ Y% R# N) P4 D
  86. #define INCLUDE_uxTaskPriorityGet               1* [6 v0 l) M6 K% E7 E) P) f9 X  d$ `
  87. #define INCLUDE_vTaskDelete                     1
    4 G0 t/ S- `, b
  88. #define INCLUDE_vTaskSuspend                    1
    # u: F2 E5 S2 b3 i9 K
  89. #define INCLUDE_xResumeFromISR                  1
    ! V/ Y9 _4 \( Q7 p3 _
  90. #define INCLUDE_vTaskDelayUntil                 1
    1 c3 o$ I, p9 m( m. R
  91. #define INCLUDE_vTaskDelay                      1
    " b7 g) T% O5 d5 g, _+ }: v
  92. #define INCLUDE_xTaskGetSchedulerState          1# z- r0 l0 L4 h
  93. #define INCLUDE_xTaskGetCurrentTaskHandle       1) c  H: M8 B/ B9 t4 S6 d) W
  94. #define INCLUDE_uxTaskGetStackHighWaterMark     0
    6 [0 f: W5 r0 G- d+ Y! b5 D
  95. #define INCLUDE_xTaskGetIdleTaskHandle          0( ]* @/ C; r+ H/ d! [, l: ^0 G8 J
  96. #define INCLUDE_xTimerGetTimerDaemonTaskHandle  0/ U2 x) l: r: ~/ D1 x
  97. #define INCLUDE_pcTaskGetTaskName               0. V) Z2 u- C  b* I
  98. #define INCLUDE_eTaskGetState                   0/ a9 Q3 \2 R+ D
  99. #define INCLUDE_xEventGroupSetBitFromISR        1
    2 I" J$ v  Z' [+ s, Q
  100. #define INCLUDE_xTimerPendFunctionCall          0# N! A( ^% q' u& t2 K4 Z0 C1 a
  101. - w1 s" I, u' b1 b% S
  102. #endif  /* FREERTOS_CONFIG_H__ */" r" t5 ^1 o* x" K1 G6 I: X
复制代码

, A! R; n7 l9 i' }, z7 ~3 w修改main.c文件,添加头文件:
: `7 u* F3 y- |! a0 m& Z9 O, }& p0 @4 I
  1. #include "FreeRTOSConfig.h"7 F3 w" U* \6 H3 r# G& F+ q2 F
  2. #include "FreeRTOS.h"& G: V2 q' Z5 N5 C
  3. #include "task.h"
复制代码

0 e* g% V, ^8 }  Y+ S这里我创建了三个任务,任务一为led1灯每间隔500ms闪烁一次,任务二led2每间隔300ms闪烁一次,任务三为串口每隔1s打印一次helloworld。
- [5 S5 E. a0 u. U6 x; L  d4 O5 P: w
2 f* k/ c3 F- p
" r9 x$ l  j- x3 v3 p/ e7 C6 u
  1. void led1_task(void* arg)
    * T4 s8 D6 i8 e" f
  2. {! s# g0 L( z9 T+ K: Q8 g3 a
  3.     while(1)
      x! g2 R9 h( ]" T0 t0 `; l$ n  R5 u5 N$ j
  4.     {- A; T) [+ h+ C& O$ u, s2 T
  5.         HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_8);
    * G9 n# J& ^$ B2 L: p9 U  }, t
  6.         vTaskDelay(500);$ Q; {1 L, Z8 W  v
  7.     }
    ; R' Q3 V4 C# ?, S
  8. }, N7 J9 I& `# n  f2 h1 A
  9. 8 U5 @6 o5 i7 Q
  10. void led2_task(void* arg)4 D6 X2 X7 v8 u
  11. {4 H) {, f/ x8 h7 c
  12.     while(1)8 t  K, ?& z, o$ s4 B1 k0 w5 C' }
  13.     {
    $ z& a6 o( ^& A: @
  14.         HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_2);6 g. g4 c5 W9 _/ u/ e: i: b
  15.         vTaskDelay(300);+ Y& l; ]$ r7 c" J) K7 a- p
  16.     }
    # L' O( I3 y& W& I" x; i& X
  17. }" c$ H" @1 n; d6 ?8 s

  18. - Y  [8 q& T1 z1 Y$ }0 |1 O# |2 M6 ~
  19. void print_task(void* arg)' H6 N1 X' |0 _8 `4 Q+ S" v& \5 A
  20. {
    + y1 a7 }" V4 w- x5 ]
  21.     while(1)
    . q  g) @# y& c
  22.     {
    & I* E* F$ h7 a, J  t* l# _: g2 z
  23.         HAL_UART_Transmit(&huart1, (uint8_t *)"HelloWorld\r\n", 12, 100);  @3 X$ p2 ~* E1 X9 q: p& _
  24.         vTaskDelay(1000);
    # d. N7 E" S/ g/ G  _9 v
  25.     }4 \" O0 H* Z+ X$ C- X6 {& Q7 `
  26. }
    & g- w8 ~6 K6 L( v1 @& e

  27. " s) `9 K  c3 Z  [
  28. int main(void)* M8 @/ C; O5 E
  29. {
    , |' w& i' h  z. Z
  30.     HAL_Init();
    ( p1 p7 r; W1 D( a3 ^% x
  31.     SystemClock_Config();5 X3 D( }0 W% H( F
  32.     MX_GPIO_Init();
    ) Z! l6 f: `. G( E1 u& m' P: C$ j
  33.     MX_USART1_UART_Init();4 i; {( }) I- z$ w
  34. * r' _9 v7 O8 c( [7 \9 E) F& G
  35.         // xTaskCreate函数参数说明:
    & @4 ]6 F9 P9 i9 U* r# z; P
  36.         // 1、任务入口函数! M4 Y" j7 W: V! |
  37.         // 2、任务名称# M' Z/ {' {7 E" ~: \0 E2 {! y
  38.         // 3、堆栈大小,单位word, ^: E) }- M& p
  39.         // 4、传递给任务的参数/ I1 {/ ?6 c/ [" `- `3 b6 o
  40.         // 5、任务优先级; w7 m. z9 N8 f; u. _3 P5 z* Z
  41.         // 6、任务句柄
    9 Z# j, Y9 T7 [  D* {
  42.         
    5 h! `5 d( X( G; |7 T/ B
  43.         // 创建任务led1灯任务- h% w( u- `& m' @" P
  44.     xTaskCreate(led1_task, "led1_task", 64, NULL, 3, NULL);
    2 x( ]1 \1 n8 w1 Q
  45.         ( k9 f) i/ r8 e+ R
  46.         // 创建任务led2灯任务
    " c# u+ K; d! s
  47.         xTaskCreate(led2_task, "led2_task", 64, NULL, 4, NULL);
    ( Y2 Z; V, V) m/ m& C' f4 k
  48.         6 J( y2 m  _! }
  49.         // 创建串口打印任务( @$ B" Y; \! {5 w$ q1 z5 C
  50.     xTaskCreate(print_task, "print_task", 128, NULL, 5, NULL);' c3 i4 b2 A( `+ p; d0 I# K

  51. ( e$ U/ T0 K' @4 w1 P
  52.         // 启动任务调度
    & p' Y+ _/ _. v* }! O* Q1 o
  53.     vTaskStartScheduler();
    7 x6 `7 T, b+ [! D0 K
  54. ; z" b% b, v4 l* n3 m% f7 ?
  55.     while (1)
    9 g, P! I4 V( v
  56.     {/ [  x0 M  T. f+ b
  57.     }9 s& ]- ~3 m: e/ \* V. S
  58. }
复制代码
% o- H+ R5 d5 H5 H9 ~% A6 c
到此,移植完毕!
  Y6 v5 ^: e! u9 g% V+ u- E! @) E  E* u9 n7 |; k' b8 J8 L7 i
总结:移植FreeRTOS还是相对简单的,主要是配置文件FreeRTOSConfig.h的配置,每个宏定义所代表的意思需要好好查阅!
$ q- Q7 H3 {8 h/ P9 @% b
7 T' B+ m% `" f" h8 ]9 m& X$ `# T$ G1 p, d; E

1 k- v* L; [) c
赞 收藏 评论0 发布时间:2022-4-10 19:56

举报

0个回答

所属标签

相似技术帖

官网相关资源

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