单片机
返回首页

ThreadX——IPC应用之事件标志

2025-02-28 来源:cnblogs

一、应用简介

在RTOS的应用开发中,事件标志主要是用来进行任务之间的事件通知。例如有A和B两个任务,A任务负责接收消息,B任务负责对消息响应。当A任务接收到消息后设置响应标志,B任务监测到响应标志被设置就执行消息响应。事件标志没被设置的时候任务是不会占用CPU的,不用像裸机程序那样不断轮询事件的发生,使得CPU的利用率更高,这也是使用RTOS的优势之一。


二、API说明

下面列出使用事件标志组时常用的几个函数


1、创建事件标志组

描述:

该函数会创建一个包含32个事件标志的事件组(其实就是一个32bit的变量),组中的32个事件标志都被初始化为零,每个事件标志由一个Bit表示(bit位置1则表明该位代表的事件标志被设置)。

参数

group_ptr :指向事件标志组控件块的指针

name_ptr :指向事件标志组名称的指针

返回值

TX_SUCCESS (0x00) :成功创建事件组

TX_GROUP_ERROR (0x06) :无效的事件组指针,指针为NULL或事件组已创建

TX_CALLER_ERROR (0x13):该服务的调用者无效

UINT tx_event_flags_create(

    TX_EVENT_FLAGS_GROUP *group_ptr,

    CHAR *name_ptr);

2、删除事件标志组

描述

此服务会删除指定的事件标志组,所有等待该组事件的挂起线程将被恢复,并给出TX_DELETED返回状态。

在删除事件标志组之前,应用程序必须确保完成(或禁用)此事件标志组的通知回调。此外,应用程序必须禁止使用已删除的事件标志组。

参数

group_ptr :指向先前创建的事件标志组的指针

返回值

TX_SUCCESS (0x00):成功删除事件标志组

TX_GROUP_ERROR (0x06):无效的事件标志组指针

TX_CALLER_ERROR (0x13):该服务的调用者无效

UINT tx_event_flags_delete(TX_EVENT_FLAGS_GROUP *group_ptr);

3、获取事件标志

描述

此服务从指定的事件标志组检索事件标志。每个事件标志组包含32个事件标志。每个标志由一个位表示。此服务可以检索由输入参数选择的各种事件标志组合。

参数

group_ptr:指向先前创建的事件标志组的指针

requested_flags:表示请求的事件标志

get_option:请求事件标志的选项(TX_AND (0x02):指定的事件标志必须全部有效;TX_OR (0x00):指定的事件部分部分有效即可;TX_AND_CLEAR (0x03):指定的事件标志必须都被设置且清除相应的事件标志;TX_OR_CLEAR (0x01):指定的事件标志部分被设置就满足条件且清除相应的事件标志)

actual_flags_ptr:指向放置检索到的事件标志的指针。请注意,获得的实际标志可能包含未被请求的标志。

wait_option:所选事件标志未被设置时服务的行为(TX_NO_WAIT (0x00000000) :不等待立即返回;TX_WAIT_FOREVER(0xFFFFFFFF):一直挂起等待直到事件标志被设置;(0x00000001 到 0xFFFFFFFE):等待的心跳节拍数,例如设置心跳是1KHZ那单位就是ms)

返回值

TX_SUCCESS(0x00)成功获得事件标志。

TX_DELETED(0x01)线程挂起时,事件标志组已删除。

TX_NO_EVENTS(0x07)服务无法在指定的等待时间内获取指定的事件。

TX_WAIT_ABORTED(0x1A)被另一个线程、计时器或中断服务打断。

TX_GROUP_ERROR(0x06)无效的事件标志组指针。

TX_PTR_ERROR(0x03)实际事件标志的无效指针。

TX_WAIT_ERROR(0x04)在非线程调用中指定了TX_NO_WAIT以外的等待选项。

TX_OPTION_ERROR(0x08)指定了无效的获取选项。

UINT tx_event_flags_get(

    TX_EVENT_FLAGS_GROUP *group_ptr,

    ULONG requested_flags, 

    UINT get_option,

    ULONG *actual_flags_ptr, 

    ULONG wait_option);

4、设置事件标志

描述

此服务根据指定的选项设置或清除事件标志组中的事件标志。 所有请求被设置事件标志的线程将从挂起状态恢复运行态。

参数

group_ptr:指向先前创建的事件标志组控制块的指针

flags_to_set:根据选择的设置选项指定要设置或清除的事件标志

set_option:将指定的事件标志与该组的当前事件标志进行“与”或“或”运算(TX_AND(0x02)、TX_OR(0x00));选择TX_AND将指定的事件标志与该组中的当前事件标志进行“与”运算。 此选项通常用于清除组中的事件标志。选择TX_OR,则将指定的事件标志与组中的当前事件进行“或”运算。

返回值

TX_SUCCESS(0x00)事件标志成功设置。

TX_GROUP_ERROR(0x06)指向事件标志组指针无效。

TX_OPTION_ERROR(0x08)指定了无效的设置选项。

UINT tx_event_flags_set(

    TX_EVENT_FLAGS_GROUP *group_ptr,

    ULONG flags_to_set,

    UINT set_option);

三、实例说明

该实例创建一个事件标志组和三个任务。标志组中包含了两个事件标志,任务1检测按键1的运行,任务2检测按键2的运行,任务3执行对应的按键响应,任务之间的通知采用事件标志的方式。


#include 'main.h'

#include 'usart.h'

#include 'gpio.h'

#include 'tx_api.h'


#define DEMO_STACK_SIZE         (2 * 1024)

#define DEMO_BYTE_POOL_SIZE     (32 * 1024)

/*事件标志*/

#define TX_EVENT_FLAG_KEY1 (1 << 0)

#define TX_EVENT_FLAG_KEY2 (1 << 1)


TX_THREAD               thread_0;

TX_THREAD               thread_1;

TX_THREAD               thread_2;


TX_BYTE_POOL            byte_pool_0;

UCHAR                   memory_area[DEMO_BYTE_POOL_SIZE];

/*事件标志组*/

TX_EVENT_FLAGS_GROUP tx_event_flags;


void    thread_0_entry(ULONG thread_input);

void    thread_1_entry(ULONG thread_input);

void    thread_2_entry(ULONG thread_input);


int main(void)

{

    HAL_Init();

    SystemClock_Config();

    MX_GPIO_Init();

    MX_USART1_UART_Init();


    tx_kernel_enter();

    while (1)

    {

    }

}


void tx_application_define(void *first_unused_memory)

{

    CHAR    *pointer = TX_NULL;


    /* Create a byte memory pool from which to allocate the thread stacks.  */

    tx_byte_pool_create(&byte_pool_0, 'byte pool 0', memory_area, DEMO_BYTE_POOL_SIZE);


    /* 创建事件标志组 */

    tx_event_flags_create(&tx_event_flags, 'my_event_group_name');


    /* Allocate the stack for thread 0.  */

    tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);

    /* Create the main thread.  */

    tx_thread_create(&thread_0, 'thread 0', thread_0_entry, 0,  

                    pointer, DEMO_STACK_SIZE, 

                    1, 1, TX_NO_TIME_SLICE, TX_AUTO_START);


    /* Allocate the stack for thread 1.  */

    tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);

    /* Create threads 1  */

    tx_thread_create(&thread_1, 'thread 1', thread_1_entry, 0,  

                    pointer, DEMO_STACK_SIZE, 

                    2, 2, TX_NO_TIME_SLICE, TX_AUTO_START);


    /* Allocate the stack for thread 2.  */

    tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);

    /* Create threads 1  */

    tx_thread_create(&thread_2, 'thread 2', thread_2_entry, 0,  

                    pointer, DEMO_STACK_SIZE, 

                    3, 3, TX_NO_TIME_SLICE, TX_AUTO_START);

}


void    thread_0_entry(ULONG thread_input)

{

    uint8_t key_cnt = 0;


    while(1)

    {

        if (HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin) != GPIO_PIN_RESET)

        {

            key_cnt++;

        }

        else

        {

            if (key_cnt > 2)

            {

                /* 按键1触发,设置事件标志 */

                tx_event_flags_set(&tx_event_flags, TX_EVENT_FLAG_KEY1, TX_OR);

            }

            key_cnt = 0;

        }


        tx_thread_sleep(20);

    }

}


void    thread_1_entry(ULONG thread_input)

{

    uint8_t key_cnt = 0;


    while(1)

    {

        if (HAL_GPIO_ReadPin(KEY2_GPIO_Port, KEY2_Pin) != GPIO_PIN_RESET)

        {

            key_cnt++;

        }

        else

        {

            if (key_cnt > 2)

            {

                /* 按键2触发,设置事件标志 */

                tx_event_flags_set(&tx_event_flags, TX_EVENT_FLAG_KEY2, TX_OR);

            }

            key_cnt = 0;

        }


        tx_thread_sleep(20);

    }

}


void    thread_2_entry(ULONG thread_input)

{

    UINT status;

    ULONG actual_events;


    while(1)

    {

        /* 等待事件标志:任意按键触发都有效 */

        status = tx_event_flags_get(&tx_event_flags, TX_EVENT_FLAG_KEY1 | TX_EVENT_FLAG_KEY2, TX_OR_CLEAR, &actual_events, TX_WAIT_FOREVER);


        if (TX_SUCCESS == status)

        {

            if (TX_EVENT_FLAG_KEY1 == (actual_events & TX_EVENT_FLAG_KEY1))

            {

                HAL_GPIO_TogglePin(LED1_GPIO_Port,LED1_Pin);

                printf('key1 is pressed, actual_events:0x%xrn', (int)actual_events);

            }


            if (TX_EVENT_FLAG_KEY2 == (actual_events & TX_EVENT_FLAG_KEY2))

            {

                HAL_GPIO_TogglePin(LED2_GPIO_Port,LED2_Pin);

                printf('key2 is pressed, actual_events:0x%xrn', (int)actual_events);

            }

        }

    }

}


效果如下:


进入单片机查看更多内容>>
相关视频
  • 【TI MSPM0 应用实战】智能小车+工业角度编码器+血氧仪+烟雾探测器!硬核参考设计详解!

  • 2022 Digi-Key KOL 系列: 你见过1GHz主频的单片机吗?Teensy 4.1开发板介绍

  • TI 新一代 C2000™ 微控制器:全方位助力伺服及马达驱动应用

  • MSP430电容触摸技术 - 防水Demo演示

  • 直播回放: Microchip Timberwolf™ 音频处理器在线研讨会

  • 基于灵动MM32W0系列MCU的指夹血氧仪控制及OTA升级应用方案分享

精选电路图
  • 1瓦线性调频增强器

  • 家用电器遥控器

  • 12V 转 28V DC-DC 变换器(基于 LM2585)

  • 红外开关

  • DS1669数字电位器

  • HA1377 桥式放大器 BCL 电容 17W(汽车音频)

    相关电子头条文章