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

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

[复制链接]
lovewyufeng 发布时间:2015-1-8 12:08
以刚拿到手的 Nucleo 072为例  其他板子用户 请举一反三哈 (工程文件在帖末
# F# c; J( Z  H. w8 I; E! e; v/ m7 C) r: M; F5 U

2 ?5 e: M+ Q6 ?" r2 Z# W2 f后续帖子:【干货】Nucleo072 usart 基于RTOS的应用  方便AT指令类外设开发
9 B/ W/ @* @! z, C5 |8 p6 q" N- ~! }5 B
需要工具  MDK5 自行下载:
) g$ A. {- `  z  x2 n5 H4 ^, i% wSTM32CUBEMX https://www.stmcu.org.cn/document/detail/index/id-2149846 Z& ~  }0 U* Q4 v
STM32CUBEF0 https://www.stmcu.org.cn/document/detail/index/id-216669) |. }) ], L6 g) u: I

' f# o0 L2 H& k7 d3 f/ o$ [( }- s' o1 q3 b+ L
安装 cubeMX  由于使用MX下载固件库速度那是不说了相当慢啊  所以下载 STM32CUBEF0固件库然后下图安装; M, H* P# X' \2 V2 b+ H1 @8 D

0 x; N5 K, h0 b3 K
! V- E8 c5 g; o. y) E5 }5 w$ K QQ截图20150108101548.jpg QQ截图20150108101556.jpg
9 ^6 J, y5 ]5 ?, [8 q) Q2 z/ j3 P- I' `, D1 C5 F( f
安装之后  新建一个工程 选择STM32F072RBT6% F3 f  J+ w8 o, z# i$ S6 f

* Y! s3 @  d* H. W' iPINOUT 勾选  FREERTOS和 USART ; ]& \( y: \/ A2 Y  O" r6 V
QQ截图20150108101539.jpg & B1 F( a8 Y' p- g
因为我们调试可能需要使用5 i& E# W4 L& K7 n
8 k$ v! W2 Q/ v: q+ `& X! C
点击软件上方  齿轮键生成  keil 工程  至此
5 ~* b. i* R' g( ?: H9 r; {; h. q# v" p/ O
MX基于 HAL的库 生成完毕1 u" H$ a, r. j2 U; R! ^* g' n" H

8 X! \* P- g; P0 ^' L4 @8 E4 `使用MDK 打开工程
/ Y( t" d8 C1 J从上到下 的组依次为  OS 的C文件5 |" }+ ]8 k( H( l% R3 b0 l0 \6 S
.s 启动文件
9 X* m, m6 ~4 H, ~( z+ ~用户文件2 t" M0 [- ^  o
HAL库文件
- R. i1 }( |" m7 w5 {) _0 A6 ^CMSIS中间件文件8 R5 N# v8 k* Q

" t1 T" G5 ^7 A/ \其中 在 第一组中的 cmsis_os.c 中实现了  cmsis_os  到FREERTOS 的中间层转换   稍后会讨论其中一处代码! ^! C; |  W" j7 a

, W7 ?3 I: g/ p! ~ QQ截图20150108101924.jpg   x/ N/ R3 N* e5 H% e

7 L7 ^5 g; V# Y: p$ O* V. i* o3 |* x* d' b
接下来  添加自己的代码  首先添加 072 上面LED吧  板子不在身边  记得是PA5 控制, T. \7 A9 t/ O" {: I: ~! T! t
5 z" Z/ \5 E7 s: ^% e- N6 ~
先看看  main.c 的 64 到 105行
% C, W1 Y* }9 h5 X. N! v0 ~

  1. % X, b( |  t  ?% S4 R3 j3 ~
  2. int main(void)
    9 a9 \& A) i% c2 P
  3. {; b5 x7 P; i. B. F

  4. $ N4 _3 j1 L$ Z/ z& e5 e% k5 _
  5.   /* USER CODE BEGIN 1 */5 ]* u% s4 V- s6 L2 h; g) w( j9 F

  6. 0 o# F. o# V, t  @
  7.   /* USER CODE END 1 */- \* y' R! n! F) m, `# \" B% G
  8. 5 C; I- _( K( n" r& {# g
  9.   /* MCU Configuration----------------------------------------------------------*/
    % t7 _: a1 {7 z& r3 A; G# ]: x( [

  10. 3 l; V" d  [' Y3 p0 d5 f
  11.   /* Reset of all peripherals, Initializes the Flash interface and the Systick. */( j$ v& W& q& W  P0 o  X
  12.   HAL_Init();$ O/ e. X" }& a, g0 z3 d3 z
  13. + L9 O! D$ M9 j% v4 L, @
  14.   /* Configure the system clock */) i  y. @) H3 o* \# o% _. V
  15.   SystemClock_Config();% i/ W: i; o- Y6 ]8 M* |3 @3 c

  16. & X: K2 _2 @' e& `0 z; P
  17.   /* Initialize all configured peripherals */2 a) Z5 x. v; |# U8 u
  18.   MX_GPIO_Init();
    8 O/ v8 ~6 q' y  D
  19.   MX_USART2_UART_Init();) ]; X, s' y1 Z& {

  20. , L4 C% Y" Q- O7 P9 q8 D. i6 Z" L- ]
  21.   /* USER CODE BEGIN 2 */' Q5 B$ [0 T& s4 y9 x
  22. ( C( j+ N0 Z! m/ n
  23.   /* USER CODE END 2 */& b0 T5 ]% B: j( A
  24. 2 }2 O) m( ~( W1 F+ A" R6 Z- J
  25.   /* Init code generated for FreeRTOS */; T0 i0 T& g2 p2 G. v, k
  26.   /* Create Start thread */
    8 [5 J9 \6 O2 \1 q& v4 [
  27.   osThreadDef(USER_Thread, StartThread, osPriorityNormal, 0, configMINIMAL_STACK_SIZE);; e$ o, \+ F+ ]4 @. m) S2 H
  28.   osThreadCreate (osThread(USER_Thread), NULL);7 V# {9 v/ R6 {" }
  29. 7 f# E( {! i# c& |. i4 ]) C5 Y
  30.   /* Start scheduler */
    % y. J7 W1 H! a5 I, O
  31.   osKernelStart(NULL, NULL);
    5 Z/ T4 ]4 M8 u% N' `0 ^6 l. [
  32. " g; s7 X. S# `4 l& s1 J
  33.   /* We should never get here as control is now taken by the scheduler */3 Y7 R9 t$ X, ]$ P8 h6 t

  34. 2 A3 N) B: ~1 h
  35.   /* USER CODE BEGIN 3 */
    " R# U) S4 |9 ?4 R0 _
  36.   /* Infinite loop */7 M6 Z% q, q4 g) q8 K
  37.   while (1). r! a$ u( F% U: i
  38.   {
    ! s" d$ |0 x6 l% B" Y. [9 m
  39. ' G, V  `  ?7 {) E4 R; Y
  40.   }# n% J5 t" f" q, R3 d8 _
  41.   /* USER CODE END 3 */6 f: g, E  t" A' w
  42. . C3 m6 p  ~. ^+ ^1 H2 {; C4 u
  43. }
复制代码
+ e+ ]3 {5 [! V
mian函数  C代码的入口  初始化一些硬件后 - z/ {) _( I, Q. F; l( V
  osThreadDef(USER_Thread, StartThread, osPriorityNormal, 0, configMINIMAL_STACK_SIZE);
  osThreadCreate (osThread(USER_Thread), NULL);
  /* Start scheduler */
  osKernelStart(NULL, NULL);

+ p3 h$ @/ W: e, w) P5 E定义了一个 线程 USER_Thread 然后启动OS  
$ N) o& K) c, }: }注意 osThreadDef  是一个宏  定义一个用于描述  线程的结构体  并不是执行函数
- Q0 V* W. ]4 L4 S# e8 N
! o# m$ L6 F; W1 q8 w2 }
宏的第二项参数 StartThread 为线程 入口函数地址。
6 k8 p; Z& n; [+ x* D' }; L  M5 t
至此mian函数的工作结束了 OS将转向 就绪线程并永不返回  也就是执行StartThread  ' t- V- k' q" r2 G. b: E
6 X! Q7 ^/ I! U& N8 U& e
修改  StartThrea函数 如下
( X" E8 m- D5 M" w$ E
- h; _! {; A4 n$ w6 ~' }7 G

  1.   O- Q$ n* z/ Q# K$ Y4 O9 t
  2. /* USER CODE BEGIN 4 */
      E; V( e( j3 f6 e9 G
  3. void Nucleo_072_Led(const void *par);
    & e1 ]* c" [" ~
  4. /* USER CODE END 4 */% z" G. ?5 x4 o4 f: o
  5. , x, s# o! J/ Y! k# D+ N' O
  6. static void StartThread(void const * argument)  e' p" y, t6 L  I# W
  7. {, A4 j7 l! v. M

  8. - Z- s; Z* m3 v4 W; C
  9.   /* USER CODE BEGIN 5 */0 k" o4 \1 l; C% Q
  10.   osThreadDef(LED_Thread, Nucleo_072_Led, osPriorityNormal, 0, configMINIMAL_STACK_SIZE);
    + j5 v2 ~$ Q; V* t
  11.   osThreadCreate (osThread(LED_Thread), NULL);
    ; ?3 I. c$ v& U/ _2 w
  12.   /* Infinite loop */$ W* V; M' Z+ e
  13.   for(;;)
    5 L; U* _9 d, j# F( Z. g
  14.   {; B5 Z' P/ y8 s5 }7 D! e
  15.     osDelay(1);' D# o- H9 a% }3 t' i5 c
  16.   }
    * f, W; R, S2 {$ F) u
  17. * o& k. s7 a. r( I: a5 s( B
  18.   /* USER CODE END 5 */ 0 B2 ]1 @* |3 d2 |# B5 P7 [
  19. / ~' w& G  c0 _8 S' h* G- A" M
  20. }
复制代码

; N# }4 ~* f$ X& w7 |$ L# N8 [/ i添加一个 LED 函数
- |  n0 A( I, q, c: b
  1. void Nucleo_072_Led(const void *par). n1 h8 C! q7 z9 I
  2. {* f+ A) h5 K& W: D; U/ y( P
  3.         GPIO_InitTypeDef GPIO_InitStruct;
    0 u6 x: m6 o/ z/ j3 N
  4.   __GPIOA_CLK_ENABLE();
    - e1 P# n4 m5 e: I1 X1 O& [+ V9 D; q( a
  5.         ! m' V4 r7 n* _% `: @. f" r( F6 O
  6.            GPIO_InitStruct.Pin = GPIO_PIN_5;
    ( g4 D3 w* z) j0 n5 ?5 v% o5 K
  7.     GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    & {2 Z* F- c- R& Z/ n) n
  8.     GPIO_InitStruct.Pull = GPIO_PULLUP;3 K! j3 Z0 I4 }' I% y+ S
  9.     GPIO_InitStruct.Speed = GPIO_SPEED_LOW;) L/ e; h9 j5 n. S& l2 M. E; V

  10. 0 j; M- t( E3 s0 E$ k9 k
  11.     HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
    # X& ?+ |; W( {5 @
  12.         / M, I9 E) e8 C
  13.         for(;;)
    . x* X! {+ k/ `3 _1 s* P! z- p
  14.         {2 G) m2 W$ U" a8 x, A9 _) }
  15.                 GPIOA->ODR^=GPIO_PIN_5;// PA5取反 LED闪烁2 k/ J: ?8 W) |/ T1 ]; q
  16.                 osDelay(500);
    4 K' X! J4 q+ S2 f! D
  17.         }
    ' v. X  p6 D6 e

  18. & }0 P0 E) H5 R  J! q/ U) p& q* c
  19. }
复制代码
* c! k2 S# @; \4 J
到这里可以编译下载到板子上运行 观察现象了7 D5 U/ G) a$ j5 t. a

9 p; E$ X- m$ H下面创建 RXT 的工程  新建一个工程  
0 z' d- d  ]# N9 y" ~- N/ {5 T/ N% E* w. O" U2 T2 j2 t/ F" Z  T
勾选 如下选项 8 L! l$ N$ a3 r8 Q: ]( w0 k, @
. \; B+ j' S! O' j" b
QQ截图20150108112304.jpg ) l7 ~3 w3 A4 R
红框 不要添加  不知为何  楼主添加 MDK的 startup 编译通不过
3 y& k3 {8 r! k% _3 A% xF4 的工程没有包含  HAL  接下来 需要自行添加HAL 库
. M0 U' [+ Q* X$ `/ ?+ n1 p0 t! |8 U/ H6 g
把原来的 main.c 复制一份更名为  rtx_main.c: ~! M" A4 f. R4 D$ L" L; @5 A

3 n  a4 W3 {. {" O6 C. H QQ截图20150108113501.jpg
8 z( q( z* L) G  H6 T3 s) `1 S% ^  g( e/ m3 i/ I) C
文件添加完毕
8 q# S' a5 J2 k' g( {
: p9 ~& h: g% P0 p' s6 s接下来定义 头文件目录和 系统宏
, b6 @5 X- r4 `  J/ r' o: k, c! E+ P" v& _! p/ k3 ]
QQ截图20150108112609.jpg
4 E1 ?' b$ P3 f; u9 g( h! m- D! w) g9 Z/ z4 T' ^8 r
修改 rtx_main.c  下面两处需要修改 3 D7 w5 [0 g; Q0 w- `/ W) o4 E
1 o6 o# w* o4 U2 l' r- t3 S
  1.   {
    7 |$ a; u5 o: T+ K; O: a' L
  2.   osThreadDef( StartThread, osPriorityNormal, 0, 0);
    + Y3 @. r( X, m7 A7 J
  3.   osThreadCreate (osThread(StartThread), NULL);
    0 V# y  b- K$ E" ]& u7 ?  r6 Q
  4.         }" t# X! b7 B; \) f; [0 q

  5. 9 S5 ]9 G% v& }3 f
  6. osThreadDef( Nucleo_072_Led, osPriorityNormal, 0, 0);1 p  ]! T) g2 R8 v9 t
  7.   osThreadCreate (osThread(Nucleo_072_Led), NULL);
复制代码
不知为何  ST写的 中间件和 MDK的 接口有一点差距  所以 创建线程的地方需要如上修改- b( B1 D* T/ U+ ?# G1 D

6 V; M. d+ m* X  {修改 stm32f0xx_hal_conf.h . G, ]  j& ]5 x, F+ q5 n% c: k
添加 图示内容  不出意外  下面 将可以直接编译了!!& Y5 Y! j8 B- T' L  O5 M
QQ截图20150108112936.jpg
: d3 }0 i- x* r/ u* Q% K+ a
% a  U5 q' [" w1 w7 k" T写的有些多了  本来想 继续写 RTOS 基于串口的  应用  太长了 下次发帖写了
7 I: _+ G0 A5 m- ?* ^+ |: A$ t4 m
下面提出一个讨论 MX 创建的  工程 FREERTOS 中 cmsis_os.c 中 创建一个信号量  
0 O) O( L3 R! c; k7 qosSemaphoreCreate参数 count 直接
# G! [2 c; \4 u
. q' u  @; `& H. w1 X( R* H5 |* P传递给 xSemaphoreCreateCounting的两个形参  
# l5 f% S7 |& w5 u( J# r/ k QQ截图20150108115258.jpg . h! W) d7 G9 {( E# r2 ~% J
原型
5 _7 F6 l+ H$ L9 g, k: C3 B4 c" R#define xSemaphoreCreateCounting( uxMaxCount, uxInitialCount ) xQueueCreateCountingSemaphore( ( uxMaxCount ), ( uxInitialCount ) )
! A" X" L. p7 l4 J) ?6 s
, k8 b  }$ k  G( [; `该宏创建一个 数值型信号量 第一个参数是 信号量最大数值  第二个则为  初始化值
+ E+ v# o; ?/ E" `6 M
8 x- Y+ e0 T4 }' Y" u, u% {基于串口使用信号量  那么需要如下要求; r$ [5 Z! y. l. G
假设 usart_sem 为串口使用的信号量
5 x2 p9 f- p3 r$ P每收到一个数据 usart_sem ++  缓冲 1024字节
1 y( f  i5 o/ @& w/ D* W需要数据的线程 osSemaphoreWait(usart_sem ); 当有数据时 线程被激活  获取数据
, E! f# K. u! Y8 M# t$ T
, z+ \- i  U: U如此我们知道 这个信号量的 最大值应为1024 ) j4 R5 A" n6 K6 G; [6 b) n+ v
可是使用 ST 的cmsis_os osSemaphoreCreate 创建一个信号亮 osSemaphoreCreate(0,1024); ) k" {) ?# f6 Q3 r: A+ L& q
" k4 v3 Z( l/ m5 \
会出现这样的问题 !  此信号量 被赋予初值1024  意味着 这个信号量将可以被osSemaphoreWait 1024次
# b" b' P8 D& p) G/ J9 S9 _显然这不是我们想要
! D7 x7 z9 L8 ^$ f1 {  K
, p* ?- M, {, V7 H# l4 J) }通常  我们需要的数值型信号量  最大值可以很大  但是初值 基本为0,或1
! ?: ]6 A7 F+ Q  `8 t& ]3 i  {
" n' j, S+ i& S不懂  这样设计意义何在?
6 @1 W6 o' w1 E4 V. D# W* h( K, w" ~9 l6 _& X
: b4 j) Y! b  O. a$ r- |/ O3 V
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 编辑
+ P8 Q% \& D7 _9 M9 R/ m
lovewyufeng 发表于 2015-1-23 12:565 u. m/ Y, u0 s4 }1 {; O
事实上  只要这个计数不为0 都能被 wait 到

1 {" `. v1 M4 h, A( w不好意思,确实被代码的名称误导了,以前用的基本上只用二值的semphore或者直接用queue了。+ _  v$ R! b$ ]" q& a
仔细看了一下内部的实现,确实我说错了。
3 k, D- c+ O1 j* Z3 Q; b* F& m在init_counter和max_counter一样的情况下,确实整个逻辑是要按照资源池来解释的,也就是确实生产者take(这个take代表获取空闲资源才能生产),消费者release(这个代表空闲资源返回)。我觉得这种情况semphore更像一个可重入的锁,处理线程拿走资源池后,直接处理完后再归还,像是个recursive mutex。
* J/ m' h9 R5 B- Q. K# U; n" Q$ G前面说的那个问题,直接用queue可能会更好。另外,今天试了一下最新的stm32cubemx和固件版本,代码已经改了,#if (configUSE_COUNTING_SEMAPHORES == 1 )        2 h" M+ x! K5 x' E
  return xSemaphoreCreateCounting(count, 0);) ]& F0 g! M. B3 @: F( i
#else+ `4 d, V5 ^! ^
  return NULL;3 S' f8 p# ^/ T# t
#endif+ y. N8 c& ?* ?, i2 I3 y4 \* Y
}9 p9 g1 X  b' Z' n

3 f0 E% ?9 r6 ^4 k! s
8 L! |& _& U6 z
9 @3 K8 p4 }8 [
5 T# X& B6 B. Y2 m# o7 B
我是东哥 回答时间:2015-1-23 07:50:34
lovewyufeng 发表于 2015-1-23 00:48+ t5 U3 [: M3 d
反过来理解是吧,说得通。可是
; }$ q" b+ n; c% q2 q有个问题。,生产一个就-1的话应该 take获取信号咯?   反过来消费应该pos ...
, a& t" A9 u* l1 j2 d; V
你陷在细节里面了,看看人家的API是怎么样写的,osSemaphoreRelease和osSemaphoreWait,我们在生产者里面应该要osSemaphoreRelease,而在消费者里面osSemaphoreWait,是吧?字面理解,相当于生产的人释放了一个东西,然后消费者就等待生产者的这个东西。再看里面的实现,osSemaphoreRelease里面是xSemaphoreGive而不是take,而osSemaphoreWait里面是xSemaphoreTake而不是give。: M" C, d; {% M8 u  @  Y
所谓的反过来理解只是一种理解方法,说take和post的逻辑也反的话是不对的。不要老想着什么时候去post,什么去take。cmsis_os的API意思很明了,生产者生产了东西就应该release,消费者就应该Wait,这不是很好理解吗?
lovewyufeng 回答时间:2015-1-23 00:48:46
我是东哥 发表于 2015-1-21 12:18; H6 P0 ?3 i& q* |( x
这个其实也没有不合理,看你怎么理解,资源一开始为0,也可以理解为空闲池一开始是满的。生产者生产了一 ...
, w9 j' N; M5 R& a
反过来理解是吧,说得通。可是
4 V3 J$ Q. r7 c& r) [有个问题。,生产一个就-1的话应该 take获取信号咯?   反过来消费应该post 释放信号咯? 那么问题是 post是非阻塞立即返回的而take是阻塞的?! e& a! ~2 K1 h. u& a$ ~
先不谈消费者应当随时饥饿,处于阻塞态。
. Y2 n' [$ F+ L生产一般在中断里吧,当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
看看 顶一下
' d* w, W0 r; v8 N6 t
cqtnheyao 回答时间:2015-1-8 12:19:01
harvardx 发表于 2015-1-8 12:13
- f9 r% k  n2 m3 A: p3 N% l2 W有钱为何不顶帖 .何况还是高质量的 .cubemx 势在必得的趋势.支持一下.
7 P+ m+ B. o9 B1 O) W1 A
据说库很大,效率低?求告知!
netlhx 回答时间:2015-1-8 12:19:08
很好,图文并茂
lovewyufeng 回答时间:2015-1-8 12:19:26
harvardx 发表于 2015-1-8 12:13
2 Q! b" Z( V& t. g/ V- x% X9 I: Q; @+ H有钱为何不顶帖 .何况还是高质量的 .cubemx 势在必得的趋势.支持一下.

2 f% i5 \" F% S: ?; p% b多谢老大 支持  继续加油
lovewyufeng 回答时间:2015-1-8 12:23:05
cqtnheyao 发表于 2015-1-8 12:19
6 V, e7 n0 }2 H7 ~# I6 z" J: p据说库很大,效率低?求告知!
$ s. F9 d( c5 s% ~+ K) K
确实 有这个毛病  楼主的贴初始化使用库  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 手机版