ThreadX——IPC应用之事件标志

  • 作者:zzssdd2
  • E-mail:zzssdd2@foxmail.com

一、应用简介

在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%x\r\n", (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%x\r\n", (int)actual_events);
            }
        }
    } 	
}

效果如下:

posted @ 2020-12-12 19:13  树·哥  阅读(518)  评论(0编辑  收藏  举报