FreeRTOS xEventGroup事件标志组

事件标志组属于任务间的通信以及同步机制之一。

1、什么是时间标志组?

事件标志组可以实现多任务间的任务同步,简单来说就是在不同的任务间传递简单的标志位(这里之前被esp吐槽说我们的代码还处在51阶段,到处flag)。裸机编程全局flag确实有用,rtos里面却是另一番景象。

事件标志组交给操作系统管理,不用自己实现超时等待机制;

裸机全局变量需要注意多个“任务”进行flag修改时的冲突,os里面则不用考虑这些问题;

eventgroup还可以解决中断入口程序中和独立任务的事件同步问题;

2、代码分析:事件标志组在freertos里面如何实现?

#define configUSE_16_BIT_TICKS          0
typedef void * EventGroupHandle_t;
#if configUSE_16_BIT_TICKS == 1
	#define eventCLEAR_EVENTS_ON_EXIT_BIT	0x0100U
	#define eventUNBLOCKED_DUE_TO_BIT_SET	0x0200U
	#define eventWAIT_FOR_ALL_BITS			0x0400U
	#define eventEVENT_BITS_CONTROL_BYTES	0xff00U
#else
	#define eventCLEAR_EVENTS_ON_EXIT_BIT	0x01000000UL
	#define eventUNBLOCKED_DUE_TO_BIT_SET	0x02000000UL
	#define eventWAIT_FOR_ALL_BITS			0x04000000UL
	#define eventEVENT_BITS_CONTROL_BYTES	0xff000000UL
#endif

以上宏定义决定事件标志组的个数,一个group是四个字节,configUSE_16_BIT_TICKS的宏定义决定可以管理的事件个数,0对应24个,1对应8个,事件标志存储于  typedef TickType_t EventBits_t.

#if( configUSE_16_BIT_TICKS == 1 )
	typedef uint16_t TickType_t;
	#define portMAX_DELAY ( TickType_t ) 0xffff
#else
	typedef uint32_t TickType_t;
	#define portMAX_DELAY ( TickType_t ) 0xffffffffUL
#endif

(图片来源于网络)

创建两个任务,touchpad_task以及led_task测试代码如下:

touchpadtask用于setevent,led_task用于等待event;当没有event到达的时候,led_task会处于sudpend状态,一直等待event到达后执行相应code,demo程序实现的是触摸按键通过event控制LED翻转。

/* Touch Pad Interrupt Example

   This example code is in the Public Domain (or CC0 licensed, at your option.)

   Unless required by applicable law or agreed to in writing, this
   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "driver/gpio.h"
#include "driver/touch_pad.h"
#include "soc/rtc_cntl_reg.h"
#include "soc/sens_reg.h"

#include "freertos/event_groups.h"

static const char *TAG = "Touch pad";
#define TOUCH_THRESH_NO_USE (0)
#define TOUCH_THRESH_PERCENT (80)
#define TOUCHPAD_FILTER_TOUCH_PERIOD (10)
#define touchpad_ct 4
#define BLINK_GPIO GPIO_NUM_22
bool led_sta=0;

#define touch_eigtht (0x01 << 0)
#define touch_nine (0x01 << 1)
#define touch_four (0x01 << 2)
#define touch_seven (0x01 << 3)

unsigned char touchpad_num[4] = {8,9,4,7};

static EventGroupHandle_t touchpad_event_group;

static bool s_pad_activated[touchpad_ct];
static uint32_t s_pad_init_val[touchpad_ct];

/*
  Read values sensed at all available touch pads.
  Use 2 / 3 of read value as the threshold
  to trigger interrupt when the pad is touched.
  Note: this routine demonstrates a simple way
  to configure activation threshold for the touch pads.
  Do not touch any pads when this routine
  is running (on application start).
 */
static void tp_example_set_thresholds(void)
{
    uint16_t touch_value;
    for (int i = 0; i < touchpad_ct; i++)
    {
        //read filtered value
        touch_pad_read_filtered(touchpad_num[i], &touch_value);
        s_pad_init_val[i] = touch_value;
        ESP_LOGI(TAG, "test init: touch pad [%d] val is %d", i, touch_value);
        //set interrupt threshold.
        ESP_ERROR_CHECK(touch_pad_set_thresh(touchpad_num[i], touch_value * 2 / 3));
    }
}

static void tp_example_touch_pad_init()
{
    for (int i = 0; i < touchpad_ct; i++)
    {
        //init RTC IO and mode for touch pad.
        touch_pad_config(touchpad_num[i], TOUCH_THRESH_NO_USE);
    }
}
/*
  Handle an interrupt triggered when a pad is touched.
  Recognize what pad has been touched and save it in a table.
 */
static void tp_example_rtc_intr(void *arg)
{
    uint32_t pad_intr = touch_pad_get_status();
    //clear interrupt
    touch_pad_clear_status();
    for (int i = 0; i < touchpad_ct; i++)
    {
        if ((pad_intr >> touchpad_num[i]) & 0x01)
        {
            s_pad_activated[i] = true;
        }
    }
}

/*
  Check if any of touch pads has been activated
  by reading a table updated by rtc_intr()
  If so, then print it out on a serial monitor.
  Clear related entry in the table afterwards

  In interrupt mode, the table is updated in touch ISR.

  In filter mode, we will compare the current filtered value with the initial one.
  If the current filtered value is less than 80% of the initial value, we can
  regard it as a 'touched' event.
  When calling touch_pad_init, a timer will be started to run the filter.
  This mode is designed for the situation that the pad is covered
  by a 2-or-3-mm-thick medium, usually glass or plastic.
  The difference caused by a 'touch' action could be very small, but we can still use
  filter mode to detect a 'touch' event.
 */
static void tp_example_read_task(void *pvParameter)
{
    static int show_message;
    int change_mode = 0;
    int filter_mode = 0;

    ESP_LOGI(TAG, "Initializing touch pad");
    touch_pad_init();
    // If use interrupt trigger mode, should set touch sensor FSM mode at 'TOUCH_FSM_MODE_TIMER'.
    touch_pad_set_fsm_mode(TOUCH_FSM_MODE_TIMER);
    // Set reference voltage for charging/discharging
    // For most usage scenarios, we recommend using the following combination:
    // the high reference valtage will be 2.7V - 1V = 1.7V, The low reference voltage will be 0.5V.
    touch_pad_set_voltage(TOUCH_HVOLT_2V7, TOUCH_LVOLT_0V5, TOUCH_HVOLT_ATTEN_1V);
    // Init touch pad IO
    tp_example_touch_pad_init();
    // Initialize and start a software filter to detect slight change of capacitance.
    touch_pad_filter_start(TOUCHPAD_FILTER_TOUCH_PERIOD);
    // Set thresh hold
    tp_example_set_thresholds();
    // Register touch interrupt ISR
    touch_pad_isr_register(tp_example_rtc_intr, NULL);
    // Start a task to show what pads have been touched

    while (1)
    {
        if (filter_mode == 0)
        {
            //interrupt mode, enable touch interrupt
            touch_pad_intr_enable();
            for (int i = 0; i < touchpad_ct; i++)
            {
                if (s_pad_activated[i] == true)
                {
                    ESP_LOGI(TAG, "T%d activated!", touchpad_num[i]);
                    // Wait a while for the pad being released
                    vTaskDelay(200 / portTICK_PERIOD_MS);
                    // Clear information on pad activation
                    s_pad_activated[i] = false;
                    // Reset the counter triggering a message
                    // that application is running
                     show_message = 1;
                     ESP_LOGI(TAG,"touch number %d",touchpad_num[i] );
                     led_sta=!led_sta;
                     switch (touchpad_num[i] )
                     {
                         case 8:
                         xEventGroupSetBits(touchpad_event_group, touch_eigtht);
                         break;

                         case 9:
                         xEventGroupSetBits(touchpad_event_group, touch_nine);
                         break;

                         case 4:
                         xEventGroupSetBits(touchpad_event_group, touch_four);
                         break;

                         case 7:
                         xEventGroupSetBits(touchpad_event_group, touch_seven);
                         break;

                         default: 
                         break;


                     }
                     
                }
            }
        }
        else
        {
            //filter mode, disable touch interrupt
            touch_pad_intr_disable();
            touch_pad_clear_status();
            for (int i = 0; i < touchpad_ct; i++)
            {
                uint16_t value = 0;
                touch_pad_read_filtered(touchpad_num[i], &value);
                if (value < s_pad_init_val[i] * TOUCH_THRESH_PERCENT / 100)
                {
                    ESP_LOGI(TAG, "T%d activated!", touchpad_num[i]);
                    ESP_LOGI(TAG, "value: %d; init val: %d", value, s_pad_init_val[i]);
                    vTaskDelay(200 / portTICK_PERIOD_MS);
                    // Reset the counter to stop changing mode.
                    change_mode = 1;
                    show_message = 1;
                }
            }
        }

        vTaskDelay(10 / portTICK_PERIOD_MS);

        // If no pad is touched, every couple of seconds, show a message
        // that application is running
        if (show_message++ % 500 == 0)
        {
            ESP_LOGI(TAG, "Waiting for any pad being touched...");
        }
        // // Change mode if no pad is touched for a long time.
        // // We can compare the two different mode.
        if (change_mode++ % 2000 == 0)
        {
            filter_mode = !filter_mode;
            ESP_LOGW(TAG, "Change mode...%s", filter_mode == 0 ? "interrupt mode" : "filter mode");
        }
    }
}

/*
 * Before reading touch pad, we need to initialize the RTC IO.
 */


void led_task()
{
    EventBits_t uxBits;

    gpio_pad_select_gpio(BLINK_GPIO);
    /* Set the GPIO as a push/pull output */
    gpio_set_direction(BLINK_GPIO, GPIO_MODE_OUTPUT);
    while (1)
    {
        uxBits = xEventGroupWaitBits(touchpad_event_group, touch_eigtht | touch_nine | touch_four | touch_seven, true, false, portMAX_DELAY);
        /*  switch(uxBits)
      {
          case uxBits & touch_nine:
          break;
          case uxBits & touch_four:
          break;
          case uxBits & touch_eigtht:
          break;
          case uxBits & touch_seven:
          break;
          default:
          break;



      }
      */ ESP_LOGI(TAG, "uxBits & touch_nine %d",uxBits);
        if (uxBits & touch_nine)
        {
             gpio_set_level(BLINK_GPIO, led_sta);
        }
        if (uxBits & touch_eigtht)
        {
            gpio_set_level(BLINK_GPIO, led_sta);
        }
        if (uxBits & touch_four)
        {
            gpio_set_level(BLINK_GPIO, led_sta);
        }
        if (uxBits & touch_seven)
        {
            gpio_set_level(BLINK_GPIO, led_sta);
        }

          vTaskDelay(300 / portTICK_PERIOD_MS);
    }
}

void app_main()
{
    // Initialize touch pad peripheral, it will start a timer to run a filter
    touchpad_event_group = xEventGroupCreate();    
    xTaskCreate(&tp_example_read_task, "touch_pad_read_task", 2048, NULL, 5, NULL);
     xTaskCreate(&led_task, "led_task", 2048, NULL, 5, NULL);
}
  1.   xEventGropCreate()
  2.   xEventGropCreateStatic()
  3.   vEventGropDelete()
  4.   xEventGropWaitBits()
  5.   xEventGropSetBits()
  6.   xEventGropSetBitsFromISR()
  7.   xEventGropClearBits()
  8.   xEventGropClearBitsFromISR()
  9.   xEventGropGetBits()
  10.   xEventGropGetBitsFromISR()
  11.   xEventGropSync()

以上函数中1\4\5\6常用,需要注意的是中断里面使用需要带ISR的才行

此外需要注意  EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet )

的返回值不具有任何意义,因为xEventGropWaitBits()函数一般处于优先级较高函数,在setbit之后,该值可能会被高优先级修改后再获取到,该bit可能被清零。

 

 

 

 

 

 

 

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值