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

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

[复制链接]
lovewyufeng 发布时间:2015-1-8 12:08
以刚拿到手的 Nucleo 072为例  其他板子用户 请举一反三哈 (工程文件在帖末
8 a4 \1 n0 v( l" `% a; F8 [
/ J. v7 {( h( h$ K. M% C
" |: r& U- u; b: q9 S+ r! J: e后续帖子:【干货】Nucleo072 usart 基于RTOS的应用  方便AT指令类外设开发  I! y, P/ ?" B; K( W  W0 j

; r' m; e9 M. D; a! ^需要工具  MDK5 自行下载:
) [0 F- c# t0 W7 b1 ]! }" qSTM32CUBEMX https://www.stmcu.org.cn/document/detail/index/id-214984
8 }9 P. ^1 k, H, k9 |STM32CUBEF0 https://www.stmcu.org.cn/document/detail/index/id-216669. B( L! Y, ~' X# ]$ |& z/ p/ E) u* L
& T0 n4 M  E3 I, `& V  t
9 D' h) i4 J9 j; |) u+ J
安装 cubeMX  由于使用MX下载固件库速度那是不说了相当慢啊  所以下载 STM32CUBEF0固件库然后下图安装5 w6 D! X; g9 d* A! }2 |

9 M/ [# s" P* l" t. ?1 j  a0 C5 V" e
% A; N- K8 \& i- F1 q& e# s QQ截图20150108101548.jpg QQ截图20150108101556.jpg
2 S9 T" I6 f& k
/ ^/ _; R( f3 x! R" v9 p& Z安装之后  新建一个工程 选择STM32F072RBT6: i9 v5 C& V7 k6 @5 A3 C% L0 N; F

% g2 g9 P% x  z/ iPINOUT 勾选  FREERTOS和 USART
) Y  A8 p" Y1 J# ~. `& x! ~ QQ截图20150108101539.jpg 6 A  F7 f9 x; Y& k
因为我们调试可能需要使用
2 I. A( N( ]/ L' o- m+ i' g& s6 i9 j) O& z0 F: A
点击软件上方  齿轮键生成  keil 工程  至此
, q8 Y* l$ h  |" K2 s9 i% C- K" w0 ^
MX基于 HAL的库 生成完毕  _+ u. b& A  D: \1 L- H; d
1 }) t& G) n  H9 D& ^; e7 G/ V) h* a
使用MDK 打开工程
7 |: ^) D" ?+ v" L从上到下 的组依次为  OS 的C文件
1 p) k) O( m3 ~/ _' V  g( P" I.s 启动文件; Q5 d! O& ^2 [' U& _/ O' [
用户文件
* Y, k  E  C0 l2 Y1 S4 C0 C2 nHAL库文件* u& f8 p, ^8 `
CMSIS中间件文件
7 ]  {% Y+ H) a4 S% e$ K6 l" @# }9 w9 Y0 r! Y
其中 在 第一组中的 cmsis_os.c 中实现了  cmsis_os  到FREERTOS 的中间层转换   稍后会讨论其中一处代码
( E4 V6 l6 C$ y; N
% b: e4 O7 S! Y* P. E QQ截图20150108101924.jpg
2 ]. w& ?9 b  n) y  @3 Q* v2 j
# h' B) I( l5 n( R% D( ]- A$ o6 W6 R% c3 N9 S6 B' e  k
接下来  添加自己的代码  首先添加 072 上面LED吧  板子不在身边  记得是PA5 控制
; |0 C" g, ~% T& }3 n% R" S# T- @' ^8 h" ~3 k" c
先看看  main.c 的 64 到 105行 ( y1 W2 P/ U2 E* f/ |
  1. 3 _9 q. G$ A' @/ @. a- s5 o
  2. int main(void)* F+ ~* G1 l2 Y. l4 a, u( s( ]
  3. {
    7 D% U9 H1 X6 P, @
  4. - R9 v7 A. Z( M% ~' ]% _7 r
  5.   /* USER CODE BEGIN 1 */9 |0 V0 }3 K  g: Y" V9 c( v$ O
  6. 6 A* l! \& j9 d  {  L& u, [6 W9 s
  7.   /* USER CODE END 1 */# v+ M- S& B2 a4 i& `7 e3 ?$ `( d
  8. & T, q2 g" F- F7 O; i# r
  9.   /* MCU Configuration----------------------------------------------------------*/
    0 I$ A5 g2 x2 _) z% a) x7 ^9 _1 t0 ?
  10. ; p6 n2 O; {0 h
  11.   /* Reset of all peripherals, Initializes the Flash interface and the Systick. */8 U) ^( w! m# N! p
  12.   HAL_Init();( K9 S) v3 u5 `
  13. " \) @( F6 ^$ o0 {% S
  14.   /* Configure the system clock */; h' Q1 C4 M7 G
  15.   SystemClock_Config();
    2 x& x+ h3 Q% n# K) s3 y: u
  16. $ i! e9 K$ _! U3 j6 x' x2 n+ O
  17.   /* Initialize all configured peripherals */
      U6 S& R! E* R2 s9 q
  18.   MX_GPIO_Init();. e" e+ X  @: ?' @
  19.   MX_USART2_UART_Init();  `3 s# L7 y& x8 B
  20. * X2 ?8 d4 R; d
  21.   /* USER CODE BEGIN 2 */
    2 J4 J4 q) C4 l! o

  22. * B, G/ U% v+ o$ i. I" h: t3 e
  23.   /* USER CODE END 2 */) M7 k5 d3 P1 X4 b
  24. ( Z( Q- x- ?/ J- F; k
  25.   /* Init code generated for FreeRTOS */
    4 y6 i; a1 r3 P1 i
  26.   /* Create Start thread */
    ; X$ _9 Q. M# k9 l+ C  j1 L1 o
  27.   osThreadDef(USER_Thread, StartThread, osPriorityNormal, 0, configMINIMAL_STACK_SIZE);
    ( F, a2 [0 e$ Z0 Q9 U" j; }
  28.   osThreadCreate (osThread(USER_Thread), NULL);
    ' D% s$ ~6 \6 f- e* ?/ d, r
  29. . O1 ~$ b3 r* j: }# _
  30.   /* Start scheduler */4 T0 a3 I1 }* o6 J3 ^$ j  T: `
  31.   osKernelStart(NULL, NULL);5 v. R3 v# f) S- D; U
  32. 6 Q( j: d/ c" c; @% h2 R" v
  33.   /* We should never get here as control is now taken by the scheduler */: l$ b% ^  n' F. C, @. s: U0 d
  34. : Z7 z4 d' ?5 r$ H
  35.   /* USER CODE BEGIN 3 */+ j( {1 `+ {: N0 q  M. c) ]
  36.   /* Infinite loop */
    ; D2 ~& z! q; p# C: a5 W
  37.   while (1)% L# X) ~4 c- M0 N0 I* h8 g
  38.   {5 n  f& ?5 q$ x
  39. + V- I! @! @" G4 _/ ?
  40.   }
    : I# U; i" @6 N' W: z9 @2 N
  41.   /* USER CODE END 3 */
    / n9 J3 L$ _, f) l& U2 ^

  42. / {- R& T! j/ l2 Y% I: y# [2 S2 a
  43. }
复制代码
' P" n8 h1 z3 A2 X1 P
mian函数  C代码的入口  初始化一些硬件后
  o: m$ Z7 S' }7 t3 t
  osThreadDef(USER_Thread, StartThread, osPriorityNormal, 0, configMINIMAL_STACK_SIZE);
  osThreadCreate (osThread(USER_Thread), NULL);
  /* Start scheduler */
  osKernelStart(NULL, NULL);

6 ?% ]# k7 Q# d/ y' [& m$ _定义了一个 线程 USER_Thread 然后启动OS  
6 T# w: ~% z( M6 ^& S2 E! \注意 osThreadDef  是一个宏  定义一个用于描述  线程的结构体  并不是执行函数- J2 n3 i/ ^. U1 j
4 D2 v% L. h$ y3 N! m) `6 Z9 i+ M  p
宏的第二项参数 StartThread 为线程 入口函数地址。9 F8 _- Q4 U( e" R; m
( m0 j) V' |% p3 F
至此mian函数的工作结束了 OS将转向 就绪线程并永不返回  也就是执行StartThread  " o+ o! p# {  B! M1 h( ^

2 l* D6 j3 ^: ~) H) |! ]! m( g2 C修改  StartThrea函数 如下
" ^, h3 \- F/ J7 M3 Z1 |0 p2 u6 c& ?
; o- H; Y  b- w+ T

  1. " t; ]: ]5 c+ B; T
  2. /* USER CODE BEGIN 4 */
    ' N% C* n0 L5 k+ n' n! }
  3. void Nucleo_072_Led(const void *par);2 A$ S7 W! X6 b1 N
  4. /* USER CODE END 4 */* Q2 h: d' g+ h
  5. 8 V0 z8 k- f- k
  6. static void StartThread(void const * argument)
    + b! F6 F4 E& C, F% t4 [# L# t
  7. {* V6 J' o0 O5 z  y5 I; U

  8. ( x9 Z* f3 g+ l8 g8 t- l1 g9 s
  9.   /* USER CODE BEGIN 5 */
    4 T6 h# h* w: v# W4 Z7 B
  10.   osThreadDef(LED_Thread, Nucleo_072_Led, osPriorityNormal, 0, configMINIMAL_STACK_SIZE);8 r. W$ H+ L) ~
  11.   osThreadCreate (osThread(LED_Thread), NULL);( s5 r) S+ c+ y
  12.   /* Infinite loop */; R) c- X4 b- k  d! ^* H
  13.   for(;;)
    : b3 b" ~8 L0 [
  14.   {
    ; Y9 i4 I: l7 ^% G
  15.     osDelay(1);" z0 n: r% g# F5 t9 P* j" M9 i, b
  16.   }9 f  s4 D2 B9 c5 F% w
  17. 1 C+ X3 l2 Z! a: y$ s7 [2 x( x
  18.   /* USER CODE END 5 */ : N7 a* k! m- z/ _& t
  19. ! Y, Y- ?0 n4 M' m7 \- Y
  20. }
复制代码

# u9 q- F& D; n+ n添加一个 LED 函数
$ }% J2 q* f3 D
  1. void Nucleo_072_Led(const void *par)8 J, K# X6 @4 g+ f/ b, h# L
  2. {
    9 b, w9 E1 h/ k5 M9 [+ L& {& g' j
  3.         GPIO_InitTypeDef GPIO_InitStruct;
    ! S" C( Q: \2 T  _0 a# H
  4.   __GPIOA_CLK_ENABLE();6 q$ _6 L5 \' I$ D3 y% E: e3 f
  5.         
    / z% t  S' C! e" I* K0 r' w" K! t
  6.            GPIO_InitStruct.Pin = GPIO_PIN_5;
    9 ?3 i7 ~1 X! `" [
  7.     GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    ! S5 c  z4 E, u: N0 v
  8.     GPIO_InitStruct.Pull = GPIO_PULLUP;
    $ y3 C* n* t8 h
  9.     GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
    # z0 T1 [  [& }: R6 a
  10. 2 p/ i- M" u0 U6 l9 l/ v  m
  11.     HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
    5 M  Q4 u$ w) u& j: {+ {' b& r
  12.         + k/ b+ B. \7 @& C5 x
  13.         for(;;)
    0 e0 H" T* n9 ~
  14.         {
    0 A6 R, d- F. H* d" a
  15.                 GPIOA->ODR^=GPIO_PIN_5;// PA5取反 LED闪烁
    - s/ |4 U: c1 t
  16.                 osDelay(500);
    / O, a# Y6 A9 L$ G5 X; l- k) d
  17.         }
    ; }% f, J4 a2 E- w+ J( O+ K; J$ O

  18. 8 k9 k4 |) t5 J
  19. }
复制代码
$ V* R9 |& u/ `4 _4 @
到这里可以编译下载到板子上运行 观察现象了% c/ `8 ?3 I1 D; A
' ~% V: t/ J( r$ Q9 M) t6 h
下面创建 RXT 的工程  新建一个工程  
3 ^- J7 P$ Y( M/ u- L! L( a5 r) j* Q& q% b: P7 j( C8 D9 q: @, D
勾选 如下选项 $ N) H* o9 k( Q% @2 ?
. z1 ]& P1 T# o, J2 u
QQ截图20150108112304.jpg ( H4 C  T6 K! H7 M" F
红框 不要添加  不知为何  楼主添加 MDK的 startup 编译通不过 , D7 p- L! q. N0 X7 z3 O& Y! W1 Y
F4 的工程没有包含  HAL  接下来 需要自行添加HAL 库 ( ]: `$ b6 F# y( C3 I/ s) \

& I4 w7 o  h. U# U  O# w, j6 A7 P把原来的 main.c 复制一份更名为  rtx_main.c* w" k7 r* O$ g- ^7 T
0 B( M$ T( y- b$ V  w
QQ截图20150108113501.jpg
: V6 o' T0 P4 r. H
" |( i3 J* l3 f* j) b% Z$ M! Q文件添加完毕 - |( A3 O3 e* n7 \0 O$ D" `$ b
) {/ M4 g" w! J# l, ~  ~0 z
接下来定义 头文件目录和 系统宏
1 K1 U1 U/ u* O! f4 m9 S1 z
& E5 I$ \; g, U4 {6 k QQ截图20150108112609.jpg
/ C7 r2 j0 o2 ?! O0 |
! B: E: j- |. ?1 m" q3 |5 [修改 rtx_main.c  下面两处需要修改 + y2 J; h) I' @  j3 ?1 y  f

: [5 m1 R& G, K6 ^: I
  1.   {# E# S- G5 g! J' n8 L8 {
  2.   osThreadDef( StartThread, osPriorityNormal, 0, 0);
    4 i: f, d! p( r+ X& a
  3.   osThreadCreate (osThread(StartThread), NULL);9 c  R! g9 n7 C5 [
  4.         }5 i* D% k1 |( m5 l% E! h6 j
  5. . Q3 w( X* \: o; f
  6. osThreadDef( Nucleo_072_Led, osPriorityNormal, 0, 0);
    ; c3 y2 ~- L4 j  C( Z% K# o2 y4 ?
  7.   osThreadCreate (osThread(Nucleo_072_Led), NULL);
复制代码
不知为何  ST写的 中间件和 MDK的 接口有一点差距  所以 创建线程的地方需要如上修改% m, V# ~4 f1 o' X+ M+ C) Q* j
! B5 n4 s/ |; a5 x; I* V$ p. D( V
修改 stm32f0xx_hal_conf.h 8 Z/ ^* b( \  R: c
添加 图示内容  不出意外  下面 将可以直接编译了!!
0 A. ^* x$ Z8 v+ D, H6 ]$ U QQ截图20150108112936.jpg 9 G; o1 N0 j: A
# m; d; v3 ~  A7 f7 e
写的有些多了  本来想 继续写 RTOS 基于串口的  应用  太长了 下次发帖写了8 D6 u7 r. u# L! C

: r7 [, K4 W: R! a& _- `1 |5 K+ U下面提出一个讨论 MX 创建的  工程 FREERTOS 中 cmsis_os.c 中 创建一个信号量  + d6 a% w& ?% P6 `
osSemaphoreCreate参数 count 直接+ \3 f+ ~+ {4 z8 @

; H( `& P" n9 ?% R$ r传递给 xSemaphoreCreateCounting的两个形参  ) ~7 U! L1 t" q# u: `) T" @$ A# }! a3 p
QQ截图20150108115258.jpg
  G4 _; Q0 k4 R5 k( f9 h* ]原型
6 k3 V! {- H1 ~$ o* P& N+ n#define xSemaphoreCreateCounting( uxMaxCount, uxInitialCount ) xQueueCreateCountingSemaphore( ( uxMaxCount ), ( uxInitialCount ) )
1 B  Y. Y7 p+ ?" Y2 l9 J6 X- L/ Y
: d: k" ~9 o1 t, j" H# L该宏创建一个 数值型信号量 第一个参数是 信号量最大数值  第二个则为  初始化值" V* s+ F/ ~/ i% M5 N% _4 M
" l5 c7 i$ H' h$ F
基于串口使用信号量  那么需要如下要求' o$ j' t$ M6 v5 [
假设 usart_sem 为串口使用的信号量
0 _2 A+ L9 z8 i9 i" {每收到一个数据 usart_sem ++  缓冲 1024字节
8 J! A2 j$ X- l) R! Y; u需要数据的线程 osSemaphoreWait(usart_sem ); 当有数据时 线程被激活  获取数据
% Q( W. t( I# X0 p* F4 g! B
3 R% H  F1 F, `% W& N如此我们知道 这个信号量的 最大值应为1024
$ C$ e  I, r. h7 Q6 X# H) _可是使用 ST 的cmsis_os osSemaphoreCreate 创建一个信号亮 osSemaphoreCreate(0,1024);
6 o* X% u+ E8 Z/ G7 m. v3 }
% s+ \1 }6 n7 f会出现这样的问题 !  此信号量 被赋予初值1024  意味着 这个信号量将可以被osSemaphoreWait 1024次5 K! S. [1 Y' d* B% O
显然这不是我们想要
+ m& \' |& ~1 V7 ]2 L  n( H& E
' A7 c% ^' G: _通常  我们需要的数值型信号量  最大值可以很大  但是初值 基本为0,或1
( ~! r4 t+ J/ |3 n' {* ~9 H) g
& M! r1 F. ^" d; R$ @不懂  这样设计意义何在?
2 ]' p( M3 ?2 [8 ]5 W! ^& t6 H/ I0 l; w* {  t1 ^

6 ~' m& o8 J7 B( `9 T 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 编辑 7 ?. P% P1 K7 I( I
lovewyufeng 发表于 2015-1-23 12:56
( z) I8 [5 M) _: H4 e事实上  只要这个计数不为0 都能被 wait 到
8 ~8 c. v6 j. ]3 h% W5 v9 ^" x# t5 H
不好意思,确实被代码的名称误导了,以前用的基本上只用二值的semphore或者直接用queue了。
$ P. r) D3 ^+ F  J& ~1 o( w* \仔细看了一下内部的实现,确实我说错了。( c1 k4 |4 _( L' u2 y8 e4 K
在init_counter和max_counter一样的情况下,确实整个逻辑是要按照资源池来解释的,也就是确实生产者take(这个take代表获取空闲资源才能生产),消费者release(这个代表空闲资源返回)。我觉得这种情况semphore更像一个可重入的锁,处理线程拿走资源池后,直接处理完后再归还,像是个recursive mutex。
9 D& X: u( _$ E前面说的那个问题,直接用queue可能会更好。另外,今天试了一下最新的stm32cubemx和固件版本,代码已经改了,#if (configUSE_COUNTING_SEMAPHORES == 1 )        
- x6 [* j! ?1 I8 {) P  return xSemaphoreCreateCounting(count, 0);  J& ~  _6 N3 s
#else; N6 E1 N- T$ j5 g9 F# `
  return NULL;
7 k+ W3 B% B9 ~  B) D' A& u* V2 h#endif/ V3 ]4 ^/ @6 L9 W0 k
}
0 v2 |  Z# k7 Y% p0 b) V
2 ^, j& {9 T9 t; K4 q+ f7 m  L* ~9 ]" |  Z9 N3 n% C& E/ v
6 K3 A, m- x; w" q8 c' i
. |5 y% ]  P5 @7 u7 X# V5 G( s3 S
我是东哥 回答时间:2015-1-23 07:50:34
lovewyufeng 发表于 2015-1-23 00:48
8 ~; v( g' {; P; R反过来理解是吧,说得通。可是
0 H& f! Q4 }# x+ L有个问题。,生产一个就-1的话应该 take获取信号咯?   反过来消费应该pos ...
; {2 u& y' W# f' W
你陷在细节里面了,看看人家的API是怎么样写的,osSemaphoreRelease和osSemaphoreWait,我们在生产者里面应该要osSemaphoreRelease,而在消费者里面osSemaphoreWait,是吧?字面理解,相当于生产的人释放了一个东西,然后消费者就等待生产者的这个东西。再看里面的实现,osSemaphoreRelease里面是xSemaphoreGive而不是take,而osSemaphoreWait里面是xSemaphoreTake而不是give。
7 W/ b9 H7 i: s( o- p+ Q所谓的反过来理解只是一种理解方法,说take和post的逻辑也反的话是不对的。不要老想着什么时候去post,什么去take。cmsis_os的API意思很明了,生产者生产了东西就应该release,消费者就应该Wait,这不是很好理解吗?
lovewyufeng 回答时间:2015-1-23 00:48:46
我是东哥 发表于 2015-1-21 12:18
3 E& ^3 W, e1 |9 n; B这个其实也没有不合理,看你怎么理解,资源一开始为0,也可以理解为空闲池一开始是满的。生产者生产了一 ...
! l. v! P: d6 w1 F' I  L
反过来理解是吧,说得通。可是6 W1 t( I% M8 j* h
有个问题。,生产一个就-1的话应该 take获取信号咯?   反过来消费应该post 释放信号咯? 那么问题是 post是非阻塞立即返回的而take是阻塞的?
# o8 q" T2 V# t5 i( C7 c3 N. B先不谈消费者应当随时饥饿,处于阻塞态。
: e; M! J" O5 Y# K生产一般在中断里吧,当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
看看 顶一下
* }+ j# S3 n; S. h
cqtnheyao 回答时间:2015-1-8 12:19:01
harvardx 发表于 2015-1-8 12:13) l: S6 k- ]5 v$ j, n/ q5 Q  a
有钱为何不顶帖 .何况还是高质量的 .cubemx 势在必得的趋势.支持一下.
4 U- K7 B) A. p! t, f
据说库很大,效率低?求告知!
netlhx 回答时间:2015-1-8 12:19:08
很好,图文并茂
lovewyufeng 回答时间:2015-1-8 12:19:26
harvardx 发表于 2015-1-8 12:13
4 r6 c  z( f2 l. i9 y+ h有钱为何不顶帖 .何况还是高质量的 .cubemx 势在必得的趋势.支持一下.
0 R9 B# X& x  B# r
多谢老大 支持  继续加油
lovewyufeng 回答时间:2015-1-8 12:23:05
cqtnheyao 发表于 2015-1-8 12:19
) i5 [0 K5 x  i/ }据说库很大,效率低?求告知!
8 ^9 A/ v+ X6 g1 R/ I4 Z
确实 有这个毛病  楼主的贴初始化使用库  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 手机版