请选择 进入手机版 | 继续访问电脑版

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

STM32 如何快速创建 FREERTOS和RTX 工程  

[复制链接]
lovewyufeng 发布时间:2015-1-8 12:08
以刚拿到手的 Nucleo 072为例  其他板子用户 请举一反三哈 (工程文件在帖末
/ `, K" l' f: c. L1 ^( _+ h( ~$ B* w- q$ r" {
7 t$ f$ L2 D% G) i
后续帖子:【干货】Nucleo072 usart 基于RTOS的应用  方便AT指令类外设开发
0 d8 L7 }% V. ~9 q& g7 f" v. o3 M+ @9 K9 r" H( ^
需要工具  MDK5 自行下载:; Y  f% M4 m9 X7 u/ @2 o
STM32CUBEMX https://www.stmcu.org.cn/document/detail/index/id-214984
8 W. `7 T9 ~; [3 E% _9 Y( w# MSTM32CUBEF0 https://www.stmcu.org.cn/document/detail/index/id-216669
+ u0 P$ G. C1 a. q  s) Y/ E6 \" ]) \5 [6 c6 e7 x' M4 |

6 d6 z; R. \' }+ ^- L7 o$ }安装 cubeMX  由于使用MX下载固件库速度那是不说了相当慢啊  所以下载 STM32CUBEF0固件库然后下图安装
; v  w- d% e: @0 \
! K9 _: o2 P1 ]# Z, F1 ]. Q! W9 n( `3 L4 K6 G
QQ截图20150108101548.jpg QQ截图20150108101556.jpg ( J' g# X9 D! l! D2 o
# `/ U+ y( s! J0 S; f& W
安装之后  新建一个工程 选择STM32F072RBT6$ t. J1 F7 K% _
1 z( k4 v, r/ I# I
PINOUT 勾选  FREERTOS和 USART
& L( f1 O6 y( h$ \ QQ截图20150108101539.jpg
2 u  r  o# w) p因为我们调试可能需要使用
% w/ d7 N, }6 @/ r8 ^1 T9 {8 v) p: H, w1 S/ s- N. T+ C
点击软件上方  齿轮键生成  keil 工程  至此
& u* x1 z+ M+ d: @) P# O
" t' J- ?- d( T( _5 J. qMX基于 HAL的库 生成完毕3 @  ^1 b% x2 U' s7 D( B, F

5 A" _1 T" P% q3 C4 Y- {2 V' Q使用MDK 打开工程
9 O) o$ y, Q8 I1 c1 M! _3 r& U从上到下 的组依次为  OS 的C文件
7 F) f, S+ l1 y- h.s 启动文件) J( R( Y3 t. a* z
用户文件6 G4 d" R5 @1 `" J% R
HAL库文件
6 p! l$ |1 k/ zCMSIS中间件文件7 A/ N# m2 ^( i" g; J2 u& a9 F

5 w3 g  ]0 {; s4 A其中 在 第一组中的 cmsis_os.c 中实现了  cmsis_os  到FREERTOS 的中间层转换   稍后会讨论其中一处代码8 @: {, W9 }! q, Y; k

% U' j( H6 i2 J2 x- m QQ截图20150108101924.jpg ( U0 g. d5 m. t% T+ l  Z3 r
+ V7 l5 }2 m4 u" Y5 h. N
6 `$ u, m* |8 Q& Q/ D& t
接下来  添加自己的代码  首先添加 072 上面LED吧  板子不在身边  记得是PA5 控制
) N: b3 `5 c# I& [  g6 W# _
; o% q( x; ^$ a$ U# }先看看  main.c 的 64 到 105行 ! L& [- d0 e. R6 K9 \  ?4 b/ U

  1. ) S  ?- M! ?# s% }& g1 l& e' y
  2. int main(void)
    + Y6 J3 s+ ]5 s
  3. {3 t5 M& |5 ]. l- H8 p# C

  4. $ h0 ^- d" G; i6 Q. s/ j
  5.   /* USER CODE BEGIN 1 */, g; i" b9 f4 h; ?! n2 l5 _

  6. ( x+ o  ~6 G# l; ~/ a9 i( t% W6 R
  7.   /* USER CODE END 1 */6 l; N9 V% ?$ A( z) t

  8. ( v3 z& T$ P. x* w1 @9 {' M
  9.   /* MCU Configuration----------------------------------------------------------*/2 W, ^: ~; E+ S! [0 J
  10. # {: I4 N% m; _) R3 n! ^
  11.   /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
    / F# ^8 G1 }8 D9 P0 ?* g
  12.   HAL_Init();
      R: i) N' C3 o, I* C$ v

  13. # \4 J' ~' J; g+ e
  14.   /* Configure the system clock */% p6 n- E8 K) K- Y
  15.   SystemClock_Config();$ I# \! q9 p' ?. [1 |+ R& ^' X

  16. * m+ |8 x! n5 y
  17.   /* Initialize all configured peripherals */1 Z  j& ^2 ~4 ?# m5 k! _
  18.   MX_GPIO_Init();- n$ T; @1 c1 G
  19.   MX_USART2_UART_Init();
    ; L; G% A$ r1 P2 \  O# u, K7 g
  20. 3 K5 T. P% v* I  O: Q' R0 I
  21.   /* USER CODE BEGIN 2 */5 A+ y6 p" @# f" R) l

  22. 0 P5 \! }" Y( B% l2 u" T1 b
  23.   /* USER CODE END 2 */3 n' O; `+ N( d. k! C2 _: N; B; I
  24. # `7 N0 O) L: C' J9 c4 l: X
  25.   /* Init code generated for FreeRTOS */1 _1 _- B% n( n# g# D. {, H
  26.   /* Create Start thread */
    , V( d( ?" x& _2 v) V6 x
  27.   osThreadDef(USER_Thread, StartThread, osPriorityNormal, 0, configMINIMAL_STACK_SIZE);
    : E; p% ~/ z6 S# Z; K2 m2 r
  28.   osThreadCreate (osThread(USER_Thread), NULL);" }/ ^) Y$ B( o$ d

  29. ( }- A: |* \* r) j
  30.   /* Start scheduler */
    $ s) x& o; n2 Y, F5 x, U  @' b
  31.   osKernelStart(NULL, NULL);  {$ K; g0 b, J" n3 N1 d

  32. & k$ c- m- k! D- r# U. k. f
  33.   /* We should never get here as control is now taken by the scheduler */
    6 g+ Y9 U6 f. Y4 M9 q

  34. - ~: J+ G& R6 u3 O% P3 A
  35.   /* USER CODE BEGIN 3 */
    + l( I$ E1 ?2 f/ ^* ]* ^
  36.   /* Infinite loop */
    2 k7 `: B. f: _: e0 r4 U
  37.   while (1)1 t& y4 V2 W+ `/ S, W3 V
  38.   {
    & S, ]$ y& i3 q; h! |+ v

  39. 4 v6 o9 Z  k% }5 \" F& o5 ?+ s
  40.   }
    ! y% p  G; n7 ~9 c7 ]4 S$ G
  41.   /* USER CODE END 3 */
    ) ~2 R# k9 W. f) U% K1 U( _; _
  42.   S: F' J3 D( C8 P: P$ @. @: X
  43. }
复制代码

1 i# w; m% G$ @& ]" P$ _mian函数  C代码的入口  初始化一些硬件后 * p$ I# ^, H' ?
  osThreadDef(USER_Thread, StartThread, osPriorityNormal, 0, configMINIMAL_STACK_SIZE);
  osThreadCreate (osThread(USER_Thread), NULL);
  /* Start scheduler */
  osKernelStart(NULL, NULL);
/ r4 s  T3 X5 d! q8 r
定义了一个 线程 USER_Thread 然后启动OS  
3 u  T" e2 b3 M' D( k3 \, ?注意 osThreadDef  是一个宏  定义一个用于描述  线程的结构体  并不是执行函数, U0 o" ^, L$ p; w/ B% B* J
7 c0 T- I$ C- l9 g" S: [
宏的第二项参数 StartThread 为线程 入口函数地址。; d7 X' h8 h3 _8 }4 i6 T. H' N

" I- O% m9 p9 }; h/ |9 Z至此mian函数的工作结束了 OS将转向 就绪线程并永不返回  也就是执行StartThread  
1 D$ x! N+ S( r" x: \2 |

+ w- A! ?' u8 x) q1 a) ^& z/ ^修改  StartThrea函数 如下- N. Z' K  `. A0 |0 `- T+ T# q$ @

" ^* M' U: A2 `( X! j) U2 B* ^
  1. ; D' w. B2 h8 h8 h
  2. /* USER CODE BEGIN 4 */
    1 \8 Z8 n0 |- l& I7 _
  3. void Nucleo_072_Led(const void *par);
    . }+ E* v6 U2 u1 h8 ~
  4. /* USER CODE END 4 */
    ) d- e6 f* c7 o$ F; ^  A
  5. 3 l9 `- W6 O, ]* ~) s5 i0 v# b$ h% e
  6. static void StartThread(void const * argument)! J7 ?) b2 [2 I
  7. {
    . h/ ^- @) m0 _; l9 N  K

  8. 9 l( |0 u0 c. l& I6 ~# N
  9.   /* USER CODE BEGIN 5 */
    . ~$ }& A. X' i# F
  10.   osThreadDef(LED_Thread, Nucleo_072_Led, osPriorityNormal, 0, configMINIMAL_STACK_SIZE);
    ) Q% W& v5 m: g: [* m
  11.   osThreadCreate (osThread(LED_Thread), NULL);, |: ?9 \9 x& k) S  ?
  12.   /* Infinite loop */" S0 _1 X- k& D) R0 L# w
  13.   for(;;)
    , c% f: Z- `. q1 f
  14.   {- x+ Q2 ]4 C1 H$ s1 D
  15.     osDelay(1);
    $ v# Q# t# E, L  l& q+ K" ?
  16.   }- u  z  O6 }+ z# |* W% t, r( A9 z# ^

  17. # I5 ?5 J- O* J) F* c; C
  18.   /* USER CODE END 5 */
    , R7 f1 \) D/ Z7 e

  19. , ^; t( j1 Q( g3 d
  20. }
复制代码
7 W( n" E3 t  a
添加一个 LED 函数+ s9 v; ~/ K' `1 L6 Q1 B+ O9 I1 |
  1. void Nucleo_072_Led(const void *par)
      p% l; f* F! `$ s9 b* V
  2. {
    , I( F3 }* z/ f0 r: J
  3.         GPIO_InitTypeDef GPIO_InitStruct;+ k1 W" |5 ~+ v" N
  4.   __GPIOA_CLK_ENABLE();
    2 ?# @9 R. u  I( g0 G4 c  Q# g4 B
  5.         
    & z: w$ v" X6 I) \& \: U- G
  6.            GPIO_InitStruct.Pin = GPIO_PIN_5;
    3 X. G$ ?& O- y* }; f. T
  7.     GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;0 D) ~% }1 ?  A! d! T7 h2 @  |. J' |
  8.     GPIO_InitStruct.Pull = GPIO_PULLUP;( m( s9 s  i# g  \8 M
  9.     GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
    # O  C' j' i3 u4 V
  10. & l8 |  K, R$ g; N
  11.     HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
    0 C/ U/ ], E' ?5 i& ~
  12.         , {' {+ o8 T) ]4 K
  13.         for(;;)
    0 \# J- b% q& F7 F5 q8 i+ G
  14.         {0 i1 _$ l3 z* y: ?8 S, |' A
  15.                 GPIOA->ODR^=GPIO_PIN_5;// PA5取反 LED闪烁0 h$ K- M- Q( j( v/ {' Z
  16.                 osDelay(500);$ P1 [" {2 z/ H; u- {; l! q, u
  17.         }
    * Z2 w0 s. C/ X9 l5 o4 p

  18. 1 m# J$ A$ ^$ k! h& s; ]
  19. }
复制代码
) Q" l  e9 l3 q$ w6 {
到这里可以编译下载到板子上运行 观察现象了" m+ K! @! o" k' M; A
$ P7 e. O+ L7 _( W1 F0 z
下面创建 RXT 的工程  新建一个工程  
6 }  a; R7 h- l! [( P' ^( n' j4 j" U( g0 ^/ ]+ m8 b* X0 E  @1 h
勾选 如下选项 / [' D& Y/ m7 Y% d" v3 p

& T$ F: V# `; x, ~ QQ截图20150108112304.jpg ) g8 a5 u2 C* Q# J8 S  m5 E
红框 不要添加  不知为何  楼主添加 MDK的 startup 编译通不过 ; j5 u& B8 p1 R4 h
F4 的工程没有包含  HAL  接下来 需要自行添加HAL 库 & K) C# T6 h9 e0 B

% I4 J8 C5 g+ E1 @% ~# l把原来的 main.c 复制一份更名为  rtx_main.c
4 A- [( `1 F0 C) s! ]# ^" \, e* M" N1 M) j9 }" D# O* H3 B
QQ截图20150108113501.jpg
0 F1 w# ?* ~" Y  q& P
6 m5 h- R; b) X8 {文件添加完毕 3 B* l( r) K) P" M+ x# F; D7 }
) |- ]: b; `7 l+ [1 G
接下来定义 头文件目录和 系统宏
/ N7 A, g; p( [- n& w/ J
. e  m3 o7 y/ C/ t- j! @ QQ截图20150108112609.jpg / G! u$ g) F8 m" c+ }
+ G, _6 k1 Q. s% S* u
修改 rtx_main.c  下面两处需要修改
0 T; B5 G& A2 h, w: a5 K
) H: \$ i' t. Y& \9 a
  1.   {
    ! E2 a9 X, R+ U: a
  2.   osThreadDef( StartThread, osPriorityNormal, 0, 0);' F) ~, w9 B, y$ x' B
  3.   osThreadCreate (osThread(StartThread), NULL);
    * r/ H* O! b' t# T8 }
  4.         }
    ) w; y; r# ?9 ?6 u1 S7 r4 H- j) n
  5. ' L& U( G$ B" s+ U  H* m0 ^* g; @
  6. osThreadDef( Nucleo_072_Led, osPriorityNormal, 0, 0);7 U; a2 j  \. m* e' h
  7.   osThreadCreate (osThread(Nucleo_072_Led), NULL);
复制代码
不知为何  ST写的 中间件和 MDK的 接口有一点差距  所以 创建线程的地方需要如上修改
* S+ A& B% K& W+ U0 \, w  v8 h5 [! {4 M
修改 stm32f0xx_hal_conf.h
- Y4 s% O0 D3 G# O, L添加 图示内容  不出意外  下面 将可以直接编译了!!
# ^8 I: p6 j# G5 a) b QQ截图20150108112936.jpg
- n$ j/ h5 X5 Z2 `) Z# F1 i; r1 o  _% F! ]+ f$ H  {5 p; M
写的有些多了  本来想 继续写 RTOS 基于串口的  应用  太长了 下次发帖写了
4 H) k$ c7 T  I/ u" C# Y; }5 i* V+ a0 v$ j' w- H  i. ?
下面提出一个讨论 MX 创建的  工程 FREERTOS 中 cmsis_os.c 中 创建一个信号量  
$ Y/ l3 O2 q# ?& gosSemaphoreCreate参数 count 直接9 L7 S6 Z; e! L# y% ~
. V- U! V4 v: }- h5 M
传递给 xSemaphoreCreateCounting的两个形参  
, ?: l' Z& o% Q6 Z QQ截图20150108115258.jpg % l# r- j# B: H) m6 e% A* W
原型   H6 J3 F/ c- r7 B! l; m
#define xSemaphoreCreateCounting( uxMaxCount, uxInitialCount ) xQueueCreateCountingSemaphore( ( uxMaxCount ), ( uxInitialCount ) )
- t9 {8 h/ M8 n& c/ p! ^, I/ N" }1 N
该宏创建一个 数值型信号量 第一个参数是 信号量最大数值  第二个则为  初始化值" ^6 [- ^/ d, l/ Z- C
# o/ i: g2 M" b+ J- |3 B
基于串口使用信号量  那么需要如下要求8 y( f* w( l. m7 [$ @, I% ~
假设 usart_sem 为串口使用的信号量
7 {" m1 Q2 n+ i! R( G每收到一个数据 usart_sem ++  缓冲 1024字节 $ r6 ^# E* Z( U
需要数据的线程 osSemaphoreWait(usart_sem ); 当有数据时 线程被激活  获取数据& J2 Y- o7 V7 O/ n* K
, T8 \5 m" ^4 P9 g2 t4 r
如此我们知道 这个信号量的 最大值应为1024
, S8 N( ?- W7 h" F; s8 Q/ H0 K可是使用 ST 的cmsis_os osSemaphoreCreate 创建一个信号亮 osSemaphoreCreate(0,1024);
0 R' @% T+ w" {# @
5 \1 n" o. O- U( K! I( n会出现这样的问题 !  此信号量 被赋予初值1024  意味着 这个信号量将可以被osSemaphoreWait 1024次
5 K: w- F: n3 V. w. L% M显然这不是我们想要 & k  O5 a: C/ F( G1 d! d
5 R  V# X4 D1 l& \5 c
通常  我们需要的数值型信号量  最大值可以很大  但是初值 基本为0,或1 ( ~5 {  C- E! H/ D, ]

/ V* X2 F( w$ `不懂  这样设计意义何在?. s2 d# M% _- Q9 {* ^9 b! h

' Q. a* N: g0 h' d5 C) P; z- q; ]& t/ ^
FREERTOS.zip (4.76 MB, 下载次数: 809)
收藏 14 评论97 发布时间:2015-1-8 12:08

举报

97个回答
我是东哥 回答时间:2015-1-24 07:31:09
本帖最后由 我是东哥 于 2015-1-24 09:21 编辑
# K- T- h1 C. n) \8 ^
lovewyufeng 发表于 2015-1-23 12:56
* X/ n! ~0 \$ ]& c# ^事实上  只要这个计数不为0 都能被 wait 到
- F! m4 \! O$ x: M5 j- r% P" T
不好意思,确实被代码的名称误导了,以前用的基本上只用二值的semphore或者直接用queue了。
% M" a1 N, y3 W. d仔细看了一下内部的实现,确实我说错了。4 z0 Z/ O3 M$ r$ Y& i) I0 T) n, q
在init_counter和max_counter一样的情况下,确实整个逻辑是要按照资源池来解释的,也就是确实生产者take(这个take代表获取空闲资源才能生产),消费者release(这个代表空闲资源返回)。我觉得这种情况semphore更像一个可重入的锁,处理线程拿走资源池后,直接处理完后再归还,像是个recursive mutex。+ _! I8 P2 E3 e8 k& t* x+ ?0 L
前面说的那个问题,直接用queue可能会更好。另外,今天试了一下最新的stm32cubemx和固件版本,代码已经改了,#if (configUSE_COUNTING_SEMAPHORES == 1 )        , Q1 l# e9 s( a- p3 t
  return xSemaphoreCreateCounting(count, 0);; r, P( u: p$ n: X7 W& `1 t
#else/ V" a- B$ H# `5 C% }6 r3 B
  return NULL;
  e8 T" X5 p8 ~6 P" ?#endif8 j1 w1 a. J! }1 v1 V; N0 ]
}/ o3 o3 R" x! ~  H

$ q1 B' V& b. ?% d7 b+ v# T) X
  `$ _1 M( X" p" ?2 j6 m5 y5 l" B/ y* S
+ t0 r) V/ l; R  d3 K# O6 r+ J
我是东哥 回答时间:2015-1-23 07:50:34
lovewyufeng 发表于 2015-1-23 00:48, x# H! M9 q% d& v0 K( G! v; v
反过来理解是吧,说得通。可是
3 W; p, V4 x/ _0 k有个问题。,生产一个就-1的话应该 take获取信号咯?   反过来消费应该pos ...

1 _8 X& h* e6 o) q8 T: c2 O你陷在细节里面了,看看人家的API是怎么样写的,osSemaphoreRelease和osSemaphoreWait,我们在生产者里面应该要osSemaphoreRelease,而在消费者里面osSemaphoreWait,是吧?字面理解,相当于生产的人释放了一个东西,然后消费者就等待生产者的这个东西。再看里面的实现,osSemaphoreRelease里面是xSemaphoreGive而不是take,而osSemaphoreWait里面是xSemaphoreTake而不是give。, |) }5 l# [% ]6 o1 M: h4 |$ t. q
所谓的反过来理解只是一种理解方法,说take和post的逻辑也反的话是不对的。不要老想着什么时候去post,什么去take。cmsis_os的API意思很明了,生产者生产了东西就应该release,消费者就应该Wait,这不是很好理解吗?
lovewyufeng 回答时间:2015-1-23 00:48:46
我是东哥 发表于 2015-1-21 12:18- G5 K3 {5 e: }: Z' ]  `1 y" n
这个其实也没有不合理,看你怎么理解,资源一开始为0,也可以理解为空闲池一开始是满的。生产者生产了一 ...

5 D& b! ?& A7 E$ e& j反过来理解是吧,说得通。可是
' b9 Q5 E* R2 |5 h/ N" S9 ?有个问题。,生产一个就-1的话应该 take获取信号咯?   反过来消费应该post 释放信号咯? 那么问题是 post是非阻塞立即返回的而take是阻塞的?
; f. V  ?: C2 K' |6 E) ]# J( Q先不谈消费者应当随时饥饿,处于阻塞态。
+ Y6 A6 s7 @: ~! d' [! Y生产一般在中断里吧,当take-到0的时候 阻塞线程阻塞谁呢
lovewyufeng 回答时间:2015-1-8 12:08:29
先把沙发占掉
oipk 回答时间:2015-1-8 12:11:23
楼上的,额,我第二个小板凳。楼主写的好,张姿势了。
liuqihui-347226 回答时间:2015-1-8 12:12:11
不错不错,看起来蛮好用的,支持一下
cqtnheyao 回答时间:2015-1-8 12:12:59
地板要站住
麟狮蕟 回答时间:2015-1-8 12:13:04
手指一抖经验到手
harvardx 回答时间:2015-1-8 12:13:49
有钱为何不顶帖 .何况还是高质量的 .cubemx 势在必得的趋势.支持一下.
木易-357428 回答时间:2015-1-8 12:16:11
看看 顶一下
6 a$ C4 b0 w& @% R& N* B" c- t: M' P
cqtnheyao 回答时间:2015-1-8 12:19:01
harvardx 发表于 2015-1-8 12:13
. Q& y8 n1 J$ F+ c有钱为何不顶帖 .何况还是高质量的 .cubemx 势在必得的趋势.支持一下.

5 E/ d: ^. u1 l. z& z据说库很大,效率低?求告知!
netlhx 回答时间:2015-1-8 12:19:08
很好,图文并茂
lovewyufeng 回答时间:2015-1-8 12:19:26
harvardx 发表于 2015-1-8 12:13
$ {8 \: {1 V' m  @有钱为何不顶帖 .何况还是高质量的 .cubemx 势在必得的趋势.支持一下.
- P; E+ M& z& c1 V$ {
多谢老大 支持  继续加油
lovewyufeng 回答时间:2015-1-8 12:23:05
cqtnheyao 发表于 2015-1-8 12:19
* o+ u) h# D( C6 q据说库很大,效率低?求告知!
6 E: m$ w9 g9 Q
确实 有这个毛病  楼主的贴初始化使用库  LED翻转使用的寄存器  请关注楼主 下篇将 发表 USART基于 OS的应用
wamcncn 回答时间:2015-1-8 12:38:19
不错,刚好 072的板子快到了
cxtarm 回答时间:2015-1-8 12:50:20
cubemx 好用吗
木易-357428 回答时间:2015-1-8 12:51:24
看看 路过

所属标签

相似分享

关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版