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

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

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

[复制链接]
lovewyufeng 发布时间:2015-1-8 12:08
以刚拿到手的 Nucleo 072为例  其他板子用户 请举一反三哈 (工程文件在帖末
; |. L' R( `7 ]2 G9 K* z# e6 C
0 y0 F. J( w* ]! [; d$ l
, [3 J0 ^8 S6 k后续帖子:【干货】Nucleo072 usart 基于RTOS的应用  方便AT指令类外设开发+ A5 D( z9 f0 g4 p/ K9 z8 ]
' r! ?: a+ g1 H8 e) q  T& v) P
需要工具  MDK5 自行下载:
) x# B9 l& N) y, k* \: RSTM32CUBEMX https://www.stmcu.org.cn/document/detail/index/id-214984
; W( v( b  V& ?! G) T- @STM32CUBEF0 https://www.stmcu.org.cn/document/detail/index/id-216669
9 D. z9 _0 m6 z# l. ~! d. c( s. P5 {

- e; t1 w! [/ d: x% r安装 cubeMX  由于使用MX下载固件库速度那是不说了相当慢啊  所以下载 STM32CUBEF0固件库然后下图安装
$ S/ y# k- x5 D" A
9 c3 V( [; R+ t" j3 l0 y
& U1 o; h) k2 f% w( z- z! } QQ截图20150108101548.jpg QQ截图20150108101556.jpg
, T( c! [7 ^. g* G- r/ W7 G
; r- G/ R. Z5 q$ l/ ^* G安装之后  新建一个工程 选择STM32F072RBT6
" N# i: p6 I( b1 m: v, m
# z; {" d6 G# c8 m4 a: r5 s: [PINOUT 勾选  FREERTOS和 USART
: R, F6 y; x9 Q* @' P% w( G QQ截图20150108101539.jpg
3 D& e- ~; A# H. r4 s因为我们调试可能需要使用
) H" \2 L% E8 U4 b1 X; f  m( f% O) I( s* ]& ?& k3 @
点击软件上方  齿轮键生成  keil 工程  至此6 m# I3 q. j2 v0 W

0 X6 K+ I6 Y  H& eMX基于 HAL的库 生成完毕
7 X& B. b$ m3 C2 j1 Z) g% N8 S+ d0 |- ^5 E& B- W" J
使用MDK 打开工程1 t7 a0 _1 @. |: k+ j
从上到下 的组依次为  OS 的C文件/ r' G& @8 G8 p
.s 启动文件
) W' A1 l9 W2 O4 z用户文件8 ~+ S7 a( \" C3 U
HAL库文件  U* A- V  U8 X. f, u
CMSIS中间件文件1 l, N0 e# z9 D* C" [. {* x
1 L3 k( I9 ~% m2 Y
其中 在 第一组中的 cmsis_os.c 中实现了  cmsis_os  到FREERTOS 的中间层转换   稍后会讨论其中一处代码  {! X: L3 O* B

9 K4 @  J- Y* G, S# y1 s8 p0 e5 ? QQ截图20150108101924.jpg
( m. e5 s/ T0 L6 f
9 z5 g# u- A( A9 j4 `9 ]2 R; W! T' v4 h8 p" y0 Z7 ~
接下来  添加自己的代码  首先添加 072 上面LED吧  板子不在身边  记得是PA5 控制. y; e' ]1 h" |0 r# G8 a6 \
1 |8 M8 p! `: |/ ~, J: ?- T5 {" u! i$ D) A
先看看  main.c 的 64 到 105行 2 C* R+ _4 u; d  M3 H

  1. ( s, P: l  H$ z- @" q4 N* ^- N
  2. int main(void)
    8 X' R  ^$ ~% m* w% \3 V3 h- W  O
  3. {
    . l& L; t7 G: T5 R

  4. : r# B8 a" }$ m/ S
  5.   /* USER CODE BEGIN 1 */
    7 A4 ~! z& _$ f! l
  6. 6 B7 P. k5 E7 s  ~* a3 ~
  7.   /* USER CODE END 1 */
    1 k8 Y" w/ s/ X2 e" R3 ^0 A

  8. : c5 |- {, ^5 |6 l5 a3 H
  9.   /* MCU Configuration----------------------------------------------------------*/
    $ f6 p2 `; l' r9 P/ n. ^& {

  10. # N% ^' G3 W# ~( S" m* N
  11.   /* Reset of all peripherals, Initializes the Flash interface and the Systick. */2 D! e% @  g% g* U# [* _
  12.   HAL_Init();
      _7 ~7 h0 l; ^$ t: Z6 E
  13. $ B* Q( ^, E- G: y" @! Z0 q
  14.   /* Configure the system clock */
    : h  K( X  M) J- O* v: k
  15.   SystemClock_Config();1 p" `# B) v* K9 L. ?$ T! O

  16. 7 C5 }  o, @# [) c
  17.   /* Initialize all configured peripherals */
    " s' V  r7 q5 a+ E; s$ k
  18.   MX_GPIO_Init();4 {, p* h& R9 P7 @0 M
  19.   MX_USART2_UART_Init();
    5 B6 x4 `. N6 D8 l# h: L
  20. 2 b& H- B9 u! ]! h: r; G
  21.   /* USER CODE BEGIN 2 */# |8 [0 O* `- n' O7 n" A8 M

  22. ' @+ k( B! d1 c0 w
  23.   /* USER CODE END 2 */
    # C) K( E  Z+ x9 L6 ?' ~% r
  24. . k! ~+ ?0 c0 a4 e; e, N) I
  25.   /* Init code generated for FreeRTOS */: w' M5 f! F& C2 H
  26.   /* Create Start thread */9 _, B2 Q$ U/ H# S) M$ y
  27.   osThreadDef(USER_Thread, StartThread, osPriorityNormal, 0, configMINIMAL_STACK_SIZE);
    - ?) O) U2 n2 s$ ~8 w5 y3 R
  28.   osThreadCreate (osThread(USER_Thread), NULL);
    % t7 m9 B8 a$ \" ~. K7 Q6 e
  29. ; M' o; y) {4 Y! r3 D# x( J
  30.   /* Start scheduler *// n# ~' z& t) S! ], X( a7 U7 u
  31.   osKernelStart(NULL, NULL);  n) T) v+ S$ d) K/ u& |' r
  32. # A  U8 d% ?6 ^1 r  o; S/ I
  33.   /* We should never get here as control is now taken by the scheduler */* a4 C" C; l8 h# e0 C3 k- F# N  B
  34. 3 i3 N+ V( p1 i# Y
  35.   /* USER CODE BEGIN 3 */3 G8 @, ]4 E% a
  36.   /* Infinite loop */
    6 {. J; X9 Z% h
  37.   while (1)2 x6 E$ v1 {8 Y8 K3 s' n) L% l
  38.   {
    8 P  a. @, I, T" N# A* V

  39.   S2 R/ K6 t( K3 h6 E5 E
  40.   }
    2 ~9 W1 y/ l& ^" w! t
  41.   /* USER CODE END 3 */
    7 m( D- O. l8 j8 e" J5 h: n* k; B

  42. : a; R% H. p" H* b3 L; I3 U- P
  43. }
复制代码
) w+ q/ b" ^& z$ X! b; V# B) d
mian函数  C代码的入口  初始化一些硬件后 1 y) v8 P5 ]; i5 e0 a2 e
  osThreadDef(USER_Thread, StartThread, osPriorityNormal, 0, configMINIMAL_STACK_SIZE);
  osThreadCreate (osThread(USER_Thread), NULL);
  /* Start scheduler */
  osKernelStart(NULL, NULL);
( }/ |" @$ N+ b8 Y5 t9 A
定义了一个 线程 USER_Thread 然后启动OS  & ?6 Y: w3 W* f; h$ V# S. N
注意 osThreadDef  是一个宏  定义一个用于描述  线程的结构体  并不是执行函数
2 H4 q% t1 H. M- o- N" X
' R6 x% O% z9 L# P
宏的第二项参数 StartThread 为线程 入口函数地址。
5 f+ y; P% ^9 l/ F0 U6 g! h8 l9 b( w( s9 D
至此mian函数的工作结束了 OS将转向 就绪线程并永不返回  也就是执行StartThread  - g# y, h! [  D5 e5 M$ G+ [* M- C6 V
9 H, A3 z6 |% t- D
修改  StartThrea函数 如下0 ?$ P5 X* h/ ?
$ K: O: s$ q6 P( Y
  1. 1 j- ?# ^# @2 E: N: Y: i
  2. /* USER CODE BEGIN 4 */
    ; v3 ^0 o& c: Q; u
  3. void Nucleo_072_Led(const void *par);" G, t  ]6 V/ _/ }' z
  4. /* USER CODE END 4 */& r" e1 X7 C$ B
  5. 3 M" ]$ H* f- a0 K
  6. static void StartThread(void const * argument)
    & j2 [, N: p" f3 ^  E' v+ ?1 ?
  7. {
    & z" W- M3 k6 Z) w% F

  8. 2 Z1 V/ R+ n  B- [# C
  9.   /* USER CODE BEGIN 5 */
    . ^3 d% a6 m3 U" [; Z0 s2 ^9 O6 M- T, g
  10.   osThreadDef(LED_Thread, Nucleo_072_Led, osPriorityNormal, 0, configMINIMAL_STACK_SIZE);
    ) X" s7 j4 F* ~
  11.   osThreadCreate (osThread(LED_Thread), NULL);. k4 i. ]* D7 r8 J. |- X+ i: Z" Z
  12.   /* Infinite loop */9 _: L: s7 r  x! _0 ?
  13.   for(;;)9 j9 J" g: D; ?4 S: ~
  14.   {
    3 V) e( L& @+ f+ |. f
  15.     osDelay(1);8 Y" w2 J0 \7 }! ~3 Q) E
  16.   }
    6 Q+ o" x$ \0 D- ~! [
  17. 3 C: B/ s4 L/ N% m" A
  18.   /* USER CODE END 5 */ 1 E0 t  o( B$ z7 O- \% {

  19. 5 G; ^1 j6 m8 ]1 {
  20. }
复制代码
3 E- _$ S; `  l! a: ~% v
添加一个 LED 函数
0 Q7 m3 i* o) _
  1. void Nucleo_072_Led(const void *par)
    ' N7 w6 g( f5 c5 z
  2. {% F) U/ T% ^& y1 _
  3.         GPIO_InitTypeDef GPIO_InitStruct;
    " R8 k1 K7 p8 e" u
  4.   __GPIOA_CLK_ENABLE();
    ( \$ t  s2 i8 T! L% W2 f: B
  5.         $ ?3 W; O% t$ G* P2 @9 C* Q
  6.            GPIO_InitStruct.Pin = GPIO_PIN_5;
    " e5 T6 N# z$ d! z% y2 A
  7.     GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    4 A  v! F+ d1 j
  8.     GPIO_InitStruct.Pull = GPIO_PULLUP;
    4 Q9 \, X2 D) |7 R
  9.     GPIO_InitStruct.Speed = GPIO_SPEED_LOW;) z' |+ a8 b7 a3 q9 J8 \4 U  a4 K, }

  10. + b1 Q2 K& D7 c" ^3 w! l4 f
  11.     HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);0 S- Y( c: ?& V$ f+ d1 y5 V5 N& S
  12.         + d- ^% |7 A# o
  13.         for(;;)4 f7 H" R1 a* [& l- C
  14.         {! ^$ c; k7 w4 y, m
  15.                 GPIOA->ODR^=GPIO_PIN_5;// PA5取反 LED闪烁" `+ }7 P" N& O* j4 W% b
  16.                 osDelay(500);
    9 j' c; R2 g* b1 E* W( n
  17.         }
    9 U% {6 w4 t  o
  18. " u' v, T/ J; \: A' J! A
  19. }
复制代码
4 c2 _7 G5 }$ @, x8 b1 G6 j" f
到这里可以编译下载到板子上运行 观察现象了
6 i! U+ w2 w4 R, P6 L1 o7 H$ j# f& o' ^* Q5 ?0 y) }
下面创建 RXT 的工程  新建一个工程  ) Y( U" @& s5 V+ ~( L4 C# B% L( s
* x8 D& ~2 {7 A3 X4 U5 U: j
勾选 如下选项
( ]8 [9 }+ ^- X/ o2 q: y% W- [
( a2 {' M1 X3 q QQ截图20150108112304.jpg
0 Y4 c7 \' k- ~! D2 J3 F$ x红框 不要添加  不知为何  楼主添加 MDK的 startup 编译通不过 5 X% t, `; E5 z  X
F4 的工程没有包含  HAL  接下来 需要自行添加HAL 库 . s) S' Y; y+ b
) P( A. Z4 ^% l; [. Q
把原来的 main.c 复制一份更名为  rtx_main.c
4 \! U1 Q  r2 R8 m5 o8 g$ M; `- ]1 v1 t6 p" Q! `% n3 r
QQ截图20150108113501.jpg
7 J+ z, @1 D2 }$ ]2 B: ~4 k  b) G  U
文件添加完毕 " _: ~/ i' s8 ~" S

: {: c% X3 D1 h& J. H接下来定义 头文件目录和 系统宏 0 J. X2 f' C8 P2 A4 a- m7 x. O8 j
; b: N( S& R7 u+ X) w$ h9 H' y
QQ截图20150108112609.jpg
, ]/ z  v7 c, L3 f$ }. q1 k7 Q- d/ }) O& }+ R
修改 rtx_main.c  下面两处需要修改
1 q' z' ~2 a- z* G- q: w
5 o' P2 R5 B/ c% F0 U. W
  1.   {
    / X7 q1 F0 u; r1 |, x9 \
  2.   osThreadDef( StartThread, osPriorityNormal, 0, 0);
    # k4 t  O2 P) C+ |0 K5 z4 X
  3.   osThreadCreate (osThread(StartThread), NULL);" `; O. G: T! [. e3 R6 T2 C/ s
  4.         }; x7 W+ z7 t& ^- ~, F' _' j7 W& n
  5. 7 W' ]0 m% ~2 u9 E
  6. osThreadDef( Nucleo_072_Led, osPriorityNormal, 0, 0);# ?% H, l8 p; c
  7.   osThreadCreate (osThread(Nucleo_072_Led), NULL);
复制代码
不知为何  ST写的 中间件和 MDK的 接口有一点差距  所以 创建线程的地方需要如上修改. |0 S" g. `# t$ s# W2 E
* |+ w  n4 `7 m/ G1 u/ _* c: s0 e
修改 stm32f0xx_hal_conf.h
; R5 o7 a" M  a% j& M添加 图示内容  不出意外  下面 将可以直接编译了!!
5 y/ p; _+ l6 D) \; W: R QQ截图20150108112936.jpg
$ d( m! U1 w% h/ ]+ |! W+ G
2 e& n* n* H4 F3 R4 s) M2 p, T写的有些多了  本来想 继续写 RTOS 基于串口的  应用  太长了 下次发帖写了4 N5 E. |1 W2 o" n

4 w7 H+ g- E; c& ]" V* N0 _下面提出一个讨论 MX 创建的  工程 FREERTOS 中 cmsis_os.c 中 创建一个信号量  * E2 }+ b: c9 k+ _) |/ J- b
osSemaphoreCreate参数 count 直接" s7 }+ E! x6 p% |  V& O* W
1 e5 ^9 p# [) C" V
传递给 xSemaphoreCreateCounting的两个形参  
& C2 Z, m. g; Q$ }& G- r- \7 R8 @ QQ截图20150108115258.jpg ( D& K2 S4 G8 f4 z6 I
原型 ( _  g, ^/ N2 ?/ o
#define xSemaphoreCreateCounting( uxMaxCount, uxInitialCount ) xQueueCreateCountingSemaphore( ( uxMaxCount ), ( uxInitialCount ) )
8 F! }: C; Z$ [: u9 L1 n4 s- E+ P8 M% T
该宏创建一个 数值型信号量 第一个参数是 信号量最大数值  第二个则为  初始化值# ^8 B* Y* o- E3 F! V

9 ?% L/ ?9 c( l$ N+ e9 o基于串口使用信号量  那么需要如下要求4 P& ~1 B8 h# o7 M( [' m+ L, q
假设 usart_sem 为串口使用的信号量
% Z8 O3 I- E% h* h) r每收到一个数据 usart_sem ++  缓冲 1024字节 , G; u4 H' B% x, t9 g" F2 I
需要数据的线程 osSemaphoreWait(usart_sem ); 当有数据时 线程被激活  获取数据
9 l/ ]- n8 R& m4 R0 l9 n$ Z+ a! _6 h. b4 y& f3 h
如此我们知道 这个信号量的 最大值应为1024 1 [. ^. o( E# q+ K
可是使用 ST 的cmsis_os osSemaphoreCreate 创建一个信号亮 osSemaphoreCreate(0,1024);
0 N  \/ c$ `7 F6 u! d# W9 G) E2 m( q3 m$ `
会出现这样的问题 !  此信号量 被赋予初值1024  意味着 这个信号量将可以被osSemaphoreWait 1024次1 L# V3 Y1 Z8 Z2 d
显然这不是我们想要
5 q) w% |8 X. W3 c2 j0 _
7 M6 H- \; n: x6 y/ q) X* o通常  我们需要的数值型信号量  最大值可以很大  但是初值 基本为0,或1
) ~- N1 z2 [1 |3 I+ H! J% W  o/ a: _
1 {6 ?; h3 O' T8 K# U) B% L不懂  这样设计意义何在?
% H5 E- d7 D! y7 t
2 ^- d% B7 f8 ~+ Y" }' o5 j
2 Z+ E4 G# Q# y. M- l0 n 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 编辑
" Y& Y; l; K: a7 b
lovewyufeng 发表于 2015-1-23 12:566 B5 q2 b, E! q2 o0 D
事实上  只要这个计数不为0 都能被 wait 到

* t5 H/ a4 j$ g不好意思,确实被代码的名称误导了,以前用的基本上只用二值的semphore或者直接用queue了。
/ W( H2 s, }) {$ Y# c仔细看了一下内部的实现,确实我说错了。8 D, @) S* r+ ~% K4 {/ [. L( _
在init_counter和max_counter一样的情况下,确实整个逻辑是要按照资源池来解释的,也就是确实生产者take(这个take代表获取空闲资源才能生产),消费者release(这个代表空闲资源返回)。我觉得这种情况semphore更像一个可重入的锁,处理线程拿走资源池后,直接处理完后再归还,像是个recursive mutex。8 l+ ?: N. T; R3 ]" O. k# d9 _0 P+ g
前面说的那个问题,直接用queue可能会更好。另外,今天试了一下最新的stm32cubemx和固件版本,代码已经改了,#if (configUSE_COUNTING_SEMAPHORES == 1 )        
0 J# m& v4 C3 J; V) b$ J  return xSemaphoreCreateCounting(count, 0);8 g# Z; Q2 X% e6 n6 z- {
#else
3 ~+ {- A% d/ v7 K# E" _  return NULL;
* ?! Y3 A+ l8 p" r: u#endif8 t$ {/ M: ~( k8 D+ ?
}# j3 V* @+ L0 v' K) K5 \6 Z" P

$ x" [! F& X; M$ V. n# i) d& l) ]* S' f$ ?2 Q4 x3 x

5 y2 `; S( L( Q+ J) s! d' K8 i6 a$ F2 f1 N; Q5 a6 Q6 ]
我是东哥 回答时间:2015-1-23 07:50:34
lovewyufeng 发表于 2015-1-23 00:48- c# \- ?. m" m2 l3 H
反过来理解是吧,说得通。可是5 k  y! F0 @9 I
有个问题。,生产一个就-1的话应该 take获取信号咯?   反过来消费应该pos ...

5 `( s# q# B8 q; X" k" f你陷在细节里面了,看看人家的API是怎么样写的,osSemaphoreRelease和osSemaphoreWait,我们在生产者里面应该要osSemaphoreRelease,而在消费者里面osSemaphoreWait,是吧?字面理解,相当于生产的人释放了一个东西,然后消费者就等待生产者的这个东西。再看里面的实现,osSemaphoreRelease里面是xSemaphoreGive而不是take,而osSemaphoreWait里面是xSemaphoreTake而不是give。
7 i! B  v/ _( _* {所谓的反过来理解只是一种理解方法,说take和post的逻辑也反的话是不对的。不要老想着什么时候去post,什么去take。cmsis_os的API意思很明了,生产者生产了东西就应该release,消费者就应该Wait,这不是很好理解吗?
lovewyufeng 回答时间:2015-1-23 00:48:46
我是东哥 发表于 2015-1-21 12:18
% n# D0 k5 |! K; V这个其实也没有不合理,看你怎么理解,资源一开始为0,也可以理解为空闲池一开始是满的。生产者生产了一 ...
" I8 T! h  q! _" C! y$ d
反过来理解是吧,说得通。可是; L: M' U7 z7 r
有个问题。,生产一个就-1的话应该 take获取信号咯?   反过来消费应该post 释放信号咯? 那么问题是 post是非阻塞立即返回的而take是阻塞的?
0 v) T4 W( N) Y" {2 D. V先不谈消费者应当随时饥饿,处于阻塞态。2 Z  ?) C' ?* @
生产一般在中断里吧,当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
看看 顶一下, G% w1 L/ T% t# W7 E0 f7 B
cqtnheyao 回答时间:2015-1-8 12:19:01
harvardx 发表于 2015-1-8 12:13
2 |0 g, B& m0 O% E. n4 O有钱为何不顶帖 .何况还是高质量的 .cubemx 势在必得的趋势.支持一下.
" y. w* [7 x' w+ G
据说库很大,效率低?求告知!
netlhx 回答时间:2015-1-8 12:19:08
很好,图文并茂
lovewyufeng 回答时间:2015-1-8 12:19:26
harvardx 发表于 2015-1-8 12:13
8 P" e0 \4 ?7 t6 q7 q有钱为何不顶帖 .何况还是高质量的 .cubemx 势在必得的趋势.支持一下.

; Z9 O: s9 l+ W/ ?多谢老大 支持  继续加油
lovewyufeng 回答时间:2015-1-8 12:23:05
cqtnheyao 发表于 2015-1-8 12:19
1 ?6 A4 t1 M5 o5 W2 W据说库很大,效率低?求告知!
( M( b" O* F: O( ]0 s
确实 有这个毛病  楼主的贴初始化使用库  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 手机版