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

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

[复制链接]
lovewyufeng 发布时间:2015-1-8 12:08
以刚拿到手的 Nucleo 072为例  其他板子用户 请举一反三哈 (工程文件在帖末
! V: T: ^  A9 k: f( V
. p7 l$ N3 K4 o& @; p1 R/ `# D. G" ~! b! W) ]
后续帖子:【干货】Nucleo072 usart 基于RTOS的应用  方便AT指令类外设开发6 B9 Q6 ~5 t) u  P7 o- }5 k: |9 r" z

% R/ x0 I  E+ V, F. ?2 h需要工具  MDK5 自行下载:! m+ _) J( d6 [
STM32CUBEMX https://www.stmcu.org.cn/document/detail/index/id-214984# \3 u/ v' ~( D+ W) K6 u
STM32CUBEF0 https://www.stmcu.org.cn/document/detail/index/id-216669  ]; s! [1 \, q( |/ i  d$ Y$ n' E
1 L+ k3 h$ X, h+ }# w

3 C* l/ S! t+ D/ [7 d安装 cubeMX  由于使用MX下载固件库速度那是不说了相当慢啊  所以下载 STM32CUBEF0固件库然后下图安装
- a/ s4 g4 {5 R% _- ?  y$ ^# V& n) e" v

$ F/ `0 G: k. {. G, H QQ截图20150108101548.jpg QQ截图20150108101556.jpg ' z3 w3 r( m5 v6 v
, W4 {/ m& e/ Y% r$ s! g
安装之后  新建一个工程 选择STM32F072RBT6/ R3 j$ _3 T; m2 T* M
0 p6 @, z( ]5 a; K/ W  L) ~. s
PINOUT 勾选  FREERTOS和 USART
) F) W( Y/ m% B3 V QQ截图20150108101539.jpg
2 L0 U; l  R2 v3 o4 Q- O7 ~) k* [因为我们调试可能需要使用6 i6 u* W2 q, h: z4 \7 H; x

* K. C6 ^3 F. s' n4 s2 i点击软件上方  齿轮键生成  keil 工程  至此1 S; s( `2 c( U

3 z7 O/ l# R* J7 v% k  kMX基于 HAL的库 生成完毕
. i8 H! T3 ?; e
) ~- k7 p1 r+ d4 D使用MDK 打开工程
' p5 n; ?7 g& R8 _, o6 C从上到下 的组依次为  OS 的C文件1 \) ^5 D3 q2 e: ?7 O
.s 启动文件; }! W; t/ i* A# p, U7 @5 p
用户文件* G" p5 ?, h: W
HAL库文件  t, l% {# J3 E7 q
CMSIS中间件文件5 E" W5 b* j% r; Q$ ~

" F% m9 w" Z& T* f其中 在 第一组中的 cmsis_os.c 中实现了  cmsis_os  到FREERTOS 的中间层转换   稍后会讨论其中一处代码" I5 c3 c) H4 A( S! V8 H

8 [5 B* T) S2 P2 I1 e QQ截图20150108101924.jpg
# S2 m, }6 V" @, U* m# X; ?5 g
- h0 W. O7 n  k1 |! h" |0 y) }1 K/ [. L
接下来  添加自己的代码  首先添加 072 上面LED吧  板子不在身边  记得是PA5 控制9 I4 {9 ]% G* L' w
  x  {0 C( c' X0 u1 k
先看看  main.c 的 64 到 105行
8 a2 n* O+ u# F' U+ i4 t* j
  1. ' u. J, i+ Q. s; \5 x% @
  2. int main(void)
    / _3 P, }+ M) }; s! s) U+ R# n6 Q( q
  3. {' E8 V9 w3 W$ t* L1 ^8 |

  4. ' y( Y+ Z* f; X: M
  5.   /* USER CODE BEGIN 1 */
    4 E9 Z6 G. k: f" ]. b) F' V

  6. " l) B0 f6 y; D# p
  7.   /* USER CODE END 1 */
    ' w- ~4 J+ g4 x

  8. 2 j+ ^% P8 U/ U# s
  9.   /* MCU Configuration----------------------------------------------------------*/
    ! Q; w& W4 n: R2 c* B, j7 V; _0 q

  10. 1 ~& B( _% O' Y7 d7 C" ^/ E
  11.   /* Reset of all peripherals, Initializes the Flash interface and the Systick. */6 p! a5 ^8 v5 _0 p4 Y; W
  12.   HAL_Init();
    % J+ p- g1 d" A1 F
  13. / c) k" |" q" \. k7 m
  14.   /* Configure the system clock *// z0 I+ O7 C/ p+ J1 H
  15.   SystemClock_Config();# i; R0 `6 s. A5 t" _- `7 K
  16. " k; P3 }$ R. c3 J. s3 k
  17.   /* Initialize all configured peripherals */
    . h- z8 h( V6 W6 O: ?- \
  18.   MX_GPIO_Init();9 x, k% G0 g0 p, u8 D: p+ N% j
  19.   MX_USART2_UART_Init();- s1 K  L$ B* _+ Z
  20. " D% ]; R* y8 m, U- j4 {9 M3 n7 N" E
  21.   /* USER CODE BEGIN 2 */# _* T+ J- h- W. I$ Z1 o. g

  22. ) {5 q, s: g! _+ g
  23.   /* USER CODE END 2 */
    7 T# [  _  c, {) L0 o7 m2 k
  24. : L9 @* t3 @# ]3 c
  25.   /* Init code generated for FreeRTOS */
    + @; U  H+ _# r) h# z9 F; p
  26.   /* Create Start thread */& e8 S6 G! E% @% \$ Z
  27.   osThreadDef(USER_Thread, StartThread, osPriorityNormal, 0, configMINIMAL_STACK_SIZE);
    ; B+ @0 e- x. u" `% o& \
  28.   osThreadCreate (osThread(USER_Thread), NULL);: `' d  J6 j3 A: O
  29. 7 M! Y* F! o1 n3 Q; Y8 q: D( `
  30.   /* Start scheduler */6 [0 B: g& d: C: n6 l
  31.   osKernelStart(NULL, NULL);
    & N2 Y& D$ A0 K* t' R. F- R2 o: a
  32. / g: Q+ r- c5 J. S* m. n2 C; [
  33.   /* We should never get here as control is now taken by the scheduler */
    9 p4 u- H) D' P5 R9 P/ K
  34. " X! ^* p( I! T# C, c
  35.   /* USER CODE BEGIN 3 */
    3 Z8 @9 v* _  q% }4 b( p4 l5 W
  36.   /* Infinite loop */
    8 P  X: X+ v' [, U1 C0 Z
  37.   while (1)
    8 X1 }6 k' K# L) f
  38.   {
    - D. P/ _* t. C2 ~& Q# V8 o
  39. 6 O5 K; f' g: y2 |( M- x7 @0 q
  40.   }) h4 S# g! Y( R/ j: k
  41.   /* USER CODE END 3 */
    & h, A$ A2 s, |: X

  42. 5 I- ^: {, f& }. I( X1 `
  43. }
复制代码
% U! ~2 J. m; L+ _8 Z) e3 v
mian函数  C代码的入口  初始化一些硬件后
$ `- Z, D& q1 U
  osThreadDef(USER_Thread, StartThread, osPriorityNormal, 0, configMINIMAL_STACK_SIZE);
  osThreadCreate (osThread(USER_Thread), NULL);
  /* Start scheduler */
  osKernelStart(NULL, NULL);

1 C2 M1 S+ I* w  x/ \定义了一个 线程 USER_Thread 然后启动OS  
& A1 s, b. R. D0 G注意 osThreadDef  是一个宏  定义一个用于描述  线程的结构体  并不是执行函数' G& o* l) B. J9 W

( x9 {  x. b  R宏的第二项参数 StartThread 为线程 入口函数地址。. P0 B2 W8 ]: Q6 i6 @' `7 ~
- ~- c- Y* u/ i4 n# D
至此mian函数的工作结束了 OS将转向 就绪线程并永不返回  也就是执行StartThread  * L5 k! _) }- d  X. ^( L

' @* e# S7 w: c# ^: R7 @, \2 Q修改  StartThrea函数 如下
0 o# s, Q9 S$ w& D$ {# r0 v- I$ x9 c8 g# [( D; J2 \' ?9 A
  1. : A" H; {: F; Z6 N6 o# |( l
  2. /* USER CODE BEGIN 4 */
      A0 c5 Q; x: m  u
  3. void Nucleo_072_Led(const void *par);
    - G) J0 w/ S8 y8 @- G, s
  4. /* USER CODE END 4 */& S* Q, a7 ^; Y7 a0 |- R) F

  5. $ y  {. x; R5 U9 E4 j4 m5 n& ]
  6. static void StartThread(void const * argument)6 w- }; Q! e# {
  7. {4 I$ h7 S8 r# V. P
  8. ' N$ C+ F+ [5 v( e4 j& p* \
  9.   /* USER CODE BEGIN 5 */
    8 d' \: d3 K4 e
  10.   osThreadDef(LED_Thread, Nucleo_072_Led, osPriorityNormal, 0, configMINIMAL_STACK_SIZE);: V6 d3 K3 c& u
  11.   osThreadCreate (osThread(LED_Thread), NULL);
    ( ?3 [4 X/ ^  ]0 C( f: `4 [' N5 o, B
  12.   /* Infinite loop */
    2 }9 |) n2 b* ]4 h
  13.   for(;;)' `' E& o7 t1 J% I- a0 x
  14.   {+ p  J, q# K: Z7 ~
  15.     osDelay(1);9 h! u1 e6 `7 [2 L/ `; l
  16.   }
    ( o$ ~1 m9 J5 G

  17. / e( h, ~; v! _9 \6 u# U
  18.   /* USER CODE END 5 */
    ; l3 I9 b, i" E% X" z

  19. - j$ i8 c9 K9 v! r) Q% a. {# u
  20. }
复制代码
$ \. k- j5 Z, O" W$ ^/ [" R
添加一个 LED 函数9 F% `4 d8 {9 t3 \4 I
  1. void Nucleo_072_Led(const void *par)
    6 [& y! t7 e, L& i/ {" ~2 j7 c/ w5 {- Y
  2. {
    : s( y6 x; u  ]9 z/ k' Y
  3.         GPIO_InitTypeDef GPIO_InitStruct;
    ! p8 z8 O8 c% t1 ?+ t
  4.   __GPIOA_CLK_ENABLE();
    - O; V; g! g% \
  5.         
    " y2 r2 A! z7 F/ O
  6.            GPIO_InitStruct.Pin = GPIO_PIN_5;5 B8 b* ]" K: \% {6 ~
  7.     GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    ; ?+ H8 k; ?) k& ?$ Z
  8.     GPIO_InitStruct.Pull = GPIO_PULLUP;
    * I0 g1 ^. s  z6 o* `
  9.     GPIO_InitStruct.Speed = GPIO_SPEED_LOW;6 v9 V4 I( q1 P+ l$ `% _  c
  10. & O& o% X$ E2 c1 h* P. u
  11.     HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);, s8 z, ~& |8 |( x2 l3 w2 M2 n& n
  12.         
    3 q  c! R1 S0 M7 p
  13.         for(;;), `# T3 N" E4 K7 u. `, z+ w' r
  14.         {" ^! v+ F0 E& t5 D9 o
  15.                 GPIOA->ODR^=GPIO_PIN_5;// PA5取反 LED闪烁: s& ]0 e8 o' Q4 J  u8 p
  16.                 osDelay(500);1 O% ^" T- a( l# j* s8 m% m5 \
  17.         }  s5 v/ }* v+ F3 n! P; r# k

  18. & }) i9 O8 o. p7 }
  19. }
复制代码
! \5 j4 u7 Q. {- E" M
到这里可以编译下载到板子上运行 观察现象了
3 I# |  e5 ?3 m% e2 j$ k; Q8 \$ V4 R# _! {
下面创建 RXT 的工程  新建一个工程  : V9 l" ~- s6 k5 g$ T+ Y

& X* }8 N& L; x. M* m( L1 m3 t( \勾选 如下选项 # b2 m5 o+ V/ I2 a- q
& b6 N% O- X9 e9 U9 b% D' f8 i+ ~& c
QQ截图20150108112304.jpg
+ Y# Z3 ^* Y' h9 ~2 @红框 不要添加  不知为何  楼主添加 MDK的 startup 编译通不过
, g( N, D4 Q  i% f* g- I+ h" HF4 的工程没有包含  HAL  接下来 需要自行添加HAL 库
$ h$ X  ^7 ~/ `2 W8 h1 R9 G% f0 P" v4 A" {3 W  G: O
把原来的 main.c 复制一份更名为  rtx_main.c* n) @0 o4 _& j" O
7 C$ k4 Y3 H5 ]) M: Y) w" T8 g
QQ截图20150108113501.jpg 5 F1 D. u0 n1 t# v7 x5 i
4 ^) F. ?# a" g, A3 \
文件添加完毕 + A- y$ ]! T4 L9 o, l& J2 O

# W; x! ~' u5 D7 x5 T$ }接下来定义 头文件目录和 系统宏
0 U- h% z2 i! X$ r, D
9 S* V2 k- _, b) D8 f5 R QQ截图20150108112609.jpg
# |8 w$ I+ H- [* W; s5 h# l/ i7 ]# c; V( \
修改 rtx_main.c  下面两处需要修改
$ E+ }9 r3 h+ Q% x$ p; }2 y& f& Y( e, n  ]; Q# x5 r
  1.   {
    / ]3 i# G2 c1 ?/ S0 S: I+ L* Z7 A, D
  2.   osThreadDef( StartThread, osPriorityNormal, 0, 0);1 F& S' E& V7 _/ w7 Q9 b4 k* L
  3.   osThreadCreate (osThread(StartThread), NULL);, v, R  A8 |$ u) [% B' q
  4.         }
    , G5 I' x& `. [( @  T4 Q
  5. 4 A* j( b! l( m
  6. osThreadDef( Nucleo_072_Led, osPriorityNormal, 0, 0);0 [/ G2 |2 ?/ s) [) e
  7.   osThreadCreate (osThread(Nucleo_072_Led), NULL);
复制代码
不知为何  ST写的 中间件和 MDK的 接口有一点差距  所以 创建线程的地方需要如上修改; t0 v% L, f. I. U5 d" G+ q' O
7 S( U- R' c/ [: L' H
修改 stm32f0xx_hal_conf.h
! Y7 a1 e2 q6 z2 o$ _, o# b" v4 ~0 R添加 图示内容  不出意外  下面 将可以直接编译了!!: H& b$ n: L9 ~, v! k# A( ?; ]
QQ截图20150108112936.jpg + ~! J  C* p4 T: }% [0 y% H

7 u7 r& z/ ]7 N* K# [$ `( Q: z写的有些多了  本来想 继续写 RTOS 基于串口的  应用  太长了 下次发帖写了2 W+ Q0 Q  L6 t! P
; b2 \: @# k& V8 w, t  T/ m
下面提出一个讨论 MX 创建的  工程 FREERTOS 中 cmsis_os.c 中 创建一个信号量  
$ W* d2 F+ t- U2 v% K+ G4 eosSemaphoreCreate参数 count 直接
0 O% T! Q  Y- g0 ^6 Y# z2 [
2 w" R+ i' [9 I2 U/ k0 \$ b- O传递给 xSemaphoreCreateCounting的两个形参  
2 s7 U0 A) b5 q5 r6 y6 G8 w% Q QQ截图20150108115258.jpg   P* ]+ Y+ G! a
原型 # v! k% T+ M& W: E$ ~
#define xSemaphoreCreateCounting( uxMaxCount, uxInitialCount ) xQueueCreateCountingSemaphore( ( uxMaxCount ), ( uxInitialCount ) )+ ]! `, y4 e6 L3 h/ ^
  }5 J6 ]/ u$ c& w4 a; `
该宏创建一个 数值型信号量 第一个参数是 信号量最大数值  第二个则为  初始化值
* ?- ]0 m% A6 G+ E1 f- a4 p$ c- v3 g! x4 O/ l
基于串口使用信号量  那么需要如下要求$ m/ b, |# p7 B& ^
假设 usart_sem 为串口使用的信号量% J3 `+ Z" n+ @3 E6 L
每收到一个数据 usart_sem ++  缓冲 1024字节
% C* Y: j& J/ j9 e$ o# b' {需要数据的线程 osSemaphoreWait(usart_sem ); 当有数据时 线程被激活  获取数据0 k+ }. `% e& n0 X9 R. f" d
) j0 n; ]8 G# Q7 M9 L
如此我们知道 这个信号量的 最大值应为1024 ; D# W$ Q9 E2 h2 k
可是使用 ST 的cmsis_os osSemaphoreCreate 创建一个信号亮 osSemaphoreCreate(0,1024);
# L$ [2 g5 h+ E/ g) J7 E* X2 ~3 T2 i" f* p2 g* k! R
会出现这样的问题 !  此信号量 被赋予初值1024  意味着 这个信号量将可以被osSemaphoreWait 1024次
3 f  f2 d+ X# i/ ~5 }& \" T) z显然这不是我们想要
5 t8 p* b. r7 p  S9 i2 V. L0 K, s* `6 z* D
通常  我们需要的数值型信号量  最大值可以很大  但是初值 基本为0,或1
# G' u- r9 m( ~7 |. z
! [/ G2 w+ b9 V+ B4 Q7 D. n不懂  这样设计意义何在?
$ V5 K$ I( ?$ H2 d3 Z# K# |
' X) Z0 }" S" |. ?
: y1 K4 I8 H. i1 W8 o: ]5 ]% Q9 ] 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 编辑 1 A6 g3 z6 a1 O. p0 g9 ?
lovewyufeng 发表于 2015-1-23 12:56, V( c! e% o; v* `
事实上  只要这个计数不为0 都能被 wait 到
0 w8 B3 D: j" D$ J' j
不好意思,确实被代码的名称误导了,以前用的基本上只用二值的semphore或者直接用queue了。
, m) a2 T5 F- k仔细看了一下内部的实现,确实我说错了。
' o7 J: p% ]  M" k6 |3 H/ q$ f$ D在init_counter和max_counter一样的情况下,确实整个逻辑是要按照资源池来解释的,也就是确实生产者take(这个take代表获取空闲资源才能生产),消费者release(这个代表空闲资源返回)。我觉得这种情况semphore更像一个可重入的锁,处理线程拿走资源池后,直接处理完后再归还,像是个recursive mutex。" D# U3 r% N) `/ n
前面说的那个问题,直接用queue可能会更好。另外,今天试了一下最新的stm32cubemx和固件版本,代码已经改了,#if (configUSE_COUNTING_SEMAPHORES == 1 )        
0 y8 `8 P/ `9 E1 ]5 H6 R0 z  return xSemaphoreCreateCounting(count, 0);
, V& e, c3 P7 O% H+ `' B#else
, n+ T) c5 K1 T& l8 w& \4 x  return NULL;0 S& {/ K* K2 V& t$ U+ Q, ~
#endif; o- G  o( z- E
}
  `) J) R  _. S8 M( P) V, n  u& ?6 Z% Z5 H- g( M5 d

1 L& N/ {* @1 q% s6 `5 h5 @
6 {$ ?) }5 F; I% ~6 z/ ]9 r' e' H3 m$ i$ x7 p6 e
我是东哥 回答时间:2015-1-23 07:50:34
lovewyufeng 发表于 2015-1-23 00:48) _0 M& t" V7 `5 B
反过来理解是吧,说得通。可是
4 w4 ^1 L. _4 l: F1 T% }# x有个问题。,生产一个就-1的话应该 take获取信号咯?   反过来消费应该pos ...
0 ]6 Y' J# N2 ^2 j8 z+ J
你陷在细节里面了,看看人家的API是怎么样写的,osSemaphoreRelease和osSemaphoreWait,我们在生产者里面应该要osSemaphoreRelease,而在消费者里面osSemaphoreWait,是吧?字面理解,相当于生产的人释放了一个东西,然后消费者就等待生产者的这个东西。再看里面的实现,osSemaphoreRelease里面是xSemaphoreGive而不是take,而osSemaphoreWait里面是xSemaphoreTake而不是give。
5 d* J) q8 j  y& g3 m$ g所谓的反过来理解只是一种理解方法,说take和post的逻辑也反的话是不对的。不要老想着什么时候去post,什么去take。cmsis_os的API意思很明了,生产者生产了东西就应该release,消费者就应该Wait,这不是很好理解吗?
lovewyufeng 回答时间:2015-1-23 00:48:46
我是东哥 发表于 2015-1-21 12:18$ O: n$ z+ P" U
这个其实也没有不合理,看你怎么理解,资源一开始为0,也可以理解为空闲池一开始是满的。生产者生产了一 ...

. D7 L! W5 I, E$ @. y, V" b/ W反过来理解是吧,说得通。可是( O, i- J9 Z8 g$ ^
有个问题。,生产一个就-1的话应该 take获取信号咯?   反过来消费应该post 释放信号咯? 那么问题是 post是非阻塞立即返回的而take是阻塞的?
$ [% s; m- s/ k% H先不谈消费者应当随时饥饿,处于阻塞态。9 e4 F' F, v% N& K$ 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
看看 顶一下
; H. g/ [) `5 Z
cqtnheyao 回答时间:2015-1-8 12:19:01
harvardx 发表于 2015-1-8 12:13- y- G& H* w4 i  U, H
有钱为何不顶帖 .何况还是高质量的 .cubemx 势在必得的趋势.支持一下.
* Q' a* c% H5 J  p* ?, i" H; U. [
据说库很大,效率低?求告知!
netlhx 回答时间:2015-1-8 12:19:08
很好,图文并茂
lovewyufeng 回答时间:2015-1-8 12:19:26
harvardx 发表于 2015-1-8 12:13
. ?6 a( Q% H1 S3 x7 ]  M有钱为何不顶帖 .何况还是高质量的 .cubemx 势在必得的趋势.支持一下.

9 r( D. D( a! d- W3 Y  |多谢老大 支持  继续加油
lovewyufeng 回答时间:2015-1-8 12:23:05
cqtnheyao 发表于 2015-1-8 12:19& I3 k% q3 D7 s/ p7 h/ g% K- A% p* C
据说库很大,效率低?求告知!
9 @# ]5 S& u2 \5 [1 ]
确实 有这个毛病  楼主的贴初始化使用库  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 手机版