avatar

松果工作室

欢迎光临

  • 首页
  • freeRTOS
  • ESP
  • 开发手册
  • 快速笔记
  • 个人收藏
  • 工具
Home LVGL 对接 EC11
文章

LVGL 对接 EC11

Posted 2024-04-21 Updated 2024-04- 21
By YCP
32~41 min read

EC11旋转编码器驱动

本驱动核心:
滚动检测:利用检测滚动一次整个周期的 AB 电平变化来判断滚动一次
读取滚动方向函数:用于对接 LVGL。

#include "ec11.h"
#include "driver/gpio.h"

int8_t enc = 0;
int FLAG = 0;   //一次变化标志位
bool CW_1 = 0;  //电平 1
bool CW_2 = 0;  //电平 2
static void IRAM_ATTR intrHandler_ENCA(void *arg) {
    int ALV = gpio_get_level(ENCA);
    int BLV = gpio_get_level(ENCB);

    //第一次中断,如果是上升沿,记录 B 的电平
    if (FLAG == 0 && ALV == 1) {
        FLAG = 1;
        CW_1 = BLV;
    }

    //第二次中断,如果是下降沿,记录 B 的电平
    if (FLAG == 1 && ALV == 0) {
        FLAG = 0;
        CW_2 = BLV;
        if (CW_1 == 0 && CW_2 == 1) {
            enc++;
        } else if (CW_1 == 1 && CW_2 == 0) {
            enc--;
        }
    }
}

void ec11Init() {
    gpio_config_t enc_config = {
            .pin_bit_mask = 1UL << ENCA,
            .mode = GPIO_MODE_INPUT,
            .pull_up_en = GPIO_PULLUP_ENABLE,
            .pull_down_en = GPIO_PULLDOWN_DISABLE,
            .intr_type = GPIO_INTR_ANYEDGE
    };
    gpio_config(&enc_config);
    gpio_install_isr_service(0);
    gpio_isr_handler_add(ENCA, intrHandler_ENCA, (void *) ENCA);

    enc_config.pin_bit_mask = 1UL << ENCB,
            enc_config.intr_type = GPIO_INTR_DISABLE;
    gpio_config(&enc_config);

    gpio_config_t btn_config = {
            .pin_bit_mask = (1ULL << BTN_PIN),
            .mode = GPIO_MODE_INPUT,
            .pull_up_en = GPIO_PULLUP_ENABLE,
            .pull_down_en = GPIO_PULLDOWN_DISABLE,
            .intr_type = GPIO_INTR_DISABLE,
    };
    gpio_config(&btn_config);
}

int16_t ec11Read() {
    if (enc > 4) {
        enc = 1;
    } else if (enc < -4) {
        enc = -1;
    }
    return enc;
}

void ec11Reset() {
    enc = 0;
}

int ec11State() {
    return !gpio_get_level(BTN_PIN);
}
#ifndef ROTARY_ENCODER_H
#define ROTARY_ENCODER_H

#include <stdint-gcc.h>

#ifdef __cplusplus
extern "C" {
#endif

#define ENCA 10
#define ENCB 6
#define BTN_PIN 9
//外部中断定义
void ec11Init();
int16_t ec11Read();
void ec11Reset();
int ec11State();
#ifdef __cplusplus
}
#endif

#endif

驱动对接

整体流程:
初始化编码器驱动,其中注册了读取编码器方向回调
编码器回调定时自动调用检测编码器方向(-1,0,1)。当然检测完需要把编码器归零,否则一直 检测在滚动。

void lv_port_indev_init(void) {
  static lv_indev_drv_t indev_drv;
  encoder_init();
  lv_indev_drv_init(&indev_drv);
  indev_drv.type = LV_INDEV_TYPE_ENCODER;
  indev_drv.read_cb = encoder_read;
  indev_encoder = lv_indev_drv_register(&indev_drv);
}

static void encoder_init(void) {
    ec11Init();
}
//本函数自动定时调用检测,利用enc_diff的正负来选择上一个下一个对象
static void encoder_read(lv_indev_drv_t *indev_drv, lv_indev_data_t *data) {
    data->enc_diff = ec11Read();
    data->state = ec11State();

    ec11Reset();//清除实时编码器数值
}

使用

创建组
创建 3 个按钮加入组

void ui_Screen1_screen_init(void){
    //创建屏幕对象
    ui_Screen1 = lv_obj_create(NULL);
    lv_obj_clear_flag( ui_Screen1, LV_OBJ_FLAG_SCROLLABLE );

    //创建一个组链接实体按键
    lv_group_t * group = lv_group_create();
    lv_indev_set_group(indev_encoder, group);

    //创建按钮1
    lv_obj_t * button1 = lv_btn_create(ui_Screen1);
    lv_obj_set_size(button1, 60, 35);
    lv_obj_set_pos(button1, 120, 20);
    lv_obj_add_event_cb(button1, btn_event_cb, LV_EVENT_ALL, NULL);

    //创建按钮2
    lv_obj_t * button2 = lv_btn_create(ui_Screen1);
    lv_obj_set_size(button2, 60, 35);
    lv_obj_set_pos(button2, 120, 80);
    lv_obj_add_event_cb(button2, btn_event_cb, LV_EVENT_ALL, NULL);

    //创建按钮3
    lv_obj_t * button3 = lv_btn_create(ui_Screen1);
    lv_obj_set_size(button3, 60, 35);
    lv_obj_set_pos(button3, 120, 160);
    lv_obj_add_event_cb(button3, btn_event_cb, LV_EVENT_ALL, NULL);


    //链接实体按键
    lv_group_add_obj(group, button2);
    lv_group_add_obj(group, button1);
    lv_group_add_obj(group, button3);
}

现象

滚动选择 3 个按键,单机确认

延伸拓展

任何包含按钮的例子都可以用本方法对接实体


static void scroll_event_cb(lv_event_t * e)
{
    lv_obj_t * cont = lv_event_get_target(e);

    lv_area_t cont_a;
    lv_obj_get_coords(cont, &cont_a);
    lv_coord_t cont_y_center = cont_a.y1 + lv_area_get_height(&cont_a) / 2;

    lv_coord_t r = lv_obj_get_height(cont) * 7 / 10;
    uint32_t i;
    uint32_t child_cnt = lv_obj_get_child_cnt(cont);
    for(i = 0; i < child_cnt; i++) {
        lv_obj_t * child = lv_obj_get_child(cont, i);
        lv_area_t child_a;
        lv_obj_get_coords(child, &child_a);

        lv_coord_t child_y_center = child_a.y1 + lv_area_get_height(&child_a) / 2;

        lv_coord_t diff_y = child_y_center - cont_y_center;
        diff_y = LV_ABS(diff_y);

        /*Get the x of diff_y on a circle.*/
        lv_coord_t x;
        /*If diff_y is out of the circle use the last point of the circle (the radius)*/
        if(diff_y >= r) {
            x = r;
        }
        else {
            /*Use Pythagoras theorem to get x from radius and y*/
            uint32_t x_sqr = r * r - diff_y * diff_y;
            lv_sqrt_res_t res;
            lv_sqrt(x_sqr, &res, 0x8000);   /*Use lvgl's built in sqrt root function*/
            x = r - res.i;
        }

        /*Translate the item by the calculated X coordinate*/
        lv_obj_set_style_translate_x(child, x, 0);

        /*Use some opacity with larger translations*/
        lv_opa_t opa = lv_map(x, 0, r, LV_OPA_TRANSP, LV_OPA_COVER);
        lv_obj_set_style_opa(child, LV_OPA_COVER - opa, 0);
    }
}

/**
 * Translate the object as they scroll
 */
extern lv_indev_t * indev_encoder;
void lv_example_scroll_6(void){
    lv_group_t * group = lv_group_create();
    lv_indev_set_group(indev_encoder, group);

    lv_obj_t * cont = lv_obj_create(lv_scr_act());
    lv_obj_set_size(cont, 200, 200);
    lv_obj_center(cont);
    lv_obj_set_flex_flow(cont, LV_FLEX_FLOW_COLUMN);
    lv_obj_add_event_cb(cont, scroll_event_cb, LV_EVENT_SCROLL, NULL);
    lv_obj_set_style_radius(cont, LV_RADIUS_CIRCLE, 0);
    lv_obj_set_style_clip_corner(cont, true, 0);
    lv_obj_set_scroll_dir(cont, LV_DIR_VER);
    lv_obj_set_scroll_snap_y(cont, LV_SCROLL_SNAP_CENTER);
    lv_obj_set_scrollbar_mode(cont, LV_SCROLLBAR_MODE_OFF);

    uint32_t i;
    for(i = 0; i < 20; i++) {
        lv_obj_t * btn = lv_btn_create(cont);
        lv_obj_set_width(btn, lv_pct(100));

        lv_obj_t * label = lv_label_create(btn);
        lv_label_set_text_fmt(label, "Button %"LV_PRIu32, i);

        lv_group_add_obj(group, btn);
    }

    /*Update the buttons position manually for first*/
    lv_event_send(cont, LV_EVENT_SCROLL, NULL);

    /*Be sure the fist button is in the middle*/
    lv_obj_scroll_to_view(lv_obj_get_child(cont, 0), LV_ANIM_OFF);
}
void LCD(void *arg) {
    lv_example_scroll_6();
    while (vTaskDelay(1), true) {
        lv_task_handler();
        GC9A01_Update();
    }
}

scroll_event_cb()为了在滚动时候让聚焦的按钮在中央,并且按钮有滚动的效果,只是界面显示回调,不包含实体按钮对接过程,对接实体按钮还是一样的流程,注册组,加入组。

坑和笔记
ESP
License:  CC BY 4.0
Share

Further Reading

Dec 23, 2024

其他笔记

EC800K AT连接移远云 配置过程 # 配置产品信息(初次连接需配置) AT+QIOTCFG="productinfo","pxxxxt","cDVTxxxxxxxxWGVB" # 连接开发者中心 AT+QIOTREG=1 # 查询当前连接状态(+QIOTSTATE: 8为正常) AT+QI

Jun 21, 2024

环形滤波算法

#include <stdio.h> #include <stdlib.h> #define BUFFER_SIZE 10 // 缓冲区大小 #define THRESHOLD 180

Jun 17, 2024

STM32 ADC采集的三种方式

采样周期 单个采集模式 ADC_Settings: 程序使用 uint16_t ADC_Read(

OLDER

LVGL 对接键盘接口

NEWER

电子技术讲座

Recently Updated

  • ESP32(八) 简单的webserver
  • ESP32(七) NVS
  • ESP32(四) STA & AP
  • 多级菜单
  • ESP32(五) ESP32 OTA

Trending Tags

WCH Linux Elec freeRTOS STM ESP Flutter Others SwiftUI

Contents

©2025 松果工作室. Some rights reserved.

Using the Halo theme Chirpy