Description
I want to get a physical rotary encoder talking to Littlevgl as my input device. Your documentation is amazing but with littlevGL being so new i’m struggling to find full working examples to help me work through this setup process - as a newbie I’m drowning a bit .
What MCU/Processor/Board and compiler are you using?
ESP32 Dev Module with Rotary Encoder and TFT screen compiled on Arduino IDE 1.8.9 (Ubuntu)
What do you want to achieve?
Spin Rotary Encoder CW/CCW - Keyboard focus moves character L/R
Click Rotary Encoder - Focused keyboard character copied to text area.
What have you tried so far?
I have started with the basic ESP32 example - added a keyboard and text area to the screen.
Added my Encoder. This works with MD_REncoder and MD_UISwitch libraries and prints “NEXT / PREV / KEY PRESS” to the Serial Monitor, i’ve unsuccessfully tried many ways to send this data to .read_cb, have spent time reading the documentation and hunting for other examples i can pick apart…
Code to reproduce
//*********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
#define RotaryPinA 32 //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 = 33; // 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);
//*********ROTARY SETUP ABOVE HERE**********
#include <lvgl.h>
#include <Ticker.h>
#include <TFT_eSPI.h>
#define LVGL_TICK_PERIOD 20
Ticker tick; /* timer for interrupt handler */
TFT_eSPI tft = TFT_eSPI(); /* TFT instance */
static lv_disp_buf_t disp_buf;
static lv_color_t buf[LV_HOR_RES_MAX * 10];
#if USE_LV_LOG != 0
/* Serial debugging */
void my_print(lv_log_level_t level, const char * file, uint32_t line, const char * dsc)
{
Serial.printf("%s@%d->%s\r\n", file, line, dsc);
delay(100);
}
#endif
/* Display flushing */
void my_disp_flush(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p)
{
uint16_t c;
tft.startWrite(); /* Start new TFT transaction */
tft.setAddrWindow(area->x1, area->y1, (area->x2 - area->x1 + 1), (area->y2 - area->y1 + 1)); /* set the working window */
for (int y = area->y1; y <= area->y2; y++) {
for (int x = area->x1; x <= area->x2; x++) {
c = color_p->full;
tft.writeColor(c, 1);
color_p++;
}
}
tft.endWrite(); /* terminate TFT transaction */
lv_disp_flush_ready(disp); /* tell lvgl that flushing is done */
}
/* Interrupt driven periodic handler */
static void lv_tick_handler(void)
{
lv_tick_inc(LVGL_TICK_PERIOD);
}
/* Reading input device (simulated encoder here) */
bool read_encoder(lv_indev_drv_t * indev, lv_indev_data_t * data)
{
static int32_t last_diff = 0;
int32_t diff = 0; /* Dummy - no movement */
int btn_state = LV_INDEV_STATE_REL; /* Dummy - no press */
data->enc_diff = diff - last_diff;;
data->state = btn_state;
last_diff = diff;
return false;
}
void setup() {
Serial.begin(57600); /* prepare for possible serial debug */
//******Rotary and button below******
R.begin();
S.begin();
S.enableDoublePress(false);
//S.enableLongPress(false);
//S.enableRepeat(false);
// S.enableRepeatResult(true);
//******Rotary and button above******
lv_init();
#if USE_LV_LOG != 0
lv_log_register_print(my_print); /* register print function for debugging */
#endif
tft.begin(); /* TFT init */
tft.setRotation(1); /* Landscape orientation */
lv_disp_buf_init(&disp_buf, buf, NULL, LV_HOR_RES_MAX * 10);
/*Initialize the display*/
lv_disp_drv_t disp_drv;
lv_disp_drv_init(&disp_drv);
disp_drv.hor_res = 320;
disp_drv.ver_res = 240;
disp_drv.flush_cb = my_disp_flush;
disp_drv.buffer = &disp_buf;
lv_disp_drv_register(&disp_drv);
/*Initialize the touch pad*/
lv_indev_drv_t indev_drv;
lv_indev_drv_init(&indev_drv);
indev_drv.type = LV_INDEV_TYPE_ENCODER;
indev_drv.read_cb = read_encoder;
lv_indev_drv_register(&indev_drv);
/*Initialize the graphics library's tick*/
tick.attach_ms(LVGL_TICK_PERIOD, lv_tick_handler);
/* Create simple keyboard */
static lv_style_t rel_style, pr_style;
lv_style_copy(&rel_style, &lv_style_btn_rel);
rel_style.body.radius = 0;
rel_style.body.border.width = 1;
lv_style_copy(&pr_style, &lv_style_btn_pr);
pr_style.body.radius = 0;
pr_style.body.border.width = 1;
/*Create a keyboard and apply the styles*/
lv_obj_t *kb = lv_kb_create(lv_scr_act(), NULL);
lv_kb_set_cursor_manage(kb, true);
lv_kb_set_style(kb, LV_KB_STYLE_BG, &lv_style_transp_tight);
lv_kb_set_style(kb, LV_KB_STYLE_BTN_REL, &rel_style);
lv_kb_set_style(kb, LV_KB_STYLE_BTN_PR, &pr_style);
/*Create a text area. The keyboard will write here*/
lv_obj_t *ta = lv_ta_create(lv_scr_act(), NULL);
lv_obj_align(ta, NULL, LV_ALIGN_IN_TOP_MID, 0, 10);
lv_ta_set_text(ta, "");
/*Assign the text area to the keyboard*/
lv_kb_set_ta(kb, ta);
}
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("KEY_PRESS "); LV_KEY_ENTER; break; //now these clearly aren't the way to do it....
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)
{
// x == DIR_CW;
if (x == DIR_CW ) {
Serial.println("NEXT");
LV_KEY_RIGHT; //now these clearly aren't the way to do it....
}
else
{
Serial.println("PREV");
LV_KEY_LEFT; //now these clearly aren't the way to do it....
}
}
//**********************Rotary End***************
}