接上篇:RTOS超低功耗平台应用---FreeRTOS启动&任务创建
. V! i) x7 m* X) \+ `0 r$ ~ f# }% J( s! S0 z3 F
* @8 J8 J4 _0 s$ E/ z5 ]* ?6 c3 G' K( {1 _- Q) J
首先了解一下信号量,一般信号量主要实现两个功能:
) @% r- |" [. q3 S9 A8 I 1,两个任务之间或者中断函数跟任务之间的同步功能
9 J5 l" J8 {- o 2,多个共享资源的管理
$ q" K5 P. i2 y' `: b, x* N FreeRTOS针对这两种功能分别提供了二值信号量和计数信号量,其中二值信号量可以理解成计数,即初始化为仅有一个资源可以使用。
9 a( Z& O7 ~- ]' y9 d2 i 实验是创建一个线程,该线程通过ISR发出的信号量打印按钮按下计数,包含一个LED闪烁任务。, |/ e; e1 D# `7 j" K; ]7 i
- /**2 H6 k% R1 p7 K4 y7 F5 X
- * @brief Start a Task.5 r; W9 P& T( a
- * @param argument: Not used
0 ]% _. `2 D" l2 O - * @retval None
: ^2 @* o: C% \- j8 c - */ g" l& b* F" L) D+ V0 U" Z9 F
- static void vAppStartTask( void *pvParameters )
* R9 J, q8 _, h - {
6 k+ n& J8 I( C, \5 j$ E - (void) pvParameters;3 N. \4 u7 f4 E# C4 X8 R
- : ^) j z* D" h" W3 {
- for(;;)3 \& u, @1 O6 D& G: E
- {
' x; ^4 D' f: y+ |- E3 ~ - BSP_LED_Toggle(LED2);4 S$ O, U; U3 e
- 2 g% K/ S6 S: |1 k3 ]8 ^$ O3 K
- vTaskDelay(200);
% l' [. |( ^, H# A# b - }; W* z- o$ S9 c9 p- f8 G
- }8 N! m( A0 u2 ]( ]+ e
- / o6 l1 o0 G% R1 o' Y7 }5 S
- /**( @$ ~$ P1 x& ]$ d
- * @brief Button Task.2 r6 f% S) K$ M+ {- o* h6 c+ [1 x3 T
- * @param argument: Not used
# k6 B' O/ j' F$ V9 |4 X9 @! s - * @retval None
, F- Q( X2 Q% w. r - */5 T* R: C) r$ u: l. F( H, W
- static void prvAppButtonTask( void *pvParameters )
$ b- }5 |$ Y6 X6 i. k - {
' h1 {" L6 ]2 S k# A - configASSERT( xTestSemaphore ); /* The assert function determines whether the semaphore is valid. */- K( c- K; Z! [
-
2 Y! g/ v2 ^3 _: n: b1 I$ h - /* This is the task used as an example of how to synchronise a task with* g* Q3 o: s; z6 O( Y2 B
- an interrupt. Each time the button interrupt gives the semaphore, this task" t i. y- |2 u, }+ N
- will unblock, increment its execution counter, then return to block
; n- B/ B4 r$ m. `) @ - again. */
* K" e1 D. i4 K7 u5 v6 j6 |% Z7 C -
$ [* Q- \, `9 k; l - /* Take the semaphore before started to ensure it is in the correct
" U. U- f8 N4 j$ D - state. *// H9 g) W# E8 e5 x# ]) I) a
- xSemaphoreTake( xTestSemaphore, mainDONT_BLOCK );) P5 C, ~0 z( ^% R" G; y j
- , L4 V. [0 m" G$ A# a
- for( ;; )0 m7 o2 @& R6 a9 j, H0 r- \
- {
; R, a6 \8 l+ Z/ ~0 m; i- ?) a/ ] - xSemaphoreTake( xTestSemaphore, portMAX_DELAY );
A# U6 _- R2 N - ulButtonPressCounts++;" I3 A8 u; C' J2 I4 I. V
- printf("Button Press Counts:%d\r\n",ulButtonPressCounts);$ b2 Z( ]! r, o6 e4 Q
- }4 n# p& t5 ?6 w, g
- }4 d' q! |- ?: ^, v9 N
6 L. u0 v0 `6 ]- /**
5 g+ m2 F3 Z+ n# U8 v% m' { - * @brief EXTI line detection callback.
: `) r( @. P( N1 E% M: o W# Q+ q" n - * @param GPIO_Pin: Specifies the pins connected EXTI line
d& U' l1 s& o. h - * @retval None+ M+ S" J0 ^9 a! r* l$ @+ P
- */6 G0 X5 k6 T3 Z2 C. p8 M0 e0 \
- void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)* f1 s6 J7 o$ Q5 F
- {
6 u0 P/ F* R, M2 d, Y& e; N - if(GPIO_Pin == KEY_BUTTON_PIN)' l3 N& \# Q! l$ h
- {# {4 |7 ~+ \, g! F# b. _2 k1 f
- if (uwIncrementState == 0)9 N1 r* J: M7 D: P
- {
+ a1 z9 c g1 q3 }; F( k3 u& i, g4 y - /* Change the Push button state */4 o' N3 P0 @4 g9 W
- uwIncrementState = 1;5 c, F% m& N E& }) |
- } e. v9 I4 R9 b3 v) b0 S$ F- e3 C# x
- else0 y- B5 y/ c9 |1 W4 A: o
- {
3 h4 @7 g0 N% W8 @1 U - /* Change the Push button state */7 c/ j8 K* e' h7 X
- uwIncrementState = 0;, ?' s9 a6 K- p0 z' z2 ?- s# c
- }5 I% Z: U# v0 ?6 n- g) w+ _# E
- } - B* \/ D! ?, v. |4 R
- }4 S6 L. G! t- K/ p8 i, ~
复制代码 主函数中使用xSemaphoreCreateBinary() 创建信号量,- xTestSemaphore = xSemaphoreCreateBinary();
复制代码 按键检测任务中使用xSemaphoreTake()函数来获取信号量。按键检测使用外部中断,信号量使用完毕后的释放也是在终端服务函数中,如下
' n+ ^) ^3 u& l; t7 g, \' T( r; @- xSemaphoreTake( xTestSemaphore, mainDONT_BLOCK ); //获取信号,传入创建的信号量句柄xTestSemaphore
复制代码- /**
4 A8 l2 P6 _" |( z - * @brief EXTI15_10 IRQ
, ^- I Y: ` z, k( N - * @param None4 }' y, O z' ]6 R% g& Y
- * @retval None6 j. ^/ q9 w5 L3 s# w8 e- F
- */
4 B4 R3 V9 p/ u: W4 u - void EXTI15_10_IRQHandler(void). I) w9 }( h# Y
- {
; p3 a& \. {5 H5 u4 i -
! a# Z) w1 ^+ ~! | - static BaseType_t xHigherPriorityTaskWoken; ( g, G; O/ t9 o2 H" s7 l$ Y5 L
-
i3 V8 {8 B; W/ }! I& S( U. t) v - /* Inerrupt message handling */
6 ~5 v2 @5 f. @8 Q - HAL_GPIO_EXTI_IRQHandler(KEY_BUTTON_PIN);
s3 G* n$ P+ j6 V- k, y - ' k Y5 ^; R5 X6 `3 ^# G# N- A* n5 e
- /* The handler releases a semaphore.
* w% }9 l( I- r# l- @4 v - xHigherPriorityTaskWoken has been initialised to zero. */
3 @0 v) Z6 [" U( r0 `/ M2 P' r1 g -
( m( v* D' Y3 }% s1 y - if (utime_tick >= 200)
6 ?! s9 }. x1 d- U" {& N0 r; y' J - { Z8 o1 K8 j0 u. k+ I
- /* The second parameter of the send sync signal is used to save + S% z( Y8 B$ d7 e: e
- whether a high-priority task is ready.*/
: A. L+ o+ I- X' S& A! { - xSemaphoreGiveFromISR( xTestSemaphore, &xHigherPriorityTaskWoken ); 8 C7 V7 B7 j3 E8 v5 R7 y
- utime_tick = 0;
6 h4 O& t' Y. y2 K - }
复制代码 8 j5 q# u9 L6 A5 D J
# H$ ~+ O# V' N3 ] 程序运行后会执行LED闪烁任务按键计数任务,当获取到信号量后计数值加1,同时释放信号量共下次资源可用。运行效果如下
2 M* g- ^- e+ L/ V, K: s9 C
/ S; x. C4 S. ]* w' C$ D8 I( k' t6 e/ N |