01. 概述; j) w U, n( Y: m+ N
任务挂起和恢复,当某个任务要停止运行一段时间就可以将这个任务挂起,当要重新运行这个任务的话就恢复这个任务的运行。FreeRTOS的任务挂起和恢复API函数如下表所示:
9 l' w7 B/ E$ P2 B! ?: g0 x- m
- k. {3 c% W$ ~+ r/ }
N0 ]0 h& i3 u
4 E4 \( a( j7 F02. vTaskSuspend函数
6 W9 I, m! |7 v. M5 k- void vTaskSuspend( TaskHandle_t xTaskToSuspend )6 Y$ ?7 j' g- h( e9 T0 u3 k0 r
- 功能:
4 s+ N9 X; I. V# Q# K: G* H - 将某个任务设置为挂起状态,进入挂起状态的任务永远都不会进入运行态。退出挂起状态的唯一的方法就是调用任务恢复函数。
$ ~3 d9 T1 H: ^ - & ~4 ^1 M" f/ u! H
- 参数:! x3 j F$ Q: E# C! e
- xTaskToSuspend 要挂起的任务句柄。为NULL表示挂起当前任务。, _# n: f/ m# `5 j# V3 x
5 J# i+ ^# V# L5 _& t0 e- 返回值:
& X4 e, c: A' X# g" q - 无
复制代码 1 G# V2 X- E/ S" A1 \7 d
温馨提示:
7 }1 V/ L% e# m
) ?% l ^3 N8 J& h调用vTaskSuspend函数是不会累计的:即使多次调用vTaskSuspend ()函数将一个任务挂起,也只需调用一次vTaskResume ()函数就能使挂起的任务解除挂起状态。在文件FreeRTOSConfig.h中,宏INCLUDE_vTaskSuspend必须设置成1,此函数才有效。
3 X, {9 O8 s% D. k4 \4 r5 J1 s& C0 _, x! Z* G. V6 S, z) }2 V) [
应用示例:; N5 `- }. m/ N9 Q( e
; c8 \1 ^4 D! d* ]- s
- void vFunction( void )# x- t) o4 u3 Q, z0 t, C
- {7 G) V. I4 s" t0 K* ^4 r
- xTaskHandlexHandle;" d! c% i+ B6 O1 v2 {- y% W
- // 创建任务,保存任务句柄.$ w1 M6 i; K( q, N9 r) F: @/ R3 q
- xTaskCreate( vTaskCode, "TASK_NAME",STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );
) c. ^6 [' y0 e4 Y6 } - // ...
+ `* p+ ?" Q) [( e - // 使用句柄挂起创建的任务.
# [ e# I' b5 f& Y - vTaskSuspend( xHandle );3 D. @, n0 k! n) M( D, R- P# g: D
- // ...
4 e r, D! \1 D7 C - // 任务不再运行,除非其它任务调用了vTaskResume(xHandle )
$ j/ d( a) A. R0 ]; [7 m5 s - //...
# M: z* P0 P' B3 w" F - // 挂起本任务.: D- g* n( @" m j3 |
- vTaskSuspend( NULL );" a+ w) e+ c" H+ l$ O
- // 除非另一个任务使用handle调用了vTaskResume,否则永远不会执行到这里
- H) d3 f/ q6 R- x" M. g3 g - }
复制代码
/ \* @0 C; J9 `/ T03. vTaskResume函数
! {/ A k9 S; y0 [! j. q; }/ o- void vTaskResume( TaskHandle_t xTaskToResume )
' k) ^' U% e! p/ [: C, p - 功能:
* y' n5 p5 H: j - 恢复挂起的任务, q" X \' y" T* Q" \
- 参数:
5 S1 K' g1 ^) W2 V1 s8 H6 B1 r! R - xTaskToResume 要恢复运行的任务句柄0 K) ~, b4 s' F
- 返回值:
; v$ ^2 P* L! F9 m. C8 L9 d) [5 H - 无
复制代码 # L7 N6 m0 s6 j) E, F& |
温馨提示:, t5 B8 l P, Z" j5 f. q
/ ]7 v5 N: F' X' H7 t通过调用一次或多次vTaskSuspend()挂起的任务,可以调用一次vTaskResume ()函数来再次恢复运行。在文件FreeRTOSConfig.h中,宏INCLUDE_vTaskSuspend必须置1,此函数才有效。
8 E$ m9 ~' ]4 b6 x2 t2 R- O+ ?0 z) T, ?% h& m: b
应用示例:8 n4 d' Y/ n% I
; L6 }# P( Q0 v1 ], R- void vFunction( void )
! e& j6 G5 z5 V - {
6 L3 |( x- P8 F( v5 d - xTaskHandle xHandle;
) N! t1 B2 {; k/ k" G+ p- { - // 创建任务,保存任务句柄: h* m+ R* {7 e) ]& H
- xTaskCreate( vTaskCode, "TASK_NAME",STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );! g. t) O- }+ ~7 l
- // ...
/ C% J4 T" O$ R0 A( E7 E - // 使用句柄挂起创建的任务: b- X$ H t" t; S* R
- vTaskSuspend( xHandle );' s3 r0 W' i. x x, l- [
- // ...
- ?1 R( E/ ?) E( U, N) U - //任务不再运行,除非其它任务调用了vTaskResume(xHandle ) + Y# |9 Z8 Z E3 J' O4 o3 Z" J
- //...* N" }5 N. V' a6 [* Z' j8 r! k% U
- // 恢复挂起的任务.6 K% ^( |: P. F1 R8 X1 u+ n1 ]+ R9 C
- vTaskResume( xHandle ); b, f, s' t- i0 ^2 F
- // 任务再一次得到处理器时间
5 [! D( k- X9 t2 M9 p - // 任务优先级与之前相同
; A9 n0 z7 K* @ b: d - }
复制代码 9 V5 l- E+ j, W/ `
04. xTaskResumeFromISR函数1 r5 A5 j2 a+ I* \3 s& l, i) S
BaseType_t xTaskResumeFromISR(TaskHandle_t xTaskToResume ); I* o" w; f2 R& \( o
功能:
* ]) }( V3 X0 h( ?5 `( P2 l 用于恢复一个挂起的任务,用在ISR中
$ j" z6 N" q+ L1 }- {: \参数:/ n" \& r4 v- ~+ g Q6 Q; W+ Q
xTaskToResume 要恢复运行的任务句柄& a8 s) s6 n3 D& G( u
返回值:* m7 \+ H* C' l$ D" C+ r
如果恢复任务后需要上下文切换返回pdTRUE,否则返回pdFALSE。由ISR确定是否需要上下文切换。( ?% f7 f* t S8 x7 H
3 J4 p2 B0 J( P, F
温馨提示:
# j- h3 c. o) o
3 a5 l" @9 P& k9 E% K通过调用一次或多次vTaskSuspend()函数而挂起的任务,只需调用一次xTaskResumeFromISR()函数即可恢复运行。
m! Z, s, H' f y$ w* `4 G( F6 f2 O4 u9 l# t+ u
xTaskResumeFromISR()不可用于任务和中断间的同步,如果中断恰巧在任务被挂起之前到达,这就会导致一次中断丢失(任务还没有挂起,调用xTaskResumeFromISR()函数是没有意义的,只能等下一次中断)。这种情况下,可以使用信号量作为同步机制。在文件FreeRTOSConfig.h中,宏INCLUDE_vTaskSuspend 和 INCLUDE_xTaskResumeFromISR 必须设置成1,此函数才有效。
Z+ Y+ B2 Z& a9 w2 T, J# @6 ?5 B% e% |
应用示例:, G" c2 Y& G% K
' Y: w/ U; K7 u6 @
- xTaskHandle xHandle; //注意这是一个全局变量/ w, d5 x5 p) }5 `4 k C
- % U [8 i8 \# `0 W0 a) s
- void vAFunction( void )5 e/ Q( p4 h: D1 f, @8 G% A7 H* k
- {
8 a* m- V: Y) E' f( e" S - // 创建任务并保存任务句柄9 w- c8 _7 S4 \6 M! y7 |( B
- xTaskCreate( vTaskCode, "NAME",STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );: c' M5 R4 }. C# L) f/ h
- ( u0 Y$ ]& y& k/ ?0 U+ z; e5 V
- // ... 剩余代码.
' `* U# n$ K" |5 Q. ~ - }7 d7 q% u+ ~0 J4 m' v6 E! W+ _/ ~ ~
- ! w- ~% Y6 b6 z3 A! U- X9 X
- void vTaskCode( void *pvParameters )
' ^$ P9 r% S/ F - {
' \7 H- q5 C+ C6 y$ ^6 G - for( ;; )
& O+ R V# d' x( b) ]/ x: C8 w - {& V8 P( s- E" T/ |' S
- // ... 在这里执行一些其它功能
2 x9 P! C4 o2 ]0 j
1 E& D3 ~7 E+ M* B$ n8 ]; L- Q- // 挂起自己
5 q+ b" c! J0 y. w/ _: c8 g c - vTaskSuspend( NULL );* G/ s# @6 x- y) p+ ^/ O' Q% g9 T1 H
- % M& z) I/ N0 f) Q3 C' a; ?/ S; }" p
- //直到ISR恢复它之前,任务会一直挂起
' z" k5 U7 K! O8 q5 Z - }
4 k$ a, n' ^* p; a' B2 S; B6 Q - }
7 G/ B; x" H7 G" @ - % u* o) T. L @3 I# G/ a! x
- void vAnExampleISR( void )
2 E: [6 }' k [) _- `4 r - {, e1 X4 t! z7 |. w5 [9 K* G
- portBASE_TYPExYieldRequired;) h5 F1 S: G7 ]& t {
' X7 R( B. V7 |2 [! G- // 恢复被挂起的任务1 ~5 B* [+ d) ^* b
- xYieldRequired = xTaskResumeFromISR(xHandle );
5 e" O7 d. H; U- t. N) S8 ^ - , Q% @0 ?+ j, z4 Q' g3 z- k Y
- if( xYieldRequired == pdTRUE )
0 [; J/ o& f+ {8 ]/ s1 c - {0 a1 \1 ~8 A4 Z, [
- // 我们应该进行一次上下文切换
$ |* \% }9 ?# d9 _3 u5 x5 l - // 注: 如何做取决于你具体使用,可查看说明文档和例程7 x+ G6 h& d" H6 V1 W" {
- portYIELD_FROM_ISR();
9 M0 ~) v6 r4 ^ - }
5 J& j) M1 O d7 Q2 z, p6 J* C1 G u - }
复制代码 6 V/ b% z5 u) z! ?9 ^: v' x0 T. g% b
1 f( k3 e; G2 y+ ]( q, F
9 g. b& Y0 L1 ]! q4 p, I% N; G0 ^1 a% P) o) W1 J5 I. e
|