What MCU/Processor/Board and compiler are you using?
- ESP32E
What LVGL version are you using?
9.1.0
What do you want to achieve?
controle a no touch display with encoder and keypad
What have you tried so far?
I’m confident that all my wiring is correct. I used SquareLine Studio 1.4.2 for the UI. Using serial print, I verified that both input devices (encoder and keypad) are working fine. My code is not the final version yet, but the issue I’m facing is that I want to start by using demos from the LVGL library, specifically the msgbox
, where I should press OK with the encoder button. I’m not sure why it’s not working
This is my main Code
// Arduino-TFT_eSPI board-template main routine. There's a TFT_eSPI create+flush driver already in LVGL-9.1 but we create our own here for more control (like e.g. 16-bit color swap).
#include <Arduino.h>
#include <lvgl.h>
#include <TFT_eSPI.h>
#include <ui.h>
////////////////////////// Include Libraries ////////////////////////////////////////////////////////
#include <Keypad_I2C.h>
#include <Keypad.h>
#include <Wire.h>
////////////////////////// Defines //////////////////////////////////////////////////////////////////
#define I2C_Addr 0x20 // I2C Address of PCF8574-board: 0x20 - 0x27
const byte NbrRows = 4; // Number of Rows
const byte NbrColumns = 3; // Number of Columns
////////////////////////// Layout of the Keys on Keypad /////////////////////////////////////////////
char KeyPadLayout[NbrRows][NbrColumns] = {
{'1', '2', '3'},
{'4', '5', '6'},
{'7', '8', '9'},
{'*', '0', '#'}};
////////////////////////// Wiring of PCF8574-IO-Pins ////////////////////////////////////////////////
byte PinsLines[NbrRows] = {0, 1, 2, 3};
/*-*/ // ROWS Pins
byte PinsColumns[NbrColumns] = {4, 5, 6}; // COLUMNS Pins
////////////////////////// Initialise KeyPad ////////////////////////////////////////////////////////
Keypad_I2C i2cKeypad(makeKeymap(KeyPadLayout), PinsLines, PinsColumns, NbrRows, NbrColumns, I2C_Addr);
//*********ROTARY SETUP BELOW HERE**********
#include <MD_REncoder.h> // This library for rotary
unsigned long lastDebounceTime = 0; // the last time the output pin was toggled
unsigned long debounceDelay = 50; // the debounce time; increase if the output flickers
int32_t RotaryCount = 0; // used to track rotary position
#define RotaryPinA 33 // SET DT PIN
#define RotaryPinB 25 // SET CLK PIN
MD_REncoder R = MD_REncoder(RotaryPinA, RotaryPinB);
#include <MD_UISwitch.h> //This library for button click (on the rotary)
const uint8_t DIGITAL_SWITCH_PIN = 35; // SET SW PIN
const uint8_t DIGITAL_SWITCH_ACTIVE = LOW; // digital signal when switch is pressed 'on'
MD_UISwitch_Digital S(DIGITAL_SWITCH_PIN, DIGITAL_SWITCH_ACTIVE);
int ButtonPressed = 0; // 0 is not pressed, 1 is pressed
/*Don't forget to set Sketchbook location in File/Preferences to the path of your UI project (the parent foder of this INO file)*/
/*Change to your screen resolution*/
static const uint16_t screenWidth = 240;
static const uint16_t screenHeight = 240;
enum
{
SCREENBUFFER_SIZE_PIXELS = screenWidth * screenHeight / 10
};
static lv_color_t buf[SCREENBUFFER_SIZE_PIXELS];
TFT_eSPI tft = TFT_eSPI(screenWidth, screenHeight); /* TFT instance */
#if LV_USE_LOG != 0
/* Serial debugging */
void my_print(const char *buf)
{
Serial.printf(buf);
Serial.flush();
}
#endif
/* Display flushing */
void my_disp_flush(lv_display_t *disp, const lv_area_t *area, uint8_t *pixelmap)
{
uint32_t w = (area->x2 - area->x1 + 1);
uint32_t h = (area->y2 - area->y1 + 1);
if (LV_COLOR_16_SWAP)
{
size_t len = lv_area_get_size(area);
lv_draw_sw_rgb565_swap(pixelmap, len);
}
tft.startWrite();
tft.setAddrWindow(area->x1, area->y1, w, h);
tft.pushColors((uint16_t *)pixelmap, w * h, true);
tft.endWrite();
lv_disp_flush_ready(disp);
}
/*Read the touchpad*/
/*void my_touchpad_read (lv_indev_t * indev_driver, lv_indev_data_t * data)
{
uint16_t touchX = 0, touchY = 0;
bool touched = false;//tft.getTouch( &touchX, &touchY, 600 );
if (!touched)
{
data->state = LV_INDEV_STATE_REL;
}
else
{
data->state = LV_INDEV_STATE_PR;
data->point.x = touchX;
data->point.y = touchY;
Serial.print( "Data x " );
Serial.println( touchX );
Serial.print( "Data y " );
Serial.println( touchY );
}
}*/
static uint32_t keypad_get_key(void)
{
/*char key_ch = 0;
Wire.requestFrom(I2C_Addr, 1);
while (Wire.available() > 0) {
key_ch = Wire.read();
}*/
char KeyRead = i2cKeypad.getKey();
return KeyRead;
}
static void keypad_read(lv_indev_t *indev_drv, lv_indev_data_t *data)
{
static uint32_t last_key = 0;
uint32_t act_key;
act_key = keypad_get_key();
if (act_key != 0)
{
data->state = LV_INDEV_STATE_PR;
Serial.printf("Key pressed : 0x%x\n", act_key);
last_key = act_key;
}
else
{
data->state = LV_INDEV_STATE_REL;
}
data->key = last_key;
}
/*Set tick routine needed for LVGL internal timings*/
static uint32_t my_tick_get_cb(void) { return millis(); }
int counter = 0;
int State;
int old_State;
int move_flag = 0;
void my_encoder_read(lv_indev_t *drv, lv_indev_data_t *data);
static lv_group_t *g;
void setup()
{
Serial.begin(115200); /* prepare for possible serial debug */
//******Rotary and button read below******
R.begin();
S.begin();
S.enableDoublePress(false);
// S.enableLongPress(false);
// S.enableRepeat(false);
// S.enableRepeatResult(true);
//******Rotary and button read above******
//******i2c keypad setup below******
Serial.println(F("--- Begin: Check Connection ..."));
Wire.begin(21, 22); // Init I2C-Bus, GPIO4-Data, GPIO5 Clock
Wire.beginTransmission(I2C_Addr); // Try to establish connection
if (Wire.endTransmission() != 0) // No Connection established
{
Serial.print(" NO ");
} // if (Wire.endTransmission() != 0)
else
{
Serial.print(" ");
} // else to if (Wire.endTransmission() != 0)
Serial.print(F("Device found on"));
Serial.print(F(" (0x"));
Serial.print(I2C_Addr, HEX);
Serial.println(F(")."));
Serial.println(F("--- End: Check Connection"));
Serial.print(F("--- Starting I2C-KeyPad-Library ..."));
i2cKeypad.begin(); // Start i2cKeypad
Serial.println(F("started."));
//******i2c keypad setup above******
String LVGL_Arduino = "Hello Arduino! ";
LVGL_Arduino += String('V') + lv_version_major() + "." + lv_version_minor() + "." + lv_version_patch();
Serial.println(LVGL_Arduino);
Serial.println("I am LVGL_Arduino");
lv_init();
#if LV_USE_LOG != 0
lv_log_register_print_cb(my_print); /* register print function for debugging */
#endif
tft.begin(); /* TFT init */
tft.setRotation(0); /* Landscape orientation, flipped */
static lv_disp_t *disp;
disp = lv_display_create(screenWidth, screenHeight);
lv_display_set_buffers(disp, buf, NULL, SCREENBUFFER_SIZE_PIXELS * sizeof(lv_color_t), LV_DISPLAY_RENDER_MODE_PARTIAL);
lv_display_set_flush_cb(disp, my_disp_flush);
/*static lv_indev_t* indev;
indev = lv_indev_create();
lv_indev_set_type( indev, LV_INDEV_TYPE_POINTER );
lv_indev_set_read_cb( indev, my_touchpad_read );*/
ui_init();
g = lv_group_create();
lv_group_set_default(g);
// encoder
static lv_indev_t *enc_drv;
enc_drv = lv_indev_create();
lv_indev_set_type(enc_drv, LV_INDEV_TYPE_ENCODER);
lv_indev_set_read_cb(enc_drv, my_encoder_read);
lv_indev_set_group(enc_drv, g);
// keypad
static lv_indev_t *kb_drv;
kb_drv = lv_indev_create();
lv_indev_set_type(kb_drv, LV_INDEV_TYPE_KEYPAD);
lv_indev_set_read_cb(kb_drv, keypad_read);
lv_indev_set_group(kb_drv, g);
lv_tick_set_cb(my_tick_get_cb);
Serial.println("Setup done");
}
void loop()
{
lv_task_handler(); /* let the GUI do its work */
delay(5);
//**********************ClickButton Start*************
MD_UISwitch::keyResult_t k = S.read();
switch (k)
{
case MD_UISwitch::KEY_NULL: /* Serial.print("KEY_NULL"); */
break;
case MD_UISwitch::KEY_UP: /*Serial.print("\nKEY_UP "); */
break;
case MD_UISwitch::KEY_DOWN: /* Serial.print("\n\nKEY_DOWN ");*/
break;
case MD_UISwitch::KEY_PRESS:
Serial.println("********************* A KEY_PRESS ");
ButtonPressed = 1;
break;
case MD_UISwitch::KEY_DPRESS:
Serial.println("KEY_DOUBLE ");
break;
case MD_UISwitch::KEY_LONGPRESS:
Serial.println("KEY_LONG ");
break;
case MD_UISwitch::KEY_RPTPRESS: /*Serial.print("\nKEY_REPEAT ");*/
break;
default: /*Serial.print("\nKEY_UNKNWN ");*/
break;
}
//**********************ClickButton End***************
//**********************Rotary Start***************
uint8_t x = R.read();
if (x)
{
if (x == DIR_CW)
{
Serial.print("NEXT ");
++RotaryCount;
Serial.println(RotaryCount);
}
else
{
Serial.print("PREV ");
--RotaryCount;
Serial.println(RotaryCount);
}
}
//**********************Rotary End***************
}
void my_encoder_read(lv_indev_t *drv, lv_indev_data_t *data)
{
static int lastBtn;
static int32_t last_diff = 0;
int32_t diff = RotaryCount;
int btn_state = 0;
if (ButtonPressed == 1)
{
data->state = LV_INDEV_STATE_PR;
ButtonPressed = 0;
Serial.println("Button Pressed and Variable RESET to 0");
}
else
{
data->state = LV_INDEV_STATE_REL;
}
/*Serial.print("diff: ");
Serial.println(diff);
Serial.print("diff - last_diff: ");
Serial.println(diff - last_diff);*/
data->enc_diff = diff - last_diff;
last_diff = diff;
if (lastBtn != btn_state)
{
lastBtn = btn_state;
}
// Serial.println();
// return false;
}
Code for First Page (Potential Issue Area)
// This file was generated by SquareLine Studio
// SquareLine Studio version: SquareLine Studio 1.4.2
// LVGL version: 9.1.0
// Project name: V0
#include "ui.h"
/**********************
* STATIC PROTOTYPES
**********************/
static void selectors_create(lv_obj_t * parent);
static void text_input_create(lv_obj_t * parent);
static void msgbox_create(void);
static void ta_event_cb(lv_event_t * e);
/**********************
* STATIC VARIABLES
**********************/
static lv_obj_t * tv;
static lv_obj_t * t1;
static lv_obj_t * t2;
/**********************/
void ui_Available_screen_init(void)
{
ui_Available = lv_obj_create(NULL);
lv_obj_remove_flag(ui_Available, LV_OBJ_FLAG_SCROLLABLE); /// Flags
ui_Image10 = lv_image_create(ui_Available);
lv_image_set_src(ui_Image10, &ui_img_available_png);
lv_obj_set_width(ui_Image10, LV_SIZE_CONTENT); /// 240
lv_obj_set_height(ui_Image10, LV_SIZE_CONTENT); /// 240
lv_obj_set_align(ui_Image10, LV_ALIGN_CENTER);
lv_obj_add_flag(ui_Image10, LV_OBJ_FLAG_ADV_HITTEST); /// Flags
lv_obj_remove_flag(ui_Image10, LV_OBJ_FLAG_SCROLLABLE); /// Flags
ui_NextMeet = lv_textarea_create(ui_Available);
lv_obj_set_width(ui_NextMeet, 143);
lv_obj_set_height(ui_NextMeet, LV_SIZE_CONTENT); /// 70
lv_obj_set_x(ui_NextMeet, -15);
lv_obj_set_y(ui_NextMeet, 67);
lv_obj_set_align(ui_NextMeet, LV_ALIGN_CENTER);
lv_textarea_set_max_length(ui_NextMeet, 6);
lv_textarea_set_placeholder_text(ui_NextMeet, "00:00h");
lv_textarea_set_one_line(ui_NextMeet, true);
lv_obj_set_style_text_color(ui_NextMeet, lv_color_hex(0x3D85C6), LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_text_opa(ui_NextMeet, 255, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_text_align(ui_NextMeet, LV_TEXT_ALIGN_CENTER, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_text_font(ui_NextMeet, &lv_font_montserrat_32, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_bg_color(ui_NextMeet, lv_color_hex(0xDEF2C5), LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_bg_opa(ui_NextMeet, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_border_color(ui_NextMeet, lv_color_hex(0x000000), LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_border_opa(ui_NextMeet, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_text_color(ui_NextMeet, lv_color_hex(0x3D85C6), LV_PART_TEXTAREA_PLACEHOLDER | LV_STATE_DEFAULT);
lv_obj_set_style_text_opa(ui_NextMeet, 255, LV_PART_TEXTAREA_PLACEHOLDER | LV_STATE_DEFAULT);
lv_obj_set_style_text_align(ui_NextMeet, LV_TEXT_ALIGN_CENTER, LV_PART_TEXTAREA_PLACEHOLDER | LV_STATE_DEFAULT);
lv_obj_set_style_text_font(ui_NextMeet, &lv_font_montserrat_32, LV_PART_TEXTAREA_PLACEHOLDER | LV_STATE_DEFAULT);
//lv_obj_add_event_cb(ui_Available, ui_event_Available, LV_EVENT_ALL, NULL);
tv = lv_tabview_create(lv_screen_active());
t1 = lv_tabview_add_tab(tv, "Selectors");
t2 = lv_tabview_add_tab(tv, "Text input");
//selectors_create(t1);
//text_input_create(t2);
msgbox_create();
}
static void msgbox_create(void)
{
lv_obj_t * mbox = lv_msgbox_create(NULL);
lv_msgbox_add_title(mbox, "Hi");
lv_msgbox_add_text(mbox, "Welcome to the keyboard and encoder demo");
lv_obj_t * btn = lv_msgbox_add_footer_button(mbox, "Ok");
lv_obj_add_event_cb(btn, msgbox_event_cb, LV_EVENT_CLICKED, mbox);
lv_group_focus_obj(btn);
lv_obj_add_state(btn, LV_STATE_FOCUS_KEY);
lv_group_focus_freeze(lv_group_create(), true);
lv_obj_align(mbox, LV_ALIGN_CENTER, 0, 0);
lv_obj_t * bg = lv_obj_get_parent(mbox);
lv_obj_set_style_bg_opa(bg, LV_OPA_70, 0);
lv_obj_set_style_bg_color(bg, lv_palette_main(LV_PALETTE_GREY), 0);
}
static void selectors_create(lv_obj_t * parent)
{
lv_obj_set_flex_flow(parent, LV_FLEX_FLOW_COLUMN);
lv_obj_set_flex_align(parent, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
lv_obj_t * obj;
obj = lv_table_create(parent);
lv_table_set_cell_value(obj, 0, 0, "00");
lv_table_set_cell_value(obj, 0, 1, "01");
lv_table_set_cell_value(obj, 1, 0, "10");
lv_table_set_cell_value(obj, 1, 1, "11");
lv_table_set_cell_value(obj, 2, 0, "20");
lv_table_set_cell_value(obj, 2, 1, "21");
lv_table_set_cell_value(obj, 3, 0, "30");
lv_table_set_cell_value(obj, 3, 1, "31");
lv_obj_add_flag(obj, LV_OBJ_FLAG_SCROLL_ON_FOCUS);
obj = lv_calendar_create(parent);
lv_obj_add_flag(obj, LV_OBJ_FLAG_SCROLL_ON_FOCUS);
obj = lv_buttonmatrix_create(parent);
lv_obj_add_flag(obj, LV_OBJ_FLAG_SCROLL_ON_FOCUS);
obj = lv_checkbox_create(parent);
lv_obj_add_flag(obj, LV_OBJ_FLAG_SCROLL_ON_FOCUS);
obj = lv_slider_create(parent);
lv_slider_set_range(obj, 0, 10);
lv_obj_add_flag(obj, LV_OBJ_FLAG_SCROLL_ON_FOCUS);
obj = lv_switch_create(parent);
lv_obj_add_flag(obj, LV_OBJ_FLAG_SCROLL_ON_FOCUS);
obj = lv_spinbox_create(parent);
lv_obj_add_flag(obj, LV_OBJ_FLAG_SCROLL_ON_FOCUS);
obj = lv_dropdown_create(parent);
lv_obj_add_flag(obj, LV_OBJ_FLAG_SCROLL_ON_FOCUS);
obj = lv_roller_create(parent);
lv_obj_add_flag(obj, LV_OBJ_FLAG_SCROLL_ON_FOCUS);
lv_obj_t * list = lv_list_create(parent);
lv_obj_update_layout(list);
if(lv_obj_get_height(list) > lv_obj_get_content_height(parent)) {
lv_obj_set_height(list, lv_obj_get_content_height(parent));
}
lv_list_add_button(list, LV_SYMBOL_OK, "Apply");
lv_list_add_button(list, LV_SYMBOL_CLOSE, "Close");
lv_list_add_button(list, LV_SYMBOL_EYE_OPEN, "Show");
lv_list_add_button(list, LV_SYMBOL_EYE_CLOSE, "Hide");
lv_list_add_button(list, LV_SYMBOL_TRASH, "Delete");
lv_list_add_button(list, LV_SYMBOL_COPY, "Copy");
lv_list_add_button(list, LV_SYMBOL_PASTE, "Paste");
}
static void text_input_create(lv_obj_t * parent)
{
lv_obj_set_flex_flow(parent, LV_FLEX_FLOW_COLUMN);
lv_obj_t * ta1 = lv_textarea_create(parent);
lv_obj_set_width(ta1, LV_PCT(100));
lv_textarea_set_one_line(ta1, true);
lv_textarea_set_placeholder_text(ta1, "Click with an encoder to show a keyboard");
lv_obj_t * ta2 = lv_textarea_create(parent);
lv_obj_set_width(ta2, LV_PCT(100));
lv_textarea_set_one_line(ta2, true);
lv_textarea_set_placeholder_text(ta2, "Type something");
lv_obj_t * kb = lv_keyboard_create(lv_screen_active());
lv_obj_add_flag(kb, LV_OBJ_FLAG_HIDDEN);
lv_obj_add_event_cb(ta1, ta_event_cb, LV_EVENT_ALL, kb);
lv_obj_add_event_cb(ta2, ta_event_cb, LV_EVENT_ALL, kb);
}
static void ta_event_cb(lv_event_t * e)
{
lv_indev_t * indev = lv_indev_active();
if(indev == NULL) return;
lv_indev_type_t indev_type = lv_indev_get_type(indev);
lv_event_code_t code = lv_event_get_code(e);
lv_obj_t * ta = lv_event_get_target(e);
lv_obj_t * kb = lv_event_get_user_data(e);
if(code == LV_EVENT_CLICKED && indev_type == LV_INDEV_TYPE_ENCODER) {
lv_keyboard_set_textarea(kb, ta);
lv_obj_remove_flag(kb, LV_OBJ_FLAG_HIDDEN);
lv_group_focus_obj(kb);
lv_group_set_editing(lv_obj_get_group(kb), kb != NULL);
lv_obj_set_height(tv, LV_VER_RES / 2);
lv_obj_align(kb, LV_ALIGN_BOTTOM_MID, 0, 0);
}
if(code == LV_EVENT_READY || code == LV_EVENT_CANCEL) {
lv_obj_add_flag(kb, LV_OBJ_FLAG_HIDDEN);
lv_obj_set_height(tv, LV_VER_RES);
}
}