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

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

[复制链接]
lovewyufeng 发布时间:2015-1-8 12:08
以刚拿到手的 Nucleo 072为例  其他板子用户 请举一反三哈 (工程文件在帖末. Z( t+ O* b% j7 W

0 F' N) ]# w2 \/ S$ A* U' z5 F- Z5 m. ?5 N
后续帖子:【干货】Nucleo072 usart 基于RTOS的应用  方便AT指令类外设开发
8 V. w$ I( `! r1 t8 T# i8 N5 o+ q5 l
需要工具  MDK5 自行下载:
& E2 o* ?" E* S& l% `STM32CUBEMX https://www.stmcu.org.cn/document/detail/index/id-214984  X4 u% `3 b8 v1 }4 e
STM32CUBEF0 https://www.stmcu.org.cn/document/detail/index/id-216669
  A1 I" `" N# G( E
2 g) K" V: v  C) b/ V
7 X0 L: |6 e  i/ Y9 N! Y安装 cubeMX  由于使用MX下载固件库速度那是不说了相当慢啊  所以下载 STM32CUBEF0固件库然后下图安装
* N) n) K6 W( C8 z6 Y. C) \1 S2 O3 P/ X3 l% _

; k  F$ }# ?: j9 H, Y( x7 N5 s9 o) C QQ截图20150108101548.jpg QQ截图20150108101556.jpg ! f6 ^! }# |) p

; U% d- `- H, o1 a  ~8 \安装之后  新建一个工程 选择STM32F072RBT6, E' r9 u# t* i, _/ i$ i
3 ]8 B. K& C% e' c9 i! }0 \
PINOUT 勾选  FREERTOS和 USART ! H' c9 t) J. k8 t: _& c' `
QQ截图20150108101539.jpg / p+ `  x  ]6 R' ^/ l" {" ~$ i
因为我们调试可能需要使用. L) G. }& ?. X/ A6 O! }3 U
& @/ r5 C' L! k2 Z
点击软件上方  齿轮键生成  keil 工程  至此" O9 O7 X. [  I0 ?/ A0 Y$ }+ t: X

+ A. a" M7 o3 V& I# ~! OMX基于 HAL的库 生成完毕
, N8 c0 ~/ P2 D4 J: E4 b4 k8 u9 u
使用MDK 打开工程
* t3 `! z' F8 I从上到下 的组依次为  OS 的C文件
1 q% @9 o6 n: ~) k7 o.s 启动文件$ s5 _2 i& N- W" z/ {  o
用户文件6 c  W2 R. {4 @! S% n
HAL库文件0 q4 _, a' U. @0 g
CMSIS中间件文件+ W  R- u. |4 m# W" x

; \9 d% `9 ^# C) K其中 在 第一组中的 cmsis_os.c 中实现了  cmsis_os  到FREERTOS 的中间层转换   稍后会讨论其中一处代码
- T- K  z: Z8 {1 Z: g) F2 W* r6 X+ @+ n; p) A
QQ截图20150108101924.jpg
* ~- ?0 h9 z- o: n% I6 a7 u3 O" y$ L% f/ r: `+ _+ ^& t

5 ~8 ~) n" S( O! B, Y7 Y: [接下来  添加自己的代码  首先添加 072 上面LED吧  板子不在身边  记得是PA5 控制
' E" ^$ r1 \4 c- l5 o% a. ]1 Q2 Q, w: x# l, F6 \/ A
先看看  main.c 的 64 到 105行 - K, W. M; }4 M; z

  1. 8 S" Z# t" r! w4 h5 h" m! n& d/ H
  2. int main(void)
    0 R8 X* N, t2 D
  3. {
    ! ^' ?8 p* v* h, w) a$ X* ~
  4.   @* e5 K4 z( i, M) y" |8 T& g
  5.   /* USER CODE BEGIN 1 */
    ; B' |3 m7 M- L. {; [

  6. : I- G6 J0 E9 C/ ?
  7.   /* USER CODE END 1 */! L2 b' \6 \4 x2 S2 X5 H, E

  8. 8 x9 Y- O+ h3 ~  Q7 z! H7 ^+ F
  9.   /* MCU Configuration----------------------------------------------------------*// k7 L  J- E4 j/ w- h

  10. 7 S( c# Q4 j# K9 H8 ~
  11.   /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
    ) Z! {2 f0 Y! g1 |( m8 y% X( S9 b
  12.   HAL_Init();$ ~2 c1 I4 G0 L0 Z1 y
  13. ) v2 U2 A' c  c. }- X+ j
  14.   /* Configure the system clock */
    ' B1 J* g7 ^* I: Z1 }4 W
  15.   SystemClock_Config();9 u( ?, R/ b3 l  z# n. s! f

  16. ' f2 f0 j5 F; e* _+ r4 u3 V
  17.   /* Initialize all configured peripherals */9 S8 I, {# l) c4 x& J4 @4 u. J
  18.   MX_GPIO_Init();
    1 [! C& ~& ?  D/ X
  19.   MX_USART2_UART_Init();- ~' I' s* p0 }# \1 g+ [$ K
  20. 0 k, R( A! q5 l" R" n) B1 \% Q
  21.   /* USER CODE BEGIN 2 */
      O! m  e2 M3 _! n7 o, K5 }& L
  22. / M* p& ?; T7 P) j* z+ E9 a* W
  23.   /* USER CODE END 2 */
    ( I3 U/ `) d1 U$ u" d4 u8 g

  24. ' J) C5 U" p2 A! e* V! N. f( f* J
  25.   /* Init code generated for FreeRTOS */1 u. U; E/ f! |; e" @, `
  26.   /* Create Start thread */
    & z# {& L9 d7 |5 c4 j" w# a
  27.   osThreadDef(USER_Thread, StartThread, osPriorityNormal, 0, configMINIMAL_STACK_SIZE);: s" ]! r( ~' k6 F
  28.   osThreadCreate (osThread(USER_Thread), NULL);, s4 n2 }& A" a; x- ?8 _

  29. 5 I3 G' _5 d, v9 W
  30.   /* Start scheduler */7 a1 t" n; d* D1 f: L8 Q, G  A
  31.   osKernelStart(NULL, NULL);
    . Q- F# k+ }  u3 p" G

  32. 4 t5 Q; l+ ?" K1 Z4 Q* r+ C
  33.   /* We should never get here as control is now taken by the scheduler */1 z% M  h/ R0 q7 {: S

  34. ; O* \3 V( C0 ~0 R& |2 X- L1 ~8 N! Y! d
  35.   /* USER CODE BEGIN 3 */
    & H7 G& S% p% w1 R1 d+ }/ I* z
  36.   /* Infinite loop */% D4 ^7 o3 a) z& Y
  37.   while (1)
    2 U. ~( K- `7 y6 e$ c
  38.   {
    4 ]9 L# N" `+ Z- l
  39. $ h3 v8 v( c0 v. [0 k' `" \4 D
  40.   }. E6 g$ c; C& F  G, r
  41.   /* USER CODE END 3 */
    - {& L5 s1 s: V% L
  42. # k/ ]: l0 V' x
  43. }
复制代码

5 h. N& T) r6 V$ w7 }mian函数  C代码的入口  初始化一些硬件后 % v+ \6 n$ z5 G/ Z+ A
  osThreadDef(USER_Thread, StartThread, osPriorityNormal, 0, configMINIMAL_STACK_SIZE);
  osThreadCreate (osThread(USER_Thread), NULL);
  /* Start scheduler */
  osKernelStart(NULL, NULL);

4 D: z" n, A+ ^3 l5 T8 Q+ ]定义了一个 线程 USER_Thread 然后启动OS  $ h1 R' k9 x+ o3 K6 S
注意 osThreadDef  是一个宏  定义一个用于描述  线程的结构体  并不是执行函数* p0 r# ]8 _1 w% b) Q: s  [
+ W) z( \' J, K* h# d7 {
宏的第二项参数 StartThread 为线程 入口函数地址。, y& W+ K3 _9 _: N% W' s3 S

2 E" f: }9 o1 U% h6 f2 u至此mian函数的工作结束了 OS将转向 就绪线程并永不返回  也就是执行StartThread  3 ^0 i) G; ]# e% H' u" ~% T; W
: y" A+ }4 r+ \8 r& ^# }# w
修改  StartThrea函数 如下* t6 z* y: J5 j7 U

2 V: G& K) j; b# U" \
  1. ( ^' [$ t+ O5 R. ?0 E" l. T5 ]$ G
  2. /* USER CODE BEGIN 4 */( b! Q9 z) n) \7 b
  3. void Nucleo_072_Led(const void *par);
    + P0 i( Z/ a. }1 e* s% T
  4. /* USER CODE END 4 */. K( m9 w6 z8 U* c: p2 _1 V0 b

  5. % ?; ?; |" T4 h! a6 T6 y0 M
  6. static void StartThread(void const * argument)
    9 s! F8 p8 J" O) |
  7. {1 L) P# ]' U  }% L: L' L

  8. ; n* b9 c# |2 m. i  q  I
  9.   /* USER CODE BEGIN 5 */: T" I9 U( n# v8 D, {# {
  10.   osThreadDef(LED_Thread, Nucleo_072_Led, osPriorityNormal, 0, configMINIMAL_STACK_SIZE);( _$ i" B) [. I. b1 L
  11.   osThreadCreate (osThread(LED_Thread), NULL);
    5 X8 M: c1 v0 i/ B
  12.   /* Infinite loop */# G: V; G# T# w! S- j1 ^
  13.   for(;;)
    6 H, k! w  o7 @6 W* j) g
  14.   {, Z  L/ b7 |! c$ s
  15.     osDelay(1);
      e/ k0 t% T2 h
  16.   }5 T) j! A1 l, @) C

  17. # Y& s5 v8 k" Q, w( M, d
  18.   /* USER CODE END 5 */ + C/ ], e9 z+ g# E, A1 b+ k

  19. ' J) z9 D$ x- s/ L) q3 O
  20. }
复制代码
8 P/ {, {) j- N
添加一个 LED 函数
4 h& |& U/ K' {: _5 `, A
  1. void Nucleo_072_Led(const void *par)2 X" T' f! v; G% H6 o: e/ i
  2. {
    9 S- M& ?& L" v0 f& ~" i; {+ T
  3.         GPIO_InitTypeDef GPIO_InitStruct;
    + n. T+ H: g6 M, I5 Q) D' b
  4.   __GPIOA_CLK_ENABLE();
    : V7 B5 z( C$ _5 Q# c6 v
  5.         2 V$ R0 i6 A1 U# M5 H4 }
  6.            GPIO_InitStruct.Pin = GPIO_PIN_5;
    8 R! B& \) l* i6 r
  7.     GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    ' r0 n0 Y( n; ?5 s+ G4 A* g
  8.     GPIO_InitStruct.Pull = GPIO_PULLUP;
    . y- P& g9 a1 j9 g# a! L7 C! K
  9.     GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
    7 `( i0 z% l% M1 i4 x' H, p: k

  10. 9 G. L0 ?+ ^3 g
  11.     HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);9 S' R5 \( O6 X) h
  12.         ' a# m: e* t' e: p8 _( N
  13.         for(;;)
    ; [* C% O- D+ S# N" I
  14.         {0 T/ {) Q" [# I$ w0 a0 I5 Q
  15.                 GPIOA->ODR^=GPIO_PIN_5;// PA5取反 LED闪烁
    & M: Z& _2 @4 ^3 n1 q) x( f4 V
  16.                 osDelay(500);2 y# j/ J2 S% |# V
  17.         }4 x! R8 T% G) ~0 [7 t# U
  18. 8 ?3 Z/ _6 O, ^7 x  U8 F
  19. }
复制代码
$ w2 O! ^# ]7 b8 r# E1 _5 \% c
到这里可以编译下载到板子上运行 观察现象了5 q# Z: e6 ]: R8 w, V
3 k$ L  ~, I6 n. ], L$ n! q$ Z
下面创建 RXT 的工程  新建一个工程  0 v% N7 y9 i/ w3 f7 i, B
; l" e4 `# _) E$ V0 Y
勾选 如下选项
- b6 X+ l* J* [# k
7 s- I: n0 u5 i- S QQ截图20150108112304.jpg $ F/ B0 w" r: W
红框 不要添加  不知为何  楼主添加 MDK的 startup 编译通不过 . s* m2 X) S$ c( p6 j
F4 的工程没有包含  HAL  接下来 需要自行添加HAL 库
/ X, ^8 B$ O' @( e! y3 d7 S) c: F- o* b6 Q( D
把原来的 main.c 复制一份更名为  rtx_main.c9 Y0 r1 e) {) C8 b' o, V

) p' l  t  g* j$ u0 V" ^ QQ截图20150108113501.jpg ( q1 O& ?; a% K- R" V' E/ C" S; p+ a1 `
, m; R) i7 T7 V- [
文件添加完毕
$ ?2 C" p4 [/ k! Q
) [2 N* h1 C, l9 e+ `% o( B& @0 o4 W接下来定义 头文件目录和 系统宏 ; b4 d7 V8 w3 s9 H" W! v( ~
! U* M# O0 k( C3 f# \
QQ截图20150108112609.jpg , S; c: e5 m6 E- y9 Y
1 ]3 v5 f0 q8 b0 V; U9 v# Z, j, `
修改 rtx_main.c  下面两处需要修改
/ _1 s: T+ q% P4 t" P  g* L
( |" Z5 p6 H: a( ~
  1.   {! @0 D3 p" ?# b' C7 q+ p0 g. e
  2.   osThreadDef( StartThread, osPriorityNormal, 0, 0);
    ) B9 w% H9 J* T+ h* u
  3.   osThreadCreate (osThread(StartThread), NULL);
    2 z6 T# |" w: E2 s. k
  4.         }
    # t7 v4 L4 Q# [* {$ M. i, W

  5. - o& {; P# i, g/ g6 D
  6. osThreadDef( Nucleo_072_Led, osPriorityNormal, 0, 0);
    7 ]( M- J9 p% F( P$ i9 X2 V
  7.   osThreadCreate (osThread(Nucleo_072_Led), NULL);
复制代码
不知为何  ST写的 中间件和 MDK的 接口有一点差距  所以 创建线程的地方需要如上修改: h* ]% j: Z4 R/ g1 P, Y' }* q
, d8 Z# I) A$ L& ^0 i
修改 stm32f0xx_hal_conf.h
4 {9 P3 Q/ g6 e( K' h, J4 b0 J# q# v添加 图示内容  不出意外  下面 将可以直接编译了!!6 j/ q0 @" ^! r8 C
QQ截图20150108112936.jpg - W) `* v& M8 Q3 a4 i! m4 d
4 ]' w! Y) d: |( ?8 j
写的有些多了  本来想 继续写 RTOS 基于串口的  应用  太长了 下次发帖写了
* n) u3 R2 _, L) m& l/ ?. I; E7 A2 C* W" ?+ k. b
下面提出一个讨论 MX 创建的  工程 FREERTOS 中 cmsis_os.c 中 创建一个信号量    @: g# l4 R' d
osSemaphoreCreate参数 count 直接
# Z4 G2 S% G& b3 _# b9 s0 c4 Q  M% J8 b& A
传递给 xSemaphoreCreateCounting的两个形参  
' q; i0 E- m9 F QQ截图20150108115258.jpg ; X* h2 C+ N, i5 D) j9 u! l+ H
原型 1 F$ o4 \. p; V# R+ Z
#define xSemaphoreCreateCounting( uxMaxCount, uxInitialCount ) xQueueCreateCountingSemaphore( ( uxMaxCount ), ( uxInitialCount ) )8 U1 N$ Z' @1 D$ W& R

! I+ u- c# j! d2 R$ x* v* P$ S该宏创建一个 数值型信号量 第一个参数是 信号量最大数值  第二个则为  初始化值  b& n& v: y) s- L' v
# X8 A' E  p* @2 p% `# y: E
基于串口使用信号量  那么需要如下要求
# D% ^4 ~& d9 e假设 usart_sem 为串口使用的信号量8 w9 p* T5 w3 s0 {0 R- M
每收到一个数据 usart_sem ++  缓冲 1024字节 ) `, u! y4 y& n3 h0 C  M% t, t7 X
需要数据的线程 osSemaphoreWait(usart_sem ); 当有数据时 线程被激活  获取数据( t: h% m" g) A2 ?3 W9 o
$ L+ H* k9 T* i( C& c
如此我们知道 这个信号量的 最大值应为1024 2 E2 Y5 u" Z/ M3 }- V* @
可是使用 ST 的cmsis_os osSemaphoreCreate 创建一个信号亮 osSemaphoreCreate(0,1024);
/ J3 w4 I" ^% L) H' e8 m2 a2 o4 a( v' A/ C2 ?/ y
会出现这样的问题 !  此信号量 被赋予初值1024  意味着 这个信号量将可以被osSemaphoreWait 1024次; w: S2 G% h! U) c# I
显然这不是我们想要
9 N7 J' R1 ~0 E
  R9 F- J7 V6 [  H5 ?通常  我们需要的数值型信号量  最大值可以很大  但是初值 基本为0,或1
8 e9 @& t4 U0 R0 d! {+ ^9 d7 j6 z. a7 J- ]3 f$ u1 W
不懂  这样设计意义何在?/ q! f5 q/ Y" j' w
4 {8 C. p( J0 {  D9 e

0 C7 [! [6 @9 V2 S4 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 编辑 . X% T! h" d6 E( N5 s1 _# u: Y4 |
lovewyufeng 发表于 2015-1-23 12:567 k) e% A- S8 X% G; [; D
事实上  只要这个计数不为0 都能被 wait 到
+ v. L: t3 u2 n
不好意思,确实被代码的名称误导了,以前用的基本上只用二值的semphore或者直接用queue了。2 s9 `2 k3 b- w; U0 J4 b0 R
仔细看了一下内部的实现,确实我说错了。8 q/ u. F7 L1 x" q# v" R2 i; v. L; V
在init_counter和max_counter一样的情况下,确实整个逻辑是要按照资源池来解释的,也就是确实生产者take(这个take代表获取空闲资源才能生产),消费者release(这个代表空闲资源返回)。我觉得这种情况semphore更像一个可重入的锁,处理线程拿走资源池后,直接处理完后再归还,像是个recursive mutex。
7 X: |( T( o* [3 F$ L前面说的那个问题,直接用queue可能会更好。另外,今天试了一下最新的stm32cubemx和固件版本,代码已经改了,#if (configUSE_COUNTING_SEMAPHORES == 1 )        
2 @6 r' p, H! f7 O  return xSemaphoreCreateCounting(count, 0);
- A% Z, _9 G& {# q  l2 N#else
2 f5 J: M8 ^5 w. }( p  return NULL;9 A7 d( _: H# H5 F. I" z8 a
#endif
' m$ [, N4 ]0 u, o$ u}7 {8 b8 Y1 }6 a" F6 i
: t. H  W  X- |4 W( r6 d
( @# o5 J" L7 W6 R6 l8 w
, R4 S( m$ f; _* `/ K. b5 @6 l" ]
6 o( l" E  n) J' g5 O* q4 W" r0 d
我是东哥 回答时间:2015-1-23 07:50:34
lovewyufeng 发表于 2015-1-23 00:482 G0 M. L' S3 a7 g& E* C  q
反过来理解是吧,说得通。可是
( O& ?( A; e1 ]: n% r; k7 @# P' L& V有个问题。,生产一个就-1的话应该 take获取信号咯?   反过来消费应该pos ...
* X& K9 E( m5 j. p- _! f0 o- M. F
你陷在细节里面了,看看人家的API是怎么样写的,osSemaphoreRelease和osSemaphoreWait,我们在生产者里面应该要osSemaphoreRelease,而在消费者里面osSemaphoreWait,是吧?字面理解,相当于生产的人释放了一个东西,然后消费者就等待生产者的这个东西。再看里面的实现,osSemaphoreRelease里面是xSemaphoreGive而不是take,而osSemaphoreWait里面是xSemaphoreTake而不是give。
# c2 z! u/ r  U* J% B# D( W. w所谓的反过来理解只是一种理解方法,说take和post的逻辑也反的话是不对的。不要老想着什么时候去post,什么去take。cmsis_os的API意思很明了,生产者生产了东西就应该release,消费者就应该Wait,这不是很好理解吗?
lovewyufeng 回答时间:2015-1-23 00:48:46
我是东哥 发表于 2015-1-21 12:18
/ a+ X3 x) @5 w. a; h5 @' p0 M& ^这个其实也没有不合理,看你怎么理解,资源一开始为0,也可以理解为空闲池一开始是满的。生产者生产了一 ...
% J5 j3 I, l3 o) \1 j( @
反过来理解是吧,说得通。可是
( s+ X: g. M/ o% Q5 f+ C: D有个问题。,生产一个就-1的话应该 take获取信号咯?   反过来消费应该post 释放信号咯? 那么问题是 post是非阻塞立即返回的而take是阻塞的?
" X4 N' s# z" Z1 x先不谈消费者应当随时饥饿,处于阻塞态。# d( M2 l- Y" M2 B, R
生产一般在中断里吧,当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
看看 顶一下
- T) s3 O+ b7 x3 Z6 R, F
cqtnheyao 回答时间:2015-1-8 12:19:01
harvardx 发表于 2015-1-8 12:13! S# S/ m, y  f, x7 O. u
有钱为何不顶帖 .何况还是高质量的 .cubemx 势在必得的趋势.支持一下.
& ^  {0 n, [1 b$ \8 @* u
据说库很大,效率低?求告知!
netlhx 回答时间:2015-1-8 12:19:08
很好,图文并茂
lovewyufeng 回答时间:2015-1-8 12:19:26
harvardx 发表于 2015-1-8 12:13# n- l& @( I1 f" t5 {' g
有钱为何不顶帖 .何况还是高质量的 .cubemx 势在必得的趋势.支持一下.

& G; X: c+ Z+ \2 e" F# ?% s多谢老大 支持  继续加油
lovewyufeng 回答时间:2015-1-8 12:23:05
cqtnheyao 发表于 2015-1-8 12:19
8 A1 w: d5 V9 b' k1 p据说库很大,效率低?求告知!
% q1 ?$ e" [" W" a' W0 C3 G* b5 q
确实 有这个毛病  楼主的贴初始化使用库  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 手机版