电子产业一站式赋能平台

PCB联盟网

搜索
查看: 134|回复: 0
收起左侧

嵌入式软件编程,事件标志组被广泛使用!

[复制链接]

561

主题

561

帖子

3987

积分

四级会员

Rank: 4

积分
3987
发表于 2025-3-4 12:04:00 | 显示全部楼层 |阅读模式
我是老温,一名热爱学习的嵌入式工程师
& @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

    l4rjzqbg4zf640134648.jpg

    / R3 _2 ~* f$ [, F大模型遍地开花,分享一下我对嵌入式端侧 AI 技术的看法。5 [0 ]7 D" H9 J6 t! ?
    1 Q! G' Y4 K; t+ C; x

    bqah1zdv2xe640134748.jpg

    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

    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关注我,一起变得更加优秀!
  • 回复

    使用道具 举报

    发表回复

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则


    联系客服 关注微信 下载APP 返回顶部 返回列表