电子产业一站式赋能平台

PCB联盟网

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

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

[复制链接]

568

主题

568

帖子

4221

积分

四级会员

Rank: 4

积分
4221
发表于 2025-3-4 12:04:00 | 显示全部楼层 |阅读模式
我是老温,一名热爱学习的嵌入式工程师: _( m' g3 d/ r
关注我,一起变得更加优秀!事件标志组 嵌入式事件标志组是一种在嵌入式系统中广泛使用的同步机制,主要用于实现多任务间的同步与通信。
0 L; ?3 u( r. t# U事件标志组是一组事件标志位的集合,每个位代表一个事件是否发生。它允许任务等待特定的事件发生,当事件发生时,相关任务将被唤醒并执行相应的操作。$ Q& `1 V0 P* V$ x  V, G7 V) n
特点
  • 灵活性:用户可以根据需要自定义每个位事件的含义,如bit0表示按键是否按下。支持一对多、多对多的同步模式,即一个任务可以等待多个事件的发生,也可以是多个任务同步多个事件。
  • 高效性:使用位操作,效率高,占用资源少。
  • 扩展性:虽然常用的是16位或32位无符号的数据类型来存储事件标志,但其中的高8位可能用作控制信息,低24位用作存储事件标志,因此可以存储多个事件标志。工作原理
  • 等待事件:任务通过调用相应的API函数(如FreeRTOS中的xEventGroupWaitBits)来等待一个或多个事件标志位的发生。可以设置等待条件,如等待所有指定的事件标志位都为1,或等待其中任意一个事件标志位为1。
  • 触发事件:当事件发生时,通过调用相应的API函数(如FreeRTOS中的xEventGroupSetBits)来设置相应的事件标志位为1,从而触发等待该事件的任务。唤醒所有符合条件的任务,类似于“广播”的作用。
  • 执行任务:被唤醒的任务根据事件标志位的状态执行相应的操作,并可以选择是否清除事件标志位。应用场景
  • 多任务同步:在需要多个任务协同工作的场景中,可以使用事件标志组来同步这些任务,但无数据传输。
  • 中断处理:在中断服务程序中设置事件标志位,以通知主任务或其他任务进行相应的处理。
  • 状态监控:用于监控系统的各种状态,如设备是否就绪、数据是否到达等。例子:在嵌入式系统中,处理USB数据的同步发送通常涉及多线程编程,并使用适当的同步机制来确保数据的一致性和完整性。在这种情况下,可以使用事件标志和消息队列来协调一个生产线程(生成USB数据)和一个消费线程(发送USB数据)。" f" b; Y$ p7 T9 ~& \8 L
    设计思路:6 X2 G$ B; I- k1 z: S8 q
  • 消息队列:用于存储从生产线程到消费线程的数据。每个数据项可能是一个指向USB数据包缓冲区的指针或包含数据包信息的结构体。
  • 事件标志:用于通知消费线程有新的数据可供处理,或者当队列为空时通知生产线程暂停生产。
  • 互斥锁:保护消息队列和事件标志的访问,防止竞态条件。  C9 h1 J) Q2 H8 c# J
    实现步骤:
    4 O+ B, W4 H+ Q$ q1. 定义消息队列和事件标志
  • 使用RTOS提供的API来创建消息队列和事件标志。
  • 消息队列应能够存储指向USB数据包的指针或相关结构体。2. 生产线程生产线程负责生成USB数据,并将其放入消息队列中。, ^/ H6 t) }# c
    void producer_thread(void *arg)
    ; W! r) W# m, f, I5 _) n) Y{  ; T% J) F- b( c% \0 I
        while (1) * ^# p7 h3 X) _/ G
        {  9 T# Z6 p$ [& h3 u% p* M
            // 生成USB数据包  6 v, a1 @% B! j- p- g
            usb_packet_t *packet = generate_usb_packet();  7 l  k" h* y  n/ I
            // 锁定互斥锁  $ z" }) C2 ^; X. Z, q- a* v
            rtos_mutex_lock(&mutex);  " b: {- x8 \; U  g7 f
            // 将数据包放入队列  ) H! \. x( f& W7 m
            if (rtos_queue_send(&usb_queue, &packet, portMAX_DELAY) == pdPASS)
    2 F* t  P6 y4 ~! J- G- k        {  # m; \8 B4 B( g! ?1 H
                // 通知消费线程有新数据  
    , B6 E) k% w: x            rtos_event_group_set_bits(&event_group, EVENT_BIT_DATA_READY);  2 w- j  l7 j. f9 R
            }  / h3 n# f, Z- y' \1 y% J4 v
            // 解锁互斥锁  & r4 ~1 ]+ r9 i! s5 g
            rtos_mutex_unlock(&mutex);  
    . O7 a" m% f3 f6 V; O4 H! e        // 等待一段时间或根据其他条件继续生成数据  
    ; u" k7 j# R# j" L/ g        vTaskDelay(pdMS_TO_TICKS(100));  % h( j1 a+ Y, J5 i; \
        }  5 @: f# b: W; M
    }
    1 Q3 Q& H/ J: R/ q3. 消费线程消费线程从消息队列中取出数据,并发送USB数据包。
    - Y) k5 o2 S3 u* X  Y, p  Yvoid consumer_thread(void *arg) 8 i. s* e6 g5 ?/ m) O) a
    {  
    - [- i9 v# U7 I+ D, L/ l) I    usb_packet_t *packet;  9 S: `0 `- g; r
        while (1) : B( V4 D) W7 U0 m8 T+ h  Y
        {  , N, j5 E1 g" W6 L& G9 r
            // 等待数据就绪事件  
      d- V0 i0 t. X- G        EventBits_t uxBits = xEventGroupWaitBits(  ) M' j8 B* @8 T1 @+ r/ E% b0 v
                &event_group,   - w( r  }% r  `
                EVENT_BIT_DATA_READY,   * G& t9 w- C! B0 s
                pdTRUE,   
    8 k8 Z  G6 m6 }2 s2 @% y* x            pdFALSE,   
    , C1 l, B( A4 ]; h            portMAX_DELAY  
    & S# v! R; P3 F) H3 k        );  
    0 i# l  }5 R$ N5 X) w4 C% a0 r        if (uxBits & EVENT_BIT_DATA_READY) . P7 l' W; S* K) u) V& r
            {  7 K4 y5 }( J6 u$ \% _, x
                // 锁定互斥锁  * d, Q4 O6 ?% D9 K5 _2 a; w- R
                rtos_mutex_lock(&mutex);  % u; p7 X* C9 T
                // 从队列接收数据包  - m6 X; G" Z/ c6 U4 J9 g
                if (rtos_queue_receive(&usb_queue, &packet, portMAX_DELAY) == pdPASS) 9 R6 n7 D- t$ n1 i' z9 Z; G7 G
                {  ) `# l: d! h4 U4 ^* t5 I
                    // 发送USB数据包  ; p0 a) k5 n, R. T1 W6 {7 p
                    send_usb_packet(packet);  , R: G0 p) Q! Z8 a) u
                    // 释放数据包(如果需要)  
    5 Q7 l2 J6 z9 ^                free_usb_packet(packet);  . O. M2 U# @% L5 T  X
                }  
    1 F8 s8 D1 {% V            // 解锁互斥锁  0 ~+ o7 j" Q, H
                rtos_mutex_unlock(&mutex);  0 x4 J6 {3 s3 O9 `2 G
            }  
    , q; k3 {( H" l" P+ ~    }  
    2 I& G7 k$ t6 K5 n. V6 e+ o: Z' J; h}
    - N4 \" h$ n1 B& @. x% g- J4. 初始化与启动创建消息队列、事件标志和互斥锁,并启动生产者和消费者线程。; C* z8 ^# e1 I# T4 Z- d% P1 {
    void app_main(void) ( S% l6 l( @: |; T3 n5 v8 Z
    {  
    0 l$ m2 k; q0 d* {    // 初始化消息队列、事件标志和互斥锁  $ r/ l5 ~7 d& c( i* ^
        rtos_queue_create(&usb_queue, ...);  3 ~; R# s8 o4 u0 y$ L
        rtos_event_group_create(&event_group);  
    1 r" H5 l' g2 k, G    rtos_mutex_create(&mutex);  
    5 t4 R0 I: C4 ~% ]3 y! W$ u  , H) g& F# v- V* Z) s
        // 创建并启动生产者和消费者线程  
    ) r; H8 u+ K% i4 [    xTaskCreate(producer_thread, "Producer", STACK_SIZE, NULL, PRIORITY, NULL);  
    ( t' k5 h" O4 ?$ E    xTaskCreate(consumer_thread, "Consumer", STACK_SIZE, NULL, PRIORITY, NULL);  + K9 [2 \4 ?. w, _
      . P0 S- P4 G4 v2 i) t
        // 其他初始化...    `3 n  J; Q2 g  H0 ^( d3 m
    }
    - X, l* q$ I' p& `注意事项
  • 在使用事件标志组时,需要注意避免竞态条件,确保任务间的同步与通信的正确性。
  • 合理安排事件标志位的数量和使用方式,避免资源浪费和效率低下。
  • 在设计系统时,应充分考虑任务间的依赖关系和同步需求,以选择合适的同步机制。1 M2 V* `+ n0 C, O5 v: t
    文章来源:牛逼的工程师网友。-END-3 [- O( n6 e* R$ J
    往期推荐:点击图片即可跳转阅读
      ?. C' ^2 N0 {% f- b8 ~, S  L- a; ]6 J/ D; H

    l4rjzqbg4zf640134648.jpg

    l4rjzqbg4zf640134648.jpg
    5 B6 z% O6 t* j4 o) T+ D- B
    大模型遍地开花,分享一下我对嵌入式端侧 AI 技术的看法。: w9 m4 {4 @' U0 Y" A/ N" ^
      W9 e5 y# z% x% S! [

    bqah1zdv2xe640134748.jpg

    bqah1zdv2xe640134748.jpg

    2 M" a! e5 j6 `  F* H% l! W我发现,嵌入式工业处理器,100%国产化已经成为趋势!# R9 m5 n. B: C* \4 O5 m
    6 y" u; ?# y% ~  L9 ]  y

    t2isnjysnu1640134848.jpg

    t2isnjysnu1640134848.jpg

    7 ?0 ^  M1 y9 U/ n. j+ K9 D嵌入式设备使用蓝牙通信技术,有哪些行业领先的芯片方案?
    ) q3 C/ Y) x, x& y4 [  b" h% w+ b9 t" l; X) Y/ z
    我是老温,一名热爱学习的嵌入式工程师, ]( `0 G) o. Y0 J/ I3 L& R
    关注我,一起变得更加优秀!
  • 回复

    使用道具 举报

    发表回复

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

    本版积分规则


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