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

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

[复制链接]
lovewyufeng 发布时间:2015-1-8 12:08
以刚拿到手的 Nucleo 072为例  其他板子用户 请举一反三哈 (工程文件在帖末
+ @( q7 s7 K. D. V8 o- L% F- c, e$ F3 B, q( ]
7 Z8 W, U- @: L& r9 j7 D& K1 Z8 I
后续帖子:【干货】Nucleo072 usart 基于RTOS的应用  方便AT指令类外设开发! x! ~2 t) I7 v" `, ^

8 p% T" f) s3 m4 j5 L. ?/ c, p需要工具  MDK5 自行下载:) a0 b1 ~, a- F3 v& M5 Y$ N
STM32CUBEMX https://www.stmcu.org.cn/document/detail/index/id-214984
; E2 I$ s% x) p, t; W1 c) y- iSTM32CUBEF0 https://www.stmcu.org.cn/document/detail/index/id-216669+ K+ R, u8 o% f4 Q. q8 m" I

) ]6 K  \; v8 B0 a! j- z; X, s& i4 j0 k$ @
安装 cubeMX  由于使用MX下载固件库速度那是不说了相当慢啊  所以下载 STM32CUBEF0固件库然后下图安装: H5 C. \/ _3 r* S; {

  h9 _# S7 S3 b7 n4 [! r# I$ N& Q" S
QQ截图20150108101548.jpg QQ截图20150108101556.jpg " }8 X* x& X; s: k( {- S) B. V
  A- L* V2 M  @+ r4 W
安装之后  新建一个工程 选择STM32F072RBT6- V+ l1 A! m4 E% H

9 V( j8 s5 l3 g4 VPINOUT 勾选  FREERTOS和 USART 0 V: f" `, s" U- I5 l1 d& z
QQ截图20150108101539.jpg
8 O' g+ L1 x, U7 y' k因为我们调试可能需要使用
% i# }% h- v$ ]9 F7 N3 D2 i9 ^4 e% t" S
点击软件上方  齿轮键生成  keil 工程  至此" x/ I0 C( L! J1 `; a

! |$ Y  |3 |8 v7 k* qMX基于 HAL的库 生成完毕1 G5 H3 u* A8 c% R6 x

9 R4 w, {2 S- P使用MDK 打开工程
3 u+ N, b/ g$ ^+ c/ x, Z从上到下 的组依次为  OS 的C文件: @$ [# V! Q' f/ Z2 |1 q! Z0 Z, e
.s 启动文件: h- q6 Q- a. @6 c, O
用户文件
3 b5 L3 Y! p) P& IHAL库文件
. o0 ~$ y4 y, m! R3 ?2 v; tCMSIS中间件文件
' i( l1 F2 c. A" v8 x, |
$ e, e9 e' @! _  k& i# l; g& a其中 在 第一组中的 cmsis_os.c 中实现了  cmsis_os  到FREERTOS 的中间层转换   稍后会讨论其中一处代码; \  v; g$ q8 \9 V0 ~
  e& T- f, f& O7 Z' e
QQ截图20150108101924.jpg . P8 F8 c3 w* s' y: F

6 y$ ~: ^% t4 v2 }) d! ~2 ~6 S( g, X; O% }: K) @
接下来  添加自己的代码  首先添加 072 上面LED吧  板子不在身边  记得是PA5 控制5 S; c/ ?( v" m, D1 o; c7 U0 j

9 j" f, O! B7 K/ s; r先看看  main.c 的 64 到 105行
8 x) y( P7 b: K8 m$ r4 R
  1. 6 g- `6 v2 \! d/ |  @; p  o
  2. int main(void)$ H. t, ?; K. H, Q& b( Y8 D
  3. {
    # `% b7 u( ^! v- _

  4. + O6 G$ d$ |4 c$ _: {
  5.   /* USER CODE BEGIN 1 */) V% _: W9 _! e3 M" g1 P
  6. ) F. `- {/ q9 [/ M3 L2 Y
  7.   /* USER CODE END 1 */
    1 A( `* q: R* |0 b1 p& S
  8. % U6 F# ^6 C2 v; m' ~/ q. q+ d
  9.   /* MCU Configuration----------------------------------------------------------*/  U, U" i- H- p7 J
  10. : N* j" K% Z% b% Z# j* e
  11.   /* Reset of all peripherals, Initializes the Flash interface and the Systick. */' h% e6 S3 j4 l
  12.   HAL_Init();( Z( T4 @' O' \1 j
  13. % {! X4 `+ ^! w- r6 r3 |
  14.   /* Configure the system clock */
    # D& ~% H5 @) U' e4 l
  15.   SystemClock_Config();/ r: X: t* U7 s

  16. " K7 g3 e$ r9 ~: B* U
  17.   /* Initialize all configured peripherals */
    + s% L# D9 [3 A7 o" i' w: o
  18.   MX_GPIO_Init();9 g. b' Y( I/ \) b4 |7 c
  19.   MX_USART2_UART_Init();
    / y9 I% I1 ^$ K2 }, x* e  y' W

  20. 5 `$ b0 i) O/ p
  21.   /* USER CODE BEGIN 2 */: p" v9 r$ `0 u
  22. $ r" M8 Z5 g. E. F7 |
  23.   /* USER CODE END 2 */; H  @' X/ \1 ?4 I

  24. 4 Z4 s/ @' B& p! F+ u$ |
  25.   /* Init code generated for FreeRTOS */  N1 I4 d6 X7 a% N7 D0 D; P
  26.   /* Create Start thread */
    9 y9 C" }) S# }
  27.   osThreadDef(USER_Thread, StartThread, osPriorityNormal, 0, configMINIMAL_STACK_SIZE);3 l5 K' Z1 }# M: @/ ^
  28.   osThreadCreate (osThread(USER_Thread), NULL);( ~, ^; `9 v; u! Y! H
  29. " @7 n, M* ?9 ~6 s' M3 C
  30.   /* Start scheduler */
    0 v& k+ n  M- W! U) ?- R
  31.   osKernelStart(NULL, NULL);# \3 P, j& S- c7 S+ H
  32. - a3 \3 J9 \& f% b3 ^
  33.   /* We should never get here as control is now taken by the scheduler */
    + O8 I% a5 c3 r& G, \
  34. ! w4 n8 L: a1 x' }1 U& D
  35.   /* USER CODE BEGIN 3 */
    ' J$ a* ^% w+ Q* D
  36.   /* Infinite loop */) v6 E" P: i" h) X# ]. C
  37.   while (1)
    & [$ W4 w( _/ y2 Y* H. C' C5 t
  38.   {. U3 L% t6 N. Z* K* V" A

  39. 1 |2 N1 {: u8 F: g, f& w! V
  40.   }* |$ g2 t/ D$ F$ h+ C  D+ z, U
  41.   /* USER CODE END 3 */
    " B, p0 p+ L( X7 S
  42. 8 C8 x  N. b* U# l# Y
  43. }
复制代码
! h2 s8 I6 G' ]; [
mian函数  C代码的入口  初始化一些硬件后
! H- Y4 f( R  g* @' s6 j
  osThreadDef(USER_Thread, StartThread, osPriorityNormal, 0, configMINIMAL_STACK_SIZE);
  osThreadCreate (osThread(USER_Thread), NULL);
  /* Start scheduler */
  osKernelStart(NULL, NULL);

! H' d# [. x" R定义了一个 线程 USER_Thread 然后启动OS    C0 K, K9 h: z# A, o, v; r6 d  |
注意 osThreadDef  是一个宏  定义一个用于描述  线程的结构体  并不是执行函数6 d  o& u; C& [1 @- y) O. d
3 `% h9 c" M5 R% D7 j) l
宏的第二项参数 StartThread 为线程 入口函数地址。1 D2 j0 \  q7 w

( x  E. H& m# A+ k9 @  D7 e; Y至此mian函数的工作结束了 OS将转向 就绪线程并永不返回  也就是执行StartThread  
/ X% @# ~' M/ I+ ^/ s8 j
% F+ L0 F5 z+ `. R( l2 k* b
修改  StartThrea函数 如下
. c( B8 I8 U$ E& m" W5 Q& H% v* Z- H* X# w# p# J. a( P

  1. ' ~- K& L) t: b+ ]3 Y' u
  2. /* USER CODE BEGIN 4 */
    5 ?4 j( W. s5 h
  3. void Nucleo_072_Led(const void *par);
    1 q8 }! d  o2 ^9 C1 C( y; f- s
  4. /* USER CODE END 4 */2 m7 D/ f9 G& e( {, y  [

  5. 8 v9 P% k2 I9 ]6 q' k% w
  6. static void StartThread(void const * argument)
    4 a3 e3 L" d; a! V6 o$ o; Q& o$ v
  7. {' p/ ^5 G/ C3 z9 w& j

  8. 3 x2 J- n8 b5 x
  9.   /* USER CODE BEGIN 5 */
    " R- [2 e( U% o/ O& N, c
  10.   osThreadDef(LED_Thread, Nucleo_072_Led, osPriorityNormal, 0, configMINIMAL_STACK_SIZE);6 q6 [  E. c" `5 I3 z
  11.   osThreadCreate (osThread(LED_Thread), NULL);* [& }* j, V, G/ Q( G
  12.   /* Infinite loop */7 z7 i9 `5 a# V* v1 F- k
  13.   for(;;)
    # }9 ?# H3 J2 [& t# R1 }* [* G
  14.   {
    1 @! t6 X& s: i
  15.     osDelay(1);
    $ Q3 j7 q" c, C' x8 I; @
  16.   }
    ! G) J& w* S& [* X1 B3 S. M
  17. 9 H$ j$ f$ k# G4 v! Y$ K! K9 e
  18.   /* USER CODE END 5 */
    ; M# i" p& S5 p7 ]$ Z) K3 n! S
  19. * G' c) `  L5 {# ]
  20. }
复制代码
0 v4 _' w$ a4 k8 q% U% P9 u8 K
添加一个 LED 函数
1 O9 k' x: c- m' p: T( _4 r
  1. void Nucleo_072_Led(const void *par)
    4 g$ n8 |8 Q) L! a* t
  2. {
    / V7 Z! N! X% \& {
  3.         GPIO_InitTypeDef GPIO_InitStruct;
    1 \0 [9 ~* y" l" G
  4.   __GPIOA_CLK_ENABLE();% k3 K/ _( W' @* D6 O
  5.         6 y7 `/ |, @5 N% i, C
  6.            GPIO_InitStruct.Pin = GPIO_PIN_5;
    1 d& S0 f& s2 S* u  U
  7.     GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;4 b$ u: Z. L- x& X6 {) Z
  8.     GPIO_InitStruct.Pull = GPIO_PULLUP;& a/ a+ x2 [: G3 L6 G9 w& e# W8 ]
  9.     GPIO_InitStruct.Speed = GPIO_SPEED_LOW;; _6 B3 F' j, a4 `! {; [% b8 K

  10. . c. i1 i( Y; E' G
  11.     HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);* T( N4 \: ]. f: Z
  12.         + ]7 Q' F. Q( ?7 h
  13.         for(;;)8 K1 ^* _5 K7 j3 O( v; L
  14.         {
    & L# l8 r% w. t* J- X
  15.                 GPIOA->ODR^=GPIO_PIN_5;// PA5取反 LED闪烁; o6 k* m$ d% j/ Z# D+ Y. {
  16.                 osDelay(500);5 S) Y& o1 O1 H# I
  17.         }
    ' H, c+ w5 L2 R: N

  18. . |. M& L% d7 m
  19. }
复制代码

5 ?' \) P3 s- t/ b# j# D到这里可以编译下载到板子上运行 观察现象了5 |5 t6 H# z/ z% {
0 w8 p5 o6 \, Q, d* m8 O. U
下面创建 RXT 的工程  新建一个工程  
" t/ L8 V  J9 ]! r" `$ k$ Q
+ l* U/ F* L  I7 e8 f5 P勾选 如下选项 # Z# i* X) n7 i  W* Z

7 w; n0 r7 X# i# R/ Z9 x+ O QQ截图20150108112304.jpg ; v. [. s3 e' ^. c- x$ k# K2 L# r
红框 不要添加  不知为何  楼主添加 MDK的 startup 编译通不过 - t; H# y# x% J0 @8 d5 H1 z
F4 的工程没有包含  HAL  接下来 需要自行添加HAL 库 * A% |4 a- d$ X: u6 Q2 \, d( A
# b! y3 M, J8 ^. n/ p
把原来的 main.c 复制一份更名为  rtx_main.c6 w' }/ [5 d! D
+ p! O( k1 r) @  ?/ W3 _
QQ截图20150108113501.jpg ! B& p3 q& [* z0 q

' H% A2 Y* l! E" z& d7 C文件添加完毕
: w: c$ h9 e" F  |: n" e, a7 ~6 a* r1 b' ~- U
接下来定义 头文件目录和 系统宏
7 z6 |+ Q2 q% @1 B, x' ]0 I' c0 ]" A3 P9 d
QQ截图20150108112609.jpg + k* X, B  |+ l* y, I$ N6 P
% K9 P  K; j* F
修改 rtx_main.c  下面两处需要修改
2 b1 {# u2 x. C+ Q; ?. Z9 E: Y& R8 a( l7 o4 s; k
  1.   {3 b& A: ]2 t. y1 T% ]
  2.   osThreadDef( StartThread, osPriorityNormal, 0, 0);
    $ [+ r) a& o  M; k
  3.   osThreadCreate (osThread(StartThread), NULL);
    6 Y; n9 q& C0 p/ I1 h$ \# L  v
  4.         }1 |2 g6 \0 T& G0 o

  5. $ j# ~# j& ^# Q0 F* G' P
  6. osThreadDef( Nucleo_072_Led, osPriorityNormal, 0, 0);# P, C& U/ a! t7 T4 Q
  7.   osThreadCreate (osThread(Nucleo_072_Led), NULL);
复制代码
不知为何  ST写的 中间件和 MDK的 接口有一点差距  所以 创建线程的地方需要如上修改& B$ x- G7 b" [1 ]- [* A4 S# n

) H/ r6 g) X4 R- J修改 stm32f0xx_hal_conf.h - U, v* ?* ?+ T. W
添加 图示内容  不出意外  下面 将可以直接编译了!!6 ]: m$ N" \$ C- d- i4 t
QQ截图20150108112936.jpg 6 \- R- K. s$ D# e6 t* a

. }) E9 w7 z7 Q* Z写的有些多了  本来想 继续写 RTOS 基于串口的  应用  太长了 下次发帖写了
$ Z  [# \& e% }0 \( `& |1 Q+ p! p9 a* z" V+ G8 ]' @
下面提出一个讨论 MX 创建的  工程 FREERTOS 中 cmsis_os.c 中 创建一个信号量  ' O+ m. O5 M0 r9 v( w) J
osSemaphoreCreate参数 count 直接
* U5 l7 }) a: R) U% j6 D/ K5 B% R! j6 e# G" a# C: I' y
传递给 xSemaphoreCreateCounting的两个形参  
2 I2 Q/ U5 P/ H; s) j7 Y# y QQ截图20150108115258.jpg
. A. y7 L. n1 L! i9 e原型
% n! i. c7 q6 y# e* N) m#define xSemaphoreCreateCounting( uxMaxCount, uxInitialCount ) xQueueCreateCountingSemaphore( ( uxMaxCount ), ( uxInitialCount ) )
" D4 D5 J' I& T
  x$ n) z/ N7 S  `0 {, d& j& X该宏创建一个 数值型信号量 第一个参数是 信号量最大数值  第二个则为  初始化值) o/ w* w1 m7 n9 w. g

) n5 |' f6 q7 f基于串口使用信号量  那么需要如下要求# x# C9 ~% I5 s+ R
假设 usart_sem 为串口使用的信号量/ h( a2 @( f/ s3 J/ v, k  a: A
每收到一个数据 usart_sem ++  缓冲 1024字节 2 M/ W! \. l0 M# `2 ^0 o+ X! x% }
需要数据的线程 osSemaphoreWait(usart_sem ); 当有数据时 线程被激活  获取数据& g6 k3 R9 A" o: a& f9 L( {

5 Y6 V/ m1 S+ L; d: G  x# a3 g如此我们知道 这个信号量的 最大值应为1024
* t0 Y% d& ^' c8 @可是使用 ST 的cmsis_os osSemaphoreCreate 创建一个信号亮 osSemaphoreCreate(0,1024);
& b% i1 z; ^; g% ^$ w/ v
& X: y8 `( c6 U6 x会出现这样的问题 !  此信号量 被赋予初值1024  意味着 这个信号量将可以被osSemaphoreWait 1024次
$ W0 I. i7 S& ]6 {# R8 \7 u显然这不是我们想要 7 ^" P8 A  ]6 H1 F3 S! j1 z) R  ^
/ \% _$ ~) b8 b8 \- p# R
通常  我们需要的数值型信号量  最大值可以很大  但是初值 基本为0,或1
& Q3 Q, R) h/ a6 }
* P! Y2 _2 f8 p" C2 N8 X. N不懂  这样设计意义何在?+ x9 {3 \& f" ^7 R$ m; Q3 ]
) o4 X6 T5 E- I4 d& h  v2 L

1 |  m* V3 y" L  Z! p0 X! U 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 编辑 " u9 y! z4 A* g( [: _
lovewyufeng 发表于 2015-1-23 12:56) f/ L% Z6 [$ ]7 ?/ h. q9 R4 C
事实上  只要这个计数不为0 都能被 wait 到
* L6 j# o. [  W7 ~: S+ a8 m
不好意思,确实被代码的名称误导了,以前用的基本上只用二值的semphore或者直接用queue了。
7 d$ u0 p8 x( l) W# K仔细看了一下内部的实现,确实我说错了。- m3 k- L2 p' p% _
在init_counter和max_counter一样的情况下,确实整个逻辑是要按照资源池来解释的,也就是确实生产者take(这个take代表获取空闲资源才能生产),消费者release(这个代表空闲资源返回)。我觉得这种情况semphore更像一个可重入的锁,处理线程拿走资源池后,直接处理完后再归还,像是个recursive mutex。
% D% R  B+ K6 C8 o& s- r. `# [前面说的那个问题,直接用queue可能会更好。另外,今天试了一下最新的stm32cubemx和固件版本,代码已经改了,#if (configUSE_COUNTING_SEMAPHORES == 1 )        
. w% s" ?1 A* w% A4 k$ ^  return xSemaphoreCreateCounting(count, 0);
# y$ F( o/ j( L0 W& t" _- A& ^#else
  x( t# u2 i( _3 A. X  return NULL;
1 `/ k- j: Z- E6 R! U, n, j" j#endif
1 r. @8 v. p7 {; i' S, m}
. h3 d7 B+ T# |" a% {! a3 [
: b/ p+ g/ }. h+ d7 q7 I  B, }* D0 a$ m" |: A+ `
/ L! F! e: `& y
' S, ^1 R% D4 \* C( G! G9 [7 h
我是东哥 回答时间:2015-1-23 07:50:34
lovewyufeng 发表于 2015-1-23 00:48
& }0 [7 ^8 F& m反过来理解是吧,说得通。可是
4 v4 t4 ^. u& P% ^% A$ D有个问题。,生产一个就-1的话应该 take获取信号咯?   反过来消费应该pos ...

8 J7 j: g( e9 {/ M3 l0 x你陷在细节里面了,看看人家的API是怎么样写的,osSemaphoreRelease和osSemaphoreWait,我们在生产者里面应该要osSemaphoreRelease,而在消费者里面osSemaphoreWait,是吧?字面理解,相当于生产的人释放了一个东西,然后消费者就等待生产者的这个东西。再看里面的实现,osSemaphoreRelease里面是xSemaphoreGive而不是take,而osSemaphoreWait里面是xSemaphoreTake而不是give。
5 R9 x- P' H! {& f所谓的反过来理解只是一种理解方法,说take和post的逻辑也反的话是不对的。不要老想着什么时候去post,什么去take。cmsis_os的API意思很明了,生产者生产了东西就应该release,消费者就应该Wait,这不是很好理解吗?
lovewyufeng 回答时间:2015-1-23 00:48:46
我是东哥 发表于 2015-1-21 12:18
4 {$ F+ I+ G* ]- R! q这个其实也没有不合理,看你怎么理解,资源一开始为0,也可以理解为空闲池一开始是满的。生产者生产了一 ...

  f& F8 q! a3 K4 Q' N& v& x+ @反过来理解是吧,说得通。可是2 j. w# @4 @( L1 f$ j
有个问题。,生产一个就-1的话应该 take获取信号咯?   反过来消费应该post 释放信号咯? 那么问题是 post是非阻塞立即返回的而take是阻塞的?
- ?2 p+ g; t" e  |先不谈消费者应当随时饥饿,处于阻塞态。# f% p8 r) t& B9 G! V, M2 g3 _
生产一般在中断里吧,当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
看看 顶一下
3 [$ u7 ?8 V+ X# t% K
cqtnheyao 回答时间:2015-1-8 12:19:01
harvardx 发表于 2015-1-8 12:13
- \2 M$ g1 E* ]) Y/ j" z有钱为何不顶帖 .何况还是高质量的 .cubemx 势在必得的趋势.支持一下.
- p* S6 P* [0 {' L, i7 A& y, c2 T
据说库很大,效率低?求告知!
netlhx 回答时间:2015-1-8 12:19:08
很好,图文并茂
lovewyufeng 回答时间:2015-1-8 12:19:26
harvardx 发表于 2015-1-8 12:13# W; q8 r# @8 H
有钱为何不顶帖 .何况还是高质量的 .cubemx 势在必得的趋势.支持一下.

" L+ R6 d* M; S; E) ?3 t! }多谢老大 支持  继续加油
lovewyufeng 回答时间:2015-1-8 12:23:05
cqtnheyao 发表于 2015-1-8 12:19& f4 ?$ h' H. ]: y% K6 l
据说库很大,效率低?求告知!
1 F: `+ s" @& 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 手机版