【LVGL】不同类型输入设备驱动接口的实现

发布时间:2024年01月07日

官方提供了lv_port_indev_template.c文件,用以实现触摸屏、鼠标、键盘、编码器、按钮五种输入设备的接口程序。使用相应的设备,就需要去掉接口部分的注释,填充相应的初始化函数和读取函数。
LVGL支持多设备输入,只需要在lv_port_indev_init()函数中注册多个输入设备结构体即可。
比如,这里注册了三个输入设备,分别对应触摸屏键盘编码器

void lv_port_indev_init(void)
{
    static lv_indev_drv_t indev_drv1, indev_drv2, indev_drv3;

    /* 初始化触摸屏 */
    touchpad_init();

    /* 注册触摸屏输入设备 */
    lv_indev_drv_init(&indev_drv1);
    indev_drv1.type = LV_INDEV_TYPE_POINTER;
    indev_drv1.read_cb = touchpad_read;
    indev_touchpad = lv_indev_drv_register(&indev_drv1);

    /* 初始化键盘 */
    keypad_init();

    /* 注册键盘输入设备 */
    lv_indev_drv_init(&indev_drv2);
    indev_drv2.type = LV_INDEV_TYPE_KEYPAD;
    indev_drv2.read_cb = keypad_read;
    indev_keypad = lv_indev_drv_register(&indev_drv2);

    /* 初始化编码器 */
    encoder_init();

    /* 注册编码器输入设备 */
    lv_indev_drv_init(&indev_drv3);
    indev_drv3.type = LV_INDEV_TYPE_ENCODER;
    indev_drv3.read_cb = encoder_read;
    indev_encoder = lv_indev_drv_register(&indev_drv3);
}

需要注意的是,键盘和编码器需要绑定到对应的group,才能对group里的控件进行响应。

	g = lv_group_create();					//创建组
	lv_group_set_default(g);				//设置当前组为默认
	lv_indev_set_group(indev_encoder, g);	//设置当前组的输入设备为编码器

对于触摸屏来说,需要在touchpad_init()函数中通过iic完成对触摸芯片的初始化,在touchpad_read()函数中判断触摸状态读取触摸坐标

static void touchpad_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
{
    static lv_coord_t last_x = 0;
    static lv_coord_t last_y = 0;

    /* 保存按下的坐标和状态 */
    if(touchpad_is_pressed())
    {
        touchpad_get_xy(&last_x, &last_y);			//获取触摸坐标点
        data->state = LV_INDEV_STATE_PR;			//触摸屏按下
    } 
    else
        data->state = LV_INDEV_STATE_REL;			//触摸屏松开

    /* 设置最后按下的坐标 */
    data->point.x = last_x;
    data->point.y = last_y;
}

键盘输入设备可以是普通按键,也可以是红外遥控键盘,只要能得到不同的键值就行。键盘输入设备的初始化keypad_init()主要对IO口进行初始化操作,通过keypad_read()查询按键状态以及当前键值。

static void keypad_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
{
    static uint32_t last_key = 0;

    /* 获取按键是否被按下,并保存键值 */
    uint32_t act_key = keypad_get_key();
    if(act_key != 0) 
    {
        data->state = LV_INDEV_STATE_PR;		//按键按下
        /* 将键值转换成 LVGL 的事件控制字符 */
        switch(act_key) 						//键值不为0,说明有按键按下
        {				
			case 21:
				act_key = LV_KEY_DOWN;
				break;
			case 64:
				act_key = LV_KEY_ENTER;
				break;
			case 67:
				act_key = LV_KEY_NEXT;
				break;
			case 68:
				act_key = LV_KEY_PREV;
				break;
			case 70:
				act_key = LV_KEY_UP;
				break;
			default:
				break;		
        }
        last_key = act_key;
    } 
    else 
        data->state = LV_INDEV_STATE_REL;		//按键释放

    data->key = last_key;
}

编码器由于既有旋钮又有按钮,故相比键盘输入设备多了读取旋钮状态的部分代码。

static void encoder_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
{
	static uint32_t last_key = 0;
	uint32_t act_key = key_scan(0);			//读取键值
	int8_t adc_num = adc_get_number();		//读取编码器增量,这里用adc采样分段量化进行模拟
    if(act_key != 0) 						//按键按下
    {
        switch(act_key) 
        {
            case 4:							
                act_key = LV_KEY_ENTER;				//enter键
                encoder_state = LV_INDEV_STATE_PR;    //按钮按下,触发相应的输入事件
                break;
            case 1:
                act_key = LV_KEY_LEFT;				//left键
                encoder_diff = -1;					//通过按键触发使编码器增量-1
                encoder_state = LV_INDEV_STATE_REL;	//按钮未按下(实际上已按下但是无需响应)
                break;
            case 5:
                act_key = LV_KEY_RIGHT;				//right键    
                encoder_diff = 1;					//通过按键触发使编码器增量1
                encoder_state = LV_INDEV_STATE_REL;	//按钮未按下(实际上已按下但是无需响应)
                break;
            default:
            	break;
        }
        last_key = act_key;
    }
    else if(adc_num != 0)					//编码器转动
	{
		encoder_diff = adc_num;				//增量为正会向下切换控件,增量为负会向上切换控件
     	encoder_state = LV_INDEV_STATE_REL;
	}
    else									//既无按键按下,也无编码器增量
    {
        encoder_diff = 0;
        encoder_state = LV_INDEV_STATE_REL;
    }
    data->key = last_key;					//编码器键值
    data->enc_diff = encoder_diff;			//编码器增量
    data->state = encoder_state;			//编码器触发状态
    encoder_diff=0;							//将增量置为0,否则会一直触发
}

adc模拟编码器增量的代码如下

uint32_t adc_value;

int8_t adc_get_number(void)
{
	int8_t ret =0;
	
	adc_value =adc_get_result(1);			//调节电位器,获取不同的ADC采样值

	if(adc_value < 400)
		adc_number = 1;
	else if(adc_value > 800 && adc_value < 1200)
		adc_number = 2;
	else if(adc_value > 1600 && adc_value < 2000)
		adc_number = 3;
	else if(adc_value > 2400 && adc_value < 2800)
		adc_number = 4;
	else if(adc_value > 3200 && adc_value < 3600)
		adc_number = 5;
	if(adc_number > adc_number_prev)
		ret = 1;
	else if(adc_number < adc_number_prev)
		ret = -1;
	adc_number_prev = adc_number;
	
	return ret;
}
文章来源:https://blog.csdn.net/zhvngchvng/article/details/135445696
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。