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

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

[复制链接]
STMCU小助手 发布时间:2022-4-10 19:56
(一)裸机工程创建' y4 O- u* N1 {# Y
使用STM32CubeMX创建裸机工程:
( D6 M3 Y; I. T( B) P. J& c! M" @. \- e
这里我是用的芯片是STM32F103RBT6,时钟主频为72MHz,配置时钟树:
% R/ K, `2 U2 ?! H8 g% g: {# Y. E9 E  h$ M
[HJAIVR6Y8OGG98AS[H.png 3 ^# d4 h! f, K9 `0 z

; L, S! m  E: y- x配置调试串口1:
7 R" j; P, z8 L) G8 f3 K' V9 T/ E
M8_G2}7WA8CT@ZUVG}0@R`0.png
6 m4 q0 M9 i3 \$ ]6 g* @) [3 ?2 t
配置两个LED灯:& f9 i2 L  G" V% k* L% s( U; M

) D* q5 Q% |3 W( z7 K 20201010162500610.png
3 j9 i7 u# }) c3 G: \: h
% E1 n4 c8 U+ a! j" W4 A" H& s8 {  H由于FreeRTOS使用系统嘀嗒定时器当作心跳,HAL库也使用了这个定时器当作超时计数用,FreeRTOS和HAL库不能同时使用SysTick定时器,所在在这里将HAL库的定时器改为其他的定时器,我改成了定时器4:/ O- l, P/ Z, ?1 \) ~

5 R. ?6 X$ s: n7 Y$ { ZW]AZRZ6{KK3FJ9V~Y{}D~Q.png
; b0 h) f+ T& i* V; F2 |" A8 E; u
3 o7 ?; Q; F) Q1 ]/ e* r配置中断,注意这里一定要选择组4,也就是全部为抢占优先级:
; D# m6 s1 ^: B; N& G
0 [3 J+ j, L- `, m8 M ANO~JLI_}E$E1]8B6U78I[X.png 6 g$ [  u) f4 w
$ t8 N! Y: ]/ N+ z" r- {
输出工程:% k' D- t. B" c* |
" W+ o' V( s& ]+ H# D) I! [
20201010162753196.png " }) N. ~, p5 K/ u" }+ u$ a, w6 f
20201010162833214.png ' ^' ]  w4 q  G0 z( B5 [. M4 M

: K/ f5 _% Z- h* W. F' V) _& `2 x8 W3 u& ^# f. I8 K
(二)移植FreeRTOS
3 w  f4 H6 K. ^7 d* c& m6 p9 Z' t/ L& e0 [
解压FreeRTOS源码包有如下文件结构:: G+ I8 ~  ?5 f. u2 w% J
/ `/ T3 @; S" O- v
7L$%8]J0YCQ2N2IE`HG1PJN.png ) F4 ]/ T% Y' V' V# G/ q  S' r
/ Z9 s: \- N2 z8 \: U/ r
在Keil工程目录下新建FreeRTOS文件夹用于存放freertos的源码。( i9 w8 D+ w& L; S/ g7 y
- j) l( _! `7 g" g
拷贝FreeRTOS/Source/文件夹内的以下文件,放入keil工程目录FreeRTOS文件夹内,效果如下图:; K' t! v3 r( C4 _2 ~1 z1 e6 {

" ~/ u" e' O3 n: _6 V5 c 2~65A5@GXSM$QGGM2S885GU.png
  o% U& C) W8 e# u( V" o
# v, a, [; n. [/ t/ d% ?4 }, n在Keil中将FreeRTOS源码加入到工程内:- j3 R1 d  C  M3 \3 \; D

. W  C" A* h, X; V8 n 0]DPJOU3QX3U0ZAN46OSQ04.png ) L  r3 N8 i8 g  |1 u  N
' H( o! }7 r  J* |# |
打开stm32f1xx_it.c文件,在头部添加FreeRTOS的三个函数导入:
  1. extern void xPortPendSVHandler(void);6 W# y: F4 q7 y- ~
  2. extern void xPortSysTickHandler(void);
    # n' O6 ^) \' O' b( v: z
  3. extern void vPortSVCHandler(void);
复制代码
) I5 S. A/ o5 a2 s
3DC746)588]2)A%~F[L%ERS.png
4 u2 G. V$ @8 X/ w; x
3 F1 Z4 a: `+ S5 p5 V! ~5 L4 k+ U在函数SVC_Handler中添加函数调用:
! F3 B4 P) l7 P4 ]+ r
4 U  k- o1 r8 `* o 20201010165147723.png
. x! {2 q% t. E/ e* c
5 `  ~+ J3 ~, G4 Q' Q; L在函数PendSV_Handler中添加函数调用:
4 E1 h( g5 k( s7 S6 ~0 I% \. S& s1 m% I* W0 Q/ F' o) v
20201010165237842.png
# P' }2 J4 I; K/ C$ R, _. b/ ^$ r" J: f, K! n: ]
在函数SysTick_Handler中添加函数调用:
3 N9 f- P+ x! G3 ]0 C' b3 U4 }' W% Y
; e1 B/ r& W- r O[VQ{YF9{KZOLWVE[9O(OGN.png
: \/ `# }8 a& a- B2 _' \6 L2 P* m# n8 y- \, B
新建一个名为FreeRTOSConfig.h的文件,这是FreeRTOS的配置文件,这里我贴一个我配置的:5 f* b" O+ \( r0 o, T+ N" ]
' V  T% p% O; C% {* ~
  1. #ifndef FREERTOS_CONFIG_H__
    ! X* I* }/ y  Z0 F" ~
  2. #define FREERTOS_CONFIG_H__3 ?$ J. y- R  y/ A4 A+ @
  3. 0 g6 {7 r! p( R* d3 C" S& V
  4. /*
      Q+ i3 H$ Q6 ~7 ~

  5. / J! L3 |& j  ]
  6. */
    , K1 Y7 l/ t2 \( `

  7. " ]! f" d6 R' N& `
  8. // 设置为1使用抢占式,为0使用时间片轮转调度。
    , B, K( t' I$ D& d( U& g
  9. #define configUSE_PREEMPTION                    1
    : B: H( ]& K, k8 }

  10. 8 r4 [0 W+ d' k9 V: @$ u" T
  11. // 设置为1使能低功耗tickless模式,为0保持系统节拍(tick)中断一直运行。* d& o( @% E+ [6 J4 {  C$ n
  12. #define configUSE_TICKLESS_IDLE                 09 Q1 m* _% ^' O" G. n" M. ]

  13. ( k' X; H+ s/ z' E* x6 n; v
  14. // 系统时钟主频
    : e8 i* p, `% H7 q. {- e4 i7 C8 M
  15. #define configCPU_CLOCK_HZ                      72000000; ]9 c3 n( {% z5 D: v3 _* c

  16.   F4 d+ f9 _6 o5 x1 U. C
  17. // 系统节拍中断的频率,即1s进中断的次数,配置为1000就是一秒进1000次中断,系统节拍就是1s。
    : ?7 i- ~  _* w( M5 h
  18. #define configTICK_RATE_HZ                      1000
    ; @8 j$ l' T7 L! e, ]

  19. ( @3 P8 [% D0 h7 h5 U6 Q. W
  20. // 任务最大优先级,对于STM32来说最大不要超过32
    % O# _4 d7 d6 j  w; ~5 q7 S
  21. #define configMAX_PRIORITIES                    32
    ! g, f6 |3 E" E! u% r3 M  y3 a5 ~; v0 R

  22. * Y- Y- T' P- g
  23. // 任务最小栈大小
    3 m, U$ d7 o1 I9 L! u" P! }
  24. #define configMINIMAL_STACK_SIZE                645 @: {0 ?6 |/ L6 {% ~8 I; ~
  25. 7 S$ y" C7 l8 I" a: ]; Q
  26. // FreeRTOR堆空间大小
      k6 ^; ^. R9 _4 z: m
  27. #define configTOTAL_HEAP_SIZE                   8192
    : S4 j% i( |# {" A

  28. % B# j7 Z1 \$ M, Z" J( R2 e
  29. // 任务名称最大长度
    8 _: l( a3 x1 x# N& s6 X
  30. #define configMAX_TASK_NAME_LEN                 16
    ! i9 v7 j* h; i: x$ a  ?! |- o4 ~
  31. 3 F. f8 e/ I; G; x
  32. // 系统节拍计数器的变量类型,即定义portTickType是表示16位变量还是32位变量。
    ; l" Q3 h3 H! u3 X" `
  33. #define configUSE_16_BIT_TICKS                  0% p, [- l+ Z' E

  34. 8 b& u$ W: R% \
  35. // 设置为1允许任务调度,为0不允许(时间片耗尽才让出CPU使用权),该参数抢占式方式下才生效9 V: V8 |* q* i
  36. #define configIDLE_SHOULD_YIELD                 1/ b8 |5 u# Q2 z
  37. ! q7 l1 o, ]" [6 l  `
  38. // 设置是否使用互斥量, g, r) e) c! o$ ]: Y, ]' B
  39. #define configUSE_MUTEXES                       1
    - `4 y- _6 W4 D, z8 U" s, I

  40. 4 D  W9 m2 A7 \, C- k$ f& M) j
  41. // 设置是否使用递归互斥量$ n" `, v# r; ]% v
  42. #define configUSE_RECURSIVE_MUTEXES             0
    1 V$ ]: i) d  n  X
  43. ' T  b6 z0 q/ S: _& o
  44. // 设置是否使用计数信号量
    * O, J4 H9 V2 y6 d6 q+ M5 N4 t
  45. #define configUSE_COUNTING_SEMAPHORES           00 T4 H) k5 O6 E$ W& [
  46. 5 F3 w* f% E. u6 A+ ~$ D6 c- x" g
  47. // 设置可以记录的队列和信号量的最大数目
    1 y; J; V6 D, K, }: K, X. i
  48. #define configQUEUE_REGISTRY_SIZE               103 y, y6 j) O. ]% ^+ S! Z& V' o
  49. , m( d% T3 ?2 ]. S, Q* z+ Y2 K! v; e" ]
  50. // 是否使用空闲钩子函数( T) G5 W$ I9 }* M
  51. #define configUSE_IDLE_HOOK                     0
    ( |7 j+ R) s# c3 E3 R
  52. . r! D& r# `4 t5 j- k
  53. // 是否使用TICK嘀嗒钩子函数
    # L% U. Z- c+ m9 Q9 c+ Z
  54. #define configUSE_TICK_HOOK                     0
    - q0 w( y0 [: F+ A2 O- C5 D
  55. - a0 E# Q6 g( \8 \! @; W, Z
  56. // 是否使用栈溢出检查& j7 N! T, w; R: B4 A
  57. #define configCHECK_FOR_STACK_OVERFLOW          0
    ! L8 N/ V0 |* |$ K/ X* Q! x
  58. 1 ]; o/ o3 a2 ]. `0 v+ O1 a: R
  59. // 是否使用内存申请失败钩子函数  i. U3 Y. l9 g; F- u, p% ~
  60. #define configUSE_MALLOC_FAILED_HOOK            06 g( u% P2 h2 W( a! ~3 e, _
  61. + X& X- j9 q) j- ~: c6 E
  62. // 是否使用软件定时器
    ; c$ `% S% a1 h  ~
  63. #define configUSE_TIMERS                        1
    0 s3 I$ q# Q( R3 \. V

  64. 6 Y% E; ]& ~) [6 m/ U* C# K
  65. // 设置软件定时器服务/守护进程的优先级5 y0 n1 k4 v( P1 J
  66. #define configTIMER_TASK_PRIORITY               3
    7 f. B4 Q0 u* V4 A
  67.   l2 y0 L  c$ p) P
  68. // 设置软件定时器命令队列的长度
    ! e" B( v& r$ B$ z- t, n
  69. #define configTIMER_QUEUE_LENGTH                10
    ) ^- T2 p+ s- ~) w: `
  70. 8 m7 b4 X# J! Q
  71. // 设置软件定时器服务/守护进程任务的堆栈深度2 Y) {) |5 ^0 b  m/ T
  72. #define configTIMER_TASK_STACK_DEPTH            configMINIMAL_STACK_SIZE3 t5 c& I6 q6 f3 n+ c3 w

  73. 4 F9 w9 T. Z' o6 E2 k
  74. // STM32的最低优先级/ ^0 u6 m$ k: i/ o. ?* d* F7 l6 a( B/ [7 H4 L
  75. #define configLIBRARY_LOWEST_INTERRUPT_PRIORITY   15
    , Y( C9 ]3 e, B4 x; M

  76. ' L7 l9 ]+ x! S/ F: J
  77. // 能够在中断服务函数中安全调用FreeRTOS API的中断最低优先级
    ! D+ ]) M+ U. C" E1 [% X  T% G
  78. #define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 1! `" g9 P. c& _; u" j% k0 ~  B

  79. " {$ e% f, I& F& [6 v. J
  80. #define configKERNEL_INTERRUPT_PRIORITY                 ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << 4 )
    ) F% L1 l8 F, Q7 F6 t. }) d
  81. #define configMAX_SYSCALL_INTERRUPT_PRIORITY         ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << 4 )) l3 M# A" Y# T  C1 N+ [

  82. 5 U) j- A1 J" L' O
  83. 6 I$ {# k1 R5 P
  84. // 将以下定义设置为1以包含API函数,或设置为0排除API函数
      d5 s5 @+ }/ U8 }
  85. #define INCLUDE_vTaskPrioritySet                1
    - h6 S% Q/ @7 X5 Y. |* ^, a
  86. #define INCLUDE_uxTaskPriorityGet               1! {" i) X& t) |8 f7 ^9 L  H' x* T
  87. #define INCLUDE_vTaskDelete                     1
    0 E& Y- s+ P. c( f+ r" R
  88. #define INCLUDE_vTaskSuspend                    15 t) G4 g1 J& p; d7 m
  89. #define INCLUDE_xResumeFromISR                  1
    ' l9 z; \' @5 P" _9 G# w
  90. #define INCLUDE_vTaskDelayUntil                 1
    5 u8 S0 L! d- ]# h& w8 z' T
  91. #define INCLUDE_vTaskDelay                      1
    8 ^  j" W6 V5 p4 `, O
  92. #define INCLUDE_xTaskGetSchedulerState          1$ `7 U  J- |3 N5 R$ x
  93. #define INCLUDE_xTaskGetCurrentTaskHandle       13 S/ J3 R. u* h3 Q; C3 [
  94. #define INCLUDE_uxTaskGetStackHighWaterMark     0( t4 E1 Z- Q2 z0 V! G6 ?
  95. #define INCLUDE_xTaskGetIdleTaskHandle          0
    / [% |8 I& v' D. C
  96. #define INCLUDE_xTimerGetTimerDaemonTaskHandle  0) ]1 b' ~$ |2 H- s$ f0 V
  97. #define INCLUDE_pcTaskGetTaskName               0
    - `* I1 ^; d" X) Q) j& z
  98. #define INCLUDE_eTaskGetState                   0# I$ L9 o- V) O5 ]" c
  99. #define INCLUDE_xEventGroupSetBitFromISR        11 p3 c! p5 j; N. ]0 E
  100. #define INCLUDE_xTimerPendFunctionCall          0
    & g4 ~( f1 A8 O

  101. ) {9 ^! ^: G, g+ n7 |8 d0 R
  102. #endif  /* FREERTOS_CONFIG_H__ */
      x( T3 X  S8 f+ r
复制代码
4 N( D2 e: T1 {/ H. J7 P
修改main.c文件,添加头文件:
) a3 n  G! i, \- M- L/ A9 l( E+ t
) Z. N! x  z" C  w! U
  1. #include "FreeRTOSConfig.h". E5 ~4 w5 ]: h6 }; n+ V
  2. #include "FreeRTOS.h"8 ?; T* ~; P2 b% b
  3. #include "task.h"
复制代码

4 y, [! y. G# ~) L8 j这里我创建了三个任务,任务一为led1灯每间隔500ms闪烁一次,任务二led2每间隔300ms闪烁一次,任务三为串口每隔1s打印一次helloworld。
1 q( G$ b9 N/ O. N1 X; L; I/ b* `' n) t( c4 S$ y+ J7 Y9 d

7 d4 U$ Z: g- {( B
  1. void led1_task(void* arg)7 q- S, `/ g% P- M9 ]
  2. {( B4 k+ Z5 L1 A( |* e$ Y. n! |* I
  3.     while(1)
    - ^! m* D. g/ P; b# @/ L
  4.     {8 ^  X3 _; A3 e2 l& x- h+ P
  5.         HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_8);5 R/ C( M- N+ P0 L
  6.         vTaskDelay(500);
    ( Y. T4 f; l, V! l& `, f
  7.     }* M$ h+ W4 _' e7 J+ F9 P1 E
  8. }
    $ E( i" w" r! X+ L& }
  9. : z3 }( P" |$ v" k, j. r
  10. void led2_task(void* arg)3 C$ ^* _+ s0 l1 H- O
  11. {
      t. \5 l6 q) H: P
  12.     while(1)7 Q/ S, P8 {+ d
  13.     {
      Z( ~" `" z* |$ h
  14.         HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_2);3 S! K" C* ?0 e, q  V
  15.         vTaskDelay(300);- V2 x1 }6 O3 C3 c" v5 _
  16.     }# B: d' _7 J6 O, E6 _
  17. }
    : ?! b7 N1 B1 B! M

  18. 0 Q( r( R4 M: y8 M/ \
  19. void print_task(void* arg)7 j/ M8 _- {7 j
  20. {
    ! Y! X+ W; A; m  q/ z
  21.     while(1). B4 A' n' W+ e# P" c5 p* ^+ H3 V9 Z& z
  22.     {
    2 E6 X/ R* V3 ]0 |
  23.         HAL_UART_Transmit(&huart1, (uint8_t *)"HelloWorld\r\n", 12, 100);
    / a- B2 e1 L& G& `" Y
  24.         vTaskDelay(1000);
    0 W% i8 f  |- w3 `( ?; g
  25.     }
    6 X* i! S3 R' o
  26. }$ z; N  |3 _: Y# x

  27. ' C" ~9 N* _3 a
  28. int main(void); {+ g: d7 U- z
  29. {
    , L7 O8 R( R9 Z+ c
  30.     HAL_Init();' C6 t7 c# `- A* ~9 {
  31.     SystemClock_Config();4 e# E7 S" N) x! d
  32.     MX_GPIO_Init();/ O- l+ P- e1 o% A
  33.     MX_USART1_UART_Init();, t5 j8 f8 T+ u* o" W! O! `
  34. ! g$ q) O% F1 x3 n
  35.         // xTaskCreate函数参数说明:! w1 G' i7 {3 g: B! g5 f% n
  36.         // 1、任务入口函数
    $ ?9 k& p3 [; \* ~1 z
  37.         // 2、任务名称
    # C7 P( S4 q% C; i4 j; W3 q
  38.         // 3、堆栈大小,单位word. T1 b' J" h+ s9 T
  39.         // 4、传递给任务的参数7 K' L8 |# I. `1 n- y
  40.         // 5、任务优先级
    1 o  X) c; W% V6 g% P4 O
  41.         // 6、任务句柄  T( W/ l1 e. m3 Y; W6 r
  42.         $ x1 Q+ Q, r, q9 O
  43.         // 创建任务led1灯任务
    . \( T  J3 r! e: O
  44.     xTaskCreate(led1_task, "led1_task", 64, NULL, 3, NULL);
    ; H/ I- D" _( p. P& i
  45.         0 e- i; R' w: Y
  46.         // 创建任务led2灯任务
    5 w0 `- C1 o7 s6 s
  47.         xTaskCreate(led2_task, "led2_task", 64, NULL, 4, NULL);* _' Z8 W) p0 [5 C6 S0 @* @
  48.         
    8 e7 g- C, V( Q8 r( N8 {  n
  49.         // 创建串口打印任务7 L0 O3 D0 ]: Y* p. R# I$ v; s7 t
  50.     xTaskCreate(print_task, "print_task", 128, NULL, 5, NULL);" \3 \# [# r' U. z! {

  51. ) q% m! V5 `" Y# o0 C/ ~
  52.         // 启动任务调度
    0 P, f7 q1 R4 q  ~7 W
  53.     vTaskStartScheduler();
    - G' i$ R+ L) P

  54. 6 U6 t# X1 V+ R6 s2 @
  55.     while (1)
    0 p) p$ O0 E8 H; x5 R4 N
  56.     {. k& ^$ b4 l  q# g# S* V8 F
  57.     }0 D: h4 K$ g" [
  58. }
复制代码
1 i6 V, D" j2 a" i; n! U
到此,移植完毕!
- z  K( K- X3 l$ u; w: T+ b" q+ m( d% J  v$ m
总结:移植FreeRTOS还是相对简单的,主要是配置文件FreeRTOSConfig.h的配置,每个宏定义所代表的意思需要好好查阅!0 y' p; B) g1 p/ e6 p- E

  |4 Y3 P, T: S
; ]2 k. \" P1 E9 C- f+ X1 O0 O. E' ?8 j. Z5 s8 o
赞 收藏 评论0 发布时间:2022-4-10 19:56

举报

0个回答

所属标签

相似技术帖

官网相关资源

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