官方提供了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; //触摸屏按下} elsedata->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; //通过按键触发使编码器增量-1encoder_state = LV_INDEV_STATE_REL; //按钮未按下(实际上已按下但是无需响应)break;case 5:act_key = LV_KEY_RIGHT; //right键 encoder_diff = 1; //通过按键触发使编码器增量1encoder_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;
}