ESP8266 MP3制作——关于SelectionList从源码中改代码的一次经历
SelectionList修改源码(这可能为扩展引脚提供一个新思路)
原因
上一篇文章已经提到了SelectionList的神奇功能,然后在setup中有这个一段代码:
u8g2.begin(/* menu_select_pin= */ 5, /* menu_next_pin= */ 4, /* menu_prev_pin= */ 2, /* menu_up_pin= */ U8X8_PIN_NONE, /* menu_down_pin= */ U8X8_PIN_NONE, /* menu_home_pin= */ 3);
- 可以定义6个引脚来完成这个功能,后续我查了一下源码,发现menu_next_pin和menu_down_pin的功能是一样的,而menu_prev_pin和menu_up_pin的功能是一样的,也就是说我如果要得到这里面全部的功能,至少需要4个引脚,但是我数了一下我的Nodemcu,只剩2个引脚可以使用,这可就难办了。
- 我第一个想到的是扩展引脚,之前好像听说过一个芯片叫74HC595,能扩展io口,买回来才知道它只能扩展o口(output)不能扩展i口(input)。而且如果要把引脚和这个功能关联起来,这个引脚肯定得是能叫得上名字的,也就是自带的引脚,很显然不能用扩展引脚。
- 接着我想能不能先看看它的映射关系是怎么样的(即是说这个库是怎么把引脚和功能关联的),**找到这种关联的关系,然后植入自己想要的代码,就可以把想要的功能继承过来了。**至于input口不够的问题,我突然也找到了一个解决办法:用nodemcu仅有的模拟引脚接收信号,不同的按钮接不同的电阻,读出来的模拟值就不同,通过这个来判断按下的是哪个键即可,至于具体电阻值等参数,自己算好然后测试就可以了。
找代码
(注:如果你使用的是新版本的arduino开发工具,要找哪个函数的源代码直接右键然后跳转到定义即可)
先观察代码:
current_selection = u8g2.userInterfaceSelectionList("Cloud Types",current_selection, string_list);if ( current_selection == 0 ) {u8g2.userInterfaceMessage("Nothing selected.", "",""," ok ");} else {u8g2.userInterfaceMessage("Selection:", u8x8_GetStringLineStart(current_selection-1, string_list ),""," ok \n cancel ");}
这个是放在loop里面的,userInterfaceSelectionList是个阻塞函数,只有当其中一个项被选中才会返回,然后弹出一个确认界面,这就是上述代码的大致功能。
很显然,我们如果想要在显示SelectionList的时候控制menu_next_pin等功能,就得查看userInterfaceSelectionList的源码
在这个文件的最上方引入了这个文件
#include <U8g2lib.h>
所以我们进入这个文件(文档\Arduino\libraries\U8g2\src\U8g2lib.h),用查找功能查找
发现它其实是调用了u8g2_UserInterfaceSelectionList这个函数,在文件的最上方看头文件:#ifndef U8G2LIB_HH #define U8G2LIB_HH#ifdef ARDUINO #include <Arduino.h> #include <Print.h> #endif#include "U8x8lib.h"#include "clib/u8g2.h"
只有后面两个比较像,而函数名是u8g2开头的,下看最后一个文件
果然找到了,不知道是只有这个库写得这么清楚还是,他直接标出这个函数的定义的.c文件的位置,所以点卡这个文件,找到这个函数即可
好啦,找到之后剩下的代码分析部分等明天再来补充,未完待续。。。
从这里开始
好久没写博客了,突然想起来我还有这篇没写完,继续补齐
分析源码
这个是我找到的库的源代码:
里面有我阅读源码的注释
uint8_t u8g2_UserInterfaceSelectionList(u8g2_t *u8g2, const char *title, uint8_t start_pos, const char *sl)
{//一些数据处理,比如说绘画位置的确定u8sl_t u8sl;u8g2_uint_t yy;uint8_t event;u8g2_uint_t line_height = u8g2_GetAscent(u8g2) - u8g2_GetDescent(u8g2)+MY_BORDER_SIZE;uint8_t title_lines = u8x8_GetStringLineCnt(title);uint8_t display_lines;if ( start_pos > 0 ) /* issue 112 */start_pos--; /* issue 112 */if ( title_lines > 0 ){display_lines = (u8g2_GetDisplayHeight(u8g2)-3) / line_height;u8sl.visible = display_lines;u8sl.visible -= title_lines;}else{display_lines = u8g2_GetDisplayHeight(u8g2) / line_height;u8sl.visible = display_lines;}u8sl.total = u8x8_GetStringLineCnt(sl);u8sl.first_pos = 0;u8sl.current_pos = start_pos;if ( u8sl.current_pos >= u8sl.total )u8sl.current_pos = u8sl.total-1;if ( u8sl.first_pos+u8sl.visible <= u8sl.current_pos )u8sl.first_pos = u8sl.current_pos-u8sl.visible+1;u8g2_SetFontPosBaseline(u8g2);//上面都是处理,这里处理完了,开始绘画for(;;){//进入第一个循环,正常情况下这个for是不会退出的//可以看到for后面没有return语句,说明写代码的人根本不希望这个函数return?!!接着往下看u8g2_FirstPage(u8g2);do{yy = u8g2_GetAscent(u8g2);if ( title_lines > 0 ){yy += u8g2_DrawUTF8Lines(u8g2, 0, yy, u8g2_GetDisplayWidth(u8g2), line_height, title);u8g2_DrawHLine(u8g2, 0, yy-line_height- u8g2_GetDescent(u8g2) + 1, u8g2_GetDisplayWidth(u8g2));yy += 3;}u8g2_DrawSelectionList(u8g2, &u8sl, yy, sl);} while( u8g2_NextPage(u8g2) );//这一段很明显就是真正在绘制窗口#ifdef U8G2_REF_MAN_PICreturn 0;
#endif//既然绘制完了,那么下面这段代码在干什么呢?//学过win32或者qt的小伙伴不难发现,这是事件处理,触发这些事件应该是更底层完成的事情,与我们无关//但是可以发现,只需要我们的写代码过程中,除了我们的按键按下,将其对应到下面的代码即可//对了,也许有读者会奇怪这里for一直卡着,那事件处理是怎么发生的呢//换句话说,我们怎么在这个循环过程中执行我们自己的代码呢?//当然是用中断了,我觉得这个库应该也是通过中断实现这个功能的(或者是定时器扫描,总之不是多线程)for(;;){event = u8x8_GetMenuEvent(u8g2_GetU8x8(u8g2));if ( event == U8X8_MSG_GPIO_MENU_SELECT )return u8sl.current_pos+1; /* +1, issue 112 */else if ( event == U8X8_MSG_GPIO_MENU_HOME )return 0; /* issue 112: return 0 instead of start_pos */else if ( event == U8X8_MSG_GPIO_MENU_NEXT || event == U8X8_MSG_GPIO_MENU_DOWN ){u8sl_Next(&u8sl);break;}else if ( event == U8X8_MSG_GPIO_MENU_PREV || event == U8X8_MSG_GPIO_MENU_UP ){u8sl_Prev(&u8sl);break;}}}
}
看了上面的代码和注释,想必该怎么做就显而易见了,那就是通过io口的中断处理按键信息,在按键按下时执行源码中对应的操作,这样子就可以将源码的功能扩展了
具体处理过程
可以发现这个函数使用的大多是局部变量,event也不例外,所以要在这个函数外部实现上述功能,有以下几个思路:
- 定义全局变量,然后在这个函数中处理这个全局变量,在函数外部就可以修改这个全局变量(变量名字越长,越有个性越好,不容易跟源代码的变量相撞)
- 修改参数,传入指针或者引用,修改值能够引起函数内发生对应的操作
思路2虽然听起来不错,这也是我最开始的思路,但是需要注意以下几个问题:
- 参数必须放在最后
- 参数必须有初始值
- 要想最后一层的函数能接收到参数,要从最外层的函数改起(但愿你能听懂我在说什么)
这样子才能保证源码的其他部分能照常运行
但是出了个大问题:arduino的c++版本似乎不支持默认参数(不知道是不是我哪里写错了,反正我看完报错信息是这么认为的)
所以的决定使用全局变量,在看下面的代码之前,建议先去了解extern的用法:
我在u8g2.h中引入了这两个变量(名字够长吧):
extern uint8_t my_bool_changed_for_selectionList; // 判断是否有按钮按下(事件触发),不用bool是因为我发现arduino好像也不支持bool
extern uint8_t my_event_for_selectionList; //具体事件
在处理对应事件的代码中,我加入了这段:
for(;;){//从这里开始添加代码if(my_bool_changed_for_selectionList == 1){ event = my_event_for_selectionList;my_bool_changed_for_selectionList = 0; if ( event == U8X8_MSG_GPIO_MENU_SELECT )return u8sl.current_pos+1; /* +1, issue 112 */else if ( event == U8X8_MSG_GPIO_MENU_HOME )return 0; /* issue 112: return 0 instead of start_pos */else if ( event == U8X8_MSG_GPIO_MENU_NEXT || event == U8X8_MSG_GPIO_MENU_DOWN ){u8sl_Next(&u8sl);break;}else if ( event == U8X8_MSG_GPIO_MENU_PREV || event == U8X8_MSG_GPIO_MENU_UP ){u8sl_Prev(&u8sl);break;}event = 0;}//代码添加结束event = u8x8_GetMenuEvent(u8g2_GetU8x8(u8g2));if ( event == U8X8_MSG_GPIO_MENU_SELECT )return u8sl.current_pos+1; /* +1, issue 112 */else if ( event == U8X8_MSG_GPIO_MENU_HOME )return 0; /* issue 112: return 0 instead of start_pos */else if ( event == U8X8_MSG_GPIO_MENU_NEXT || event == U8X8_MSG_GPIO_MENU_DOWN ){u8sl_Next(&u8sl);break;}else if ( event == U8X8_MSG_GPIO_MENU_PREV || event == U8X8_MSG_GPIO_MENU_UP ){u8sl_Prev(&u8sl);break;}}
接下来是处理按钮按下的伪代码:
interupt function()... //消抖操作if(按钮"select"按下)my_event_for_selectionList = U8X8_MSG_GPIO_MENU_SELECT;my_bool_changed_for_selectionList = 1;
测试之后发现没问题,而且这个办法同样适用于u8g2.userInterfaceMessage这个函数,有兴趣的可以自己试一下
内容就这么多,难免有些啰嗦,望见谅,如果有大佬发现有哪些做得不够,还望不吝指出
ESP8266 MP3制作——关于SelectionList从源码中改代码的一次经历相关推荐
- vue源码中优秀代码片段(一)
一.前言 笔者在读Vue源码时, 手记一些源码中优美的代码片段,一起来学习吧 二.代码片段 1. makeMap 检测某值是否在字符串(逗号分隔的字符串)中存在, 运用了柯里化函数和缓存函数 源码鉴赏 ...
- 初学者也能看懂的 Vue2 源码中那些实用的基础工具函数
1. 前言 大家好,我是若川.最近组织了源码共读活动,感兴趣的可以加我微信 ruochuan12 想学源码,极力推荐之前我写的<学习源码整体架构系列>jQuery.underscore.l ...
- 初学者也能看懂的 Vue3 源码中那些实用的基础工具函数
1. 前言 大家好,我是若川.最近组织了源码共读活动.每周读 200 行左右的源码.很多第一次读源码的小伙伴都感觉很有收获,感兴趣可以加我微信ruochuan12,拉你进群学习. 写相对很难的源码,耗 ...
- 首发全DIY强大微信朋友圈截图制作生成小程序源码下载点赞,评论等等
这是一款朋友圈截图制作的一款小程序源码 主要的特点是DIY,之前小编发布过朋友圈截图的小程序 不管之前那款小程序只能生成点赞数量,无法获取用户名等等 但是这一款就不一样了,这一款刚刚也说了特点是DIY ...
- DIY微信朋友圈截图制作生成小程序源码下载
这是一款朋友圈截图制作的一款小程序源码 主要的特点是DIY,之前小编发布过朋友圈截图的小程序 不管之前那款小程序只能生成点赞数量,无法获取用户名等等 但是这一款就不一样了,这一款刚刚也说了特点是DIY ...
- 实用工具证件照制作微信小程序源码
这是一款证件照制作的微信小程序,里面也支持直接微信公众号版本生成安装 支持多种尺寸制作 支持相册上传于直接相机拍摄 支持电子照存档等等 拥有小程序推荐功能,可以给其它的小程序实现引流 另外还支持换装美 ...
- 全新实用工具证件照制作微信小程序源码下载支持多种证件生成与制作
这是一款证件照制作的微信小程序,里面也支持直接微信公众号版本生成安装 支持多种尺寸制作 支持相册上传于直接相机拍摄 支持多种类型的证件制作如,职业证件,公务员证件,身份证等各种类型 支持电子照存档等等 ...
- 小程序源码:百变头像框制作微信小程序源码下载,免服务器和域名
这是一款头像框制作的微信小程序源码 支持多种模板制作! 如一些热门的,王者头像框,国旗头像框,职业头像框等等 这一款小程序是免服务器和免域名的 所以也就是说这是一款纯前端的一款微信小程序源码 无需设置 ...
- 个人免费可访问网页制作【GitHub】及其二维码制作(需要有网页源码)——论前端的浪漫
个人免费可访问网页制作[GitHub]及其二维码制作(需要有网页源码)--论前端的浪漫 创建GitHub仓库 上传网页源码资源 更改repository 名字 二维码制作 源码修改 结尾 今天发现一个 ...
最新文章
- 【超分辨率实验】Matlab-使用深度学习的单图像超分辨率(Single Image Super-Resolution Using Deep Learning)
- P4219-[BJOI2014]大融合【LCT】
- python迷宫最短路径_python实现最短路径的实例方法
- linux sipp 呼叫转移_SIPp 学习笔记 一 (安装)
- 软件工程——硬件汇编程序设计实验——顺序程序实验
- mysql-基本操作
- number string java_java基础系列(一):Number,Character和String类及操作
- QT5基础教程(介绍,下载,安装,第一个QT程序)
- java 数组和集合的区别
- Linux查看日志命令(汇总)
- 你还在为找素材发愁吗?自媒体高手都知道的免费自媒体素材网
- android 解析接收数据格式,Android JSON数据格式解析
- android七牛短视频sdk源码,使用七牛开发短视频
- fat,fat32,ntfs,ext2,ext3等 文件系统说明
- 腾讯云部署hexo博客系统
- 空间数据引擎oracle_SQL/Oracle数据库是怎样与GIS的应用相联系起来的?
- html视频教程全套
- android view保存成背景,Android用VideoView实现MP4作为页面背景
- 执行Http请求时doGet和doPost的区别
- carsim中质心加速度_CarSim与Simulink联合仿真
热门文章
- 纯虚函数 和 抽象类
- pikachu靶场-5 远程命令,代码执行漏洞(RCE)
- 调试多线程 查死锁的bug gcore命令 gdb对多线程的调试 gcore pstack 调试常用命令...
- Matlab坐标轴正负指数显示
- 数字游戏——数位dp问题
- 游戏服务器生成全局唯一ID的几种方法
- 总谐波失真80_总谐波失真
- DB 查询分析器 6.04 发布 ,本人为之撰写的相关技术文章达78篇
- 运维脚本 内存管理统计(5)
- linux strcpy函数,C语言中函数strcpy ,strncpy ,strlcpy,strcpy_s的用法