官方提供了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;
}