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

【安富莱】【RTX操作系统教程】第13章 事件标志组

[复制链接]
baiyongbin2009 发布时间:2016-1-27 16:12
本帖最后由 baiyongbin2009 于 2016-1-27 16:13 编辑 ( H7 {* _% r9 i& [; o/ p& j
: E- s, Y2 j4 \0 v5 X* ?
第13章    事件标志组
    前面的章节我们已经讲解了任务管理和时间管理,从本章节开始讲解任务间的通信和同步机制。首先讲解任务间的通信和同步机制之一,事件标志组。
    本章教程配套的例子含Cortex-M3内核的STM32F103和Cortex-M4内核的STM32F407。
13.1 事件标志组
13.2 事件标志组API函数
13.3 实验例程说明(任务间通信)
13.4 实验例程说明(中断方式通信)
13.5      总结

! n9 [$ c: [& n2 N
13.1  事件标志组, k8 v2 l3 b3 e0 a, k1 [8 E$ J. r8 p

, q8 R* N) l: g! K" U
13.1.1  为什么要使用事件标志
    事件标志组是实现多任务同步的有效机制之一。也许有不理解的初学者会问采用事件标志组多麻烦,搞个全局变量不是更简单,其实不然。在裸机编程时,使用全局变量的确比较方便,但是在加上RTOS后就是另一种情况了。使用全局变量相比事件标志组主要有如下三个问题:
    (1)使用事件标志组可以让RTOS内核有效的管理任务,全局变量是无法做到的,任务的超时等机制需要用户自己去实现。
    (2)使用了全局变量就要防止多任务的访问冲突,使用事件标志组已经处理好了这个问题。用户无需担心。
    (3)使用事件标志组可以有效的解决中断服务程序和任务之间的同步问题。

* N& n  U2 ^9 v( `- P1 U, Y6 {6 e

! i* V; c7 y/ J& k  D  p( o
13.1.2   RTX任务间事件标志组的实现
    任务间事件标志组的实现是指各个任务之间使用事件标志组实现任务的通信或者同步机制。
    RTX每个任务创建的时候,会自动创建16个事件标志,事件标志被存储到每个任务的任务控制块中。也就是说每个任务支持16个事件标志。下面我们通过如下的框图来说明一下RTX事件标志的实现,让大家有一个形象的认识。
                              
13.1.png
运行条件:
创建2个任务Task1和Task2
运行过程描述如下:
1.  任务Task1运行过程中调用函数os_evt_wait_and,等待事件标志位被设置,任务Task1由运行态进入到挂起态
2.  任务Task2设置了任务Task1的事件标志,任务Task1由挂起态进入到就绪态,在调度器的作用下由就绪态又进入到运行态。

5 Q$ K, m1 s2 ?8 S4 H' a
上面就是一个简单RTX任务间事件标志通信过程。

5 z+ t* m, B& [( m4 E7 S; t& V
, a2 B# _6 f$ K& z. c2 ?( \
13.1.3  RTX中断方式事件标志组的实现
    RTX中断方式事件标志组的实现是指中断函数和RTX任务之间使用事件标志。下面我们通过如下的框图来说明一下RTX事件标志的实现,让大家有一个形象的认识。
13.2.png
运行条件:
创建1个任务和一个串口接收中断
运行过程描述如下:
1.  任务Task1运行过程中调用函数os_evt_wait_and,等待事件标志位被设置,任务Task1由运行态进入到挂起态
2.  Task1挂起的情况下,串口接收到数据进入到了串口中断服务程序,在串口中断服务程序中设置Task1的事件标志,任务Task1由挂起态进入到就绪态,在调度器的作用下由就绪态又进入到运行态。

! L, _# d/ d7 O  R
上面就是一个简单RTX中断方式事件标志通信过程。实际应用中,中断方式的消息机制切记注意以下四个个问题:
(1)中断函数的执行时间越短越好,防止其它低于这个中断优先级的异常不能得到及时响应。
(2)实际应用中,建议不要在中断中实现消息处理,用户可以在中断服务程序里面发送消息通知任务,在任务中实现消息处理,这样可以有效的保证中断服务程序的实时响应。同时此任务也需要设置为高优先级,以便退出中断函数后任务可以得到及时执行。
(3)中断服务程序中一定要调用专用于中断的事件标志设置函数isr_evt_set。
(4)在RTX操作系统中实现中断函数跟裸机编程是一样的。
      A.  另外强烈推荐用户将Cortex-M3内核的STM32F103和Cortex-M4内核的STM32F407的NVIC优先级分组设置为4,即:NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);这样中断优先级的管理将非常方便。
      B.  用户要在RTX多任务开启前就设置好优先级分组,一旦设置好切记不可再修改。
+ @+ X- j1 i% I" T& h4 x8 Z
赞 收藏 评论8 发布时间:2016-1-27 16:12

举报

8个回答
baiyongbin2009 回答时间:2016-1-27 16:36:00
13.2 事件标志组API函数
    使用如下6个函数可以实现RTX的事件标志组:
os_evt_clr
os_evt_get
os_evt_set
os_evt_wait_and
os_evt_wait_or
isr_evt_set
关于这6个函数的讲解及其使用方法可以看教程第3章3.3小节里面说的参考资料rlarm.chm文件
13.3.png
                              
这里我们重点的说一下函数os_evt_set,isr_evt_set和os_evt_wait_and,因为本章节配套的例子使用的是这三个函数。
- t, u* s* _7 ^+ n: ?, c
13.2.1  函数os_evt_set
函数原型:
  1. void os_evt_set (0 s8 b5 b9 V' V" e2 w+ A
  2.     U16    event_flags,    /* 16位的事件标志设置 */
    1 D2 b$ {) l* O* n3 p
  3.     OS_TID task );         /* 要设置事件标志的任务ID */
复制代码

) F, o; A. l$ z! b! ~1 h
函数描述:
函数os_evt_set用于设置指定任务的事件标志。
(1)第1个参数表示16个可设置的事件标志位。因为RTX的每个任务创建时有16个可设置的事件标志,这里用U16类型的变量event_flag就可以表示,变量event_flag的某个位设置为1,那么指定RTX任务的事件标志相应位就设置为1。变量event_flag设置为0的位对RTX任务的事件标志相应位没有影响。比如设置变量event_flag = 0x0003就表示将RTX任务事件标志的位0和位1设置为1,其余位没有变化。
(2)第2个参数是任务ID。

9 V  c" Q, Z8 g5 R5 P" F
使用这个函数要注意以下问题:
1.     此函数是用于任务代码中调用的,故不可以在中断服务程序中调用此函数,中断服务程序中使用的是isr_evt_set
使用举例:
  1. #include <rtl.h>2 f6 M' G" z/ u5 R' l. A
  2. 0 M6 r0 x- ^0 o- _0 ~, u$ ?5 p
  3. __task void task1 (void) {
    ; A$ `- h7 O" ?  E: B
  4.    ..5 x* L+ O+ n' E* f
  5.   os_evt_set (0x0003, tsk2);. h  q5 a( I+ a# P8 j
  6.    ..% N* F8 y* D6 G6 Z
  7. }
复制代码

% D1 n9 x1 B7 q% x4 v' {0 l
% ^4 w& z, K3 b0 D
13.2.2 函数isr_evt_set
函数原型:
  1. void isr_evt_set (/ }' h# D! }* W- w% e1 H
  2.     U16    event_flags,    /* 16位的事件标志设置 */
    . b3 ^/ S2 Y, [" Y- c* C+ T
  3.     OS_TID task );         /* 要设置事件标志的任务ID */
复制代码

" l; C3 _2 C0 P5 C# j. o6 B9 {
函数描述:
函数isr_evt_set用于设置指定任务的事件标志。
(1)第1个参数表示16个可设置的事件标志位。因为RTX的每个任务创建时有16个可设置的事件标志,这里用U16类型的变量event_flag就可以表示,变量event_flag的某个位设置为1,那么指定RTX任务的事件标志相应位就设置为1。变量event_flag设置为0的位对RTX任务的事件标志相应位没有影响。比如设置变量event_flag = 0x0003就表示将RTX任务事件标志的位0和位1设置为1,其余位没有变化。
(2)第2个参数是任务ID。
8 c# a* Y5 c: K* Q& v: O, f2 M
使用这个函数要注意以下问题:
1.     此函数是用于中断服务程序中调用的,故不可以在任务中调用此函数,任务中使用的是os_evt_set。
2.     事件标志函数isr_evt_set的调用不能太频繁,太频繁的话会大大增加系统内核的开销,会造成事件标志得不到及时处理从而造成丢失事件标志的情况。
使用举例:
  1. #include <rtl.h>
    4 ]8 ^/ a+ D5 J; B& _

  2.   y% M' x! W8 v* A
  3. void EXTI0_IRQHandler (void){; y  }2 \: l1 [9 ?" a
  4.    ..+ ]9 c. N3 V8 o* Y
  5.   isr_evt_set (0x0003, tsk2);
    8 f! M# A$ `: T& T3 P% Z+ T
  6.    ..
    $ B$ W2 x8 W" y4 e' M! }
  7. }
复制代码
/ L" @' b& K0 j$ _) c: M/ ?
4 q4 q7 r6 I' O6 d$ M% P- G/ T
13.2.3 函数os_evt_wait_and
函数原型:
  1. OS_RESULT os_evt_wait_and (
    + ^* Z  c/ u, h7 x. S
  2.     U16 wait_flags,    /* 16位的事件标志等待 */
    : _) L4 N$ b' L8 ]2 ^
  3.     U16 timeout );     /* 超时时间设置 */
复制代码

$ W0 }' O% m! Z* o+ Y  ~7 @, N
函数描述:
函数os_evt_wait_and用于等待事件标志被设置。
(1)第1个参数表示任务等待的事件标志位。因为RTX的每个任务创建时有16个可以设置的事件标志,这里用U16类型的变量event_flag就可以设置,变量event_flag的那位设置为1,那么RTX任务的事件标志就等待那个位被设置为1。而且要所有要求的位都被设置为1才可以。比如设置变量event_flag = 0x0003就表示RTX任务在等待事件标志的位0和位1都被设置为1。
(2)第2个参数表示设在的等待时间,范围0-0xFFFF,当参数设置为0-0xFFFE时,表示等这么多个时钟节拍,参数设置为0xFFFF时表示无限等待直到事件标志满足要求。
(3)函数返回OS_R_EVT表示等待的事件标志位都被设置了,也就是返回成功。返回OS_R_TMO表示超时。

; r3 }5 ~: R6 ]
使用这个函数要注意以下问题:
1.     当要求的事件标志位都被设置为1时或者设置的超时时间溢出时,函数os_evt_wait_and才会返回。
2.     如果函数os_evt_wait_and返回前所要求的事件标志位都设置了,那么此函数会在返回前将相应的事件标志位清零,其它位不受此影响。如果初学者不是太理解这个问题,可以看本章节配套的例子,这样会有一个清晰的认识。
使用举例:
  1. #include <rtl.h>& Y9 z, z5 m9 F0 X* N9 V: U- s
  2. #define BIT_0       (1 << 0)
    $ h; w  S' s6 f) B8 @7 j; r+ p# G1 c
  3. #define BIT_1       (1 << 1)
    ; x+ y! h/ Y+ t; x: y; P$ i
  4. #define BIT_ALL (BIT_0 | BIT_1)
    9 e/ Y+ q( ?$ v$ X- r% z

  5. . V$ Y, m& Q/ O! e4 H
  6. __task void AppTaskMsgPro(void), f  f+ k  ^  N5 P% }+ }- ]
  7. {
    $ ^4 n: b4 z' O: R
  8. OS_RESULT xResult;- x- g( ?, W" F
  9. const uint16_t usMaxBlockTime = 500; /* 延迟周期 */
    $ j+ y- t' B8 f
  10.          
    ( [- D) X& t) }4 j8 z& K
  11.     while(1), S! w0 d' |/ Y* b; z  t% I
  12.     {, a0 T- ~/ @; Q5 C5 Y
  13. /*
    3 m! v. |, q# s* w# F2 v6 x* t
  14. 1. 等待K2按键按下设置bit0和K3按键按下设置bit1,都设置了执行OS_R_EVT消息6 w. ?2 D; y% J, t3 T+ [( n
  15. 2. 退出前bit0和bit1被清除,这里是bit0和bit1都被设置才表示“退出”。
    4 t# o( a+ \8 ^( L8 L; |/ O
  16. 3. 每个任务都有自己的16位事件标志位,也就是os_evt_wait_and的第一个参数是无符号16位整形。
    3 P0 F# m% V9 j' z4 W0 C
  17. */$ x- v9 L, W' x2 L" M
  18.           xResult = os_evt_wait_and (BIT_ALL, usMaxBlockTime);1 t! N9 J6 X& Q% }
  19.                   
    % `( S) S; G1 M  f( _, f
  20.           switch (xResult)
      G. w) B; ?; I% z6 J
  21.           {
    : x/ G6 H* o& u% }, O! N' ]  w
  22.               /* 接收到bit1和bit0都被设置的消息 */* }- N8 ~9 H# Y! a6 A; K" A2 E
  23.                case OS_R_EVT:& [# L6 a3 w1 c
  24.                     printf("接收到bit0和bit1都被设置的消息\r\n");8 ?2 m( G6 B% q; Y# w' r2 @( A
  25.                     break;   
    ( c/ e" t  F3 b" q- U; H1 l) |$ N, P) q

  26. 8 ?% p9 Y# q3 U6 m6 T" W# J; ]. j
  27.                     /* 超时 */
    2 v4 q9 Y! r+ D4 P
  28.                     case OS_R_TMO:, ^8 b) W& a  {
  29.                         bsp_LedToggle(1);
    + M+ H' ^+ h8 [7 J7 j0 D( Z
  30.                         bsp_LedToggle(4);
    & B' {! W0 q" \7 C
  31.                         break;* T# E  [8 L/ \8 q; h
  32.                               
    1 r% l8 M  y' ^. ^: U
  33.                     /* 其他值不处理 */
    ! {8 h: E7 B! a' a1 I3 g
  34.                     default:                    
    . }* ~' a: H+ j4 N  Z
  35.                         break;: k! z' h5 u  g# J8 F; m7 p
  36.           }        ' B% _5 f; M7 X0 s, z. W+ H& B- X1 e) O
  37.     }+ e  v  e0 b6 X6 C* |
  38. }
复制代码
3 ?' B+ x8 h/ J/ B' o

4 d3 P$ W5 g3 e
baiyongbin2009 回答时间:2016-1-27 16:58:32
13.3 实验例程说明(任务间通信)
* o: j7 a) ]1 i: W  ^8 V
13.3.1 STM32F103开发板实验
配套例子:
    V4-409_RTX实验_事件标志组
实验目的:
    1. 学习RTX的事件标志组
实验内容:
    1.     K1按键按下,串口打印。
    2.     K2键按下,直接发送事件标志给任务AppTaskMsgPro,设置bit0 。
    3.     K3键按下,直接发送事件标志给任务AppTaskMsgPro,设置bit1 。
    4.     任务AppTaskMsgPro只有接收到bit0和bit1都被设置了才执行串口打印信息。
    5.     各个任务实现的功能如下:
      AppTaskUserIF任务  :按键消息处理。
      AppTaskLED任务     :LED闪烁。
      AppTaskMsgPro任务 :消息处理,等待任务AppTaskUserIF发来的事件标志。  
      AppTaskStart任务    :启动任务,也是最高优先级任务,这里实现按键扫描。
RTX配置:
    RTX配置向导详情如下:
13.4.png
Task Configuration
Number of concurrent running tasks
     允许创建4个任务,实际创建了如下四个任务
                  AppTaskUserIF任务   :按键消息处理。
                  AppTaskLED任务     :LED闪烁。
                  AppTaskMsgPro任务 :消息处理,等待任务AppTaskUserIF发来的事件标志。
                  AppTaskStart任务    :启动任务,也是最高优先级任务,这里实现按键扫描。
    Number of tasks with user-provided stack
     创建的4个任务都是采用自定义堆栈方式。
RTX任务调试信息:
13.5.png
Event Value:任务AppTaskMsgPro当前的事件标志数值。
Event Mask:任务AppTaskMsgPro等待的事件标志数值。
程序设计:
任务栈大小分配:
staticuint64_t AppTaskUserIFStk[512/8];   /* 任务栈 */
staticuint64_t AppTaskLEDStk[256/8];      /* 任务栈 */
staticuint64_t AppTaskMsgProStk[512/8];  /* 任务栈 */
staticuint64_t AppTaskStartStk[512/8];     /* 任务栈 */
将任务栈定义成uint64_t类型可以保证任务栈是8字节对齐的,8字节对齐的含义就是数组的首地址对8求余等于0。如果不做8字节对齐的话,部分C语言库函数,浮点运算和uint64_t类型数据运算会出问题。
系统栈大小分配:
13.6.png
RTX初始化:
  1. /*
    " _3 z$ D4 v1 d
  2. *********************************************************************************************************2 L! m2 j9 F" l
  3. *    函 数 名: main1 q% Z9 `/ r+ `
  4. *    功能说明: 标准c程序入口。, I9 @! |( X* Y, L$ u
  5. *    形    参: 无9 F* z$ F, M+ s4 N
  6. *    返 回 值: 无
    ! x0 X& d0 j# e/ M9 H
  7. *********************************************************************************************************
    / L9 o# H: p3 B3 }
  8. */
      @4 |% [6 e0 N' S2 x4 R
  9. int main (void)+ B9 _9 v. E: a1 s- u
  10. {   
    5 H$ \8 y) A0 A4 L$ W
  11.      /* 初始化外设 */3 ~' f9 H! c6 ]. T5 K
  12.      bsp_Init();
    2 f3 z/ F& Y( w' g
  13.    
    ; ]+ ^' ~; {5 z1 ~& w
  14.      /* 创建启动任务 */
    9 P; w# ]  g) p' S2 y
  15.      os_sys_init_user (AppTaskStart,             /* 任务函数 */
    5 W! U1 G1 l: g& X& a
  16.                        4,                        /* 任务优先级 */
    * ~1 Q7 b- Z2 O, H
  17.                        &AppTaskStartStk,         /* 任务栈 */
    , s# V! k5 n3 {: k  W+ R
  18.                        sizeof(AppTaskStartStk)); /* 任务栈大小,单位字节数 */
    , {6 N* H; V8 T
  19.      while(1);! m. h& f% F4 W( K. A3 u! `% v
  20. }
复制代码

9 s, S/ P8 W; Y1 F% Y
RTX任务创建:
  1. /*
    & T0 ~, y7 A, i$ @* M1 W
  2. *********************************************************************************************************6 T6 z' m; {2 w. ^6 @0 B
  3. *    函 数 名: AppTaskCreate
    / w2 E  P4 N9 q' R) H
  4. *    功能说明: 创建应用任务3 E% X0 U& H" I/ A+ q. W; T$ j
  5. *    形    参: 无1 y9 b- ]! x2 J: i( e9 v1 b% @
  6. *    返 回 值: 无+ b/ q1 l/ \2 K: {5 R/ r
  7. *********************************************************************************************************
    / c3 \" ~! |2 v9 f6 B7 D' \4 F" i4 ]
  8. */5 d- s2 x; O& G3 v
  9. static void AppTaskCreate (void)
    & e9 j' [1 b- a2 L# I- w( t5 }7 F
  10. {
    4 W* W7 ^5 j$ i) {
  11.      HandleTaskUserIF = os_tsk_create_user(AppTaskUserIF,             /* 任务函数 */. E) ^) W; \, r* T* a; u, J: T( X+ s
  12.                                            1,                         /* 任务优先级 */
    9 d9 y# g- n3 N7 v$ G
  13.                                            &AppTaskUserIFStk,         /* 任务栈 */
    ! y% V9 t& C  Z$ {
  14.                                            sizeof(AppTaskUserIFStk)); /* 任务栈大小,单位字节数 */# p+ i+ G6 O$ n
  15.     * R* x& Z# S$ o: W! g8 V6 s
  16.      HandleTaskLED = os_tsk_create_user(AppTaskLED,              /* 任务函数 */- \- x) X+ d' f% a& U3 U
  17.                                         2,                       /* 任务优先级 *// V) j  p& o: E5 u- ^+ g
  18.                                         &AppTaskLEDStk,          /* 任务栈 */
    " I/ |$ G, u, k) D9 I/ o$ m- Q
  19.                                         sizeof(AppTaskLEDStk));  /* 任务栈大小,单位字节数 */' ~: J' V% ~9 V7 C1 S$ n( H
  20.     2 S: |) G5 c4 l' u6 m
  21.      HandleTaskMsgPro = os_tsk_create_user(AppTaskMsgPro,             /* 任务函数 */5 s1 s$ w, \# m# [# |9 O0 N7 H
  22.                                            3,                         /* 任务优先级 */
    3 D4 X1 d* v0 q9 E/ q2 Y3 A
  23.                                            &AppTaskMsgProStk,         /* 任务栈 */
    ; s6 d" e9 ^2 t
  24.                                            sizeof(AppTaskMsgProStk)); /* 任务栈大小,单位字节数 */
    1 X* p5 g7 s% S, v$ T
  25. }
复制代码
5 N% l$ d# K% _" g9 E4 @" a, O
四个RTX任务的实现:
  1. /*, L$ E% d7 }( g) Z
  2. *********************************************************************************************************0 G) O5 R) ]3 W9 \! H
  3. *    函 数 名: AppTaskUserIF
    ! \# N  X# H- P2 C6 i% _
  4. *    功能说明: 按键消息处理     
    , Y  v5 X  `, M+ |* K& K4 X
  5. *    形    参: 无
    4 {2 t6 t, s0 o9 E8 D
  6. *    返 回 值: 无
    ; Z- x4 e" N* `& V4 M8 H
  7. *   优 先 级: 1  (数值越小优先级越低,这个跟uCOS相反)% `2 W3 v' F' L
  8. *********************************************************************************************************
    - X& w! q  o# q; _$ S4 e
  9. */
    7 _- n  G5 l0 C3 Z/ ^- R- P7 ^( T& _' O
  10. __task void AppTaskUserIF(void)% R. C5 W7 _; W  i! L
  11. {, E+ m. B7 U5 H% T* G
  12.      uint8_t ucKeyCode;1 c* v% d! E+ B0 Q
  13. 7 t' c/ c( Q) W; j
  14.     while(1)
    4 n* x8 E7 F6 D+ _
  15.     {
    4 X( _) {4 x- o* Q8 l! G
  16.          ucKeyCode = bsp_GetKey();
    ' \+ v3 q, _0 m6 t3 E4 H
  17.         
    * |. ~# {( i" e) `
  18.          if (ucKeyCode != KEY_NONE)0 G6 W0 K: P; M, L/ c4 ]1 g
  19.          {
    7 ^9 n8 p& t$ Y; f: {  _
  20.               switch (ucKeyCode)
    : S% N' e; q6 Y2 {
  21.               {
    2 k% A% d5 n" L9 c2 j6 B& X( Y+ ^
  22.                    /* K1键按下,打印调试说明 *// ]0 [8 ?" T& h# I& w, O+ M
  23.                    case KEY_DOWN_K1:9 `5 n) R4 S5 [$ K2 p6 F! W2 w
  24.                        printf("K1键按下,使用MDK中自带的RTX调试组件,请务必使用MDK4.74版本进行调试\r\n");2 s" @+ k! s) O2 O
  25.                        break;  
    % |: p" _' z8 M9 w9 ~
  26. 7 B# ]5 s# A) K8 R
  27.                    /* K2键按下,直接发送事件标志给任务AppTaskMsgPro,设置bit0 */
    , ~3 G6 p( y' f; i8 a: s) y- @1 C' B
  28.                    case KEY_DOWN_K2:: v& A3 v2 M% f; x; T/ _
  29.                        printf("K2键按下,直接发送事件标志给任务AppTaskMsgPr,bit0被设置\r\n");+ R/ {" U4 o9 d! J' ?6 Q. d7 D
  30.                        os_evt_set (BIT_0, HandleTaskMsgPro);
    ) a" u0 B5 Y# @/ p$ n* o
  31.                        break;
    8 ]5 B  P, G8 s
  32.                  ' ~& o3 J+ ~5 U' V! u4 q
  33.                    /* K3键按下,直接发送事件标志给任务AppTaskMsgPro,设置bit1 */: z5 {3 y/ b! @' b
  34.                    case KEY_DOWN_K3:
    8 J( @0 Y# U5 a) u! f- g# b
  35.                        printf("K3键按下,直接发送事件标志给任务AppTaskMsgPro,bit1被设置\r\n");0 I# S, ^* A: p6 I8 L7 Q
  36.                        os_evt_set (BIT_1, HandleTaskMsgPro);
    3 W7 x  O  f9 i. b0 D9 m/ y
  37.                        break;
    2 k) s6 J+ y/ M: e' |) O7 u

  38. 9 Q2 _. P% g5 X( x+ v  N  S
  39.                    /* 其他的键值不处理 */
    ) e( K1 q% T8 I2 H- [+ U/ M  q1 E/ R' _
  40.                    default:                    
    " o; \& g# s) v2 \1 Y
  41.                        break;
    ( {! w4 e8 h4 w( Q* s
  42.               }
    5 h. M2 a, y" \4 ?) n+ n) s$ ?
  43.          }
    ! _; S2 I! h& c, t
  44.         
    & ~& u. w) r, v( L% x
  45.          os_dly_wait(20);
    0 V2 Q+ Q8 e; g. l
  46.      }
    ; V$ {9 G- ?+ W" ?: b
  47. }
    : J$ H, U/ X. H- }6 l

  48. . b2 C% r0 Z6 n8 Z& ^$ P
  49. /*% z5 P! l! c0 B0 d2 |9 I1 L2 u+ [
  50. *********************************************************************************************************
    . ~0 T3 w+ y) g  O4 L
  51. *    函 数 名: AppTaskLED
    ; e0 O$ F  ]4 i5 `8 S& }
  52. *    功能说明: LED闪烁。
    5 f8 p: w# K6 M# ~) u; j' t
  53. *    形    参: 无
    4 Z: D1 N; y) t  n
  54. *    返 回 值: 无1 _$ M1 z5 X. B, V
  55. *   优 先 级: 2 6 Q% \3 ^. A7 v% q" m) D7 j/ a7 p
  56. *********************************************************************************************************7 W7 `0 \8 n* v8 {& D! d
  57. */
    5 i( f; ?7 h! _7 r6 `: O
  58. __task void AppTaskLED(void)
    : c# _0 u6 n5 t/ A5 K" Y
  59. {0 {& q, U$ ~+ }" c5 g
  60.      const uint16_t usFrequency = 200; /* 延迟周期 */0 _" A* h8 [9 J5 f
  61.     % h; L4 J2 R! G" V% P# [4 ]4 E
  62.      /* 设置延迟周期 */
    ) c7 q: ]5 N+ a  a0 I; {
  63.      os_itv_set(usFrequency);
    3 U' {! X& {2 b/ h" z
  64.     % G- x; n9 k$ N8 {# |
  65.     while(1)
    # g  @: u% c# ~: M0 e" F. t/ P% \
  66.     {7 Y7 h1 S2 V# W( N* @1 g# b: V
  67.          bsp_LedToggle(2);
    , T3 T$ S9 [- O# ~4 e3 a
  68.          bsp_LedToggle(3);
    ! |: S8 A+ L3 a0 P2 K8 h( A
  69. ; ]$ m; X- x8 L' U1 u; W# I
  70.          /* os_itv_wait是绝对延迟,os_dly_wait是相对延迟。*/
    9 z- o3 c: d8 ~& z! i# D8 |( s: v- M" C
  71.          os_itv_wait();
    # o; ]6 y8 e1 Q4 l; D8 T) O- r
  72.     }
    1 W7 \8 ?; L6 V: z; e
  73. }0 T. w" H) x/ y$ Y
  74. 8 k7 P3 }. C) m9 a/ l1 I
  75. /*! [/ O7 ~7 V' x
  76. *********************************************************************************************************
    ! s& G' t0 ?! P4 R4 ~" Y! P
  77. *    函 数 名: AppTaskMsgPro
    ) \) P: V; h/ s7 G! L5 D
  78. *    功能说明: 消息处理,等待任务AppTaskUserIF发来的事件标志, x6 k$ Z* t, E2 L1 w6 C/ V
  79. *    形    参: 无4 m6 P3 p6 E, b( y/ K' d9 x  E
  80. *    返 回 值: 无
    ) ^6 }4 u  C2 ~; ~6 Z. C
  81. *   优 先 级: 3 ) u* Z* ^' [+ H: `- J& k
  82. *********************************************************************************************************
    4 l: ^$ K0 M  U: m7 C$ A; {2 [, v, m
  83. */0 W: }# K& ?5 e/ [2 S. W! M
  84. __task void AppTaskMsgPro(void)
    . |8 l  x+ C5 A* _, i- c  u
  85. {
    ) m8 C1 P9 b5 D* F7 {
  86.      OS_RESULT xResult;
    / z- v5 J* ]* Y" H- \6 E
  87.      const uint16_t usMaxBlockTime = 500; /* 延迟周期 */1 U. J; n3 N) _6 B6 y7 @7 }" {
  88.    
    3 P3 f1 S& W; E/ x
  89.     while(1)4 q4 Q# g1 O' R% E
  90.     {1 e& E- E4 j+ N7 Y* r
  91.          /*
    8 ?! m' f' U- B. Q0 e
  92.            1. 等待K2按键按下设置bit0和K3按键按下设置bit1,都设置了执行OS_R_EVT消息  s  w/ V6 M$ g9 Y  @# T
  93.            2. 退出前bit0和bit1被清除,这里是bit0和bit1都被设置才表示“退出”。
    2 y5 V0 p7 M8 q* M6 ~" }3 b
  94.            3. 每个任务都有自己的16位事件标志位,也就是os_evt_wait_and的第一个参数是无符号16位整形。
    ; G2 f4 c7 V$ n
  95.          */
    6 V" Q, H* ]* \
  96.          xResult = os_evt_wait_and (BIT_ALL, usMaxBlockTime);: A* o) ]9 [3 Y" B" B5 |
  97.         
    ' V- K1 _9 j  P; o. S3 S4 p1 A/ V7 `
  98.          switch (xResult)
    1 d; z  |) r+ U; N2 t) x+ O3 B- c
  99.          {; q0 l; R2 z2 j3 R
  100.               /* 接收到bit1和bit0都被设置的消息 */
    8 I! z7 z. V5 f" |/ a! p1 m$ I- ]9 W
  101.               case OS_R_EVT:+ \; }3 w0 y6 W- A# I* k$ ?
  102.                    printf("接收到bit0和bit1都被设置的消息\r\n");9 {% h5 |( L# v" I
  103.                    break;  % X+ K1 a* B% O- f% {0 F) B

  104. 1 K! L% e3 Z9 O* ?& e
  105.               /* 超时 */, @! H8 M5 V+ G
  106.               case OS_R_TMO:
    6 V7 A2 B5 r4 q( m3 c8 `2 R
  107.                    bsp_LedToggle(1);; }% l9 y* {' F2 d0 Y
  108.                    bsp_LedToggle(4);7 B1 `# I2 i( r' y
  109.                    break;# X  d& I3 w. m. u
  110.              7 I) s4 C5 d% z  E
  111.               /* 其他值不处理 */, l/ U! Z8 {8 X( z/ z; t8 C8 ~" n6 A
  112.               default:                    
    ! b* Z6 z0 `/ f) h
  113.                    break;
      C! D) J2 C6 s: U
  114.          }   
    0 N/ A6 Y  x" c2 D- T3 D
  115.     }% c8 r6 D( W1 c, C
  116. }- p0 a! [! y7 W8 i5 q! V5 V7 T

  117. # ?, n8 U' G( j: x+ v
  118. /*
    & V; @6 P9 n4 D
  119. *********************************************************************************************************$ n, V) U, b5 l- H# C; X
  120. *    函 数 名: AppTaskStart0 D/ j$ r7 h8 c8 T; T% H3 l
  121. *    功能说明: 启动任务,也就是最高优先级任务。这里实现按键扫描。7 {: n1 m. e1 t: a/ \" Y' X; W! @1 Q
  122. *    形    参: 无
    : d7 v% ^) w, i- T/ x( |
  123. *    返 回 值: 无
    7 j- i8 v6 i4 u* |) E
  124. *   优 先 级: 4 $ Z( N7 N8 l+ B5 \4 O. U
  125. *********************************************************************************************************/ `5 z0 S4 r6 K8 e3 l1 s  e. @
  126. */
    / R9 o( C! t3 M- |( ~4 B7 s. d
  127. __task void AppTaskStart(void)
    ' Y* t7 Q. J( X& I! p
  128. {
    1 S, J, d+ U. a+ l
  129.      /* 创建任务 */! S  S( g  ]& ]6 m0 U3 A0 _
  130.      AppTaskCreate();  r) F6 S- t4 L! T% ^& n3 q$ j1 s  K+ p
  131.    
    7 Q- f7 ]& A0 y6 m
  132.     while(1)
    / R( R1 \+ T$ u. A2 x' N. U4 N$ ~
  133.     {
    / Q# o. R1 G$ F$ \/ ~7 W
  134.          /* 按键扫描 */
    ( U8 y! G/ l9 o/ C, k/ ?& ?0 D
  135.          bsp_KeyScan();
    ( J$ }) M6 i+ T5 u  k! B
  136.         os_dly_wait(10);9 w! h5 Q! M* B1 _
  137.     }2 _3 y+ Z% Q% I/ ~9 p
  138. }
复制代码
/ w  C2 \6 O8 M9 |2 w1 v) L
. K9 d5 p4 M) @. M" {4 Q" k: j& P
baiyongbin2009 回答时间:2016-1-27 17:03:54
13.3.2 STM32F407开发板实验
配套例子:
    V5-409_RTX实验_事件标志组
实验目的:
    1. 学习RTX的事件标志组
实验内容:
    1. K1按键按下,串口打印。
    2. K2键按下,直接发送事件标志给任务AppTaskMsgPro,设置bit0 。
    3. K3键按下,直接发送事件标志给任务AppTaskMsgPro,设置bit1 。
    4. 任务AppTaskMsgPro只有接收到bit0和bit1都被设置了才执行串口打印信息。
    5. 各个任务实现的功能如下:
       AppTaskUserIF任务  :按键消息处理。
       AppTaskLED任务     :LED闪烁。
       AppTaskMsgPro任务 :消息处理,等待任务AppTaskUserIF发来的事件标志。
       AppTaskStart任务    :启动任务,也是最高优先级任务,这里实现按键扫描。
RTX配置:
    RTX配置向导详情如下:
13.7.png
Task Configuration
Number of concurrent running tasks
      允许创建4个任务,实际创建了如下四个任务
                AppTaskUserIF任务   :按键消息处理。
                AppTaskLED任务     :LED闪烁。
                AppTaskMsgPro任务 :消息处理,等待任务AppTaskUserIF发来的事件标志。
                AppTaskStart任务    :启动任务,也是最高优先级任务,这里实现按键扫描。
    Number of tasks with user-provided stack
      创建的4个任务都是采用自定义堆栈方式。
RTX任务调试信息:
13.8.png
Event Value:任务AppTaskMsgPro当前的事件标志数值。
Event Mask:任务AppTaskMsgPro等待的事件标志数值。
程序设计:
任务栈大小分配:
    staticuint64_t AppTaskUserIFStk[512/8];   /* 任务栈 */
    staticuint64_t AppTaskLEDStk[256/8];      /* 任务栈 */
    staticuint64_t AppTaskMsgProStk[512/8];  /* 任务栈 */
    staticuint64_t AppTaskStartStk[512/8];     /* 任务栈 */
    将任务栈定义成uint64_t类型可以保证任务栈是8字节对齐的,8字节对齐的含义就是数组的首地址对8求余等于0。如果不做8字节对齐的话,部分C语言库函数,浮点运算和uint64_t类型数据运算会出问题。
系统栈大小分配:
13.9.png
RTX初始化:
  1. /*
    6 d& U& Y% S/ U" L/ C
  2. *********************************************************************************************************
    8 O  j: x, e; X9 f: A- Y
  3. *    函 数 名: main
    ' N1 c. |- A0 B+ P
  4. *    功能说明: 标准c程序入口。4 t" s. u" N3 h, M. j' M
  5. *    形    参: 无' X" z" f8 G, j
  6. *    返 回 值: 无
    ' L. f8 ?# n: r( y4 }) E
  7. *********************************************************************************************************" L! }6 ]& c1 ?$ J) V
  8. */
    , M: R0 l: n- p/ x7 M7 Y- S- q
  9. int main (void)
    ! w7 G' G2 ^1 W6 B0 e% I* w+ @
  10. {   : y& c) c, ^. [. j
  11.      /* 初始化外设 */3 w% f1 c& e6 y6 g4 D2 X/ V
  12.      bsp_Init();
      T4 w8 U5 }8 c, \# H: n/ n
  13.    
    % Z5 j. F# c* c
  14.      /* 创建启动任务 */
    $ B9 i' f% y) [; P1 ~, v, k" D" |
  15.      os_sys_init_user (AppTaskStart,             /* 任务函数 */, s" \  T/ X. H: s4 m- ]
  16.                        4,                        /* 任务优先级 */
    * ^6 V# C1 U" ]6 @
  17.                        &AppTaskStartStk,         /* 任务栈 */+ q% s, E, ^' p8 }# X
  18.                        sizeof(AppTaskStartStk)); /* 任务栈大小,单位字节数 */
    - }1 u: H2 W6 c$ Y7 L$ D; x8 `" h
  19.      while(1);  w0 e7 `% ~7 p0 G
  20. }
复制代码
) X# Q5 v" D8 G: i
RTX任务创建:
  1. /*
    ! h: l( Z7 u6 d. Q
  2. *********************************************************************************************************
    ! |# B, k1 C9 X7 c
  3. *    函 数 名: AppTaskCreate
      M, U! W( Q$ t1 x0 M  L9 c& B6 J# y
  4. *    功能说明: 创建应用任务
    ; K0 _2 i* f2 t, u
  5. *    形    参: 无
    ) v1 r! A( P+ U! O% V
  6. *    返 回 值: 无
    & E& }+ p, J/ S# a& t8 H# T
  7. *********************************************************************************************************
    , p+ \- j& ?9 e: B- I1 y
  8. */: L/ r/ ?+ t4 _3 k( V3 j3 i7 Q
  9. static void AppTaskCreate (void)
    % m9 [: ~7 ?- m7 m
  10. {
    - x  @2 g$ K9 r4 z4 ?1 i
  11.      HandleTaskUserIF = os_tsk_create_user(AppTaskUserIF,             /* 任务函数 */
    3 X/ s0 I& t) L# Q
  12.                                            1,                         /* 任务优先级 */5 E+ u' Z7 @( y1 @
  13.                                            &AppTaskUserIFStk,         /* 任务栈 */
    3 K. G7 `% N9 B$ p3 r- W
  14.                                            sizeof(AppTaskUserIFStk)); /* 任务栈大小,单位字节数 */
    7 w, l: f- x* t# D9 C
  15.    
    % U8 z9 J" E# s# [7 H4 f% `! c
  16.      HandleTaskLED = os_tsk_create_user(AppTaskLED,              /* 任务函数 */
    2 Q" q+ G$ H; q' M9 M- X- E  B
  17.                                         2,                       /* 任务优先级 */
    2 q. @7 a+ _7 {, \% ^
  18.                                         &AppTaskLEDStk,          /* 任务栈 */' L4 K" ~! K: W6 t5 U' g* I
  19.                                         sizeof(AppTaskLEDStk));  /* 任务栈大小,单位字节数 */  E# H8 X% X0 M+ X9 _; K
  20.    
    3 l3 ]9 |, F0 V4 K: \
  21.      HandleTaskMsgPro = os_tsk_create_user(AppTaskMsgPro,             /* 任务函数 */" c2 d6 r. s  K; g$ A1 V
  22.                                            3,                         /* 任务优先级 */* x7 t+ @1 X- T+ q( a' R
  23.                                            &AppTaskMsgProStk,         /* 任务栈 */" Y* u) C( v! [# _
  24.                                            sizeof(AppTaskMsgProStk)); /* 任务栈大小,单位字节数 */" H6 `2 R2 D. t+ V2 p, `; C5 N
  25. }
复制代码
" R1 z: B5 K8 i$ u
四个RTX任务的实现:
  1. /*! r* e2 f4 F+ z# W" U$ _& S4 e" d
  2. *********************************************************************************************************
    1 [' N  ?) O0 u( |4 n
  3. *    函 数 名: AppTaskUserIF5 x- y' p6 M: I: V' {
  4. *    功能说明: 按键消息处理     
    ; o: y. ~6 G. k9 L. B
  5. *    形    参: 无/ M" x+ J* X' B
  6. *    返 回 值: 无4 U5 H5 Y" T' z+ M
  7. *   优 先 级: 1  (数值越小优先级越低,这个跟uCOS相反). ]5 Y+ @- J0 T! [6 K
  8. *********************************************************************************************************# ]/ z) L2 T( c2 B; v  I1 K4 i, k
  9. */
    ; d  l) Y6 n+ Y2 J; t, c/ w, `
  10. __task void AppTaskUserIF(void)$ l$ }& v8 E! s3 \9 N
  11. {
    8 ^4 ~' _1 q2 e$ X
  12.      uint8_t ucKeyCode;3 h- [$ P( S: ], F6 |* Z4 E: H

  13. ; u0 W  ]7 r' O# x. X6 ^
  14.     while(1)4 T7 X! Y9 d% K0 h/ k* n1 Z
  15.     {, O6 T- ^, f, L+ M
  16.          ucKeyCode = bsp_GetKey();
    1 k$ @5 k, Y& p' O) @- M
  17.         6 [0 ^* Z8 B# e# V5 a" u
  18.          if (ucKeyCode != KEY_NONE)# U( C! E8 K4 h$ ]. V
  19.          {
    2 N: `3 T; @' T! @$ R" ~8 E
  20.               switch (ucKeyCode)
    % u7 A# [6 u6 q  S1 Q$ v. i; w) c
  21.               {5 z/ w$ `* j" I% }' p% j4 k
  22.                    /* K1键按下,打印调试说明 */
    - p# [  T  X5 a% z
  23.                    case KEY_DOWN_K1:4 H' E) ]/ }6 N- c1 U$ Y  o
  24.                        printf("K1键按下,使用MDK中自带的RTX调试组件,请务必使用MDK4.74版本进行调试\r\n");
    0 m; ]: n. q4 v! o; q' l3 y+ M
  25.                        break;  
    2 G( v+ y- r& E$ a* ]9 r
  26. ; L, S; Z8 A, s) L. L: j% B' ]1 I: t& a
  27.                    /* K2键按下,直接发送事件标志给任务AppTaskMsgPro,设置bit0 */
    * n# y9 @5 Y& J( j/ K
  28.                    case KEY_DOWN_K2:
    ( D& L7 |3 H  h% J( t2 }
  29.                        printf("K2键按下,直接发送事件标志给任务AppTaskMsgPr,bit0被设置\r\n");# X  v7 C2 U& i& O( s* ~
  30.                        os_evt_set (BIT_0, HandleTaskMsgPro);
      i6 P$ E: ]- A- E: D% E
  31.                        break;
    9 P" h& F# M, k/ J) A
  32.                   
    : @: b  N; }0 [7 C2 V7 H. X0 T' V
  33.                    /* K3键按下,直接发送事件标志给任务AppTaskMsgPro,设置bit1 */
    , j, k1 C% o" j: e
  34.                    case KEY_DOWN_K3:& `& h; f7 ?" Z5 Z% a" p
  35.                        printf("K3键按下,直接发送事件标志给任务AppTaskMsgPro,bit1被设置\r\n");$ W0 Q$ C5 E; {
  36.                        os_evt_set (BIT_1, HandleTaskMsgPro);
    ) S. Q% u$ Z  x$ T" i3 P
  37.                        break;% V9 b; Q& m7 w5 D& `
  38. 5 B* ~3 F7 w1 e9 V$ Y9 _6 ]* i6 Z
  39.                    /* 其他的键值不处理 */
    ) s8 P* W. D8 i, |/ E% e
  40.                    default:                    1 i3 r+ n: E% H+ K
  41.                        break;1 R2 R8 R% }% r( R* |. w; n+ Y7 C7 O! E
  42.               }) ?9 F$ W6 I9 ^4 `( O8 j
  43.          }" U$ [1 T+ i) x. j$ }9 Z
  44.         - p7 h+ o) I( G2 H. K! R6 g9 i
  45.          os_dly_wait(20);6 T+ C! c5 u2 `0 d, f- I# X* Y
  46.      }: `7 C6 f+ U6 C* C" K( |
  47. }
    + ~. q" o6 |6 l4 o7 [/ H8 p
  48.   u7 ^( A. w3 h+ e0 k
  49. /*8 g$ D2 z! k8 H
  50. *********************************************************************************************************
    ' T3 Z" p; a& N/ O
  51. *    函 数 名: AppTaskLED
    ' [2 S% Z& @! @" N$ k- ^8 v
  52. *    功能说明: LED闪烁。& |' m" s+ ^" `# C
  53. *    形    参: 无
    & @, E6 C- W& h$ D5 I0 x
  54. *    返 回 值: 无
    ' l# O. p  Z+ V" H7 Q! L6 B
  55. *   优 先 级: 2 : e, _% P. m& a
  56. *********************************************************************************************************
    + C; O1 u: V: {6 |  a
  57. */
    + O5 o4 {6 @: |% {& L
  58. __task void AppTaskLED(void)
    7 f5 X" ^, P0 m, V- h8 `6 H
  59. {
    , B, b' R2 ?! d; E9 d
  60.      const uint16_t usFrequency = 200; /* 延迟周期 */
    . G* ]; L5 x! s- U# v( c! M" t
  61.     ; g. `. ~1 W) m! Y  M# Q8 F
  62.      /* 设置延迟周期 */7 X6 M2 M0 X2 j6 ?
  63.      os_itv_set(usFrequency);# r$ Y: e# W5 l5 h/ ^2 h4 Q1 x# y
  64.    
    0 g6 ~9 U( Z/ B& U
  65.     while(1)% r; [7 p" K0 L, d  E
  66.     {
    ) U  F) B. U$ N/ d& v& {/ e! ?
  67.          bsp_LedToggle(2);
    $ k# o# Q- U. M6 ^" X5 s
  68.          bsp_LedToggle(3);  y1 `# v5 L6 f* y

  69. # O/ v" [! U5 y  |, ~. Y- T
  70.          /* os_itv_wait是绝对延迟,os_dly_wait是相对延迟。*/
    6 ^8 M/ V* y' e" E
  71.          os_itv_wait();! x& z; i" H3 o- o+ U
  72.     }
    " ]  l, ]! f7 K) y5 _0 |% n" m! V
  73. }
    . o9 K2 K) g# \9 L
  74. 9 ?0 i3 l8 Z; X* H! ?5 q
  75. /*
    : U$ s0 m" b2 z  }) t
  76. *********************************************************************************************************
    ! S& ]1 m% e/ m& b
  77. *    函 数 名: AppTaskMsgPro
    9 l! d4 |! U( B$ Y4 E/ K1 h
  78. *    功能说明: 消息处理,等待任务AppTaskUserIF发来的事件标志6 c' ^+ e5 t5 D2 \: x
  79. *    形    参: 无9 J3 b- ^! Z4 h; e8 M
  80. *    返 回 值: 无
    * P% V. x% d7 d' W
  81. *   优 先 级: 3
    * w) }; A" v" T' {
  82. *********************************************************************************************************/ d# f: J) Q/ F  z* ?
  83. */- O; x7 A- ^& R
  84. __task void AppTaskMsgPro(void)
    % Q* N* H+ v2 o$ o$ A. r
  85. {1 n7 x. s. h, o2 J% |& m9 k' G0 _
  86.      OS_RESULT xResult;3 E7 r9 T) Q% O6 W$ D; S" o1 E
  87.      const uint16_t usMaxBlockTime = 500; /* 延迟周期 */
    8 Y8 v5 w3 B& N; R$ c
  88.     $ _0 }' V& C; n# {+ I) C* E2 }; I
  89.     while(1)
    - t, G, d; E9 [% U4 _! E
  90.     {. k- _+ T- P! o8 e, \  y/ v
  91.          /*  l& A8 v! _8 U7 J& ]
  92.            1. 等待K2按键按下设置bit0和K3按键按下设置bit1,都设置了执行OS_R_EVT消息; f  \2 L) I9 l( i2 z
  93.            2. 退出前bit0和bit1被清除,这里是bit0和bit1都被设置才表示“退出”。  y3 W& C# b; t1 n' v6 u2 L( o
  94.            3. 每个任务都有自己的16位事件标志位,也就是os_evt_wait_and的第一个参数是无符号16位整形。
    ' A) `/ K- B/ O/ Q
  95.          */4 M" A, |7 g6 M; ~1 T
  96.          xResult = os_evt_wait_and (BIT_ALL, usMaxBlockTime);
    * @, ^  f% ?7 U# R6 E  f2 n* e
  97.         
    & D, X9 y2 p) W/ c6 k" D/ T' y/ V# _
  98.          switch (xResult)
    8 c) y/ \9 u; ?$ p6 \6 `  Q
  99.          {- b9 ]+ v' Q& n& v( w: M0 @
  100.               /* 接收到bit1和bit0都被设置的消息 */
    ( ~6 U( I/ H9 @: m3 i& x
  101.               case OS_R_EVT:! m! r  I" g5 d
  102.                    printf("接收到bit0和bit1都被设置的消息\r\n");0 I: F  x7 l7 ]
  103.                    break;  
    $ ^1 ~6 v+ V% A" s0 c2 B9 e
  104. 3 Y& x9 o" Y* r, w$ q  ]: C
  105.               /* 超时 */
    8 \/ f8 ^0 N( K: K7 b. `
  106.               case OS_R_TMO:
    6 d4 ~+ w1 E( N/ ^9 j
  107.                    bsp_LedToggle(1);
    & N. r( t$ h5 t9 m5 d
  108.                    bsp_LedToggle(4);
    & x5 m% S# r+ Z! v
  109.                    break;
    6 \  A/ G# G% \1 o7 j9 k
  110.              ' C4 v3 X/ h# _: z/ ?: |
  111.               /* 其他值不处理 */. A+ ]2 D/ ]- _2 C" c' e/ l5 k
  112.               default:                    1 D/ p8 {! x/ P! y- ?% U+ G4 c
  113.                    break;/ B+ M3 }$ j' r1 E
  114.          }   9 V! y6 ?( V& K
  115.     }+ Y) R/ O8 |! k5 e( ?
  116. }+ L& x- n- F6 |7 U

  117. 5 x& @+ c' @2 D6 R2 U
  118. /*, V! B' Q1 N: h+ a' C) A1 W: I
  119. *********************************************************************************************************
    8 g! [7 |- @. v. a6 y  W
  120. *    函 数 名: AppTaskStart
    * Q7 o' w" r! a; Q" F2 P+ n, n9 g0 x
  121. *    功能说明: 启动任务,也就是最高优先级任务。这里实现按键扫描。
    : A+ r7 T" A* O9 `7 R
  122. *    形    参: 无
    9 b4 y/ O) B; L+ F
  123. *    返 回 值: 无' u5 M4 T; d( W9 C. z# u
  124. *   优 先 级: 4
    ; d! M5 E% E* p* g6 J8 j
  125. *********************************************************************************************************
    8 B9 ]1 Y" [9 M7 A
  126. */
    - }" k; O2 h# u, z) o- u0 x
  127. __task void AppTaskStart(void)9 E4 B7 V1 F1 F& ?3 @, i
  128. {
    2 N4 e4 k: K1 r
  129.      /* 创建任务 */6 B1 k6 J% q. x2 a7 h! K
  130.      AppTaskCreate();4 \4 `9 K  n* N: C6 D/ d
  131.     / I8 y' J* D, q+ Q" X' Q/ Z
  132.     while(1), p" P' X( ?/ D1 ?1 w1 \
  133.     {1 R9 r/ }2 [& a) @5 p# Z; `. L
  134.          /* 按键扫描 */3 A! _# U  T) Y' I, f% n
  135.          bsp_KeyScan();
    4 o5 _, l  j. r3 y! \0 I! d- J4 E( @
  136.         os_dly_wait(10);
    5 S* }3 ?8 `. z! L7 i# \; [
  137.     }3 W: }* K$ ^" ^' x' w
  138. }
复制代码

2 b- n4 ~) F  W, X- y% R
; e! R9 s8 g- [1 ~; j; _
zhangdaijin 回答时间:2016-1-27 17:26:17
谢谢分享
baiyongbin2009 回答时间:2016-1-27 17:33:58
13.4 实验例程说明(中断方式通信)
# L& ~. Y. L, l. x
13.4.1 STM32F103开发板实验
配套例子:
    V4-410_RTX实验_事件标志组(中断方式)
实验目的:
    1. 学习RTX的事件标志组(中断方式)
实验内容:
    1.     K1按键按下,串口打印。
    2.     K2键按下,启动单次定时器中断,50ms后在定时器中断给任务AppTaskMsgPro发送事件标志,设置bit0。
    3.     K3键按下,启动单次定时器中断,50ms后在定时器中断给任务AppTaskMsgPro发送事件标志,设置bit1。
    4. 任务AppTaskMsgPro只有接收到bit0和bit1都被设置了才执行串口打印信息。               
    5. 各个任务实现的功能如下:
   AppTaskUserIF任务  :按键消息处理。
    AppTaskLED任务     :LED闪烁。
    AppTaskMsgPro任务 :消息处理,等待定时器中断发来的事件标志。
    AppTaskStart任务    :启动任务,也是最高优先级任务,这里实现按键扫描。
RTX配置:
    RTX配置向导详情如下:
                              
13.10.png
Task Configuration
    Number of concurrent running tasks
    允许创建4个任务,实际创建了如下四个任务
                  AppTaskUserIF任务   :按键消息处理。
                  AppTaskLED任务     :LED闪烁。
                  AppTaskMsgPro任务 :消息处理,等待定时器中断发来的事件标志。
                  AppTaskStart任务    :启动任务,也是最高优先级任务,这里实现按键扫描。
     Number of tasks with user-provided stack
     创建的4个任务都是采用自定义堆栈方式。
RTX任务调试信息:
13.11.png
Event Value:任务AppTaskMsgPro当前的事件标志数值。
Event Mask:任务AppTaskMsgPro等待的事件标志数值。
程序设计:
任务栈大小分配:
    staticuint64_t AppTaskUserIFStk[512/8];   /* 任务栈 */
    staticuint64_t AppTaskLEDStk[256/8];      /* 任务栈 */
    staticuint64_t AppTaskMsgProStk[512/8];  /* 任务栈 */
    staticuint64_t AppTaskStartStk[512/8];     /* 任务栈 */
    将任务栈定义成uint64_t类型可以保证任务栈是8字节对齐的,8字节对齐的含义就是数组的首地址对8求余等于0。如果不做8字节对齐的话,部分C语言库函数,浮点运算和uint64_t类型数据运算会出问题。
系统栈大小分配:
13.12.png
RTX初始化:
  1. /*
    2 W  I7 R0 S9 z: S& c6 |# m  n, b1 R( H, ?
  2. *********************************************************************************************************  c& U9 `/ y8 G4 h9 h1 E/ C) ?
  3. *    函 数 名: main7 g  k1 m% x. M2 f% M# U8 N5 l0 ~
  4. *    功能说明: 标准c程序入口。
    - m1 A; v; e; h: {
  5. *    形    参: 无
    ; H/ ^  A1 y' N8 v# V
  6. *    返 回 值: 无  q; s8 Y- Y* E  P; f: J# N' _
  7. *********************************************************************************************************
    2 C4 i& R6 V5 P/ U3 P
  8. */
    # o/ Z. A' i: @- ^( Z6 J
  9. int main (void)
    ; _: Q6 |5 @" u/ R0 F0 \0 x
  10. {   ! |# y( _  _# o# A- t, J' @, t
  11.      /* 初始化外设 */
    : m; a" w- M1 M" i8 l2 j
  12.      bsp_Init();
    ( g8 G7 j/ x" r% d. z
  13.    
    ( u8 z3 W3 V$ u
  14.      /* 创建启动任务 */1 [6 M! g3 z  }: D
  15.      os_sys_init_user (AppTaskStart,             /* 任务函数 */$ H. S0 _1 f+ i) D$ j
  16.                        4,                        /* 任务优先级 */( G) r* K& w( B' d$ ]( o
  17.                        &AppTaskStartStk,         /* 任务栈 */  v2 H( r* ]% z
  18.                        sizeof(AppTaskStartStk)); /* 任务栈大小,单位字节数 */" V+ V3 F/ y/ E5 x4 \
  19.      while(1);% Y& V% [. i# m: A7 D7 Z' `7 r0 ]% `
  20. }
复制代码
4 _6 n4 L# q) C
RTX任务创建:
  1. /*8 w" l; z+ }$ U3 a( i) S
  2. *********************************************************************************************************
    ; D. i+ V  Z8 X6 |! @
  3. *    函 数 名: AppTaskCreate" e! E! `5 L# Z% V) z% U4 }6 k
  4. *    功能说明: 创建应用任务
      t6 |- G3 e  H8 C$ ~/ S
  5. *    形    参: 无
    " `8 i& s6 ?- C, C$ X
  6. *    返 回 值: 无6 R0 Z! f% H0 v1 j
  7. *********************************************************************************************************, M7 k) c4 u4 t. V- I& q
  8. */
    3 k) J* }9 X! K" m% \+ ~
  9. static void AppTaskCreate (void)
    ; a2 i, Z0 v# \
  10. {. R  i$ G- E6 U3 }7 E* J7 g
  11.      HandleTaskUserIF = os_tsk_create_user(AppTaskUserIF,             /* 任务函数 */
    & v: b2 f; d$ h9 {% F: x/ s8 r& \6 q
  12.                                            1,                         /* 任务优先级 */
    " f7 y' e, M0 D$ o- T# i
  13.                                            &AppTaskUserIFStk,         /* 任务栈 */, e$ j  Z; c- F9 j8 z
  14.                                            sizeof(AppTaskUserIFStk)); /* 任务栈大小,单位字节数 */
    ) S7 ~5 Z5 i& v- _9 a+ d6 F
  15.     , g3 U# T0 z  X" N
  16.      HandleTaskLED = os_tsk_create_user(AppTaskLED,              /* 任务函数 */
    " J5 T6 ]( j2 M, ?% Z, k* W& c
  17.                                         2,                       /* 任务优先级 */- D! a$ ~/ n- Y. O# i4 R  L
  18.                                         &AppTaskLEDStk,          /* 任务栈 */
    # j2 }; f& c$ Z* M" f4 X( U
  19.                                         sizeof(AppTaskLEDStk));  /* 任务栈大小,单位字节数 */$ @* U9 ?& n  x' P9 N0 L
  20.     / n/ L0 R2 q7 v; I$ {
  21.      HandleTaskMsgPro = os_tsk_create_user(AppTaskMsgPro,             /* 任务函数 */: m8 i8 [, d+ m. J7 q8 {9 H
  22.                                            3,                         /* 任务优先级 */8 T+ S3 q# e% k% b
  23.                                            &AppTaskMsgProStk,         /* 任务栈 */
    ( G0 h' A- O9 L! P# I$ i  {
  24.                                            sizeof(AppTaskMsgProStk)); /* 任务栈大小,单位字节数 */. C1 f; E" R" x3 I- n! ]7 w  R8 l
  25. }
复制代码

7 ]2 ]+ Y! U( ], l+ T( {& ]: B
四个RTX任务的实现:
  1. /*$ T" P6 c$ v, p" v  t
  2. *********************************************************************************************************
    5 v% N! d- {$ e- T# `
  3. *    函 数 名: AppTaskUserIF0 }3 [- _: W: K' X
  4. *    功能说明: 按键消息处理     ) b3 u* x" v* L8 k
  5. *    形    参: 无
      H1 h. |% r' }. R" ^( K% _
  6. *    返 回 值: 无
    $ P$ C" l  b8 h7 G3 m2 J$ S
  7. *   优 先 级: 1  (数值越小优先级越低,这个跟uCOS相反). J3 Y5 p2 [+ t5 x; N" M; n' q. @6 C( b
  8. *********************************************************************************************************
    ' a. y' Y8 O2 i0 i( r. n: ^& V& D2 w
  9. */5 I# V, q$ p% c$ Y
  10. __task void AppTaskUserIF(void). J3 e5 m' [5 [9 v$ l! D$ f
  11. {
    , d8 J" E! A; M, Y+ Q
  12.      uint8_t ucKeyCode;
    ! V2 O% ^8 S" ?5 E  k8 {$ s1 E
  13. ; k1 W( v2 f! h* r1 [) X7 X. y
  14.     while(1)5 n# r1 u  b0 i3 Y0 C8 Z
  15.     {1 s: I  R& E4 z5 ~4 y% x6 C
  16.          ucKeyCode = bsp_GetKey();3 u7 ]/ p* @. R% D" @% E
  17.         
    8 n7 `5 T, P& ^- R1 w! S3 J
  18.          if (ucKeyCode != KEY_NONE)
    : I8 B' P/ z+ G
  19.          {
    5 d' n2 J$ F! A) Z8 }8 h
  20.               switch (ucKeyCode). Z5 z0 ?4 h* R7 I9 C9 Q) h
  21.               {3 Y0 R0 I7 ]; @0 ?5 }% ]
  22.                    /* K1键按下,打印调试说明 */& t+ m& B; J9 `0 @7 F+ _
  23.                    case KEY_DOWN_K1:
    ! F6 f% Y7 X" L4 j& Q/ t8 e
  24.                        printf("K1键按下,使用MDK中自带的RTX调试组件,请务必使用MDK4.74版本进行调试\r\n");
    , l. h7 m0 z2 J) ~4 }' Z
  25.                        break;  
    8 t' P# r7 O3 B8 g) J# K
  26.                   4 u# F" H0 n0 }6 F) N- z
  27.                    /* K2键按下,启动单次定时器中断,50ms后在定时器中断给任务AppTaskMsgPro发送事件标志 */
    * x/ J; [5 \5 c+ U/ r
  28.                    case KEY_DOWN_K2:" q& E& @- i# @) e6 h
  29.                        printf("K2键按下,启动单次定时器中断,50ms后在定时器中断给任务AppTaskMsgPro发送事5 T  k0 w8 k4 S! ]! |
  30. 件标志\r\n");! U& j4 t- p# g8 D+ D& ^1 x

  31. * g6 Z3 E% u' [
  32.                        bsp_StartHardTimer(1 ,50000, (void *)TIM_CallBack1);' C# @$ j7 _. W) o& p
  33.                        break;
    & f1 M2 D9 Y: M; |- ?3 c# ]
  34.                   
    : ^2 i/ B7 X5 k9 p+ y4 o
  35.                    /* K2键按下,启动单次定时器中断,50ms后在定时器中断给任务AppTaskMsgPro发送事件标志 */5 o% c4 |1 ~8 y! L! o. R
  36.                    case KEY_DOWN_K3:
    5 Y  V- K) f9 L8 J% G; H# N6 w
  37.                        printf("K3键按下,启动单次定时器中断,50ms后在定时器中断给任务AppTaskMsgPro发送事. f$ D  |# ?$ s: K$ V4 H
  38. 件标志\r\n");
    1 s: e7 X: f$ N7 m$ z2 V( N

  39. 2 t. R5 E4 K6 a% k" a6 \
  40.                        bsp_StartHardTimer(1 ,50000, (void *)TIM_CallBack2);
    2 {; p" O+ O6 u
  41.                        break;
    / k' d% u8 ?. Z# t4 B  F2 k6 I
  42. # h0 o* {( _. \* B: X# Y/ d7 X
  43.                    /* 其他的键值不处理 */1 K' _; [% n8 B$ m
  44.                    default:                    : p$ P  D. n8 }! j# ?! G2 u' F
  45.                        break;; o3 f6 o  K$ a' W! V
  46.               }
    $ s2 X. [+ y2 d8 ^& U
  47.          }
    . N0 r) d% s, b1 k# Y3 W' B" n
  48.         ( g) y9 W8 b2 I, t
  49.          os_dly_wait(20);; Q# Z2 A7 A( P5 n+ n1 }
  50.      }9 s. J' u# ]2 I9 X3 [, [
  51. }) s" D( c- S. y+ s' c

  52. 6 ^. [* s( @" u9 r
  53. /*  z3 T# m8 V  b. v
  54. *********************************************************************************************************
    7 ]1 g+ D, u# ^
  55. *    函 数 名: AppTaskLED
    , V+ }% x6 }8 m( E
  56. *    功能说明: LED闪烁。/ d* o( r, `1 ^6 S3 z5 w% e4 H
  57. *    形    参: 无2 i: I9 k8 c1 M! _, I& E6 U
  58. *    返 回 值: 无# [5 ~) h4 H4 ]" a0 Z4 j5 q7 R
  59. *   优 先 级: 2
    . E1 e, N+ A% E" y- |8 y3 I: h
  60. *********************************************************************************************************4 r! @! ^! u9 |" R4 [
  61. */
    ! [+ h  a; R) P8 a
  62. __task void AppTaskLED(void)
    6 H" D) O4 h& [& ~4 U7 D
  63. {
    0 W% I6 K9 v% K. }, Y
  64.      const uint16_t usFrequency = 200; /* 延迟周期 */4 P3 |( K1 V$ d6 w& b
  65.    
    2 p& }, S7 }' L7 A' L$ F
  66.      /* 设置延迟周期 */
    5 S$ A, j# N4 A4 |. d
  67.      os_itv_set(usFrequency);/ {6 z- ?2 N" J0 ~  O
  68.    
    ! K* F; n( r7 j( N( Q1 l
  69.     while(1)
      o% P! m/ M: |' [: T! d
  70.     {
    1 ]4 {* ?- y6 @0 M9 p
  71.          bsp_LedToggle(2);
    6 n1 U' }; M( K) p/ T6 Z
  72.          bsp_LedToggle(3);8 s% k  |% t9 s

  73.   l/ p& H& p, i; H$ S' u
  74.          /* os_itv_wait是绝对延迟,os_dly_wait是相对延迟。*/, P- q- U3 i& e$ O( }5 {' q( Q# U
  75.           os_itv_wait();
    6 f: E4 X) [& E/ I+ _
  76.     }
    4 s# v0 P" O+ N% H" f8 |3 J1 c
  77. }- W( k; w: B0 n, K& h+ ^+ g
  78. * O! Z+ q+ n! m) t" M$ e& Y
  79. /*& f' a0 D4 V8 U( T- \2 \! h, B( `
  80. *********************************************************************************************************
    ' N5 B& Z# k6 k; P) F8 F
  81. *    函 数 名: AppTaskMsgPro8 X" x* {6 y3 t
  82. *    功能说明: 消息处理,等待定时器中断发来的事件标志: q# Q" i8 s9 h  C( B
  83. *    形    参: 无
    ; O6 |/ Y% m' }2 w4 D6 m" @
  84. *    返 回 值: 无
    . s# |, U: k. E7 j. ?
  85. *   优 先 级: 3
    4 b2 L) u# c/ l! I) d9 b) U
  86. *********************************************************************************************************
    ; U# L7 ~% ]+ s' R4 G2 j5 l+ @
  87. */% R; G; w) i1 w4 N: k
  88. __task void AppTaskMsgPro(void)
    & I9 ~+ R6 |- L0 l0 y5 C
  89. {7 x. b* ~& B4 V: {2 D8 P
  90.      OS_RESULT xResult;2 r5 U/ L1 S( G; P7 A
  91.      const uint16_t usMaxBlockTime = 500; /* 延迟周期 */* V# r( U/ p  R% M2 I. h* `
  92.    
      S$ ?- h( @! Q+ Z7 |/ z
  93.     while(1)! O/ F5 v/ v# a8 L) `: a0 Y* o
  94.     {
    6 H, j- q3 ]9 n$ k% h
  95.          /*% i0 g. N5 _) N& I
  96.            1. 等待K2按键按下设置bit0和K3按键按下设置bit1,都设置了执行OS_R_EVT消息5 @/ F1 Q; I4 a% o# `6 `: n
  97.            2. 退出前bit0和bit1被清除,这里是bit0和bit1都被设置才表示“退出”。
    $ p: r* x/ b) t$ r! k
  98.            3. 每个任务都有自己的16位事件标志位,也就是os_evt_wait_and的第一个参数是无符号16位整形。
    $ O/ V( K# a" W! C& g
  99.          */% {/ ~+ u* J5 ~& w0 N2 {
  100.          xResult = os_evt_wait_and (BIT_ALL, usMaxBlockTime);1 b( E8 s2 e! v7 C2 F, ~/ ?
  101.         
    5 R2 |( B2 }/ t2 \# P( \
  102.          switch (xResult)% B* T: \( f! Q2 B$ N  R( N/ L
  103.          {, t6 J% A4 w- E7 I, {! B* M1 R& E
  104.               /* 接收到bit1和bit0都被设置的消息 */
    1 {0 z  ?& j( j1 |4 ]
  105.               case OS_R_EVT:
    9 h+ Y6 I2 [, U( A' W
  106.                    printf("接收到bit0和bit1都被设置的消息\r\n");/ W* z! z( _) z
  107.                    break;  
    , _  @' N4 |+ s1 N
  108. 4 T' p& ?) ?9 _9 V" ]1 \
  109.               /* 超时 */
    * N2 w1 p. b: t4 T3 r6 m
  110.               case OS_R_TMO:
    8 T  @; v2 ~1 t& [6 Y* S
  111.                    bsp_LedToggle(1);
    1 Z4 g3 R5 ]5 }* p  w) M; l
  112.                    bsp_LedToggle(4);9 H7 r: j7 _/ O9 [' F5 `2 P3 u
  113.                    break;6 p! U0 f% i1 h$ p) C
  114.              4 W1 D3 b; Y& V9 D0 \
  115.               /* 其他值不处理 */
    - y& }6 x& i" S$ u+ }4 H
  116.               default:                    $ I. u* u. [: g6 _
  117.                    break;, Q/ k! b! W' f2 o* o: n! ^9 r
  118.          }   
    $ J% t  H  H# R) O
  119.     }
    + r) q$ Z! k0 N" U9 F
  120. }
    ) O8 ~! H0 e; E4 C

  121. / A8 b. U5 j$ \* e
  122. /*) t  T+ o; K, p& I
  123. *********************************************************************************************************/ A9 L# x9 S5 l8 q  O5 i
  124. *    函 数 名: AppTaskStart7 s7 K$ B' r, A
  125. *    功能说明: 启动任务,也就是最高优先级任务。这里实现按键扫描。7 a5 Q9 @. n+ }" e7 V, t2 `" E
  126. *    形    参: 无3 X: N) O0 x& w. ~; g7 w; ]) l
  127. *    返 回 值: 无' l2 W' b/ ~; [: Z) h6 t1 l) B
  128. *   优 先 级: 4 ; E( Q& o$ }7 K
  129. *********************************************************************************************************
    ' Q  q+ h% B$ o+ a+ Q7 o# U; W
  130. */
    6 {) f7 j" t* Z. }. k! A" t+ m
  131. __task void AppTaskStart(void)5 i6 N0 w" n6 E
  132. {
    & W8 v9 L. w9 g! w( R7 C
  133.      /* 创建任务 */
    : n1 v2 `5 b% V0 ]' m. b8 }" _, k- m; E
  134.      AppTaskCreate();
    : W2 a% d6 `4 V
  135.    
    ; r/ z) w% v, t9 p" b- `
  136.     while(1)* @  f  D6 q0 F% B2 F8 t/ h
  137.     {
    6 |' O2 H& o1 c$ N: q4 K* E' U- s8 c
  138.          /* 按键扫描 */
    - y3 `  S' r9 P  q. }" d  _
  139.          bsp_KeyScan();% z- T3 s: ~& Q& g
  140.         os_dly_wait(10);
    7 [  M5 d7 Q  E9 d. N* Z9 M
  141.     }
    % e7 S/ O1 e- t6 M4 a( k8 F
  142. }
复制代码

; T# d# p5 ?8 A8 c! s; S
定时器中断回调函数中发送事件标志:
    定时器中断的初始化和中断函数在bsp_timer.c文件中实现,这个不是教程的重点,故不作介绍。这里主要关心RTX的事件标志函数在中断服务程序中的使用方法。
  1. /*
    : x2 ]5 }. x& |8 f7 J
  2. *********************************************************************************************************
      Z& Q$ n* u8 X: y+ ]) F
  3. *    函 数 名: TIM_CallBack1
    ( |$ c6 t* b) t& s2 \0 d
  4. *    功能说明: 定时器中断的回调函数,此函数被bsp_StartHardTimer所调用。                        . x* y0 U- u  O+ a( n
  5. *    形    参: 无; z" }* P1 k  r% R- y6 ]+ u
  6. *    返 回 值: 无
    # B8 a3 H! \, ~) c, }! T: k
  7. *********************************************************************************************************0 `1 ]% V, \" Q9 }8 B5 @
  8. */7 J0 M0 x6 m2 {7 P5 x4 ]2 ?3 l
  9. static void TIM_CallBack1(void)$ M. F0 x1 Q( @# x4 p
  10. {9 M# F3 u- V+ o9 s
  11.      /* 发送事件标志,设置bit0 */+ L' C9 X$ j3 Q* b& W1 @/ M
  12.      isr_evt_set (BIT_0, HandleTaskMsgPro);
    ' M) v4 b2 k& w. r# g8 y3 I8 ~
  13. }) S4 |* A* [, k! U+ T3 v2 |" D

  14. 7 ^" R& Y: [" g7 c& Q& Y" P8 K) j
  15. static void TIM_CallBack2(void)
    % z3 G% L$ T- a5 i3 c6 T. j
  16. {! b" Q* a; N, d7 X$ H1 q. c
  17.      /* 发送事件标志,设置bit1 */! D" r5 Y$ p' q7 ?
  18.      isr_evt_set (BIT_1, HandleTaskMsgPro);
    9 k. E9 e/ w" C
  19. }
复制代码
; G( B9 Q) W8 w; ~$ q

0 T; Y! K+ l1 w  x: M: I
) Q' g, ^( |* ~* D  @# J3 \
baiyongbin2009 回答时间:2016-1-27 17:39:38
13.4.2   STM32F407开发板实验
配套例子:
    V5-410_RTX实验_事件标志组(中断方式)
实验目的:
    1. 学习RTX的事件标志组(中断方式)
实验内容:
    1.     K1按键按下,串口打印。
    2.     K2键按下,启动单次定时器中断,50ms后在定时器中断给任务AppTaskMsgPro发送事件标志,设置bit0。
    3.     K3键按下,启动单次定时器中断,50ms后在定时器中断给任务AppTaskMsgPro发送事件标志,设置bit1。
    4.     任务AppTaskMsgPro只有接收到bit0和bit1都被设置了才执行串口打印信息。               
    5.     各个任务实现的功能如下:
    AppTaskUserIF任务  :按键消息处理。
    AppTaskLED任务     :LED闪烁。
    AppTaskMsgPro任务 :消息处理,等待定时器中断发来的事件标志。
    AppTaskStart任务    :启动任务,也是最高优先级任务,这里实现按键扫描。
RTX配置:
    RTX配置向导详情如下:
13.13.png
                              
Task Configuration
    Number of concurrent running tasks
    允许创建4个任务,实际创建了如下四个任务
                AppTaskUserIF任务   :按键消息处理。
                AppTaskLED任务     :LED闪烁。
                AppTaskMsgPro任务 :消息处理,等待定时器中断发来的事件标志。
                AppTaskStart任务    :启动任务,也是最高优先级任务,这里实现按键扫描。
    Number of tasks with user-provided stack
     创建的4个任务都是采用自定义堆栈方式。
RTX任务调试信息:
13.14.png
Event Value:任务AppTaskMsgPro当前的事件标志数值。
Event Mask:任务AppTaskMsgPro等待的事件标志数值。
程序设计:
任务栈大小分配:
    staticuint64_t AppTaskUserIFStk[512/8];   /* 任务栈 */
    staticuint64_t AppTaskLEDStk[256/8];      /* 任务栈 */
    staticuint64_t AppTaskMsgProStk[512/8];  /* 任务栈 */
    staticuint64_t AppTaskStartStk[512/8];     /* 任务栈 */
    将任务栈定义成uint64_t类型可以保证任务栈是8字节对齐的,8字节对齐的含义就是数组的首地址对8求余等于0。如果不做8字节对齐的话,部分C语言库函数,浮点运算和uint64_t类型数据运算会出问题。

: O7 w; ^8 l, T& M
系统栈大小分配:
13.15.png
RTX初始化:
  1. /*
    $ H: v, o+ }- p# y3 e
  2. *********************************************************************************************************
    , I% \9 W& V# V' k- |5 Z
  3. *    函 数 名: main
    ; m% S+ ~9 l% Z8 j' V
  4. *    功能说明: 标准c程序入口。
    0 a1 i: L: J( r' I  H
  5. *    形    参: 无: [( [! p  R! @! y& g1 S& O
  6. *    返 回 值: 无
    * Z8 ]# h. g! M6 B9 ?
  7. *********************************************************************************************************
    0 K! \$ @/ K, f: X/ z
  8. */
    7 o2 {# g4 @  V8 y5 e& e0 Q
  9. int main (void)
    / j7 h' e+ m+ N  e9 U7 g3 @
  10. {   & d0 S; m" K* i5 W
  11.      /* 初始化外设 */; x2 p! l2 J- u4 h! ]& g& }
  12.      bsp_Init();; Q! D' r: v% ?$ @2 S
  13.     , H$ h  a, b- y. j6 i
  14.      /* 创建启动任务 */. k+ P6 X2 d; @1 f# r
  15.      os_sys_init_user (AppTaskStart,             /* 任务函数 */
    - p" N) x4 H! M- ?4 H7 C# l3 i
  16.                        4,                        /* 任务优先级 */$ Q2 J2 j8 I+ ?& z- j  [# x
  17.                        &AppTaskStartStk,         /* 任务栈 */
    , G3 U( f  p+ `# P( u1 F3 }
  18.                        sizeof(AppTaskStartStk)); /* 任务栈大小,单位字节数 */' W$ z0 Q+ P" E, X
  19.      while(1);
    ' m$ \$ [( _, b1 o( Z+ p
  20. }
复制代码

" }6 W. j- W1 H* x4 c
RTX任务创建:
  1. /*. N8 X0 t) ^% R5 u
  2. *********************************************************************************************************
    ( u" }, p) h: ]% ^, M$ _, c3 d- a
  3. *    函 数 名: AppTaskCreate: N3 k& T# g) W8 E4 D# t. i
  4. *    功能说明: 创建应用任务6 H7 r/ |/ A* H2 M
  5. *    形    参: 无
    2 x/ v; }1 [5 \* O2 i: A) q
  6. *    返 回 值: 无
    5 k' B3 f  Z! l5 ~1 t
  7. *********************************************************************************************************; {# `2 d1 q+ g6 ^+ q
  8. */$ b! L7 {: q0 I: R2 N
  9. static void AppTaskCreate (void)9 F( ^. U: ~: O, D7 N
  10. {
    : ^4 l+ u- ^) K% T
  11.      HandleTaskUserIF = os_tsk_create_user(AppTaskUserIF,             /* 任务函数 */2 C8 h! t! l) h- Q/ T! g
  12.                                            1,                         /* 任务优先级 */
    ' ^  X* I% R9 D- [4 Y; _
  13.                                            &AppTaskUserIFStk,         /* 任务栈 */2 N3 l$ v) G2 Y
  14.                                            sizeof(AppTaskUserIFStk)); /* 任务栈大小,单位字节数 */2 H+ V; x5 I( q2 Z; t
  15.    
    0 D9 m& E2 ^" v+ Y
  16.      HandleTaskLED = os_tsk_create_user(AppTaskLED,              /* 任务函数 */% N6 I+ Z- f6 N; t! Q
  17.                                         2,                       /* 任务优先级 */6 J  x1 J( w2 Q: V
  18.                                         &AppTaskLEDStk,          /* 任务栈 */2 z  n- k' B0 S+ ~# W: q  Q/ A/ _& G5 @
  19.                                         sizeof(AppTaskLEDStk));  /* 任务栈大小,单位字节数 */
    - j- {1 [( x  _9 y
  20.     / y' ?% K( N9 J- e  C
  21.      HandleTaskMsgPro = os_tsk_create_user(AppTaskMsgPro,             /* 任务函数 */
    ; F4 k; i! f2 b1 {+ q5 d' W: m0 P
  22.                                            3,                         /* 任务优先级 */. \% ]2 L* p! [# ~- j; [# M
  23.                                            &AppTaskMsgProStk,         /* 任务栈 */- {  H: Q* o8 o
  24.                                            sizeof(AppTaskMsgProStk)); /* 任务栈大小,单位字节数 */
    , k. _' s6 _1 A2 E/ o& G2 G. \
  25. }
复制代码
# E: V) p4 I/ T+ d7 l# }2 A& e! c8 g
四个RTX任务的实现:
  1. /*  a& D. Q+ m7 X5 b
  2. *********************************************************************************************************
    ; j! |( w5 R# z# W8 @$ n# l
  3. *    函 数 名: AppTaskUserIF' s2 Z! [" \7 M! v) [7 s
  4. *    功能说明: 按键消息处理     2 q4 S5 j8 i" {5 w4 i% `
  5. *    形    参: 无
    & s+ D5 _! \1 p/ l& w1 j
  6. *    返 回 值: 无
    0 D' ~6 ~! a! h7 P
  7. *   优 先 级: 1  (数值越小优先级越低,这个跟uCOS相反)# r! n. n; E, \! k* ^8 H' R
  8. *********************************************************************************************************% @: p: E! H& l
  9. */2 y; O5 F7 }* y4 c9 q6 f
  10. __task void AppTaskUserIF(void)
    . M; Q% }( |& H' n. j& I6 z9 s
  11. {, x) `  K# l& L/ [
  12.      uint8_t ucKeyCode;
    2 j" {3 b* P# R' ~- C3 ^

  13. ; N, k1 x8 d1 p" r2 k7 c# M3 F% N( e! f- E
  14.     while(1)
    1 Q) i6 ^9 B# F: h! l# _& U
  15.     {5 g- D: t( m# V5 U0 O7 g
  16.          ucKeyCode = bsp_GetKey();- ?& _8 B7 d$ d2 B; v7 k) L/ N% H
  17.         ) x* S7 s: z3 ~; K
  18.          if (ucKeyCode != KEY_NONE)2 \  b, V6 [$ I9 a% u6 u
  19.          {
    % b7 g' [, k0 N' N; B% d" F+ }5 m* W
  20.               switch (ucKeyCode)
    ' ]; g3 K2 f( p& C, t& p$ R; S
  21.               {
    . |8 H- Q. K  m+ @, ~# n
  22.                    /* K1键按下,打印调试说明 */8 j# c' r* C. B# S' \; R
  23.                    case KEY_DOWN_K1:" B2 l+ A) l3 b- ]. d9 Y
  24.                        printf("K1键按下,使用MDK中自带的RTX调试组件,请务必使用MDK4.74版本进行调试\r\n");4 h) o0 H  e" Z- x8 {4 f
  25.                        break;  
    8 _1 v9 Q" A4 ]8 S: X# k% y* v
  26.                   ' O( N8 I, T1 w2 g1 p+ f" K! @* \
  27.                    /* K2键按下,启动单次定时器中断,50ms后在定时器中断给任务AppTaskMsgPro发送事件标志 */' Z5 R! `: Y& h# K
  28.                    case KEY_DOWN_K2:
      e8 b% B( I3 }
  29.                        printf("K2键按下,启动单次定时器中断,50ms后在定时器中断给任务AppTaskMsgPro发送事) C% f' @% F4 K$ u
  30. 件标志\r\n");
    9 r6 p; Z6 c# k$ Y

  31. ) m) A9 M7 a# ^0 G% m' o- R# m
  32.                        bsp_StartHardTimer(1 ,50000, (void *)TIM_CallBack1);0 K$ K# p1 \& i& v
  33.                        break;: m- u; R, M& i' v* m. ^7 x
  34.                   " O4 |  K" A* n/ v
  35.                    /* K2键按下,启动单次定时器中断,50ms后在定时器中断给任务AppTaskMsgPro发送事件标志 */4 h. a( Y3 M& C" \: a4 b
  36.                    case KEY_DOWN_K3:
    9 Y1 |7 l$ w3 R1 Q3 G
  37.                        printf("K3键按下,启动单次定时器中断,50ms后在定时器中断给任务AppTaskMsgPro发送事
    . B! s  @7 }, s7 o( L  v4 \
  38. 件标志\r\n");
    1 o; R) S& ^+ {! v; K. j3 A

  39. $ B, |% v2 t0 i. `. Z; [
  40.                        bsp_StartHardTimer(1 ,50000, (void *)TIM_CallBack2);5 L* g" R- a. d( |; o
  41.                        break;  Z& R4 W8 c* `
  42. / H$ |1 @1 t3 k, y% W6 P; |
  43.                    /* 其他的键值不处理 */
    2 i9 h& Z  l% M6 J( ~
  44.                    default:                    $ T: f2 V" I( E2 a+ @8 P
  45.                        break;
    2 r& r. Q9 M7 N, H* w9 X# s$ c- ^
  46.               }
    % ~- ~5 _3 Q  M" n9 T
  47.          }4 ^9 W( B) R- A  {4 C
  48.         
    0 i! K) O. {! D) G
  49.          os_dly_wait(20);2 S  \( @' w0 J7 j- U* j
  50.      }
    / b4 [/ u2 \9 j
  51. }
    , c8 g7 j1 a6 |
  52. 0 Z% B" t, N! O$ T# w6 y
  53. /*, {, G. ?" u, ]% l7 U* y0 y3 N
  54. *********************************************************************************************************( P; m, v+ h8 @3 P
  55. *    函 数 名: AppTaskLED: w7 ~" Y" N9 {
  56. *    功能说明: LED闪烁。4 ^( [+ b8 G$ H; [8 P( X
  57. *    形    参: 无
    ( V) ~) R. o( Z. }
  58. *    返 回 值: 无0 S2 S. F# |% e& M5 q, x
  59. *   优 先 级: 2
    - E, Z/ b, c4 U5 u# D
  60. *********************************************************************************************************
    6 H* j6 c5 u5 n, s7 _' x- b7 f
  61. */$ J8 u& I  k( k1 F, V
  62. __task void AppTaskLED(void)+ X) S9 z$ }% N" s( _6 n8 `
  63. {
    ( K1 e  \7 s( H' v, V( c1 q
  64.      const uint16_t usFrequency = 200; /* 延迟周期 */9 ?7 y4 g# a0 D6 t- i: W; ?
  65.    
    9 n) m; J5 `* t5 h" X/ k2 K
  66.      /* 设置延迟周期 */5 l1 V  Y7 {7 r( T) L: F
  67.      os_itv_set(usFrequency);2 Z, H6 _5 F1 _/ {
  68.    
    4 _# `- Z+ u2 I2 ?2 L. Z
  69.     while(1)) N$ n/ U0 h1 c% }1 ]# ^4 R3 h' D
  70.     {
    $ M5 e5 B7 p# [9 s
  71.          bsp_LedToggle(2);8 I  x; P5 {0 Z9 S; [0 f4 w4 H
  72.          bsp_LedToggle(3);
    * [1 R" t" ^& `) ?3 E+ |! L

  73.   l5 u7 O+ a; G) u* h- ^5 w5 V
  74.          /* os_itv_wait是绝对延迟,os_dly_wait是相对延迟。*/
    % u4 F7 E9 q; r9 p# t+ @
  75.          os_itv_wait();2 U9 m1 @# R, ?& F0 {; u4 j
  76.     }
    * P* {& z1 b( F& Q2 E# p8 W
  77. }5 e% I3 N2 U2 d+ q
  78. % f, Y6 k+ w! C8 R
  79. /*
    $ A. e' ~7 J; r* X5 N$ ^  D
  80. *********************************************************************************************************
    / b/ v% r5 d1 ?8 s1 P
  81. *    函 数 名: AppTaskMsgPro: l6 E+ I5 O9 d/ {  g7 k( C0 ^0 q
  82. *    功能说明: 消息处理,等待定时器中断发来的事件标志
    0 q9 O1 _+ i. E/ S2 k) R
  83. *    形    参: 无
    ; |# c$ n( q8 a/ D3 ~0 F
  84. *    返 回 值: 无
    : ~; Y) S5 i- v2 n
  85. *   优 先 级: 3
    % d: |8 d, R0 g* ^
  86. *********************************************************************************************************/ \% A+ J( Q. Q* S: O  v
  87. */
    % Q6 j3 R: k" E5 L& R  ]
  88. __task void AppTaskMsgPro(void)
    7 Q4 x; w+ w5 y2 w4 m
  89. {  w/ z# w- u: {
  90.      OS_RESULT xResult;1 d; v) D9 C% g9 a% R
  91.      const uint16_t usMaxBlockTime = 500; /* 延迟周期 */
    9 B# t; G7 s( ]* ^- ]% |& X4 W
  92.    
    4 ~; ?5 w3 T8 z, d9 `! q6 A, }' W0 }
  93.     while(1)
    . g! G/ `# Z8 ~" u0 W, ^
  94.     {0 Y9 \9 ~9 r7 H/ F# u* g1 m& y3 O1 v
  95.          /*
    # L! ^8 {. t* R) H" C$ v% B% T
  96.            1. 等待K2按键按下设置bit0和K3按键按下设置bit1,都设置了执行OS_R_EVT消息
    3 O: U, i1 s' F) P9 Q" T
  97.            2. 退出前bit0和bit1被清除,这里是bit0和bit1都被设置才表示“退出”。  b! I/ T6 D& J! {' p& b8 Y
  98.            3. 每个任务都有自己的16位事件标志位,也就是os_evt_wait_and的第一个参数是无符号16位整形。
    5 ?+ ~( O% r) ~! x5 y  `
  99.          */
    + G# W& Q1 B& w- Y
  100.          xResult = os_evt_wait_and (BIT_ALL, usMaxBlockTime);- g- c; ?3 \% e, F, O
  101.         * {; S% l* ], l/ d
  102.          switch (xResult)" |1 L! ^: L: {/ X" l
  103.          {
    ; P+ m$ o5 p6 \, `$ R( P  l
  104.               /* 接收到bit1和bit0都被设置的消息 */0 w6 K& e# U; c6 H
  105.               case OS_R_EVT:
    ; k! \# I& T4 Y( F9 y  P
  106.                    printf("接收到bit0和bit1都被设置的消息\r\n");/ x& d# y1 a6 A) e7 l* H
  107.                    break;  
    * L7 b' \# c4 {
  108. % y" X2 H! E3 ~7 E  d
  109.               /* 超时 *// H& a0 F2 x# P. y0 V1 c
  110.               case OS_R_TMO:
    ; ^1 U, e3 G; Y8 {5 {% w
  111.                    bsp_LedToggle(1);& \  ^2 u9 e8 z  ~
  112.                    bsp_LedToggle(4);. \6 H7 p& B5 J1 C9 c. ]
  113.                    break;8 c! h+ I0 _/ r6 K: T( |7 x$ L
  114.              % c, {9 _+ P/ ]6 J/ V8 Q9 n  f- l
  115.               /* 其他值不处理 */
    7 h# {* ]+ R7 z. w2 z7 M
  116.               default:                    
    - t( x+ H7 t3 L# I* N
  117.                    break;2 ?; }- n3 g* K. V2 x5 V
  118.          }   
    0 k! P  x( h8 z3 K3 H: C' d1 K
  119.     }
    6 ^7 {0 D2 c, Q( }$ \. H2 T. Y
  120. }9 A) g9 p' V0 B

  121. + d* R  J3 j$ \& L) T* J
  122. /** C7 ^1 a9 [, a2 r. L8 x" J0 n1 Q: W
  123. *********************************************************************************************************" B& w* F1 a" v: A9 k
  124. *    函 数 名: AppTaskStart0 V0 o% D( X+ u! h
  125. *    功能说明: 启动任务,也就是最高优先级任务。这里实现按键扫描。
    1 }) F* o: Q" `3 c. K
  126. *    形    参: 无2 W3 e' G$ `4 T
  127. *    返 回 值: 无
    4 r/ n3 b: j) R
  128. *   优 先 级: 4
    7 ]7 R/ M1 l) u1 R1 \' g* m
  129. *********************************************************************************************************) `: V  {% m7 P' P
  130. */
    " `5 e# d' p$ o: P# T& J3 z6 O
  131. __task void AppTaskStart(void)9 A& S9 q" C. c* g; ^% {
  132. {3 z0 a. n* d! O& |- L
  133.      /* 创建任务 */
    & Y6 u2 \$ q( [+ Q
  134.      AppTaskCreate();
    * l, F) Y8 t  |( D
  135.     ) f' b$ L* [2 o) @$ V
  136.     while(1)
    ! E6 _& T; V+ a  M; H
  137.     {' ?9 }/ ?% X5 E
  138.          /* 按键扫描 */
    ; W' E8 ?9 N' x5 M9 M9 x
  139.          bsp_KeyScan();
    ' E) F! a% d6 }. d4 `: U, I6 ^
  140.         os_dly_wait(10);$ i! \& [; g+ Y) V0 M; H
  141.     }' Z6 J$ N* n( i/ p  X8 j
  142. }
复制代码
& q. c7 B' f0 |6 O7 @5 A
定时器中断回调函数中发送事件标志:
    定时器中断的初始化和中断函数在bsp_timer.c文件中实现,这个不是教程的重点,故不作介绍。这里主要关心RTX的事件标志函数在中断服务程序中的使用方法。
  1. /*
    % W% a. |2 K4 ~0 C
  2. *********************************************************************************************************2 X& i+ R% X- {
  3. *    函 数 名: TIM_CallBack1
    : _; j7 v" p% d  S5 n/ h& o) |
  4. *    功能说明: 定时器中断的回调函数,此函数被bsp_StartHardTimer所调用。                        1 S( h! }" G8 _- s; ^6 n: z/ J' h
  5. *    形    参: 无# Y1 M, n1 X/ @) q
  6. *    返 回 值: 无7 G( @+ `# H1 v9 D% g9 }
  7. *********************************************************************************************************
    # o& b2 W9 T4 F8 _/ K% q( ]4 c8 T7 d
  8. */$ J: U  S# ]* R; H
  9. static void TIM_CallBack1(void)3 A* x% p% h$ ?5 a% B
  10. {
    9 i" e" u3 k: D& w
  11.      /* 发送事件标志,设置bit0 */
    $ t9 Q+ L, H/ I0 a) ~; J/ z
  12.      isr_evt_set (BIT_0, HandleTaskMsgPro);
    7 O1 _; a1 k7 V" c/ I6 j
  13. }8 S* s# o3 }4 @" q* `1 L
  14. # ]) e' Q- `5 p0 ]" B- A9 E! c
  15. static void TIM_CallBack2(void)
    - C& P- u7 b1 Q
  16. {
    % `- [3 }$ m: Y* W- d8 S/ M9 O& s
  17.      /* 发送事件标志,设置bit1 */
    8 G) p: i, ]' S- W; i( s
  18.      isr_evt_set (BIT_1, HandleTaskMsgPro);
    8 @' O  _' l1 x4 |- b
  19. }
复制代码
7 o+ R- V, v0 e0 ~

+ n7 P# E+ b+ {2 z/ s8 X0 F
baiyongbin2009 回答时间:2016-1-27 17:40:23
13.5 总结
    本章节就为大家讲解了任务间的通信和同步机制之一,事件标志组,初学者要稍花些时间将其掌握。
6 [  k3 F5 |2 [* N& q* V7 n# y4 ^
watershade 回答时间:2016-3-3 17:42:26
应该对应于cmsis-rtos的signal吧,至于数量在cmsis_os.h中定义osFeature_Signals
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版