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

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

[复制链接]
lovewyufeng 发布时间:2015-1-8 12:08
以刚拿到手的 Nucleo 072为例  其他板子用户 请举一反三哈 (工程文件在帖末/ x) f' G! v8 ?+ \, @8 m
# g2 O) w1 `' _( H  H. S8 P, a
5 A$ _( O" y' i
后续帖子:【干货】Nucleo072 usart 基于RTOS的应用  方便AT指令类外设开发
4 u7 X4 \* i! Z% J( k! |' O' c! h% Z$ K; K  a# H+ u1 i& Q
需要工具  MDK5 自行下载:8 j" u! m2 U( @
STM32CUBEMX https://www.stmcu.org.cn/document/detail/index/id-214984
. [1 r( W/ t9 fSTM32CUBEF0 https://www.stmcu.org.cn/document/detail/index/id-216669
& ?% D9 v' W& _' P. R5 x1 E# {" n4 p" l$ s) y
! `1 ]; V! U' V! A/ X  r. @. y) y
安装 cubeMX  由于使用MX下载固件库速度那是不说了相当慢啊  所以下载 STM32CUBEF0固件库然后下图安装9 l( y$ M  I3 m: O7 J1 P

, d: R: c7 D( k: Q. K
+ ], s+ M. x! S QQ截图20150108101548.jpg QQ截图20150108101556.jpg
& C9 {0 N) Q) _. n0 Q6 K
7 w6 v- e- \2 n$ F$ a/ J. t, p安装之后  新建一个工程 选择STM32F072RBT6
7 ~. h7 e( [% v" ]
5 z$ q" u' l) L/ s7 [4 T% iPINOUT 勾选  FREERTOS和 USART
3 b) G; h, D+ y/ T1 [0 Z6 ^3 A QQ截图20150108101539.jpg ' Q9 E4 Z8 ^" R! B$ ~& G% ]9 a
因为我们调试可能需要使用
/ ]2 z4 j& D* l; F- F9 ~7 f% U, }/ H4 y9 b. {( F# c' V& `+ r
点击软件上方  齿轮键生成  keil 工程  至此& }& O- r3 O" R

% ?6 E1 j0 j' O0 |MX基于 HAL的库 生成完毕: M. K$ {4 X! [: T1 W

+ U) X1 B! P* f3 P$ Q$ }7 o使用MDK 打开工程2 X( p- G# {2 m& i9 c) v9 E
从上到下 的组依次为  OS 的C文件( n7 ?  A( z* e0 P
.s 启动文件" z( U% w; Y; X6 |# ?( u& C
用户文件1 Q2 s- p8 q. A$ [, n
HAL库文件
1 v  @. }; v3 pCMSIS中间件文件
3 j  t" |7 v; q* E) |: i0 P4 U+ j' |
# A0 k$ m$ W  p1 R" c, Y其中 在 第一组中的 cmsis_os.c 中实现了  cmsis_os  到FREERTOS 的中间层转换   稍后会讨论其中一处代码- W6 V3 A4 b& x

3 V; l# I! O6 n0 x+ e! A QQ截图20150108101924.jpg 2 @" _1 C; j# e1 F- T% Y3 [1 s

6 l* X) y' M9 t- l1 ]" m: C3 k: o/ x& w6 {6 m$ I, X. [- V
接下来  添加自己的代码  首先添加 072 上面LED吧  板子不在身边  记得是PA5 控制8 V* C+ I; @& h9 O& m, E. [
6 c+ v# \& t! j
先看看  main.c 的 64 到 105行 4 X$ V( W& D$ h, T7 l5 I

  1. 5 J" z* b' t. C' u2 p/ l9 k
  2. int main(void)
    - T, ~/ J9 _  `. M& L3 S
  3. {: E) k) ^, }1 Y. Z* q" [+ t! k* W

  4. & r2 p! u: v) c2 n' t0 H1 B5 e
  5.   /* USER CODE BEGIN 1 */
    & r! O3 v5 v8 S1 a
  6. " s9 y3 S$ L7 n3 E/ Y
  7.   /* USER CODE END 1 */  O! @' y0 o$ h3 H/ O% O
  8. ! _6 D  e8 d$ @/ R, n
  9.   /* MCU Configuration----------------------------------------------------------*/* F2 `3 N, B# J  q, P: w9 t, }% Y

  10. 7 n: y; I1 T3 ?" j
  11.   /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
    8 Q5 W+ D4 ^# C6 B
  12.   HAL_Init();' n0 G7 ]8 U6 N; s0 M* ]8 I
  13. 4 p. C/ F  F, W" D
  14.   /* Configure the system clock */
    , F) h, M( M3 Z! e! R
  15.   SystemClock_Config();
    2 i5 A" Z$ [+ I4 L! z9 h
  16. & B: n0 R$ Z* [7 I! u* W& l
  17.   /* Initialize all configured peripherals */' ^1 z& t' G6 W! j5 D  i
  18.   MX_GPIO_Init();) _9 _" o! a! t
  19.   MX_USART2_UART_Init();" m; R2 Q, q' H! q3 z2 }/ v
  20. + R# l& e" f5 a- Y
  21.   /* USER CODE BEGIN 2 */2 h7 A2 z  z& i8 Z
  22. * [) d; a3 @9 l% d6 k: ]* o
  23.   /* USER CODE END 2 */
    9 e0 ?' z4 R! Y( d$ G# e& p, F

  24. 2 ]  l2 m- E5 b$ e) s. F3 y' {
  25.   /* Init code generated for FreeRTOS */) P4 I6 g2 k/ |, K7 S
  26.   /* Create Start thread */! M) o% w7 U: d- M" d
  27.   osThreadDef(USER_Thread, StartThread, osPriorityNormal, 0, configMINIMAL_STACK_SIZE);. E/ [. k& |% C1 W+ N
  28.   osThreadCreate (osThread(USER_Thread), NULL);" ]: p) W$ U: K* N1 T; b' t% z8 T

  29. ) ~" {0 O. H& k* F
  30.   /* Start scheduler */; e0 |: n: t/ p$ q
  31.   osKernelStart(NULL, NULL);
    + k0 u2 a# C$ R! s# U7 P8 X8 t
  32. " c# g8 M6 ?) k$ ]# c
  33.   /* We should never get here as control is now taken by the scheduler */5 j! Y1 D2 |" U3 W

  34. $ a' o; y6 ?1 B9 k2 Y
  35.   /* USER CODE BEGIN 3 */# ^: |& U& M- x, {+ ?
  36.   /* Infinite loop */
    1 [. Y1 b% i0 Y6 S4 ]3 `
  37.   while (1)* G3 J5 N' s8 Q- B+ D
  38.   {* ?5 U" A/ T& k! V1 G" I  b( T7 x

  39. : C* U- L9 F, N
  40.   }
    + V" w- o7 a- h. E
  41.   /* USER CODE END 3 */
    # w* q) \+ k+ c% ^7 s; U  ~
  42. 0 `$ R6 g7 K0 K9 U/ S  M& I+ Z, a
  43. }
复制代码
- \# a' R; c- \+ c8 q& c: D
mian函数  C代码的入口  初始化一些硬件后
( x7 m9 m- _( S% }' }! j
  osThreadDef(USER_Thread, StartThread, osPriorityNormal, 0, configMINIMAL_STACK_SIZE);
  osThreadCreate (osThread(USER_Thread), NULL);
  /* Start scheduler */
  osKernelStart(NULL, NULL);

% r' ^  C  ?1 K4 @6 h: b定义了一个 线程 USER_Thread 然后启动OS  
6 L3 H2 Z4 `% W" @% x注意 osThreadDef  是一个宏  定义一个用于描述  线程的结构体  并不是执行函数8 B( ?* m$ Y: N. Y0 ~2 b6 f

' G5 }% [* A" A9 V' r9 x宏的第二项参数 StartThread 为线程 入口函数地址。3 d4 v% Q. N( @

8 \5 \4 f% r( A! {8 f& t! G. y# \2 A至此mian函数的工作结束了 OS将转向 就绪线程并永不返回  也就是执行StartThread  * e5 Y4 A# d9 }# p& v# r

1 z$ Q  t; i. o! a" s- F修改  StartThrea函数 如下
2 @% P) p7 }, Q7 @, q1 \' ~% c9 M9 k2 _  F& y
  1. 5 {" m* I8 s  K3 h
  2. /* USER CODE BEGIN 4 */
    8 V3 B- E" o9 M" n6 m' i8 j
  3. void Nucleo_072_Led(const void *par);
    . u2 f( w( u6 N3 {
  4. /* USER CODE END 4 */0 Z" f$ L3 ]% W& n- ~0 ]

  5. $ G& Z' Z  a! F3 I
  6. static void StartThread(void const * argument)
    3 G6 _0 V: |* }! g
  7. {' n$ ~& v0 v3 k
  8. ! L% R9 R# {- J% ?0 w# e+ {" F
  9.   /* USER CODE BEGIN 5 */
    ( C/ I3 L; G6 b" v$ @( c% W
  10.   osThreadDef(LED_Thread, Nucleo_072_Led, osPriorityNormal, 0, configMINIMAL_STACK_SIZE);$ M- }1 e% h$ K
  11.   osThreadCreate (osThread(LED_Thread), NULL);/ ?: v, z/ Z! H; R  C2 K; t
  12.   /* Infinite loop */4 w& q9 n4 A! n" p
  13.   for(;;)
    " y! {7 O1 ]6 Z- K
  14.   {
    . n# W! q! l* G7 U7 \1 O/ j) }
  15.     osDelay(1);
    & _* i2 ]( v, o0 e5 h
  16.   }
    ! Q3 B( g- A4 k+ Y4 J7 V) \! f
  17. : [! y/ W$ c- r5 H  J. A
  18.   /* USER CODE END 5 */
    : w3 ?5 E2 \7 l& z; t  \& i; v3 j7 b

  19. ) m+ X. j8 J& z$ X
  20. }
复制代码

1 f  H: {+ ~8 u( H! S添加一个 LED 函数5 S. X+ k' S- M/ a- z% S
  1. void Nucleo_072_Led(const void *par)
    / M  f) s0 ?/ M) a) c  q
  2. {
    ( R1 x1 b6 g, U$ K% H
  3.         GPIO_InitTypeDef GPIO_InitStruct;0 R2 x, N* n, g1 z2 w
  4.   __GPIOA_CLK_ENABLE();
    4 J; \7 K0 x, g# ]* M
  5.         
    2 o$ d" O- l+ s% R
  6.            GPIO_InitStruct.Pin = GPIO_PIN_5;2 u; N! M0 z9 h( K2 f
  7.     GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;" e+ e, b0 O# p6 B
  8.     GPIO_InitStruct.Pull = GPIO_PULLUP;
    - E/ o/ A/ U3 U  C+ L, f2 j" a; \& K
  9.     GPIO_InitStruct.Speed = GPIO_SPEED_LOW;0 s% A' \7 }. K

  10. & P! s7 \) P* D' l
  11.     HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);( m( d# U& U4 \6 }2 X7 t
  12.           _7 r/ t' p, J
  13.         for(;;)  U  g" \& ~$ D) g& y* [  W7 v# U
  14.         {3 H6 R. l7 t+ J# l8 z& r6 g% _
  15.                 GPIOA->ODR^=GPIO_PIN_5;// PA5取反 LED闪烁
    * }* y1 z3 i, V  Z' B3 \8 _
  16.                 osDelay(500);# O5 \0 K$ f9 a; {. s# S8 \
  17.         }( K5 N# Y  _. M8 X, ]% Y

  18. , }, F9 c* i& z9 V( ]
  19. }
复制代码
/ J) {7 B( B: q) \) H
到这里可以编译下载到板子上运行 观察现象了& z$ J, N( L) k3 @$ |
! e5 G! B8 [2 c5 x# V
下面创建 RXT 的工程  新建一个工程  
% w: m3 k* M: B+ j. U) I% d5 I2 F$ h
勾选 如下选项 ! Y8 ^) b% }0 V5 h
) K% B- Q* j. {( W, C- h9 c
QQ截图20150108112304.jpg 5 ~+ @4 z) Z5 F& @' S
红框 不要添加  不知为何  楼主添加 MDK的 startup 编译通不过
7 |2 G3 m/ x5 e  i* PF4 的工程没有包含  HAL  接下来 需要自行添加HAL 库
+ s  [# ?5 b* U! I& D" S( {. s/ C& s) S; |
把原来的 main.c 复制一份更名为  rtx_main.c" q* y* v) ]0 O7 A( U: O

3 g* s$ N# |9 o: Q QQ截图20150108113501.jpg
& ^; X  G& F7 W# @9 Z5 H, }5 b! x4 C( _: O; E' g1 s6 {
文件添加完毕
% S8 X' i9 Q- e0 [: N8 j. y0 y& \$ i' K
接下来定义 头文件目录和 系统宏
# E& ^( V( f, P( f2 ]" D) y, c" T' Y! q; l! d% E* r" Z/ f
QQ截图20150108112609.jpg
! N- j1 i% R- F2 ]4 h0 l
$ B* H8 q1 T8 L, V0 U0 l, k修改 rtx_main.c  下面两处需要修改
3 t+ o( a/ H# _+ Z4 w/ d  f6 t' R7 k
  1.   {. ]% ]9 k) x" N2 P6 S
  2.   osThreadDef( StartThread, osPriorityNormal, 0, 0);
      s" N/ {3 d* j1 F* s4 o
  3.   osThreadCreate (osThread(StartThread), NULL);
    1 |: j+ d8 z& w$ F3 D8 d
  4.         }0 s+ C5 d. V) D$ Z

  5. : n& ?9 s+ y  E1 ~) _
  6. osThreadDef( Nucleo_072_Led, osPriorityNormal, 0, 0);1 f1 x2 Y& \4 b- U$ q7 d, X* f( l2 {
  7.   osThreadCreate (osThread(Nucleo_072_Led), NULL);
复制代码
不知为何  ST写的 中间件和 MDK的 接口有一点差距  所以 创建线程的地方需要如上修改
) e4 x- a0 Y" l+ p* M/ \' D3 b! ?$ m' N( y: M+ P
修改 stm32f0xx_hal_conf.h
. ]% u1 o8 n/ g1 r) X添加 图示内容  不出意外  下面 将可以直接编译了!!
3 m. h% @7 Y! ~& m6 u QQ截图20150108112936.jpg
+ q  R' z- b5 E6 ]# v" G2 }' A5 ?1 Y6 P+ \
写的有些多了  本来想 继续写 RTOS 基于串口的  应用  太长了 下次发帖写了8 m5 W$ H; `# C/ `1 Y  ]

' `5 x9 h7 z, ~/ @. d. ?下面提出一个讨论 MX 创建的  工程 FREERTOS 中 cmsis_os.c 中 创建一个信号量  3 j( t3 M5 j3 {: E9 C: i! R8 {2 \! W
osSemaphoreCreate参数 count 直接
* f! [- V) P( c( E3 X$ Y3 j& D+ ^0 ~, e  c7 t
传递给 xSemaphoreCreateCounting的两个形参  
, ]1 t/ W; G, V5 u QQ截图20150108115258.jpg ( ~2 ?7 z* g; K7 {
原型 * [0 u& Q. J* R
#define xSemaphoreCreateCounting( uxMaxCount, uxInitialCount ) xQueueCreateCountingSemaphore( ( uxMaxCount ), ( uxInitialCount ) )
$ l4 V  r% V/ i0 U9 Q) ]
* X" a& j  [" o1 ^1 I3 N该宏创建一个 数值型信号量 第一个参数是 信号量最大数值  第二个则为  初始化值8 x5 K0 `8 ?! x" w) J

0 V4 f% b. p: |! u基于串口使用信号量  那么需要如下要求
3 W2 @" \% h$ k; k, b# @假设 usart_sem 为串口使用的信号量
2 p4 a5 A! q8 {, n2 M0 _3 c' U每收到一个数据 usart_sem ++  缓冲 1024字节 3 A  u$ w1 o5 n1 Z: T
需要数据的线程 osSemaphoreWait(usart_sem ); 当有数据时 线程被激活  获取数据, ]$ H- J: w+ ]! a. ]5 F# v+ x$ Q

: Q- B1 k4 ~' }9 ^: v如此我们知道 这个信号量的 最大值应为1024 5 d( P5 L) o! r, o5 `
可是使用 ST 的cmsis_os osSemaphoreCreate 创建一个信号亮 osSemaphoreCreate(0,1024); 8 y7 q! n5 u( z" Y
7 l3 Y& r" \! L
会出现这样的问题 !  此信号量 被赋予初值1024  意味着 这个信号量将可以被osSemaphoreWait 1024次
0 U+ A2 B' m% h, v3 `显然这不是我们想要 7 R" H; b* k# y
/ L* B3 F; T7 X& C' W
通常  我们需要的数值型信号量  最大值可以很大  但是初值 基本为0,或1 4 z0 S( D' T6 q# Z9 q# F

3 y. M, |$ `. _+ I不懂  这样设计意义何在?
" \; h6 k9 P0 ?/ w, \6 T
4 b3 |- C$ J1 W2 V! N' `
$ Q) @" [. B8 A+ a5 ~8 B 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 编辑
% O  s" `0 ]9 O* k9 I- \
lovewyufeng 发表于 2015-1-23 12:56% d* Y' b& V& A" W
事实上  只要这个计数不为0 都能被 wait 到

$ ?4 R) X- n& B3 v! ^不好意思,确实被代码的名称误导了,以前用的基本上只用二值的semphore或者直接用queue了。
( }$ n3 e/ W2 h3 Q$ v+ N: X" C仔细看了一下内部的实现,确实我说错了。
5 B& O5 s# \* P1 V在init_counter和max_counter一样的情况下,确实整个逻辑是要按照资源池来解释的,也就是确实生产者take(这个take代表获取空闲资源才能生产),消费者release(这个代表空闲资源返回)。我觉得这种情况semphore更像一个可重入的锁,处理线程拿走资源池后,直接处理完后再归还,像是个recursive mutex。
2 P$ k, r  |; n3 R. I前面说的那个问题,直接用queue可能会更好。另外,今天试了一下最新的stm32cubemx和固件版本,代码已经改了,#if (configUSE_COUNTING_SEMAPHORES == 1 )        
6 ]  L+ Y" \0 f7 `. w" u  return xSemaphoreCreateCounting(count, 0);
9 q) X" d% t& @) j#else
9 x! e) l+ S9 p0 Q  return NULL;3 j' l+ A2 C- H! J7 F1 o6 y
#endif
9 z$ l. `/ {: m2 j& L  @# K6 e}5 q0 u5 W, y9 m, U/ a
1 q: @+ W+ b# e3 K
+ U0 V0 Q/ H. r7 o' C6 w

1 v$ d+ V, I) Q5 d7 U& _& u* \
, U5 I' S* ?0 Q( ~  {4 p
我是东哥 回答时间:2015-1-23 07:50:34
lovewyufeng 发表于 2015-1-23 00:48
8 r6 v/ O) R" u2 G- s反过来理解是吧,说得通。可是
' _/ e4 L  D9 e" V( G" _. @有个问题。,生产一个就-1的话应该 take获取信号咯?   反过来消费应该pos ...

& q  @* P9 O: r. Y4 |% T  k3 @9 z你陷在细节里面了,看看人家的API是怎么样写的,osSemaphoreRelease和osSemaphoreWait,我们在生产者里面应该要osSemaphoreRelease,而在消费者里面osSemaphoreWait,是吧?字面理解,相当于生产的人释放了一个东西,然后消费者就等待生产者的这个东西。再看里面的实现,osSemaphoreRelease里面是xSemaphoreGive而不是take,而osSemaphoreWait里面是xSemaphoreTake而不是give。
, Z+ X' z5 K. L) o所谓的反过来理解只是一种理解方法,说take和post的逻辑也反的话是不对的。不要老想着什么时候去post,什么去take。cmsis_os的API意思很明了,生产者生产了东西就应该release,消费者就应该Wait,这不是很好理解吗?
lovewyufeng 回答时间:2015-1-23 00:48:46
我是东哥 发表于 2015-1-21 12:188 T+ L% W" g0 r; \  |0 l
这个其实也没有不合理,看你怎么理解,资源一开始为0,也可以理解为空闲池一开始是满的。生产者生产了一 ...
& S1 e! ~" z* a
反过来理解是吧,说得通。可是
% X* H* U0 f  d7 g% F, |  y; s有个问题。,生产一个就-1的话应该 take获取信号咯?   反过来消费应该post 释放信号咯? 那么问题是 post是非阻塞立即返回的而take是阻塞的?
- _# q; D0 _9 u( x, x! j先不谈消费者应当随时饥饿,处于阻塞态。
% O1 @' x/ R4 u2 S, W$ f5 B生产一般在中断里吧,当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
看看 顶一下, F' b4 S% Y6 B% h
cqtnheyao 回答时间:2015-1-8 12:19:01
harvardx 发表于 2015-1-8 12:134 ]( Y; e0 @3 _" ]% x' `1 y$ [1 l
有钱为何不顶帖 .何况还是高质量的 .cubemx 势在必得的趋势.支持一下.
5 d  \5 J0 y4 f
据说库很大,效率低?求告知!
netlhx 回答时间:2015-1-8 12:19:08
很好,图文并茂
lovewyufeng 回答时间:2015-1-8 12:19:26
harvardx 发表于 2015-1-8 12:13
0 s& ?% W. d6 a4 _2 r有钱为何不顶帖 .何况还是高质量的 .cubemx 势在必得的趋势.支持一下.
- {" U9 \; h" }2 {; C
多谢老大 支持  继续加油
lovewyufeng 回答时间:2015-1-8 12:23:05
cqtnheyao 发表于 2015-1-8 12:199 w) o$ x; M3 A- @" ]5 K; q
据说库很大,效率低?求告知!
8 ~/ i1 G0 w5 X
确实 有这个毛病  楼主的贴初始化使用库  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 手机版