请选择 进入手机版 | 继续访问电脑版

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

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

[复制链接]
lovewyufeng 发布时间:2015-1-8 12:08
以刚拿到手的 Nucleo 072为例  其他板子用户 请举一反三哈 (工程文件在帖末3 B! `8 `& F& @" O- P

) A( O0 E+ n7 X5 s& M
4 [/ ]8 B' ~: e0 l# Y后续帖子:【干货】Nucleo072 usart 基于RTOS的应用  方便AT指令类外设开发
1 t0 C# d% J8 {$ a* C  A' Y. L  R1 i2 o* c; R- N2 J) A
需要工具  MDK5 自行下载:
0 L4 @, a) E6 [4 Y* L/ u3 q& rSTM32CUBEMX https://www.stmcu.org.cn/document/detail/index/id-2149849 \  O/ s: Z, w1 |* w, g% ]
STM32CUBEF0 https://www.stmcu.org.cn/document/detail/index/id-216669
9 T: M0 n$ S" G* z+ x  }8 k4 ^0 _4 _2 h6 w
! f* k0 x  d* Y
安装 cubeMX  由于使用MX下载固件库速度那是不说了相当慢啊  所以下载 STM32CUBEF0固件库然后下图安装
% M; ?' C5 s# a
( ^& [9 A+ z% L, v) p9 A
+ M6 r& c; r. S5 X/ x+ `: ?4 E QQ截图20150108101548.jpg QQ截图20150108101556.jpg ! F/ G9 h9 t# s) m
5 h" \( c2 F/ n. y1 Y, p0 {; G
安装之后  新建一个工程 选择STM32F072RBT6
7 O& _; x( d& d! F! X2 q5 A  A) ~+ u' R( N2 v% Y5 m* S7 q
PINOUT 勾选  FREERTOS和 USART & o: C, A* z( p" n1 }
QQ截图20150108101539.jpg
4 e: @3 p$ b# B* l( M因为我们调试可能需要使用- n5 j* X1 u" j2 k5 d5 W
& _! ?* Y8 Z7 a% u$ ]
点击软件上方  齿轮键生成  keil 工程  至此, m" o# l. e- \  V0 O) B
7 V' }2 P# z+ V. o/ J# v
MX基于 HAL的库 生成完毕' J& w' o1 A6 n% X7 @: ]
3 G0 n& k$ @" L$ A6 w
使用MDK 打开工程
  l+ t* Y7 m! d8 I* g从上到下 的组依次为  OS 的C文件
. k- `3 @$ n5 Z/ L+ J) f.s 启动文件
. ]7 \; Y3 ]' [- r+ |用户文件" V5 F, M: q: y" H" S0 B  o
HAL库文件" ?! o" R0 W- w- m, U0 a
CMSIS中间件文件
( V6 Y% v& v) W1 ?% @/ d  R' I
" Y8 z5 i+ G2 P9 l1 r其中 在 第一组中的 cmsis_os.c 中实现了  cmsis_os  到FREERTOS 的中间层转换   稍后会讨论其中一处代码
8 E4 K% g5 R6 W+ S3 D3 C4 \
0 n% F* a4 h9 }% t: @# U. ]7 \ QQ截图20150108101924.jpg + t* ]/ y6 [. h  n6 N5 H

0 x4 ^. u' U6 ?2 k3 V
- K& U6 d7 \4 ]$ i. v( B# w8 ~接下来  添加自己的代码  首先添加 072 上面LED吧  板子不在身边  记得是PA5 控制! q2 @7 l; ?7 |! X4 o% y
' |* n6 V4 _, v
先看看  main.c 的 64 到 105行
0 A$ A% |) M  U3 E; {0 V9 w& c
  1. ) z( \" K) V: U9 L7 r' ]
  2. int main(void)$ H) ]5 d0 P( T6 L7 z
  3. {
    ' l- B( ]# Y' e

  4. ! l7 b, ?  k. u4 V% T
  5.   /* USER CODE BEGIN 1 */' s- r9 X& g& ]! y5 _" j# U. b

  6. " t" e! N9 W4 L7 r
  7.   /* USER CODE END 1 */4 G7 z) j. L) G" y- X& A

  8. : I0 k, ^& B% d, Z1 j! u+ c
  9.   /* MCU Configuration----------------------------------------------------------*/5 N8 g7 M: `- N# }3 u# e4 S

  10. 6 P. A$ W7 k* h6 R7 V
  11.   /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
    ) d! f/ \& V% C, B* S  n
  12.   HAL_Init();' A: p! q  g- y' @6 p  G

  13. : Z: D2 z+ g" k
  14.   /* Configure the system clock */
    2 d3 j0 {1 d0 S5 ]# W
  15.   SystemClock_Config();
    9 b$ t" q& @2 {0 R5 i

  16. " x8 _; G0 x7 O. m; r8 ~/ D
  17.   /* Initialize all configured peripherals */9 D* j3 F" d9 L
  18.   MX_GPIO_Init();
    ! u+ F( y$ _3 n) c
  19.   MX_USART2_UART_Init();* c2 i  Y/ C# Q0 _
  20. + B) D4 P! b3 L. X; B
  21.   /* USER CODE BEGIN 2 */+ d7 Z9 o; U$ L) L- b3 N" r( O, b
  22.   P- H. S0 c4 X  Y. H# o
  23.   /* USER CODE END 2 */
    - ~* [. s3 c( s, M" a3 }- k1 t0 e

  24. " i+ Q7 c2 c! G( p  T
  25.   /* Init code generated for FreeRTOS */
    1 t( c' w: S# r% {+ ^% q* \
  26.   /* Create Start thread */3 X( q4 l0 [  Z) u
  27.   osThreadDef(USER_Thread, StartThread, osPriorityNormal, 0, configMINIMAL_STACK_SIZE);+ ^2 O! x3 H7 h! x7 n9 q  C& q
  28.   osThreadCreate (osThread(USER_Thread), NULL);
    / U& x7 z: E4 R

  29. ' n+ F& u7 c6 |; ]/ g0 B4 r
  30.   /* Start scheduler */1 c% ]! u4 \  W  N2 ^  C$ S& P: e
  31.   osKernelStart(NULL, NULL);
    : R" `$ ]* \( V! D( L% `2 z
  32. 8 A: [5 I$ J; Z( G) ~
  33.   /* We should never get here as control is now taken by the scheduler */
    . f6 z, j$ t: @8 x7 d

  34.   C1 @- d; e- q5 a/ T# P
  35.   /* USER CODE BEGIN 3 */  f7 W. b/ I7 Q4 l& k
  36.   /* Infinite loop */2 g3 k8 L( h% {, ^: ?2 m( e1 W- Q" h
  37.   while (1)* P9 W2 ~! u$ r; F+ t; u* f
  38.   {
    9 t6 u/ Z6 }6 W1 `
  39. ) B" b8 Z8 y, M& e3 u8 `2 X
  40.   }/ n5 R  U1 S4 x( |
  41.   /* USER CODE END 3 */
    6 ]! K0 G, }% R' @) @0 `

  42. 9 ~$ j2 J- K! Y, `
  43. }
复制代码
7 [: l& m& n0 S" ]
mian函数  C代码的入口  初始化一些硬件后 1 U, M8 \" e0 W
  osThreadDef(USER_Thread, StartThread, osPriorityNormal, 0, configMINIMAL_STACK_SIZE);
  osThreadCreate (osThread(USER_Thread), NULL);
  /* Start scheduler */
  osKernelStart(NULL, NULL);
9 F: y' V2 X; a  n. q3 }4 c: x- G
定义了一个 线程 USER_Thread 然后启动OS  : b' S0 n) F2 D. d& E
注意 osThreadDef  是一个宏  定义一个用于描述  线程的结构体  并不是执行函数
+ w4 q* h( f4 b+ [0 R7 F+ |% Z
! ?8 ]5 K0 m: t* H
宏的第二项参数 StartThread 为线程 入口函数地址。
2 p" M. }9 _" ^3 N6 I5 ^5 Z8 {: u) D& ?) G& t$ l/ ?% C  O+ N
至此mian函数的工作结束了 OS将转向 就绪线程并永不返回  也就是执行StartThread  3 q! o, }9 F+ D

% _% T  `5 h6 L1 T" ^1 n修改  StartThrea函数 如下8 `& d  m2 }! b% E& O5 S  W
8 V6 s8 l8 J( U

  1. - ?7 s! q0 S+ Z% m5 P
  2. /* USER CODE BEGIN 4 */1 ]9 ~! k- U) @2 [& C# e
  3. void Nucleo_072_Led(const void *par);
    $ X  z. i4 ~/ d8 t8 V0 L# k& A
  4. /* USER CODE END 4 */
    - h5 T. F/ G5 l* X% r+ T

  5. 2 d  k% ]* r6 Q! Q  F6 Z' w
  6. static void StartThread(void const * argument)/ P( H+ L4 V, B$ u* W/ P
  7. {
    1 b' M1 ]  n' z: {
  8. 1 U4 ^" d" `* [- ^7 a5 c
  9.   /* USER CODE BEGIN 5 */
    & r5 g1 e' ]' G7 E+ S7 ]
  10.   osThreadDef(LED_Thread, Nucleo_072_Led, osPriorityNormal, 0, configMINIMAL_STACK_SIZE);8 N- F$ f* a% B1 O. z
  11.   osThreadCreate (osThread(LED_Thread), NULL);+ s3 Y8 Y# y1 u2 ~3 I, n! T( T
  12.   /* Infinite loop */# F6 t1 M  T0 `+ R
  13.   for(;;)2 L( W7 `' Y2 Y8 i
  14.   {
    2 [. c! |* f8 n) f3 _
  15.     osDelay(1);
    ! a4 H) e8 T1 P* @# f0 Z" ^* D
  16.   }
    ' h( u) `8 ^% N* {2 d# ?0 K- }; |
  17. 0 C5 k$ `% v1 w: ~$ u2 l
  18.   /* USER CODE END 5 */
    ( i7 v0 `% @# c' Y
  19. 2 F/ L$ d5 U6 y, V
  20. }
复制代码
" g; }6 _4 u  A" e, j% c4 c
添加一个 LED 函数( a. {% G: A' J! B+ m: F
  1. void Nucleo_072_Led(const void *par)
    / H/ |! k7 {& F& j8 q
  2. {* h+ V; ~1 O. @* ]; \% \# l1 N4 v$ Y
  3.         GPIO_InitTypeDef GPIO_InitStruct;% `+ S- [) V- D
  4.   __GPIOA_CLK_ENABLE();
    . m/ U8 W& J4 ]8 I
  5.         
    * n+ B, x; [. O5 g, \# B
  6.            GPIO_InitStruct.Pin = GPIO_PIN_5;7 b" y2 y- ]1 E! V1 j8 {+ P4 }: p
  7.     GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    " {$ a; o% {5 [* J% \+ C
  8.     GPIO_InitStruct.Pull = GPIO_PULLUP;
    0 y5 |. R. E' g6 [! N! h
  9.     GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
    ; Q. b+ x' S# n* t& n$ ^  y. V
  10. - |3 ?6 q- T/ b! R: y
  11.     HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);6 l$ Q! O! k- ^8 h* a2 K& C1 A6 K4 B5 i
  12.         
    7 d# k$ B+ O  [9 w5 u
  13.         for(;;)( y9 O5 Q7 T! Z, i! N
  14.         {
    5 ]. K; v0 H. e$ E6 U
  15.                 GPIOA->ODR^=GPIO_PIN_5;// PA5取反 LED闪烁
    : e3 w  Q1 h! V6 t$ [2 s$ q
  16.                 osDelay(500);* F4 S% Z2 o& U" s
  17.         }7 ]' P0 D! c# @
  18. ) t4 F  ~( o$ }; T6 z
  19. }
复制代码
& A3 p* s, Z$ P, g: x- y/ |6 d9 z
到这里可以编译下载到板子上运行 观察现象了
% i+ [. O6 T4 \+ ~5 {  G1 @  f6 ^/ V8 K* i9 f# i5 v$ G( @- P
下面创建 RXT 的工程  新建一个工程  
$ D: b# [. a/ Y2 ?  u
* k2 |$ T0 d3 S, ]  X# k$ P勾选 如下选项
- x6 L; k( n/ G! D. A! c! M
1 R. F) M% M: Y) a QQ截图20150108112304.jpg
4 y. J! P9 q% A% J  P5 y红框 不要添加  不知为何  楼主添加 MDK的 startup 编译通不过 : Y' n' z6 z. O! }& U  v
F4 的工程没有包含  HAL  接下来 需要自行添加HAL 库
3 s; J# j2 z; O% L( Y* e) S
2 u4 c* F7 S  t2 g7 m+ B, A2 o3 ?把原来的 main.c 复制一份更名为  rtx_main.c
" k" B% b- |' ?0 Y7 ?( t* A) V2 ^3 g9 [
QQ截图20150108113501.jpg , ~& r' b0 m6 a  @  h

# N% f& T* _7 j' p6 d- ^, e文件添加完毕 ' d& K/ T0 A1 e) \0 Y( ~( H7 V3 o/ I
" j' |  Z& }. T+ [
接下来定义 头文件目录和 系统宏
% C' H6 a5 Q/ |, I
) a4 z4 k* x# I  {7 h QQ截图20150108112609.jpg 7 K" |7 }- r, r- `  j$ l

) {2 R8 Y) O( D: ?修改 rtx_main.c  下面两处需要修改
: R3 i5 O  r& y" J  z$ \6 S' o+ J2 |! \; P, l" T
  1.   {! @) h. a: v% @2 q
  2.   osThreadDef( StartThread, osPriorityNormal, 0, 0);
    ' {+ s: |( x) B  t3 r
  3.   osThreadCreate (osThread(StartThread), NULL);
    7 Q, h( S/ M( {3 `9 y6 Q
  4.         }0 ]5 [: e- p* y- P' w
  5. & M* M1 f$ i- p  S- W0 d
  6. osThreadDef( Nucleo_072_Led, osPriorityNormal, 0, 0);% f3 m7 L  Y& P) Y
  7.   osThreadCreate (osThread(Nucleo_072_Led), NULL);
复制代码
不知为何  ST写的 中间件和 MDK的 接口有一点差距  所以 创建线程的地方需要如上修改8 ?6 v8 J" h; W& O% i  H( j4 x
2 J5 u+ L$ J" o5 C4 [& U
修改 stm32f0xx_hal_conf.h 4 E+ W3 w# _' J2 ?
添加 图示内容  不出意外  下面 将可以直接编译了!!, _4 P3 X# B$ h) q9 _/ H5 k
QQ截图20150108112936.jpg , c/ @* n# f* g& n* D

0 U) E  \' O0 c8 U写的有些多了  本来想 继续写 RTOS 基于串口的  应用  太长了 下次发帖写了
: W! X9 D6 W. k. E+ i+ v$ N! P9 r' d) \( s/ a* }' w
下面提出一个讨论 MX 创建的  工程 FREERTOS 中 cmsis_os.c 中 创建一个信号量  
/ I8 ^: }5 Y5 d6 {osSemaphoreCreate参数 count 直接
$ E: w% Z6 h7 F/ d. h* s* I3 O4 I) f/ Y, l9 M
传递给 xSemaphoreCreateCounting的两个形参  
+ l* x; y- G( @0 T9 z$ ?) y QQ截图20150108115258.jpg
$ O6 B& }: w' f/ \& l  x3 V原型 3 z: N3 p% u+ w$ g5 D& }5 R1 Y
#define xSemaphoreCreateCounting( uxMaxCount, uxInitialCount ) xQueueCreateCountingSemaphore( ( uxMaxCount ), ( uxInitialCount ) )
( q$ Y. r- \0 Z# i2 Q# U
3 y+ V2 w: h: W& s该宏创建一个 数值型信号量 第一个参数是 信号量最大数值  第二个则为  初始化值, u2 V* g/ U: e7 B

3 M- k2 r& S$ l- U1 f/ z  T2 m2 `基于串口使用信号量  那么需要如下要求
, E6 p5 z2 `& ~$ W9 T9 l: f, @假设 usart_sem 为串口使用的信号量6 x. O7 A$ L0 q
每收到一个数据 usart_sem ++  缓冲 1024字节 & T7 [" J9 k9 Y( L% E) {
需要数据的线程 osSemaphoreWait(usart_sem ); 当有数据时 线程被激活  获取数据
6 u6 X: v  V. R0 j7 f0 n
* N# ?6 y; s4 i如此我们知道 这个信号量的 最大值应为1024
5 _6 L+ ?% A; }0 X" e$ f: w可是使用 ST 的cmsis_os osSemaphoreCreate 创建一个信号亮 osSemaphoreCreate(0,1024); " U: D, h1 O8 J$ O6 }( X$ x

/ L; b+ ?* `8 S会出现这样的问题 !  此信号量 被赋予初值1024  意味着 这个信号量将可以被osSemaphoreWait 1024次
; Y, H3 S& ~, g) h显然这不是我们想要
2 Q0 R' s/ M) o. ?, i/ P, F% P3 \0 O+ a1 z  w# j/ N- f
通常  我们需要的数值型信号量  最大值可以很大  但是初值 基本为0,或1
. _3 @2 q6 W( f* S6 X9 v  ^9 k2 ^; T
: Z9 K* Z+ t7 ]5 w; r6 l2 u不懂  这样设计意义何在?
" R1 {$ a2 `! ^7 y/ b1 Z+ E% J2 y4 n- Y
! _$ q2 }4 J! n8 R3 r* @
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 编辑 & ]/ Q% a3 t! L. g/ K( f; {
lovewyufeng 发表于 2015-1-23 12:56
# T8 Y- k5 {- c& w) Z- J' I, v. C  \. w事实上  只要这个计数不为0 都能被 wait 到

  O+ L6 A1 t! l* L不好意思,确实被代码的名称误导了,以前用的基本上只用二值的semphore或者直接用queue了。8 H0 ]2 y! L+ }% X' J5 W
仔细看了一下内部的实现,确实我说错了。
/ d* \9 S" J  @9 [在init_counter和max_counter一样的情况下,确实整个逻辑是要按照资源池来解释的,也就是确实生产者take(这个take代表获取空闲资源才能生产),消费者release(这个代表空闲资源返回)。我觉得这种情况semphore更像一个可重入的锁,处理线程拿走资源池后,直接处理完后再归还,像是个recursive mutex。
8 D3 a9 h! x* r1 [& x2 T3 h* c5 A前面说的那个问题,直接用queue可能会更好。另外,今天试了一下最新的stm32cubemx和固件版本,代码已经改了,#if (configUSE_COUNTING_SEMAPHORES == 1 )        
; d7 P# M$ Y3 J0 C0 x5 _+ T  return xSemaphoreCreateCounting(count, 0);
+ D& w2 L3 @: J( i" Y#else% ]2 k8 e# {8 c* g/ B" j3 o+ z
  return NULL;) F# I2 D' c+ v/ t
#endif
# U# M1 _" k( C$ u' V( k}
! g) o, ^' j7 w8 ~6 O' Z% k4 O
4 b* ^% v' F( X/ o

( R# S% ~+ j9 S; o" P; w& d" g" n: z$ E2 O% I' ?+ _
我是东哥 回答时间:2015-1-23 07:50:34
lovewyufeng 发表于 2015-1-23 00:486 o+ {+ r8 x6 x! d& T3 U
反过来理解是吧,说得通。可是5 C- @- j3 a6 W2 h- C
有个问题。,生产一个就-1的话应该 take获取信号咯?   反过来消费应该pos ...

' \( c1 }: f, W" c* C! O6 o7 D你陷在细节里面了,看看人家的API是怎么样写的,osSemaphoreRelease和osSemaphoreWait,我们在生产者里面应该要osSemaphoreRelease,而在消费者里面osSemaphoreWait,是吧?字面理解,相当于生产的人释放了一个东西,然后消费者就等待生产者的这个东西。再看里面的实现,osSemaphoreRelease里面是xSemaphoreGive而不是take,而osSemaphoreWait里面是xSemaphoreTake而不是give。
2 |1 \; B) V4 y, j7 D所谓的反过来理解只是一种理解方法,说take和post的逻辑也反的话是不对的。不要老想着什么时候去post,什么去take。cmsis_os的API意思很明了,生产者生产了东西就应该release,消费者就应该Wait,这不是很好理解吗?
lovewyufeng 回答时间:2015-1-23 00:48:46
我是东哥 发表于 2015-1-21 12:186 x' B6 g# q* Q+ R0 j4 O  B
这个其实也没有不合理,看你怎么理解,资源一开始为0,也可以理解为空闲池一开始是满的。生产者生产了一 ...
( q7 H6 J8 T- o& R& L
反过来理解是吧,说得通。可是) q; x1 y  k9 ?4 t+ |3 k" O1 z
有个问题。,生产一个就-1的话应该 take获取信号咯?   反过来消费应该post 释放信号咯? 那么问题是 post是非阻塞立即返回的而take是阻塞的?
( R  W( \# Z  J# m. u, p- Z先不谈消费者应当随时饥饿,处于阻塞态。
9 y7 y* i  D* J5 L; u" G" u生产一般在中断里吧,当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
看看 顶一下
4 [$ v$ S& m: v. C
cqtnheyao 回答时间:2015-1-8 12:19:01
harvardx 发表于 2015-1-8 12:13
: m) \4 O- w2 V$ O+ _有钱为何不顶帖 .何况还是高质量的 .cubemx 势在必得的趋势.支持一下.

6 C* }+ A. O: G; }  A2 K) C% a据说库很大,效率低?求告知!
netlhx 回答时间:2015-1-8 12:19:08
很好,图文并茂
lovewyufeng 回答时间:2015-1-8 12:19:26
harvardx 发表于 2015-1-8 12:13
- E- k$ w* y7 a+ k) t$ w9 v有钱为何不顶帖 .何况还是高质量的 .cubemx 势在必得的趋势.支持一下.

2 ^  Z1 v" m, p; \2 E多谢老大 支持  继续加油
lovewyufeng 回答时间:2015-1-8 12:23:05
cqtnheyao 发表于 2015-1-8 12:19
1 Y6 J# X" Y5 y- m- S据说库很大,效率低?求告知!
8 u5 X8 u+ o- o. J. x3 Y/ _3 g$ f* G
确实 有这个毛病  楼主的贴初始化使用库  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 手机版