【建筑施工监测与安防系统】六、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 显示效果
|