|
我是老温,一名热爱学习的嵌入式工程师
& @8 B0 k8 q c3 r# s关注我,一起变得更加优秀!事件标志组 嵌入式事件标志组是一种在嵌入式系统中广泛使用的同步机制,主要用于实现多任务间的同步与通信。( f) Z: t) u8 G" s
事件标志组是一组事件标志位的集合,每个位代表一个事件是否发生。它允许任务等待特定的事件发生,当事件发生时,相关任务将被唤醒并执行相应的操作。
, K! e/ [& L2 I4 o特点 灵活性:用户可以根据需要自定义每个位事件的含义,如bit0表示按键是否按下。支持一对多、多对多的同步模式,即一个任务可以等待多个事件的发生,也可以是多个任务同步多个事件。高效性:使用位操作,效率高,占用资源少。扩展性:虽然常用的是16位或32位无符号的数据类型来存储事件标志,但其中的高8位可能用作控制信息,低24位用作存储事件标志,因此可以存储多个事件标志。工作原理 等待事件:任务通过调用相应的API函数(如FreeRTOS中的xEventGroupWaitBits)来等待一个或多个事件标志位的发生。可以设置等待条件,如等待所有指定的事件标志位都为1,或等待其中任意一个事件标志位为1。触发事件:当事件发生时,通过调用相应的API函数(如FreeRTOS中的xEventGroupSetBits)来设置相应的事件标志位为1,从而触发等待该事件的任务。唤醒所有符合条件的任务,类似于“广播”的作用。执行任务:被唤醒的任务根据事件标志位的状态执行相应的操作,并可以选择是否清除事件标志位。应用场景 多任务同步:在需要多个任务协同工作的场景中,可以使用事件标志组来同步这些任务,但无数据传输。中断处理:在中断服务程序中设置事件标志位,以通知主任务或其他任务进行相应的处理。状态监控:用于监控系统的各种状态,如设备是否就绪、数据是否到达等。例子:在嵌入式系统中,处理USB数据的同步发送通常涉及多线程编程,并使用适当的同步机制来确保数据的一致性和完整性。在这种情况下,可以使用事件标志和消息队列来协调一个生产线程(生成USB数据)和一个消费线程(发送USB数据)。* h: y/ q8 k9 T
设计思路:
- c( f* U* w. j. z消息队列:用于存储从生产线程到消费线程的数据。每个数据项可能是一个指向USB数据包缓冲区的指针或包含数据包信息的结构体。事件标志:用于通知消费线程有新的数据可供处理,或者当队列为空时通知生产线程暂停生产。互斥锁:保护消息队列和事件标志的访问,防止竞态条件。
/ n1 b6 U6 @; r& l# m2 w实现步骤:. z7 \& R& _' `$ p4 {
1. 定义消息队列和事件标志使用RTOS提供的API来创建消息队列和事件标志。消息队列应能够存储指向USB数据包的指针或相关结构体。2. 生产线程生产线程负责生成USB数据,并将其放入消息队列中。
B+ F# ~8 n! k: c9 a/ N; W3 gvoid producer_thread(void *arg) ) \. S& A, @9 u1 E
{
; Z/ q/ G3 s# A. N# `" x! D4 e( I while (1)
' r2 I s" g- [3 e1 M1 l. K+ I { ; L# b- c( Z) C# k- S$ n @6 @
// 生成USB数据包
9 O8 v0 x7 \/ Y9 p usb_packet_t *packet = generate_usb_packet();
0 u8 H$ i3 i$ [; j // 锁定互斥锁
- J: J: @7 ]$ Q# D" L6 p& {) |+ M rtos_mutex_lock(&mutex); ! }& f; n5 [% i/ y, p% g
// 将数据包放入队列 . D' q; w+ z9 o
if (rtos_queue_send(&usb_queue, &packet, portMAX_DELAY) == pdPASS)
: g/ ]5 j z, V4 ^4 G- ^" X {
" u* R4 j. \+ ]4 z% m a, x // 通知消费线程有新数据
3 ~/ F5 {2 S5 V7 g s rtos_event_group_set_bits(&event_group, EVENT_BIT_DATA_READY);
1 y- o! M3 W, j) ]" q: o% E* R# V } & i9 M7 s5 s7 g, l7 q
// 解锁互斥锁 % H7 l' T) h) j; T0 T1 ]
rtos_mutex_unlock(&mutex); 2 j, r1 c, S5 r f s; V% i7 V4 C# J
// 等待一段时间或根据其他条件继续生成数据 . {% H% q5 G2 P
vTaskDelay(pdMS_TO_TICKS(100));
4 W: T8 e5 B1 W }
5 q6 X* v3 q2 h}) X1 y6 y4 n1 ?
3. 消费线程消费线程从消息队列中取出数据,并发送USB数据包。2 U* }, G/ E& J# K. x' p
void consumer_thread(void *arg) , s% v# O# Q6 Z, D3 Y' ]5 x
{ $ o# a* L* B7 w2 x5 k' Q
usb_packet_t *packet; 5 g3 M! o- @% z
while (1) 1 d! W1 @5 D" \; u
{ # l! V( I& b" g2 e- y9 w
// 等待数据就绪事件 3 M4 d: f- H, o% u
EventBits_t uxBits = xEventGroupWaitBits( 6 T: K9 M2 Q( _/ V' J4 A1 X3 B
&event_group,
+ a! y6 H4 z4 c8 V( [ EVENT_BIT_DATA_READY,
7 E) O' r& p, L9 T pdTRUE,
7 X, Y$ x% V8 q3 C+ S pdFALSE, ( ]- r+ d3 Y9 Z3 v( C, ^
portMAX_DELAY
# K- j+ a C/ m6 Y' v* I );
8 ?! N7 R) s ? if (uxBits & EVENT_BIT_DATA_READY) ! q) F$ D' k- y" m
{
) v' O9 J% L* v! u // 锁定互斥锁
2 ?4 |9 ]' s* @, @! T- { rtos_mutex_lock(&mutex);
* h0 c9 e5 A, c D0 l // 从队列接收数据包
5 m9 z# N0 q4 i4 E7 L! k& h& D if (rtos_queue_receive(&usb_queue, &packet, portMAX_DELAY) == pdPASS)
. V/ d* D# z0 l. v% w+ e { * W# O4 }: R' k! n) N J7 O) r# g
// 发送USB数据包 * z/ y+ n: W4 G# L/ A- s
send_usb_packet(packet); " i1 l, T5 g+ h" C- C+ m9 U- B f
// 释放数据包(如果需要)
7 \) O4 ]; s/ d9 e) a, d free_usb_packet(packet); 1 p. P* I6 _: U5 p3 L9 Q- c
} & j$ _( B: W f: ^
// 解锁互斥锁
, F9 K8 v1 v+ [( K4 W/ X b7 P rtos_mutex_unlock(&mutex);
- D9 k" B$ I6 Q }
- K! [: l# C$ | }
; S1 U9 E" H+ r3 P}
4 j5 M6 D/ i4 d- o5 C4. 初始化与启动创建消息队列、事件标志和互斥锁,并启动生产者和消费者线程。
2 [( S& D y) g" N+ Vvoid app_main(void) 1 L( q, f( w4 v& h8 Y) k
{ . t5 w8 T% n' p1 j% {% a
// 初始化消息队列、事件标志和互斥锁 ! |) ^) K; h" q$ i
rtos_queue_create(&usb_queue, ...); & a8 x( \4 O! ~ K
rtos_event_group_create(&event_group); 3 f; N* D* J7 w
rtos_mutex_create(&mutex);
2 E, I$ V& p. w! l, w % k# j I* }8 d( p2 S$ w
// 创建并启动生产者和消费者线程 9 p* c _7 H Y' K4 E* Z
xTaskCreate(producer_thread, "Producer", STACK_SIZE, NULL, PRIORITY, NULL); , ]# y, Z6 I4 Q/ r- G5 n
xTaskCreate(consumer_thread, "Consumer", STACK_SIZE, NULL, PRIORITY, NULL); q- [. N* }. G1 p
) f8 @1 G- N0 s% ]& C // 其他初始化...
9 q! P2 l- g( _8 A: z) ]/ M}
7 s7 x* _) C0 R4 L$ q注意事项 在使用事件标志组时,需要注意避免竞态条件,确保任务间的同步与通信的正确性。合理安排事件标志位的数量和使用方式,避免资源浪费和效率低下。在设计系统时,应充分考虑任务间的依赖关系和同步需求,以选择合适的同步机制。
* Y/ @/ M+ ^) q7 @( V) @文章来源:牛逼的工程师网友。-END-
. X# M7 I8 [- a/ G$ L# }3 h0 B: i* T1 i往期推荐:点击图片即可跳转阅读
% k) k6 P. i6 {% `6 W$ b: K
( Z; S0 {6 i& Z- [
l4rjzqbg4zf640134648.jpg
/ R3 _2 ~* f$ [, F大模型遍地开花,分享一下我对嵌入式端侧 AI 技术的看法。5 [0 ]7 D" H9 J6 t! ?
1 Q! G' Y4 K; t+ C; x
bqah1zdv2xe640134748.jpg
( c1 s" L7 \+ U# {( {
我发现,嵌入式工业处理器,100%国产化已经成为趋势!2 j( ?( _: P4 S9 X2 U/ h3 J
8 X2 g- J% [- G K4 t( u6 K
t2isnjysnu1640134848.jpg
" _0 s5 y& r' I" \
嵌入式设备使用蓝牙通信技术,有哪些行业领先的芯片方案?8 {6 ]- d1 ?2 `& w/ f f2 H
# }3 ]# y. d& T, y, [
我是老温,一名热爱学习的嵌入式工程师
' s4 D5 ?' f- M$ u2 Y关注我,一起变得更加优秀! |
|