1634|3

155

帖子

1

TA的资源

一粒金砂(高级)

楼主
 

【建筑施工监测与安防系统】六、Kaluga的adc_button案例结合lvgl [复制链接]

 

       本篇将以lv_port_esp32案例作为模板,加上Kaluga的adc_button案例——按键控制RGB多彩灯变化。

1、Kaluga的板载按键和LED

      Kaluga共有六个按键,实际在ESP-LyraT-8311A扩展板上。这六个按键都是接入到ESP32的ADC输入脚——GPIO6。案例注释写成IO7了,后来经过查看电路图发现谬误,经过查看S2的Datasheet确定就是IO6。

      Kaluga的六个按钮分别串联不同阻值的电阻,按下后产生不同的电压输入,经由ADC读取后判断具体点击的按钮。

 

 

图6-1 Kaluga的按键电路

 

      Kaluga核心板有一个WS2812 RGB LED,相较三个IO驱动的普通RGB LED,只需一个GPIO(IO45)就可以实现控制。

 

图6-2 Kaluga的WS2812 RGB LED电路

 

2、完整移植led_strip组件

      上篇测评已经将组件移植到lv项目工程中,最简单方法就是将目录“..\esp-dev-kits\esp32-s2-kaluga-1\components\led_strip”拷贝到“..\lv_port_esp32\components”。

      代码也是参考的adc_button案例,其中定义了LED初始化函数example_rmt_init(),说明加下表。

 

表6-1 example_rmt_init()说明表

参数

说明

uint8_t gpio_num

接入Din的IO编号,即45。

int led_number

串联的LED数量,Kaluga只有一个。

uint8_t rmt_channel

RMT通道号,本例为通道0。

返回值类型:esp_err_t

 

      example_rmt_init()初始化了ESP32的RMT(Remote Control)接口。此接口是用来驱动红外发射管以产生红外控制信号,此处显示是利用其产生WS2812驱动时序。

 

图6-3 IDF文档RMT页截图

 

      adc_button案例在调用example_rmt_init()时,传入的参数0和参数1都是宏定义形式,而且是menuconfig配置自动生成的宏定义。

 

    // CONFIG_EXAMPLE_RMT_TX_GPIO是控制IO编号
    // CONFIG_EXAMPLE_STRIP_LED_NUMBER是串联的LED数量
    // 两个宏都是menuconfig配置自动生成的
    ESP_ERROR_CHECK(example_rmt_init(CONFIG_EXAMPLE_RMT_TX_GPIO, CONFIG_EXAMPLE_STRIP_LED_NUMBER, RMT_CHANNEL_0));

 

      最简单的移植方法,就是直接把参数改为45和1。不过,本人想尝试自定义menuconfig配置项,方法也很简单,就是在lv项目的main目录中创建Kconfig.projbuild文件,并添加代码如下:

 

menu "Example Configuration"
    config EXAMPLE_RMT_TX_GPIO
        int "WS2812 GPIO"
        default 45
        help
            Set the GPIO number used for transmitting the RMT signal.

    config EXAMPLE_STRIP_LED_NUMBER
        int "Number of LEDS in a strip"
        default 1
        help
            A single RGB strip contains several LEDs.

endmenu

 

      添加文件后,menuconfig就会出现“Example Configuration”选项,并包含子配置项“WS2812 GPIO”和“Number of LEDS in a strip”。一旦配置后,自动生成的“../build/config/sdkconfig.h”就会包含宏定义。

 

 

 

图6-4 自定义WS2812相关的menuconfig配置项

 

3、项目main.c代码

/*********************
 *      INCLUDES
 *********************/
#include <stdbool.h>
#include <stdio.h>
#include <stdint.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"

#include "esp_freertos_hooks.h"
#include "esp_system.h"
#include "esp_log.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_heap_caps.h"

#include "driver/gpio.h"
#include "driver/adc.h"
#include "driver/rmt.h"

#include "led_strip.h"

/* Littlevgl specific */
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
#include "lvgl.h"
#else
#include "lvgl/lvgl.h"
#endif

#include "lvgl_helpers.h" //for lv_esp32_driver



/*********************
 *      DEFINES
 *********************/
#define TAG               "demo" // LOG tag
#define LV_TICK_PERIOD_MS 1      // LVGL tick 1ms
#define NO_OF_SAMPLES     64     // 64 samples and get the average value
#define SAMPLE_TIME       200    // ADC sampling period
#define DEVIATION         0.1    // voltage ± 0.1

/**********************
 *  STATIC PROTOTYPES
 **********************/
static void lv_tick_task(void *arg);       //inc LVGL tick
static void guiTask(void *pvParameter);    //gui task func
static void create_demo_application(void); //create initial screen

void setLabel2(int i);                     //change Label2 text -- LED color
double adc_voltage_conversion(uint32_t adc_reading);//adc to voltage
esp_err_t example_rmt_init(uint8_t gpio_num, int led_number, uint8_t rmt_channel);//initialize rmt interface
void button_task(void *arg);               //button task func
void led_task(void *arg);                  //led task func
void adc_init(void);                       //initialize adc interface

static const adc_channel_t channel = ADC_CHANNEL_5;    // PIO6 if ADC1, GPIO17 if ADC2
static const adc_bits_width_t width = ADC_WIDTH_BIT_13;// ADC resolution
static const adc_atten_t atten = ADC_ATTEN_DB_11;      // ADC attenuation
static const adc_unit_t unit = ADC_UNIT_1;             // ADC1
static xQueueHandle adc_queue = NULL;                  // queue for voltage value
led_strip_t *strip;                                    // WS2812 driver interface
lv_obj_t * label2;                                     // label on screen showing LED color


/**********************
 *   APPLICATION MAIN
 **********************/
void app_main() {
    // CONFIG_EXAMPLE_RMT_TX_GPIO is the IO num, CONFIG_EXAMPLE_STRIP_LED_NUMBER is the LED count
    // both generation by menuconfig
    ESP_ERROR_CHECK(example_rmt_init(CONFIG_EXAMPLE_RMT_TX_GPIO, CONFIG_EXAMPLE_STRIP_LED_NUMBER, RMT_CHANNEL_0));

    // create queue & initialize adc
    adc_queue = xQueueCreate(1, sizeof(double));
    adc_init();

    // pin button & led task to core 0(last parameter)
    xTaskCreatePinnedToCore(&button_task, "button_task", 3 * 1024, NULL, 5, NULL, 0);
    xTaskCreatePinnedToCore(&led_task, "led_task", 3 * 1024, NULL, 5, NULL, 0);

    // pin the guiTask to core 1(last parameter)
    xTaskCreatePinnedToCore(guiTask, "gui", 4096*2, NULL, 0, NULL, 1);
}


/* Creates a semaphore to handle concurrent call to lvgl stuff
 * If you wish to call *any* lvgl function from other threads/tasks
 * you should lock on the very same semaphore! */
SemaphoreHandle_t xGuiSemaphore;

static void guiTask(void *pvParameter) {

    (void) pvParameter;
    xGuiSemaphore = xSemaphoreCreateMutex();

    lv_init();
    /* Initialize SPI or I2C bus used by the drivers */
    lvgl_driver_init();

    lv_color_t* buf1 = heap_caps_malloc(DISP_BUF_SIZE * sizeof(lv_color_t), MALLOC_CAP_DMA);
    assert(buf1 != NULL);
    /* Use double buffered when not working with monochrome displays */
#ifndef CONFIG_LV_TFT_DISPLAY_MONOCHROME
    lv_color_t* buf2 = heap_caps_malloc(DISP_BUF_SIZE * sizeof(lv_color_t), MALLOC_CAP_DMA);
    assert(buf2 != NULL);
#else
    static lv_color_t *buf2 = NULL;
#endif

    static lv_disp_buf_t disp_buf;
    uint32_t size_in_px = DISP_BUF_SIZE;
    /* Initialize the working buffer depending on the selected display.
     * NOTE: buf2 == NULL when using monochrome displays. */
    lv_disp_buf_init(&disp_buf, buf1, buf2, size_in_px);
    lv_disp_drv_t disp_drv;
    lv_disp_drv_init(&disp_drv);
    disp_drv.flush_cb = disp_driver_flush;
    disp_drv.buffer = &disp_buf;
    lv_disp_drv_register(&disp_drv);

    /* Create and start a periodic timer interrupt to call lv_tick_inc */
    const esp_timer_create_args_t periodic_timer_args = {
        .callback = &lv_tick_task,
        .name = "periodic_gui"
    };
    esp_timer_handle_t periodic_timer;
    ESP_ERROR_CHECK(esp_timer_create(&periodic_timer_args, &periodic_timer));
    ESP_ERROR_CHECK(esp_timer_start_periodic(periodic_timer, LV_TICK_PERIOD_MS * 1000));

    /* Create the demo application */
    create_demo_application();

    while (1) {
        /* Delay 1 tick (assumes FreeRTOS tick is 10ms */
        vTaskDelay(pdMS_TO_TICKS(10));

        /* Try to take the semaphore, call lvgl related function on success */
        if (pdTRUE == xSemaphoreTake(xGuiSemaphore, portMAX_DELAY)) {
            lv_task_handler();
            xSemaphoreGive(xGuiSemaphore);
        }
    }

    /* A task should NEVER return */
    free(buf1);
#ifndef CONFIG_LV_TFT_DISPLAY_MONOCHROME
    free(buf2);
#endif
    vTaskDelete(NULL);
}

static void create_demo_application(void) {
    /* Get the current screen  */
    lv_obj_t * scr = lv_disp_get_scr_act(NULL);

    /*Create a Label on the currently active screen*/
    lv_obj_t * label1 =  lv_label_create(scr, NULL);
    label2 =  lv_label_create(scr, NULL);  //added by author

    /*Modify the Label's text*/
    lv_label_set_text(label1, "ADC Button Demo with LVGL");
    lv_label_set_text(label2, "Nihao Shijie! Wonderful Tianjin!");

    /*Align the Label to the center*/
    lv_obj_align(label1, NULL, LV_ALIGN_CENTER, 0, 0);
    lv_obj_align(label2, NULL, LV_ALIGN_CENTER, 0, 50); //added by author
}

static void lv_tick_task(void *arg) {
    (void) arg;
    lv_tick_inc(LV_TICK_PERIOD_MS);
}

/* 
    change label2 text if button pressed
*/
void setLabel2(int i) {
    if(pdTRUE == xSemaphoreTake(xGuiSemaphore, portMAX_DELAY)) {
        switch(i) {
            case 0:
                lv_label_set_text(label2, "LED color: red");
                break;
            case 1:
                lv_label_set_text(label2, "LED color: green");
                break;
            case 2:
                lv_label_set_text(label2, "LED color: blue");
                break;
            case 3:
                lv_label_set_text(label2, "LED color: yellow");
                break;
            case 4:
                lv_label_set_text(label2, "LED color: purple");
                break;
            case 5:
                lv_label_set_text(label2, "LED color: white");
                break;
        }
        lv_obj_align(label2, NULL, LV_ALIGN_CENTER, 0, 50);

        xSemaphoreGive(xGuiSemaphore);
    }   
}

void adc_init(void) {
    if(unit == ADC_UNIT_1) {
        adc1_config_width(width);
        adc1_config_channel_atten(channel, atten);
    } else {
        adc2_config_channel_atten((adc2_channel_t)channel, atten);
    }
}

esp_err_t example_rmt_init(uint8_t gpio_num, int led_number, uint8_t rmt_channel) {
    ESP_LOGI(TAG, "Initializing WS2812");
    rmt_config_t config = RMT_DEFAULT_CONFIG_TX(gpio_num, rmt_channel);

    /*!< set counter clock to 40MHz */
    config.clk_div = 2;

    ESP_ERROR_CHECK(rmt_config(&config));
    ESP_ERROR_CHECK(rmt_driver_install(config.channel, 0, 0));

    led_strip_config_t strip_config = LED_STRIP_DEFAULT_CONFIG(led_number, (led_strip_dev_t)config.channel);
    strip = led_strip_new_rmt_ws2812(&strip_config);

    if(!strip) {
        ESP_LOGE(TAG, "install WS2812 driver failed");
        return ESP_FAIL;
    }

    /*!< Clear LED strip (turn off all LEDs) */
    ESP_ERROR_CHECK(strip->clear(strip, 100));
    /*!< Show simple rainbow chasing pattern */

    return ESP_OK;
}

double adc_voltage_conversion(uint32_t adc_reading) {
    double voltage = 0;
    voltage = (2.60 * adc_reading) / 8191;
    return voltage;
}

/* 
    read adc_voltage per SAMPLE_TIME ms,
    send the voltage value to queue(adc_queue)
*/
void button_task(void *arg) {
    /*!<Continuously sample ADC1*/
    while(1) {
        uint32_t adc_reading = 0;
        double voltage = 0;

        /*!< Multisampling */
        for(int i=0; i<NO_OF_SAMPLES; i++) {
            if (unit == ADC_UNIT_1) {
                adc_reading += adc1_get_raw((adc1_channel_t)channel);
            } else {
                int raw;
                adc2_get_raw((adc2_channel_t)channel, width, &raw);
                adc_reading += raw;
            }
        }

        adc_reading /= NO_OF_SAMPLES;

        voltage = adc_voltage_conversion(adc_reading);
        ESP_LOGD(TAG, "ADC%d CH%d Raw: %d   ; Voltage: %0.2lfV", unit, channel, adc_reading, voltage);

        xQueueSend(adc_queue, (double *)&voltage, 0);
        vTaskDelay(pdMS_TO_TICKS(SAMPLE_TIME));
    }

    vTaskDelete(NULL);
}

/* 
    read voltage value from queue,
    judge key value to change led color and label text
*/
void led_task(void *arg) {
    double voltage = 0;

    while(1) {
        xQueueReceive(adc_queue, &voltage, portMAX_DELAY);

        if(voltage > 2.6) {
            continue;
        } else if(voltage > 2.41 - DEVIATION && voltage <= 2.41 + DEVIATION) {
            ESP_LOGI(TAG, "rec(K1) -> red");
            ESP_ERROR_CHECK(strip->set_pixel(strip, 0, 255, 0, 0));
            ESP_ERROR_CHECK(strip->refresh(strip, 0));
            setLabel2(0);
        } else if(voltage > 1.98 - DEVIATION && voltage <= 1.98 + DEVIATION) {
            ESP_LOGI(TAG, "mode(K2) -> green");
            ESP_ERROR_CHECK(strip->set_pixel(strip, 0, 0, 255, 0));
            ESP_ERROR_CHECK(strip->refresh(strip, 0));
            setLabel2(1);
        } else if(voltage > 1.65 - DEVIATION && voltage <= 1.65 + DEVIATION) {
            ESP_LOGI(TAG, "play(K3) -> blue");
            ESP_ERROR_CHECK(strip->set_pixel(strip, 0, 0, 0, 255));
            ESP_ERROR_CHECK(strip->refresh(strip, 0));
            setLabel2(2);
        } else if(voltage > 1.11 - DEVIATION && voltage <= 1.11 + DEVIATION) {
            ESP_LOGI(TAG, "set(K4) -> yellow");
            ESP_ERROR_CHECK(strip->set_pixel(strip, 0, 255, 255, 0));
            ESP_ERROR_CHECK(strip->refresh(strip, 0));
            setLabel2(3);
        } else if(voltage > 0.82 - DEVIATION && voltage <= 0.82 + DEVIATION) {
            ESP_LOGI(TAG, "vol(K5) -> purple");
            ESP_ERROR_CHECK(strip->set_pixel(strip, 0, 255, 0, 255));
            ESP_ERROR_CHECK(strip->refresh(strip, 0));
            setLabel2(4);
        } else if(voltage > 0.38 - DEVIATION && voltage <= 0.38 + DEVIATION) {
            ESP_LOGI(TAG, "vol+(K6) -> white");
            ESP_ERROR_CHECK(strip->set_pixel(strip, 0, 255, 255, 255));
            ESP_ERROR_CHECK(strip->refresh(strip, 0));
            setLabel2(5);
        }
    }

    vTaskDelete(NULL);
}

 

 

图6-5 显示效果

 

最新回复

就是在lv项目的main目录中创建Kconfig.projbuild文件。很想学习这个例子,我翻了好多还没有搞定。   详情 回复 发表于 2022-8-15 07:25
点赞 关注(1)
 
 

回复
举报

6628

帖子

0

TA的资源

五彩晶圆(高级)

沙发
 

自定义menuconfig配置项,方法确实简便,在lv项目的main目录中创建Kconfig.projbuild文件可行

 
 
 

回复

6842

帖子

11

TA的资源

版主

板凳
 

就是在lv项目的main目录中创建Kconfig.projbuild文件。很想学习这个例子,我翻了好多还没有搞定。

点评

哈哈,我也是翻看源码,一路猜测找到的,确实资料比较少。 IDF的文档也是检索功能不好  详情 回复 发表于 2022-8-15 08:53
 
 
 

回复

155

帖子

1

TA的资源

一粒金砂(高级)

4
 
lugl4313820 发表于 2022-8-15 07:25 就是在lv项目的main目录中创建Kconfig.projbuild文件。很想学习这个例子,我翻了好多还没有搞定。

哈哈,我也是翻看源码,一路猜测找到的,确实资料比较少。

IDF的文档也是检索功能不好

 
 
 

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

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/10 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表