摘要:支持显示控制器,,,,,,,,,,,,,,,,,,,,,,等。和的功能包括包括所有图形程序线框圆画。支持很丰富的字体库。仅文本输出字符设备。仅允许使用每个字符固定大小像素的字体。直接写到显示屏上,无需微控制器中的缓冲需要消耗较少的空间资源。
1.U8g2 是用于嵌入式设备的单色图形库。
2.U8g2 还包括 U8x8 库。U8g2 和 U8x8 的功能包括:
U8g2图形库使用技巧(硬件驱动接口部分的分析和选择):
U8g2图形库的驱动接口主要取决于所选用的lcd屏幕的驱动芯片方案,目前常用的驱动接口多为spi和i2c两种串行总线,如果需要较高的刷新帧率,spi的驱动方式是比较好的选择,spi的驱动时钟频率一般可以达到8Mbit,而i2c的方式一般只能达到400Kbit,但是使用spi方式驱动的时候,需要比较多的io管脚资源,一般最少需要3个io(三线spi方式),而i2c方式一般只需要2个io就可以满足,考虑到~~呆萌的瓦力平衡机器人~~包含了两路对时序要求很高的foc电机控制,所以果断选择了比较高效的spi方式(选用的oled模组的驱动方案采用的是SSD1306,该方案既支持i2c方式,也支持spi的方式);
U8g2图形库使用技巧(软件驱动程序分析和记录):
U8g2图形库的代码框架写得非常的完善,只需要实现底层几个读写接口函数,就可以把整个图形库驱动起来,它的几乎所有的初始化函数接口都定义在u8g2_d_setup.c源文件中,该源文件实现了u8g2图形库所有支持lcd驱动方案的初始化方法,通过函数名来区分,初始化函数的名字包含了很多硬件相关的信息,就拿我在使用的oled模组的初始化函数来作为例子,模组驱动方案为SSD1306,分辨率为128x64,驱动接口为三线spi方式,所以可选的初始化方法如下:
u8g2_Setup_ssd1306_128x64_noname_1 /*芯片SSD1306,分辨率128x64,128字节页大小*/u8g2_Setup_ssd1306_128x64_noname_2 /*芯片SSD1306,分辨率128x64,256字节页大小*/u8g2_Setup_ssd1306_128x64_noname_f /*芯片SSD1306,分辨率128x64,1024字节页大小*/
考虑到esp32的ram资源比较充足的,果断选择了u8g2_Setup_ssd1306_128x64_noname_f方法,到这里了就结束了!spi的驱动方式体现在哪里呢?
接着往里扒--->
void u8g2_Setup_ssd1306_i2c_128x64_noname_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb)
该函数需要传入四个参数--->
u8g2_t *u8g2; /*u8g2图形库结构体指针*/const u8g2_cb_t *rotation; /*u8g2图形库ui旋转:U8G2_R0(无旋转),U8G2_R1(顺时针90°),U8G2_R2(顺时针180°)......*/u8x8_msg_cb byte_cb; /*u8g2图形库字节交互回调函数*/u8x8_msg_cb gpio_and_delay_cb; /*u8g2图形库gpio和延时回调函数*/
所以和spi部分相关的就是--->
u8x8_msg_cb byte_cb; /*u8g2图形库字节交互回调函数*/
这个callback函数需要我们自己实现如下的方法--->
uint8_t u8x8_byte_hw_spi(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr){ uint8_t max_transfer_sz = 0; switch(msg) { case U8X8_MSG_BYTE_SEND: //ESP_LOGI(TAG, "U8X8_MSG_BYTE_SEND:%d,%d", arg_int ,spi_device_max_transfer_sz(u8g2_spi)); max_transfer_sz = spi_device_max_transfer_sz(u8g2_spi); if (arg_int <= max_transfer_sz) { u8g2_tran.length = arg_int*8, u8g2_tran.tx_buffer = (const void *)arg_ptr, u8g2_tran.rxlength = 0, u8g2_tran.rx_buffer = NULL, spi_device_polling_transmit(u8g2_spi, &u8g2_tran); } else { int packet_num = arg_int/max_transfer_sz; int packet_remain = arg_int%max_transfer_sz; uint8_t *data_prt = (uint8_t *)arg_ptr; if (packet_num > 0) { for (int i=0;i 0) { u8g2_tran.length = packet_remain*8, u8g2_tran.tx_buffer = (const void *)data_prt, u8g2_tran.rxlength = 0, u8g2_tran.rx_buffer = NULL, spi_device_polling_transmit(u8g2_spi, &u8g2_tran); } } break; case U8X8_MSG_BYTE_SET_DC: u8g2_ssd1306_set_dc(arg_int); break; default: return 0; } return 1;}
而剩下的u8x8_msg_cb gpio_and_delay_cb这个callback主要是用来做输入相关功能的回调接口(瓦力ui配合rc遥控器实现的输入交互就是通过该接口实现的),u8g2库可以通过该接口来读取硬件按键输入的状态信息然后进行处理--->
uint8_t u8x8_gpio_and_delay(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, U8X8_UNUSED void *arg_ptr){ case U8X8_MSG_GPIO_MENU_SELECT: u8x8->gpio_result = u8g2_gpio_menu_select(); vTaskDelay(3); break; case U8X8_MSG_GPIO_MENU_NEXT: u8x8->gpio_result = u8g2_gpio_menu_next(); vTaskDelay(3); break; case U8X8_MSG_GPIO_MENU_PREV: u8x8->gpio_result = u8g2_gpio_menu_prev(); vTaskDelay(3); break; case U8X8_MSG_GPIO_MENU_HOME: u8x8->gpio_result = u8g2_gpio_menu_home(); vTaskDelay(3); break; case U8X8_MSG_GPIO_MENU_UP: u8x8->gpio_result = u8g2_gpio_menu_up(); vTaskDelay(3); break; case U8X8_MSG_GPIO_MENU_DOWN: u8x8->gpio_result = u8g2_gpio_menu_down(); vTaskDelay(3); break; case U8X8_MSG_GPIO_RESET: u8g2_ssd1306_set_rst(arg_int); break; default: break; } return 1;}
到此底层相关的工作基本做完,接下来就是一些基于上层API接口的花活了--->
void u8g2_ssd1306_init(spi_device_handle_t handle){ u8g2_spi = handle; //Initialize non-SPI GPIOs gpio_set_direction(PIN_NUM_DC, GPIO_MODE_OUTPUT); gpio_set_direction(PIN_NUM_RST, GPIO_MODE_OUTPUT); //Reset the display gpio_set_level(PIN_NUM_RST, 0); vTaskDelay(100 / portTICK_RATE_MS); gpio_set_level(PIN_NUM_RST, 1); vTaskDelay(100 / portTICK_RATE_MS); u8g2_Setup_ssd1306_128x64_noname_f( &u8g2, U8G2_R0, u8x8_byte_hw_spi, u8x8_gpio_and_delay); // init u8g2 structure ESP_LOGI(TAG, "u8g2_InitDisplay"); u8g2_InitDisplay(&u8g2); // send init sequence to the display, display is in sleep mode after this, ESP_LOGI(TAG, "u8g2_SetPowerSave"); u8g2_SetPowerSave(&u8g2, 0); // wake up display ESP_LOGI(TAG, "u8g2_ClearBuffer"); u8g2_ClearBuffer(&u8g2); ESP_LOGI(TAG, "u8g2_SetFont"); u8g2_SetFont(&u8g2, u8g2_font_6x10_mf); ESP_LOGI(TAG, "u8g2_DrawStr"); u8g2_DrawStr(&u8g2, 20, 14, "esp32 foc +-x%/"); ESP_LOGI(TAG, "u8g2 init all done!");}
虽然是花活,其中也有一些需要注意的地方,例如在设置字库的时候,如果选择了一些精简字库,会导致字符刷新出现字符像素残留的现象,特别是在动态刷新一些数字的情景下,效果很差,十分影响显示效果;
小结:
这次主要记录了为~~呆萌的瓦力平衡机器人~~选择ui图像库的心路历程以及在开始使用该图形库时所需要做的一些前期分析和实操过程中需要注意的技术要点;
以下是一些和本文相关的文章链接和U8g2的wiki链接:
一、~~呆萌的瓦力平衡机器人~~链接:
二、U8g2 wiki链接:
1.U8g2_wiki;
后续的计划:
下一期准备记录在做U8g2界面刷新和两路foc电机驱动遇到的冲突问题,以及我的解决思路;
大家如果也感兴趣,可以加qun交流学习(群里提供了丰富的esp32资料):
燥起来吧,sao年!!!!!!
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/119239.html
摘要:新公司已经呆了一个多月,目前着手一个数据可视化的项目,数据可视化肯定要用到图形库如等,经决定我的这个项目用阿里旗下蚂蚁金服所开发的图表库。数据提示框内提示的信息还可以通过格式化函数动态指定。 新公司已经呆了一个多月,目前着手一个数据可视化的项目,数据可视化肯定要用到图形库如D3、Highcharts、ECharts、Chart等,经决定我的这个项目用阿里旗下蚂蚁金服所开发的G2图表库。...
摘要:十开放模式识别项目开放模式识别项目,致力于开发出一套包含图像处理计算机视觉自然语言处理模式识别机器学习和相关领域算法的函数库。 一、开源生物特征识别库 OpenBROpenBR 是一个用来从照片中识别人脸的工具。还支持推算性别与年龄。使用方法:$ br -algorithm FaceRecognition -compare me.jpg you.jpg二、计算机视觉库 OpenCVOpenC...
摘要:在文末,我会附上一个可加载的模型方便学习中文艺术字渲染用原生可以很容易地绘制文字,但是原生提供的文字效果美化功能十分有限。 showImg(https://segmentfault.com/img/bVWYnb?w=900&h=385); WebGL 可以说是 HTML5 技术生态链中最为令人振奋的标准之一,它把 Web 带入了 3D 的时代。 初识 WebGL 先通过几个使用 Web...
阅读 2031·2021-11-15 17:57
阅读 722·2021-11-11 16:54
阅读 2570·2021-09-27 13:58
阅读 4012·2021-09-06 15:00
阅读 894·2021-09-04 16:45
阅读 3463·2019-08-30 15:56
阅读 1768·2019-08-30 15:53
阅读 1556·2019-08-30 14:12