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

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

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

[复制链接]
lovewyufeng 发布时间:2015-1-8 12:08
以刚拿到手的 Nucleo 072为例  其他板子用户 请举一反三哈 (工程文件在帖末3 D  Y- i# d" t  {# p6 S  Q, \
0 Y4 s) A  R1 k1 X

+ p# }! B- z1 K) Y7 t- ]后续帖子:【干货】Nucleo072 usart 基于RTOS的应用  方便AT指令类外设开发6 r& ^& N  y) r
( W. t! I$ d' u1 u% l7 B
需要工具  MDK5 自行下载:
& J8 s' m- S" K" M! g0 ~* p: J* x# ?STM32CUBEMX https://www.stmcu.org.cn/document/detail/index/id-214984
+ D, K. H0 j, T" {! T  n4 L2 LSTM32CUBEF0 https://www.stmcu.org.cn/document/detail/index/id-216669
" \# l/ `1 ~1 [/ k0 b! e. q- E5 Q% r$ Z, `

; E+ q1 W, e# h9 T' y' @安装 cubeMX  由于使用MX下载固件库速度那是不说了相当慢啊  所以下载 STM32CUBEF0固件库然后下图安装2 c7 I- @2 q- K% D

# n6 x: _; i# k$ Q7 j7 H$ {% O9 m* e- {. H1 c( s
QQ截图20150108101548.jpg QQ截图20150108101556.jpg
* T9 }4 t4 c2 m  |+ S4 I, |1 x4 y  D' k. I. }" ]. G  Y1 D! z
安装之后  新建一个工程 选择STM32F072RBT6/ P( s* o( E8 ~- e9 D9 A' _% N
1 e5 Y! u* D, t: _8 w
PINOUT 勾选  FREERTOS和 USART - S* i6 s4 b  |1 |" Q9 B0 e
QQ截图20150108101539.jpg
' X( ~/ o2 x( ~! s因为我们调试可能需要使用# Y, J+ h3 s$ m4 @
) _- p( L) B5 X: u, e5 _8 G
点击软件上方  齿轮键生成  keil 工程  至此: L; b( h# q% W# ~2 w6 n) j$ F2 J
* ^6 q# t6 E( C5 L% z2 ~
MX基于 HAL的库 生成完毕! n1 Z% o4 e+ E% s

- [, y" E: Y& j; j使用MDK 打开工程/ a/ A2 V3 Z9 J, D8 m
从上到下 的组依次为  OS 的C文件
/ o! y+ s' d7 J3 \' l6 @' f" Z.s 启动文件8 I8 r; o7 H& O7 l
用户文件0 c; _( T; k: y% e2 t! p
HAL库文件
6 s1 t# n2 V7 O- `CMSIS中间件文件
$ M: F; P; Y7 @4 O+ m3 ]
4 o  G6 G! j( x0 e( s其中 在 第一组中的 cmsis_os.c 中实现了  cmsis_os  到FREERTOS 的中间层转换   稍后会讨论其中一处代码+ {  E: g( i+ ?! n% {8 R6 `- {

4 s1 |9 H# b! i QQ截图20150108101924.jpg
; J  \+ F+ I4 n# ?+ C( L% j5 g
6 y- U  T2 D# s  ]1 \  N7 {( W! m" `1 G
接下来  添加自己的代码  首先添加 072 上面LED吧  板子不在身边  记得是PA5 控制- T9 z1 [6 k- S

! k% C* b% W9 {2 _# Q先看看  main.c 的 64 到 105行
+ R6 G- n; B4 d. f- V2 B  x0 a

  1. 0 @, z1 `$ ?6 |3 @/ N4 u. E; e
  2. int main(void)
    + k1 b* q% y3 M* k" Y
  3. {" d( N; \+ ]1 u# L

  4. . ]5 d# E) n2 l
  5.   /* USER CODE BEGIN 1 */) ?: ?$ l' N& \4 D$ `4 `. [6 \& m

  6. 8 ^0 A- ]/ c. R! R# R* R
  7.   /* USER CODE END 1 */: E1 g+ [( T+ X& f# p. m

  8. : A; U4 T# h6 r, i* g7 ]
  9.   /* MCU Configuration----------------------------------------------------------*/
    # `* B" ~) X- {/ F* i' M( S

  10. ; g4 V! Q0 Z( E: j
  11.   /* Reset of all peripherals, Initializes the Flash interface and the Systick. *// A, Q( G( s# `- F. D) v7 V
  12.   HAL_Init();
    1 m- a& x3 T2 p* r% a$ G* J
  13. + A1 j. k4 y2 h8 K" W/ P
  14.   /* Configure the system clock */% x2 R) ?% \9 q9 e' Z( z7 x
  15.   SystemClock_Config();
      L8 V8 n& x9 y- s' V5 c9 a) p
  16. * H* C+ v3 Q; p; L! v) k
  17.   /* Initialize all configured peripherals */
    - G+ A1 j& A3 f( s6 U/ b
  18.   MX_GPIO_Init();
    5 v: v7 g9 {% N
  19.   MX_USART2_UART_Init();+ U' j* J) D0 P, }

  20. . S% R+ I" V, l
  21.   /* USER CODE BEGIN 2 */
    & K8 V. ?+ `& n( X; V8 t4 Y0 m8 y

  22. $ @/ Q' q# Z$ U  n
  23.   /* USER CODE END 2 */
    . i( {( F. _/ d+ A7 e

  24. ! H! k2 o6 W5 O+ o6 k
  25.   /* Init code generated for FreeRTOS */
    $ Z5 B5 X( }3 W4 s7 U
  26.   /* Create Start thread */- }+ v; k( P' Z# Z
  27.   osThreadDef(USER_Thread, StartThread, osPriorityNormal, 0, configMINIMAL_STACK_SIZE);3 s# q3 l% g* F8 p. U
  28.   osThreadCreate (osThread(USER_Thread), NULL);# X' @3 [3 K; j9 d8 J( r1 k' t

  29. ) ^- j( W% H$ ^2 @
  30.   /* Start scheduler *// T3 @: Q" H$ s; u  o
  31.   osKernelStart(NULL, NULL);: w' Z  y3 u! m. l$ P& ?5 y' A) A4 K
  32. # L7 V8 D& B( l0 ]; p) Q# G% r" F
  33.   /* We should never get here as control is now taken by the scheduler */
    : o  t7 x/ ~1 v, K! O1 o5 a

  34. % T0 v% f* i* ~! X- h! z
  35.   /* USER CODE BEGIN 3 */. k6 l' M. x, o; E4 p
  36.   /* Infinite loop */
    7 H) P8 e* j+ {7 N/ O
  37.   while (1)
    , X5 `1 _, i/ {2 M5 N8 T
  38.   {9 J* r6 e* z3 \& T" y! v" I3 n
  39. 4 A. d4 z$ u) C$ T$ O4 n( [( R
  40.   }
    / I' O+ ]( `. H% E
  41.   /* USER CODE END 3 */6 d/ q# E* w1 ^% o% S

  42. 2 @& Z! r3 O5 q# z! m  B
  43. }
复制代码
0 G8 R, p1 A) Z  h% `. D
mian函数  C代码的入口  初始化一些硬件后
. P0 u0 k2 t: u+ }9 E" A
  osThreadDef(USER_Thread, StartThread, osPriorityNormal, 0, configMINIMAL_STACK_SIZE);
  osThreadCreate (osThread(USER_Thread), NULL);
  /* Start scheduler */
  osKernelStart(NULL, NULL);

; Z( j- L! ]& t$ M0 o" g定义了一个 线程 USER_Thread 然后启动OS  
( z% R3 ^( B8 T& r8 u2 D注意 osThreadDef  是一个宏  定义一个用于描述  线程的结构体  并不是执行函数
7 c# N# D# r( V

) @/ S7 F# v* T8 T; m宏的第二项参数 StartThread 为线程 入口函数地址。; B" h" @# W$ ~; i: ~" G4 e
7 h9 D* V; Y: [2 c: f9 E- X
至此mian函数的工作结束了 OS将转向 就绪线程并永不返回  也就是执行StartThread  
9 u" M+ W' s, m5 U

8 r* s+ z; w" t! m修改  StartThrea函数 如下0 W" w& u, {7 E* W4 |1 U

3 q7 W6 c, ?4 g0 x8 G

  1. 3 X& @$ O8 I* b6 r
  2. /* USER CODE BEGIN 4 */
    / S* x7 g% f' G) f" E/ T. S' v
  3. void Nucleo_072_Led(const void *par);7 I& C& U9 s6 C4 u% L
  4. /* USER CODE END 4 */
    7 F; @; l% K6 M; K% E7 u9 k

  5. . ~3 s; N! w# g# `6 b
  6. static void StartThread(void const * argument)" w- }. k- ~. x! ]
  7. {
    % q! n$ f# e! o
  8. 5 b2 L& Y) \4 Q7 ~; [1 m: Z, E! P, t
  9.   /* USER CODE BEGIN 5 */
    & V5 c  Z! q1 W* W; ~2 i! A. i7 \
  10.   osThreadDef(LED_Thread, Nucleo_072_Led, osPriorityNormal, 0, configMINIMAL_STACK_SIZE);
    . R5 q: A& d% y& {" m6 F9 G
  11.   osThreadCreate (osThread(LED_Thread), NULL);: ]. x( d' U+ [
  12.   /* Infinite loop */+ ~: P5 l6 q# S9 R  w; }1 z4 u
  13.   for(;;)4 I) u( p1 \3 K4 G& B, u
  14.   {0 C; F# ~+ _, N1 K1 G/ m% T, o
  15.     osDelay(1);
    # o6 @0 `% F: U8 ]1 I( d$ |
  16.   }8 M* m' s5 V; g. c4 Q/ u1 X9 F, b
  17. , H3 p' p$ Q  l) A# i5 P0 H, n
  18.   /* USER CODE END 5 */ - n) A% ]. o7 |2 V% [
  19. ( o" Q& p: a0 z6 B$ c5 u
  20. }
复制代码
- b7 c  Y' c1 r4 E! y2 p* j* k3 ^
添加一个 LED 函数
2 |+ I' U1 i9 u2 i/ C
  1. void Nucleo_072_Led(const void *par)
    9 I9 y' L8 w# t5 A2 M
  2. {- ^$ ]. B, I0 Z
  3.         GPIO_InitTypeDef GPIO_InitStruct;
    0 G3 j" L2 U0 r% @
  4.   __GPIOA_CLK_ENABLE();0 h* j; G$ \. ?6 P3 {) v/ L) J
  5.         , V3 S" l' h! W6 z8 ^+ V
  6.            GPIO_InitStruct.Pin = GPIO_PIN_5;
    0 n* Y  t' R0 A6 t
  7.     GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    1 r5 w$ S* }# g  I' }* J$ K$ o- I
  8.     GPIO_InitStruct.Pull = GPIO_PULLUP;0 _& T8 N6 M( F2 P
  9.     GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
    0 C" v" m$ ~6 R' [- @4 x3 h( \6 g

  10. # b% C! o3 p- X6 w8 y( D+ [
  11.     HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);0 ?* w- V! N3 Y/ q" e: W
  12.         ! P, X. Z+ i3 ~( }' A
  13.         for(;;)
    / S$ }% A5 z. m: l1 i
  14.         {
    , ^: D) Y5 P5 P
  15.                 GPIOA->ODR^=GPIO_PIN_5;// PA5取反 LED闪烁8 R" K4 A' f6 D5 d
  16.                 osDelay(500);
    * Y% s& l3 s9 b% u3 l) }
  17.         }
    ) C- [: C, U6 U# R8 i! X$ F7 g) O! Z

  18. + i' }, R' v1 f# e6 ]. \0 n. }
  19. }
复制代码
! \2 Y- G* y" w0 m+ J. \) u
到这里可以编译下载到板子上运行 观察现象了
$ Q: l5 ~- ^7 u% P4 u! E* |* W8 l( b$ h1 f
下面创建 RXT 的工程  新建一个工程  
  ~2 p; n. e) O6 a1 E3 n
; j/ j7 H3 g1 u* X6 n0 ?4 u$ W, \勾选 如下选项 " M5 ~* }( E7 Z9 C. B

! \5 F  `* k& \9 q QQ截图20150108112304.jpg
5 a) A& K3 L" y/ H$ u" z红框 不要添加  不知为何  楼主添加 MDK的 startup 编译通不过 5 B, Z& [6 O9 w2 B9 k
F4 的工程没有包含  HAL  接下来 需要自行添加HAL 库 3 U; {0 S) ^4 t2 [  l

( A4 J) _1 a) U, y6 E把原来的 main.c 复制一份更名为  rtx_main.c2 W. L( o' Z$ v
0 Z3 R+ c' g8 F
QQ截图20150108113501.jpg 4 C+ X: r" @" t! f+ A3 a: M

) z) r3 a1 s$ G7 q+ ?文件添加完毕 9 K$ [1 T$ W" }9 D+ e* j! t' n2 l

8 I3 D& }5 h+ a$ n) U$ h接下来定义 头文件目录和 系统宏
/ H6 m2 p5 ~- x" g0 R
' u4 x7 q  L; h9 P' j QQ截图20150108112609.jpg 3 P- p2 _2 o) A4 }- q1 ~

  H9 m5 v) w* p+ I/ k修改 rtx_main.c  下面两处需要修改
& x: J1 M- C0 s9 ^/ [: @
5 }& q1 a* E7 W- @1 P
  1.   {
    . |6 s, g6 u1 K0 l1 _1 g
  2.   osThreadDef( StartThread, osPriorityNormal, 0, 0);
    * [$ z' P0 U5 O# C
  3.   osThreadCreate (osThread(StartThread), NULL);
    3 P6 Y2 L) V- M) l% X4 g$ K" W
  4.         }
    6 h5 S6 k4 @  Q" w3 l
  5. / g3 T1 ]" _. _( R
  6. osThreadDef( Nucleo_072_Led, osPriorityNormal, 0, 0);. ~: l1 f6 Y. e6 q% @+ F* e! E3 N* a/ m
  7.   osThreadCreate (osThread(Nucleo_072_Led), NULL);
复制代码
不知为何  ST写的 中间件和 MDK的 接口有一点差距  所以 创建线程的地方需要如上修改
+ G& X% B9 B9 E0 ~4 @
. T1 C. r- F+ }8 G/ h; k修改 stm32f0xx_hal_conf.h
- v5 u: z" w4 ^4 J* r添加 图示内容  不出意外  下面 将可以直接编译了!!
# B. l, p! f; J% m" L& Z QQ截图20150108112936.jpg # ?' d9 D( r5 X1 ~* N0 S

* w/ n: b6 j+ o: r( z  m4 z写的有些多了  本来想 继续写 RTOS 基于串口的  应用  太长了 下次发帖写了! l  |' r$ v$ \7 g/ O+ Z6 k

& Z. \& l0 j6 J" z0 c9 }% W( v8 x下面提出一个讨论 MX 创建的  工程 FREERTOS 中 cmsis_os.c 中 创建一个信号量  
) @7 e3 Q0 h" c( S6 BosSemaphoreCreate参数 count 直接
2 P. Z' K7 G0 V5 h, K9 U& y
' h% }# Y/ e: l/ P2 a传递给 xSemaphoreCreateCounting的两个形参  
+ W! K: l' D# G& o; W* b QQ截图20150108115258.jpg
( V2 E4 s+ J# e0 }原型 9 _* {. w# x4 v: U
#define xSemaphoreCreateCounting( uxMaxCount, uxInitialCount ) xQueueCreateCountingSemaphore( ( uxMaxCount ), ( uxInitialCount ) )6 k' Z1 k& g/ D1 m1 u! `8 [3 w

/ f7 ]0 B# b8 }; o  W! |( l. N该宏创建一个 数值型信号量 第一个参数是 信号量最大数值  第二个则为  初始化值
) _5 z  Y5 U, p6 Y+ H8 `! L; I
7 }& `2 ]( O2 T2 @! H基于串口使用信号量  那么需要如下要求$ @0 @3 T3 Z& B- Z$ z; M
假设 usart_sem 为串口使用的信号量2 w% {: [3 J8 _
每收到一个数据 usart_sem ++  缓冲 1024字节
" {$ I! O' T& M7 Y% I2 H需要数据的线程 osSemaphoreWait(usart_sem ); 当有数据时 线程被激活  获取数据- H# h% ~( b  p9 g0 N# D  C

% o0 _8 r" C% G2 v  \如此我们知道 这个信号量的 最大值应为1024
2 u: H8 _* A/ ^% `可是使用 ST 的cmsis_os osSemaphoreCreate 创建一个信号亮 osSemaphoreCreate(0,1024);
$ g" A/ @; F% W; p2 f( M
3 O% @% ~7 j7 P! g) y# J+ A6 i会出现这样的问题 !  此信号量 被赋予初值1024  意味着 这个信号量将可以被osSemaphoreWait 1024次) W: c+ S; L) {  Q' I' |% K' t
显然这不是我们想要
* ~/ o0 y8 Z% e) H) i+ h; H; o/ c
通常  我们需要的数值型信号量  最大值可以很大  但是初值 基本为0,或1 * U! D/ \7 z, p
: c9 v% [4 m, O/ ^: E/ S
不懂  这样设计意义何在?& Z8 Q' a5 R; M3 n2 b

* f% D: A% g$ o$ X
2 f# V$ `, v; U' C/ e 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 编辑 ; ~4 D0 F" h+ N4 }; T& j
lovewyufeng 发表于 2015-1-23 12:56
, d* x7 T% b( H: z事实上  只要这个计数不为0 都能被 wait 到
5 _7 F* |; m7 ^+ n; A/ V
不好意思,确实被代码的名称误导了,以前用的基本上只用二值的semphore或者直接用queue了。
- E* T: [5 S, Y3 f! Z: X仔细看了一下内部的实现,确实我说错了。- ]% m$ A' {: |/ H* y# r* p
在init_counter和max_counter一样的情况下,确实整个逻辑是要按照资源池来解释的,也就是确实生产者take(这个take代表获取空闲资源才能生产),消费者release(这个代表空闲资源返回)。我觉得这种情况semphore更像一个可重入的锁,处理线程拿走资源池后,直接处理完后再归还,像是个recursive mutex。& ~( L* Q! t4 S
前面说的那个问题,直接用queue可能会更好。另外,今天试了一下最新的stm32cubemx和固件版本,代码已经改了,#if (configUSE_COUNTING_SEMAPHORES == 1 )        
9 Q' Q& b" @  E# S  S3 G  return xSemaphoreCreateCounting(count, 0);5 v) T( `+ ]4 B$ q8 R7 N
#else7 Z8 O/ ]3 i) O# h7 l4 q6 S
  return NULL;
3 g/ e4 N+ l- u. S0 s: y#endif
1 ]2 z6 |. Q1 m# ]4 _1 j9 ]}
% l/ `& e) Z7 z. ], f5 E
. b0 c% y$ K9 [7 u( m* x0 f. x- J( a* p" q+ g! B- E

% q/ B0 G, s9 ~. G& V. f' }( L5 I4 v" q5 K
我是东哥 回答时间:2015-1-23 07:50:34
lovewyufeng 发表于 2015-1-23 00:486 C% w* o4 m3 o: e) I3 m- L
反过来理解是吧,说得通。可是1 Y. Y! @1 @  s$ Y, }8 [! v" I
有个问题。,生产一个就-1的话应该 take获取信号咯?   反过来消费应该pos ...
+ _0 H8 w2 J; u: h2 X
你陷在细节里面了,看看人家的API是怎么样写的,osSemaphoreRelease和osSemaphoreWait,我们在生产者里面应该要osSemaphoreRelease,而在消费者里面osSemaphoreWait,是吧?字面理解,相当于生产的人释放了一个东西,然后消费者就等待生产者的这个东西。再看里面的实现,osSemaphoreRelease里面是xSemaphoreGive而不是take,而osSemaphoreWait里面是xSemaphoreTake而不是give。
3 C: Q- H4 H4 m  u3 v' a* @- l, Y% Z- q7 J所谓的反过来理解只是一种理解方法,说take和post的逻辑也反的话是不对的。不要老想着什么时候去post,什么去take。cmsis_os的API意思很明了,生产者生产了东西就应该release,消费者就应该Wait,这不是很好理解吗?
lovewyufeng 回答时间:2015-1-23 00:48:46
我是东哥 发表于 2015-1-21 12:18+ Q+ H3 `. q* P( l
这个其实也没有不合理,看你怎么理解,资源一开始为0,也可以理解为空闲池一开始是满的。生产者生产了一 ...
% ~, V2 D+ A% b* @$ F& {9 X8 |1 M8 B8 K6 O
反过来理解是吧,说得通。可是- G/ r: V: o* }9 q0 u/ V6 Q2 c0 Q7 E
有个问题。,生产一个就-1的话应该 take获取信号咯?   反过来消费应该post 释放信号咯? 那么问题是 post是非阻塞立即返回的而take是阻塞的?9 @3 T% }* n) I# \/ _
先不谈消费者应当随时饥饿,处于阻塞态。6 V1 i3 p7 u4 _# S/ P) W
生产一般在中断里吧,当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
看看 顶一下) Y+ l* y9 b& ?9 P/ g8 U; V
cqtnheyao 回答时间:2015-1-8 12:19:01
harvardx 发表于 2015-1-8 12:13" W- Q/ V7 A  ]2 ^
有钱为何不顶帖 .何况还是高质量的 .cubemx 势在必得的趋势.支持一下.
6 @8 h' |& I) p( w+ j8 Z/ D: @
据说库很大,效率低?求告知!
netlhx 回答时间:2015-1-8 12:19:08
很好,图文并茂
lovewyufeng 回答时间:2015-1-8 12:19:26
harvardx 发表于 2015-1-8 12:13' M: t* d; [9 G
有钱为何不顶帖 .何况还是高质量的 .cubemx 势在必得的趋势.支持一下.
3 ]0 P. U' e- X; s. p7 D
多谢老大 支持  继续加油
lovewyufeng 回答时间:2015-1-8 12:23:05
cqtnheyao 发表于 2015-1-8 12:19$ u+ z( T) q' }( @
据说库很大,效率低?求告知!
) {9 S  S3 ^7 ]1 [+ W+ F
确实 有这个毛病  楼主的贴初始化使用库  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 手机版