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

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

[复制链接]
lovewyufeng 发布时间:2015-1-8 12:08
以刚拿到手的 Nucleo 072为例  其他板子用户 请举一反三哈 (工程文件在帖末)9 a, J" N6 G% E5 y( W# w

3 l, d+ D' t+ [  |5 X1 e& }8 D" X6 ]; T( e+ t) [
后续帖子:【干货】Nucleo072 usart 基于RTOS的应用  方便AT指令类外设开发
# N2 D% W( h% ?+ e7 j+ c4 g% P1 x( s5 {* l! _# {9 Z% T
需要工具  MDK5 自行下载:
" @6 @/ c- `" l  N  r" WSTM32CUBEMX https://www.stmcu.org.cn/document/detail/index/id-214984
! }# ]( O) Y. G- [5 V$ nSTM32CUBEF0 https://www.stmcu.org.cn/document/detail/index/id-216669
1 t( n/ `3 s# y! E. A9 j  t6 {4 f1 q5 X. \' |
8 P7 a0 ?+ |' S3 ?4 ^- L4 z
安装 cubeMX  由于使用MX下载固件库速度那是不说了相当慢啊  所以下载 STM32CUBEF0固件库然后下图安装
- y2 P) n! u. H9 P. ?5 a1 q' S1 M1 e; o
. g. }, _0 S# P# i1 D0 J  ^6 j4 ]% b! [. b
QQ截图20150108101548.jpg QQ截图20150108101556.jpg
  k/ S! {4 O5 }
8 F  F( H( C* X  e9 C3 o安装之后  新建一个工程 选择STM32F072RBT6
: D) i' o+ @/ ^- H/ a) m  r' c# J7 w
PINOUT 勾选  FREERTOS和 USART ' M! I) {9 U& q: o0 P
QQ截图20150108101539.jpg   R  ^4 L0 \# l4 e7 b* {9 Z0 p5 M
因为我们调试可能需要使用$ g& E8 [4 j' ^+ H, l# b9 N6 i+ k

+ E# n; R) x( v: R/ D  w点击软件上方  齿轮键生成  keil 工程  至此
+ T2 ~# C$ O9 A% S6 A
# b- [8 J$ O  T) WMX基于 HAL的库 生成完毕
$ M' @: Q6 N( @  G, A* J! m2 B: W$ A# r0 G0 f: s
使用MDK 打开工程1 k! i( Z& h' ?6 A- ?
从上到下 的组依次为  OS 的C文件  J7 A: D/ S2 W; k8 d1 g2 q
.s 启动文件
& C" l! G5 A5 `/ c2 w. [2 u用户文件
" g; A# M! v7 KHAL库文件
" c6 m+ h# n2 l9 `4 t2 M7 hCMSIS中间件文件! l; |8 o  ?* F  Q# Q

) s3 i4 W: n" ?/ @! P其中 在 第一组中的 cmsis_os.c 中实现了  cmsis_os  到FREERTOS 的中间层转换   稍后会讨论其中一处代码, I$ w3 D2 E1 e* _

! P1 Y  n( F$ U) i' W3 s* H: N QQ截图20150108101924.jpg
6 `6 K) W3 X3 ^9 `( m4 p% Q
) @+ K. B8 Z* D3 B/ ]  a( ^6 I1 m0 d# k# Y) U
接下来  添加自己的代码  首先添加 072 上面LED吧  板子不在身边  记得是PA5 控制
9 I! w8 Y9 ?+ ?
5 R3 Q2 H% K* v先看看  main.c 的 64 到 105行 . T$ C# O9 a, _* b( O

  1. 8 x  v( r7 c! O  W. F! g( u3 d
  2. int main(void)* P+ F4 h: ]/ S7 b0 Z, {- }/ [1 s
  3. {8 l) @8 H: i1 t$ _' {, S
  4. & D$ F8 a2 ^) ?% H
  5.   /* USER CODE BEGIN 1 */4 Z* E$ b  _9 O* Q8 G

  6. 9 s# M8 K* H5 x0 C5 D
  7.   /* USER CODE END 1 */- V* z+ W: r# T. E, K( ^

  8. 4 w8 n* Z0 y6 l. K2 m$ d5 B$ E. s
  9.   /* MCU Configuration----------------------------------------------------------*/- _" L2 Y* ?- J2 C0 n

  10. % @- o7 a) H6 j
  11.   /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
    4 k$ B8 v( j9 n% v$ B& Q
  12.   HAL_Init();
    ( V& V/ m- E7 v0 ~
  13. 5 y1 A# }) S2 W# W- K$ P0 H
  14.   /* Configure the system clock */' T! ^+ e3 o( [
  15.   SystemClock_Config();/ a% [" u) f5 F  a5 w  ^

  16. 3 j4 d9 W$ [" v% r1 Z
  17.   /* Initialize all configured peripherals */
    / A% j# ]% i1 O" R
  18.   MX_GPIO_Init();
    ) p% m6 a  V9 w. }2 c. R% x
  19.   MX_USART2_UART_Init();
    7 |* P5 I) J' g! K
  20. , s7 e  D. _' d  g3 q7 {) c5 L' Y
  21.   /* USER CODE BEGIN 2 */' U4 ]  [; E4 f, o
  22. * G5 w$ J+ k$ }) I
  23.   /* USER CODE END 2 */* x" A% T7 \' Z  H2 v1 L9 h+ @. |
  24.   N1 P% {, \3 S- C+ s! s5 x
  25.   /* Init code generated for FreeRTOS */
    ( X  d5 T8 a& z
  26.   /* Create Start thread */0 c0 N4 K) \' x# w
  27.   osThreadDef(USER_Thread, StartThread, osPriorityNormal, 0, configMINIMAL_STACK_SIZE);
    & w- F; x5 f4 K, F; I8 ^6 F. D
  28.   osThreadCreate (osThread(USER_Thread), NULL);4 n% O2 h" S$ b- m' h/ T

  29. $ K1 s: \+ u& m: l" u, T! }) K
  30.   /* Start scheduler */
    # ~/ i7 A# }  n, A) f2 X
  31.   osKernelStart(NULL, NULL);* u3 y# e+ ?9 C: a! B

  32.   }) A( G! D; D0 T( _4 e
  33.   /* We should never get here as control is now taken by the scheduler */" z+ X8 t5 `/ F

  34. 4 i8 t7 z  x; w( L0 G
  35.   /* USER CODE BEGIN 3 */! k+ j0 Y$ i. c: U8 z
  36.   /* Infinite loop */6 u) ], m+ c1 M" h' T$ Z, ~
  37.   while (1)7 m  E% C) R3 Z; i9 g9 ^9 B9 t
  38.   {
    1 A& M5 x; U; `9 M& F" Z

  39. 6 p3 T1 g1 m4 q2 j
  40.   }& \. B' E' b$ y! n4 J3 V$ ?
  41.   /* USER CODE END 3 */0 ?8 X5 i* b  S) }
  42. / i4 ?3 o: r, m+ w3 j1 ^" g6 i
  43. }
复制代码
% }: K+ X$ E: p0 F
mian函数  C代码的入口  初始化一些硬件后 % F5 ]. j# f0 j5 S# V; d
  osThreadDef(USER_Thread, StartThread, osPriorityNormal, 0, configMINIMAL_STACK_SIZE);
  osThreadCreate (osThread(USER_Thread), NULL);
  /* Start scheduler */
  osKernelStart(NULL, NULL);
6 J, Z1 N1 d# H' s/ z
定义了一个 线程 USER_Thread 然后启动OS  ; N/ I( b( k) I' x; ?  V7 J
注意 osThreadDef  是一个宏  定义一个用于描述  线程的结构体  并不是执行函数# Q: F* s2 f$ R* J$ I
- ]5 b& \' h6 l7 x- G
宏的第二项参数 StartThread 为线程 入口函数地址。: u) I" E( b; V4 v
$ H; w1 {" v7 {
至此mian函数的工作结束了 OS将转向 就绪线程并永不返回  也就是执行StartThread  0 A  s" G3 B) l5 r7 {

2 n: e) |& m  A. m7 B修改  StartThrea函数 如下
1 ~4 k3 {% }, o3 w$ j, U+ W7 i! N( x8 [! H4 `

  1. + {( d+ \: Y  q; s/ b
  2. /* USER CODE BEGIN 4 */2 P5 R$ l8 D4 |) J- Q
  3. void Nucleo_072_Led(const void *par);
    8 T* O. X( j- ]+ B, W7 u3 D6 }. s
  4. /* USER CODE END 4 */
    * x/ y) ^" O6 u$ p6 J4 l

  5. 2 L" R- H4 ~+ L% r
  6. static void StartThread(void const * argument)4 `9 X6 M- ^5 h1 h6 U6 c. U
  7. {; n4 X% F# h% G0 H+ h

  8. ; r) O, \$ v8 W3 I% u# h
  9.   /* USER CODE BEGIN 5 */
    * b  A0 v, q+ h5 O
  10.   osThreadDef(LED_Thread, Nucleo_072_Led, osPriorityNormal, 0, configMINIMAL_STACK_SIZE);
    / }- `: v' J0 w( g/ O' O) W
  11.   osThreadCreate (osThread(LED_Thread), NULL);9 j8 L& D$ @  u
  12.   /* Infinite loop */. n) E+ z3 f6 T" b! U0 z" D+ M
  13.   for(;;)- E$ @& S' a# W9 d* C7 e
  14.   {
    ! P1 V5 R! G  r! O( g" ]* J8 n& C/ ^1 g
  15.     osDelay(1);
    , M1 d, O4 }3 u( A% u- K
  16.   }
      t# y* y1 o, H1 [
  17. 0 x: ~& S- R5 g7 Y, V5 S( H7 U
  18.   /* USER CODE END 5 */
    , Y3 y, ?2 t6 W3 n% p) i
  19. " u/ x2 b2 K& a7 X% u& p4 {- s! H
  20. }
复制代码

. t. d6 [' j3 m1 r$ V3 y& d' g/ ~# p添加一个 LED 函数# N& y; N* x2 R' I. N3 h6 u
  1. void Nucleo_072_Led(const void *par)
    8 \& L2 I' {! G$ A
  2. {! z! l5 ~. L: c, j( d5 ?9 }
  3.         GPIO_InitTypeDef GPIO_InitStruct;! C1 |, B0 k. M+ Z) M/ y1 J5 A
  4.   __GPIOA_CLK_ENABLE();
    3 N/ x' x, ]7 |: J  p
  5.         % U+ n! f' z5 @0 c+ @
  6.            GPIO_InitStruct.Pin = GPIO_PIN_5;4 o$ B& S/ O7 [  i% H
  7.     GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    7 M  F8 `+ _; q2 l
  8.     GPIO_InitStruct.Pull = GPIO_PULLUP;
    1 l2 r+ Y' U. l. Y2 r# Q
  9.     GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
    $ G* U1 Y1 u8 a4 H0 i; R+ @4 U: y! E

  10. - D! z, m( h" [4 W8 t+ ^
  11.     HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);+ h6 A3 o1 V. H5 H9 L" O! Z
  12.           @2 ]" `' |3 M; B6 e
  13.         for(;;)! a& G9 i& H5 j
  14.         {
    0 E7 d. e; M, J/ {" z9 @" s# T2 }
  15.                 GPIOA->ODR^=GPIO_PIN_5;// PA5取反 LED闪烁7 ]' E3 ^. C; |0 R7 j
  16.                 osDelay(500);* T( T  g; X4 S( ]5 Y' e) {
  17.         }. T! ]1 E/ S. \/ x: i

  18. ( p3 |( {5 {! ~
  19. }
复制代码
5 p. i! Z* }' P- L/ a" V/ ~; m
到这里可以编译下载到板子上运行 观察现象了
" h8 t  K# u9 R+ r6 E: P
, \% ?- Y+ N6 j下面创建 RXT 的工程  新建一个工程  
  w# z6 H1 g: a! K9 q" i+ j, y) R0 T. H$ s
勾选 如下选项 ! T1 @6 F% d1 x1 a0 P  p; |6 Q3 X. A

* P* ~. d" A/ ?5 q. F3 s QQ截图20150108112304.jpg
6 a/ ]5 v% d; N& X红框 不要添加  不知为何  楼主添加 MDK的 startup 编译通不过 9 L# C( ^5 K8 a, |5 D: I' t% |
F4 的工程没有包含  HAL  接下来 需要自行添加HAL 库 1 M: ]2 y, b; S: s. m, k" c/ i

1 T: P& r' p. @$ {4 L2 o把原来的 main.c 复制一份更名为  rtx_main.c
; @8 h* B3 E$ T- w5 h6 q
3 Q- w6 F; A# B+ D' P! c7 G" Y QQ截图20150108113501.jpg # a& n( f, s- N! X5 Q" X, d
9 T# r4 Z; U3 |) O/ K7 k
文件添加完毕
; x$ Q6 a( }+ H+ |1 d0 N' l- V0 ?5 a1 t3 `$ R$ r1 m( q- r
接下来定义 头文件目录和 系统宏   A7 ]) [1 {" I9 m

; f4 }" U+ t% L) J! |/ M* t/ Z/ { QQ截图20150108112609.jpg
5 ?9 A$ u1 _' E) P& n' B" b
, |6 l! k! H8 f) \- W  h$ I修改 rtx_main.c  下面两处需要修改
5 \3 i# B3 [- T5 @; z; L" P1 [$ w4 t  Y* I8 Z2 X  g( a: \  p6 N
  1.   {9 r: u6 v6 x, v- G- E; ~
  2.   osThreadDef( StartThread, osPriorityNormal, 0, 0);4 n# a2 @" t7 k4 y+ J# T
  3.   osThreadCreate (osThread(StartThread), NULL);
    ( Z% d9 Z1 \5 @8 E; E
  4.         }
    ' `# C- Y( s9 n6 ~  @7 n/ c+ @
  5. 9 P# P) {/ f$ A" S3 q. A
  6. osThreadDef( Nucleo_072_Led, osPriorityNormal, 0, 0);
    ' {3 J+ o6 N/ Z. g% y
  7.   osThreadCreate (osThread(Nucleo_072_Led), NULL);
复制代码
不知为何  ST写的 中间件和 MDK的 接口有一点差距  所以 创建线程的地方需要如上修改
" Y: C0 i7 `( h% A* Z4 q4 G: o7 y/ X/ C0 u
修改 stm32f0xx_hal_conf.h
* `; l/ N9 a% @8 [+ M添加 图示内容  不出意外  下面 将可以直接编译了!!- `  m4 [. g% u- c# g
QQ截图20150108112936.jpg ! _. X% K" H' ~' }+ F
4 t% n8 k2 C& w% u7 ?
写的有些多了  本来想 继续写 RTOS 基于串口的  应用  太长了 下次发帖写了; n# \  s% w3 r- E" F; \/ N+ g

/ o& P- J% t- Z$ N* \; ?8 ^下面提出一个讨论 MX 创建的  工程 FREERTOS 中 cmsis_os.c 中 创建一个信号量  
' E+ N; Z% s) G, @( |$ hosSemaphoreCreate参数 count 直接
) c0 c6 u5 h3 k: Y% [1 A( @) I" s) o9 @9 g1 M
传递给 xSemaphoreCreateCounting的两个形参  , _: ]  G; N* G' A" c( \* U: A# w1 ]
QQ截图20150108115258.jpg - m! [; q7 k5 }6 S8 g
原型 7 X1 l4 {6 s8 w! b7 i) Q. n
#define xSemaphoreCreateCounting( uxMaxCount, uxInitialCount ) xQueueCreateCountingSemaphore( ( uxMaxCount ), ( uxInitialCount ) )
6 E* M& t9 D. i$ z  H1 q9 u
5 J0 I* s6 [0 Q! q$ }5 Q该宏创建一个 数值型信号量 第一个参数是 信号量最大数值  第二个则为  初始化值2 L* o8 h9 w" ]
' G3 u5 P9 C/ _1 ^- X9 M# ~
基于串口使用信号量  那么需要如下要求
% M% G% j$ u* R) |1 W; K" s7 l假设 usart_sem 为串口使用的信号量* w  x6 C5 G/ I# U. V% s
每收到一个数据 usart_sem ++  缓冲 1024字节 7 F% }6 E5 ]2 s( [/ l5 X% `2 _& F  F
需要数据的线程 osSemaphoreWait(usart_sem ); 当有数据时 线程被激活  获取数据
" ^* i& ?. U' k: b4 d
: z9 E% F) C4 t& G+ e$ h如此我们知道 这个信号量的 最大值应为1024
/ @. X' x8 I# b+ k, H可是使用 ST 的cmsis_os osSemaphoreCreate 创建一个信号亮 osSemaphoreCreate(0,1024); ( R  R4 T& g1 E3 I5 h8 f- P( p  m% o
6 M  @$ l) v& ^0 A
会出现这样的问题 !  此信号量 被赋予初值1024  意味着 这个信号量将可以被osSemaphoreWait 1024次/ i: j6 U. D, \- m7 Y
显然这不是我们想要
& y: o2 y; r8 b  t8 m& j9 e8 c! N! C/ @' ~9 O; p4 R# i: a# b
通常  我们需要的数值型信号量  最大值可以很大  但是初值 基本为0,或1
$ @, Q) a+ Y/ @6 O' w4 V
1 E# D1 _! ^* x- m: M4 a; I不懂  这样设计意义何在?$ d) Q5 K& D% r8 w

- Y" E6 L3 G' M& x8 t8 w8 m/ K1 f, u2 s
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 编辑
( n, v; o8 G) ]1 c: @; B8 W4 }
lovewyufeng 发表于 2015-1-23 12:56
! L8 a: u: h! l, G) U9 A1 S& w事实上  只要这个计数不为0 都能被 wait 到
' J! V/ {9 n* V/ _. e  e
不好意思,确实被代码的名称误导了,以前用的基本上只用二值的semphore或者直接用queue了。
: r0 p/ P& W( M( ^8 a仔细看了一下内部的实现,确实我说错了。
+ R6 ~8 }4 ]; O3 I! W在init_counter和max_counter一样的情况下,确实整个逻辑是要按照资源池来解释的,也就是确实生产者take(这个take代表获取空闲资源才能生产),消费者release(这个代表空闲资源返回)。我觉得这种情况semphore更像一个可重入的锁,处理线程拿走资源池后,直接处理完后再归还,像是个recursive mutex。
8 T, n: N5 D9 j: B+ A( U/ t1 |前面说的那个问题,直接用queue可能会更好。另外,今天试了一下最新的stm32cubemx和固件版本,代码已经改了,#if (configUSE_COUNTING_SEMAPHORES == 1 )        9 E0 ^' R$ ^' o6 T; I8 \9 _
  return xSemaphoreCreateCounting(count, 0);" k7 J* g$ c+ [
#else) [( c7 W/ |) b  ?6 B9 R/ M& Y
  return NULL;4 y9 R) V& ^+ f+ m- h: V
#endif
" N/ D/ J$ B/ }: j- P$ V5 g' v}
/ |! _1 ~, U2 Z. d  R0 B0 y
1 ^+ j' }, C; e8 {0 j: x* G9 P/ F- y8 x

& n( V* \1 V0 Z% Z4 Q+ i5 z# S: F1 U
  d& y$ M5 R- Q5 F
我是东哥 回答时间:2015-1-23 07:50:34
lovewyufeng 发表于 2015-1-23 00:48. v! H7 s- v8 {2 {
反过来理解是吧,说得通。可是8 d8 b1 S2 N4 `) H# B& G. p; f
有个问题。,生产一个就-1的话应该 take获取信号咯?   反过来消费应该pos ...

9 L2 [8 `( u; j" \9 V9 T2 q你陷在细节里面了,看看人家的API是怎么样写的,osSemaphoreRelease和osSemaphoreWait,我们在生产者里面应该要osSemaphoreRelease,而在消费者里面osSemaphoreWait,是吧?字面理解,相当于生产的人释放了一个东西,然后消费者就等待生产者的这个东西。再看里面的实现,osSemaphoreRelease里面是xSemaphoreGive而不是take,而osSemaphoreWait里面是xSemaphoreTake而不是give。, k: z1 I( w/ U3 s, P
所谓的反过来理解只是一种理解方法,说take和post的逻辑也反的话是不对的。不要老想着什么时候去post,什么去take。cmsis_os的API意思很明了,生产者生产了东西就应该release,消费者就应该Wait,这不是很好理解吗?
lovewyufeng 回答时间:2015-1-23 00:48:46
我是东哥 发表于 2015-1-21 12:18
/ \$ N2 Y1 C+ O9 o4 w2 }这个其实也没有不合理,看你怎么理解,资源一开始为0,也可以理解为空闲池一开始是满的。生产者生产了一 ...

  L1 q2 v6 a1 f0 C1 B- ~+ Z反过来理解是吧,说得通。可是
! v$ `: |* \. y/ J4 {9 P; y) x有个问题。,生产一个就-1的话应该 take获取信号咯?   反过来消费应该post 释放信号咯? 那么问题是 post是非阻塞立即返回的而take是阻塞的?
5 U  R0 v5 r7 r; R: x先不谈消费者应当随时饥饿,处于阻塞态。
; j& R. a# t0 C2 ~. P1 n生产一般在中断里吧,当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
看看 顶一下
  c" z* |$ g% {. A' G! h1 e8 Z
cqtnheyao 回答时间:2015-1-8 12:19:01
harvardx 发表于 2015-1-8 12:13
' l9 _9 f2 g' i8 S. H8 K& E有钱为何不顶帖 .何况还是高质量的 .cubemx 势在必得的趋势.支持一下.
9 O' ?' N( E3 S, K
据说库很大,效率低?求告知!
netlhx 回答时间:2015-1-8 12:19:08
很好,图文并茂
lovewyufeng 回答时间:2015-1-8 12:19:26
harvardx 发表于 2015-1-8 12:13
0 {7 w) z  x! n有钱为何不顶帖 .何况还是高质量的 .cubemx 势在必得的趋势.支持一下.

, l2 o, W8 `4 K% u" ^" H多谢老大 支持  继续加油
lovewyufeng 回答时间:2015-1-8 12:23:05
cqtnheyao 发表于 2015-1-8 12:19
( [4 W6 L4 g5 i, Y6 B3 P6 Z3 o据说库很大,效率低?求告知!
1 G5 {! i* f) E2 ?) O' e
确实 有这个毛病  楼主的贴初始化使用库  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管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版