lvgl使用旋转编码器做为外部输入设备
一、前述
使用的是7.11版本的lvgl,使用旋转编码器(EC11)做为外部输入设备,平时使用触摸屏的多,但触摸屏小贵(是我太穷了),还得加个触摸芯片,也麻烦,不如旋转编码器合算,当然编码器也不如触摸屏方便。因为是第一次使用编码器做为输入设备,网上也搜不到相关的内容,只有官网上有一些实例,自己就看着改,折腾了一下,弄好了,记录一下。
二、实现步骤
(1) 初始化编码器做为输入设备。
(2) 设置相关函数。
(5) 创建一个"组",把"组"挂载到输入设备上。
(4) 将各个控件加入到创建的"组"中。
三、具体实现代码
(1)、初始化编码器做为外部输入设备
用过lvgl的应该都知道初始化一个输入设备应该要做哪些工作,只需要修改很少的东西就可以实现,这里就直接贴代码了。
打开lv_port_indev.c文件,在lv_port_indev_init()这个初始化函数里添加注册编码器输入设备的代码。
lv_indev_t * indev_encoder;
int32_t encoder_diff;
lv_indev_state_t encoder_state;
void lv_port_indev_init(void)
{
lv_indev_drv_t indev_drv;
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);
}
(2)、设置相关函数
lv_port_indev.c文件中是有输入设备回调函数的例子,但是都不完整,需要补充,编码器的话有个encoder_read()函数,如下。
static bool encoder_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
{
data->enc_diff = encoder_diff;
data->state = encoder_state;
encoder_diff = 0;
/*Return `false` because we are not buffering and no more data to read*/
return false;
}
和原先的程序相比,只是加入了把"encoder_diff"这个变量置0这一行代码,如果不置0,一直是正数或负数,会识别为一直在转动,那么会一直在控件之间进行切换。
然后还需要一个检测编码器是否转动或按下的程序,如下。
void Key_Scanf(void)
{
static bool but_flag = true;
if(digitalRead(EC_K)==0) //编码器的按键
encoder_state = LV_INDEV_STATE_PR; //按下
else
encoder_state = LV_INDEV_STATE_REL; //松开
if(digitalRead(EC_A)==0&&digitalRead(EC_B)==1&&but_flag) //编码器左转
{
encoder_diff--;
but_flag = false;
}
else if(digitalRead(EC_A)==1&&digitalRead(EC_B)==0&&but_flag)//编码器右转
{
encoder_diff++;
but_flag = false;
}
else if(digitalRead(EC_A)==1&&digitalRead(EC_B)==1)
but_flag = true;
}
在上面这段代码中,通过检测编码器的相关引脚,判断是否转动或按下,然后修改相关变量值,实现编码器的接入。用过编码器应该就能看懂。
这里使用的是查询的方式,需要定时调用这个检测编码器状态的函数。使用中断来检测更好(如果使用中断就需要修改代码了),没有中断就只能定时调用了。当然定时调用也是没问题的。
在上面代码中的"but_flag"变量我是用来防止同时触发好几次的,因为是定时调用的,间隔过小会触发好几次,所有就加了这个静态变量防止发生这种现象。
"encoder_state "这个变量是检测编码器是否按下。
"encoder_diff"这个变量是检测编码器是否旋转和旋转方向,有正有负,没有转动时应该为0。注意在其他地方使用记得声明一下变量。
到此与输入设备相关的函数就设置好了,下面就是有关"组"的了。
(3)、创建、挂载"组"
使用编码器需要使用"组"来配合。首先创建一个"组",在把这个组加载到前面创建的输入设备中,代码如下。
//指针
lv_group_t * group;
//创建一个group
group= lv_group_create();
//将group加载到输入设备中。注意,下面这个函数的第一个参数是注册输入设备时返回的指向新输入设备的指针,不要写错了
lv_indev_set_group(indev_encoder,group);
(4)、将控件加入到"组"中
把控件加入到"组"中使用void lv_group_add_obj(lv_group_t * group, lv_obj_t * obj);这个函数。例如下面的程序。
/* 创建一个按钮 */
btn_exit = lv_btn_create(lv_scr_act(),NULL);
lv_obj_set_size(btn_exit,40,20);
lv_obj_align(btn_exit, NULL, LV_ALIGN_IN_TOP_RIGHT, 0, 0);
label_btn_exit = lv_label_create(btn_exit,NULL);
lv_label_set_text(label_btn_exit,"exit");
/* 把控件添加到组中 */
lv_group_add_obj(group,btn_exit);
/* 创建一个开关 */
sw_motor = lv_switch_create(lv_scr_act(), NULL);
lv_obj_set_size(sw_motor,45,26);
lv_obj_align(sw_motor, NULL, LV_ALIGN_CENTER, 30, -10);
/* 把控件添加到组中 */
lv_group_add_obj(group,sw_motor);
在上面程序中,创建了"按钮"和"开关"两个控件,都加入到先前创建的"组"中,这样,在这个界面,转动编码器那么就在会这两个控件之间进行切换选择。
加入"组"中的先后顺序,就对应着你使用编码器在各个对象之间进行切换的先后顺序。最先加入的会先被选择,后加入的就会排在后面,就是这样的选择顺序。
三、遇到的一些问题及解决办法
要注意,并不是所有的控件都能加入"组"中。不应该说不能,应该说加入"组"也没用,我试了试,比如这个"标签"这个控件,加入到"组"中就没效果,聚焦不会切换到这个"标签"。这个"组"还有编辑模式,不知道是不是切换到编辑模式后在把"标签"控件加入到"组"中才有效果,这个我没有试。
还有一个非常重要的地方,那就是使用"页签"时,不能单纯的把"页签"加入到"组"中就完事了。这个地方好坑啊,最开始我就是用的"页签"做界面切换,然后怎么设置"组"都没用,不能正常切换显示,后来看了官方的一个有关编码器做为输入设备的例程才知道有问题,在这个例程中是把这个"页签"加入到"组"了,但是不单单如此,程序中还特地写了一个回调函数用来切换"页签"的显示页面,看到这个我才发觉不能正常使用。我也没找到好的办法,官方例程都没这样用,那应该就是不行了。虽然正经方法不行,但是可以使用一些歪点子,那就是在页签切换界面,不使用编码器做为输入设备,或者直接把扫描编码器的程序替换了,换成切换"页签"的子页面的程序,等进入了下一界面,再把扫描编码器的程序换回来,懂得都懂,不多说了。(补充:后来发现应该是同一个页面的子控件不会自动聚焦,超出屏幕范围的控件就不能正常的显示,不像使用触摸屏那样可以滑动整个页面来进行选择,所以对此加入了一个用于聚焦显示的回调函数,每次改变选择的"组"中的成员时,就会调用这个函数,通过相关函数获取所选择的对象并进行聚焦显示。这样就不会有控件无法显示的情况了。这个编码器的例程在"lv_demo_keypad_encoder.c"这个文件里,可以看一下。)
还有一个问题,就是如果有不止一个"组"加载到了同一个"输入设备",可能会窜着来。上面我说了我使用的"页签",然后选中"页签"的某一个子页面时切换到另一个界面,然后我有好几个页面,每个页面都要控件,每个页面的控件我都单独创建了一个"组",然后分开放,结果我发现,虽然不在一个"组"中,但是却可以直接从一个"组"的控件切换到另一个"组"的控件中,而且我发现改变一下把不同的"组"加载到"输入设备"的顺序后,现象还又变了,真有意思,可能是因为挂载到同一个输入设备中导致的,需要注意一下。对此我用了最笨的方法,那就是多创建几个"输入设备",一个对应一个"组",在不同的界面,“使能"不同的"输入设备”,完成"分时复用",只需要加很少的代码,效果杠杠滴。
四、结语
在本文中没有给出一个完整的demo,因为还有MCU、显示设备,每个人的都不一定一样,所有就只叙述了关键部分。只要看懂了,是一点问题也没有。
上面几个遇到的问题,也不清楚是哪里不对,反正都有法子解决,就没有深究,如果有清楚的,有好的解决办法的,可以留言告诉我,感谢。
使用EC11旋转编码器时,可以在两个信号线上加个RC低通滤波,R:10K,C:0.01uf,效果会好很多,手册上就是这样的。
如果我哪里没说清楚,还有什么问题,可以留言,这个会通过邮箱提示我,我看到会回复的。
使用编码器的简单例子:https://download.csdn.net/download/wojueburenshu/85772073
上面这个程序中,用的单色OLED和旋转编码器。感觉单色屏幕使用起来不是很方便,有些控件显示有问题,就没多研究了。
以上纯属个人经验,并且个人能力也有限,可能出现差错,如有问题请指正,我就改。
下面放几个链接。
英文的lvgl说明文档,7.11版本:https://docs.lvgl.io/latest/en/html/index.html
中文的lvg说明l文档,7.11版本:http://lvgl.100ask.net/7.11/index.html
(下面链接里面的的案例不像上面那个可以在线操作,但好歹是中文的。)
更多推荐
所有评论(0)