当前位置: 首页 > wzjs >正文

邯郸做商城网站的公司湖北网络推广seo

邯郸做商城网站的公司,湖北网络推广seo,专业网站建设服务公司哪家好,wordpress微信qq登陆STM32 移植 U8G2 u8g2 (Universal 8bit Graphics Library version2 的缩写)是用于嵌入式设备的单色图形库,可以在单色屏幕中绘制 GUI。u8g2 内部附带了例如 SSD13xx,ST7xx 等很多 OLED,LCD 驱动。内置多种不同大小和风…

STM32 移植 U8G2

u8g2 (Universal 8bit Graphics Library version2 的缩写)是用于嵌入式设备的单色图形库,可以在单色屏幕中绘制 GUI。u8g2 内部附带了例如 SSD13xx,ST7xx 等很多 OLED,LCD 驱动。内置多种不同大小和风格的字体,可以显示中文,其次就是图形程序实现线,框,圆等图形绘制。

1. 建立裸机工程

在移植 u8g2 之前先创建 STM32F103 的 Keil5 工程模板(如何搭建 Keil 模板这里不多介绍),用来编译 STM32 驱动源码和 u8g2 源码。这也是支持 u8g2 开发的一个单片机运行环境,并且调试好屏幕驱动,确保屏幕初始化成功。

屏幕驱动只是为了验证屏幕可行性,移植后方便排除因屏幕不显示的问题,u8g2 附带屏幕驱动程序,受支持的屏幕可以使用里面的驱动程序 。整体移植操作和芯片无关,所以无论什么芯片移植方法都相同。

2. 下载源码

在 Github 官网搜索 u8g2 进行下载,或通过 https://github.com/olikraus/u8g2 链接下载,u8g2 没有发行版,所以直接下载 master 分支源码,下载后可以得到一个 u8g2-master.zip 这样的源码压缩包,如下图。

请添加图片描述

3. u8g2 文件概览

u8g2 源码主要需要使用 cppsrc/csrc/ 这两个文件夹。分别为 u8g2 对 C++ 兼容支持库,u8g2 源码文件夹

请添加图片描述

cppsrc 对 C++ 兼容支持,方便把 u8g2 移植到 C++ 应用。cppsrc 用 C++ 类简单封装了 u8g2 普通操作函数(实际还是依赖 csrc),如下所示,把 u8g2 移植到 C++ 应用才需要这部分代码。

/*u8g2_line.c */
void U8G2::drawLine(u8g2_uint_t x1, u8g2_uint_t y1, u8g2_uint_t x2, u8g2_uint_t y2) 
{u8g2_DrawLine(&u8g2, x1, y1, x2, y2);
}

其他就是一些说明文档,辅助工具程序,版本变更信息,LICENSE 等等,这部分保留 LICENSE(开源许可) 其余可以删除精简工程。

4. 移植 u8g2

在 Keil 项目管理器新建一个 u8g2 文件夹,添加 u8g2 目录 u8g2/csrc/ 下所有的.c 文件。即使 u8g2 移植到 C++ 应用,这部分也是需要的(u8g2 C++ 部分实际还是依赖 csrc 的源码)。

请添加图片描述

添加 u8g2 的头文件目录 u8g2/csrc/,即 u8g2 源码和头文件在同一个目录。

5. 驱动函数选择

csrc 目录下屏幕驱动文件以 u8x8_d_xx_yy_zz.c 格式命名,其中 xx 芯片型号,yy 屏幕分辨率,zz 识别名称,zz 不是一定的,可以为空或 noname。

例如:SSD1312 芯片驱动,128x64 分辨率的 OLED,使用的驱动文件为 u8x8_d_ssd1312_128x64_noname.c

驱动配置函数通常和文件同名,在驱动文件中找到同名函数即可,比如这里就是:

uint8_t u8x8_d_ssd1312_128x64_noname(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)

注意:驱动文件和驱动函数也可能不对应,例如 ssd1312 的驱动函数可能定义在 ssd1306 的驱动文件,这是 u8g2 为了把相近屏幕的驱动函数统一到一个文件。

如果要减小代码量,其它型号屏幕驱动和分辨率对应的 .c 驱动文件可以删除。

6. u8g2_d_setup.c

csrc 目录下找到这个文件,文件包含各种屏幕的配置函数,实上选择的屏幕驱动函数就会被这些配置函数调用。

屏幕配置函数以 u8g2_Setup_xx_yy_zz_gg_[1/2/f].c 命名,具体字段解释如下:

xx 芯片型号,ssd1306,sh1106 等等。

yy 通信方式,识不是一定的,i2c 表示为 i2c 接口,如果没有则表示 spi 通信。

zz 屏幕分辨率,128x64,128x80 等等。

gg 识别名称,gg 不是一定的,可以为 noname 也可以为空。

[1/2/f] 显存 BUF 大小,1:128字节,2:256 字节,f:1024 字节。

例如:SSD1312 芯片驱动,128x64 分辨率 SPI 通信的 OLED,希望使用 1024 字节显存,使用的配置函数为 u8g2_Setup_ssd1312_128x64_noname_f

/*ssd1312 f*/
void u8g2_Setup_ssd1312_128x64_noname_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb)
{uint8_t tile_buf_height;uint8_t *buf;u8g2_SetupDisplay(u8g2, u8x8_d_ssd1312_128x64_noname, u8x8_cad_001, byte_cb, gpio_and_delay_cb);buf = u8g2_m_16_8_f(&tile_buf_height);u8g2_SetupBuffer(u8g2, buf, tile_buf_height, u8g2_ll_hvline_vertical_top_lsb, rotation);
}

可以看到上方函数调用了 u8x8_d_ssd1312_128x64_noname(),如果要减小代码量,其它的配置函数可以删除或注释,只留下选择的即可。

7. u8g2_d_memory.c

csrc 目录下找到 u8g2_d_memory.c,文件里面是 u8g2 对显存的定义。在屏幕配置函数中,只调用了 u8g2_m_16_8_f(),所以如果编译 u8g2 时如果提示内存不足,除此之外其它显存函数可以删除或注释。

uint8_t *u8g2_m_16_8_f(uint8_t *page_cnt)
{#ifdef U8G2_USE_DYNAMIC_ALLOC*page_cnt = 8;return 0;#elsestatic uint8_t buf[1024];*page_cnt = 8;return buf;#endif
}

8. 对接屏幕驱动

把屏幕相关的硬件控制对接给 u8g2,需要我们实现 GPIO 控制和数据发送这 2 个统一驱动函数,函数原型如下,函数名称可以自定义:

uint8_t (*u8x8_msg_cb)(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);

最终通过注册的的方式提供给 u8g2。

8.1 对接 GPIO

把屏幕的 GPIO 控制函数按照用途对接到指定位置,比如 SPI 屏幕要对接 CSDCRESET 对应的 GPIO。

uint8_t u8x8_stm32_gpio_and_delay(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
{/**STM32 supports HW SPI, Remove unused cases like U8X8_MSG_DELAY_XXX & U8X8_MSG_GPIO_XXX */switch (msg) {case U8X8_MSG_GPIO_AND_DELAY_INIT:/*Insert codes for initialization*/break;case U8X8_MSG_DELAY_MILLI:/* ms Delay */sleep_ms(arg_int);break;#ifdef _USE_SPI/*SPI Interface*/case U8X8_MSG_GPIO_CS:/*Insert codes for SS pin control */HAL_GPIO_WritePin(GPIOA, GPIO_PIN_15, arg_int);break;case U8X8_MSG_GPIO_DC:/*Insert codes for DC pin control */HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, arg_int);break;case U8X8_MSG_GPIO_RESET:/*Insert codes for RST pin control*/HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, arg_int);break;case U8X8_MSG_GPIO_SPI_CLOCK:/*Insert codes for CLOCK pin control */break;case U8X8_MSG_GPIO_SPI_DATA:/*Insert codes for DATA pin control */break;#endif /*_USE_SPI*/#ifdef _USE_I2Ccase U8X8_MSG_GPIO_I2C_CLOCK:/*Insert codes for CLOCK pin control */HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, arg_int);break;case U8X8_MSG_GPIO_I2C_DATA:/*Insert codes for CLOCK pin control */HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, arg_int);break;
#endif /*_USE_I2C*/}return 1;
}

如果使用 GPIO 模拟时序通信还要对接模拟通信 GPIO,比如软件模拟 I2C 还要对接 SCLSDA 对应 GPIO,同时还要对接延时函数,u8g2 才能模拟时序。

8.2 对接数据

把屏幕的数据发送函数对接到指定位置,如果屏幕使用 SPI 接口,U8X8_MSG_BYTE_SEND 对应的是 SPI 数据发送函数,可以参考如下写法:

uint8_t u8x8_byte_stm32_hw_spi(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
{HAL_StatusTypeDef _res = HAL_ERROR;switch (msg) {case U8X8_MSG_BYTE_SEND:/*Insert codes to transmit data*/_res = HAL_SPI_Transmit(&hspi3, arg_ptr, arg_int, TX_TIMEOUT);if (_res != HAL_OK) return 0;break;case U8X8_MSG_BYTE_INIT:/*Insert codes to begin SPI transmission*/break;case U8X8_MSG_BYTE_SET_DC:/*Control DC pin, U8X8_MSG_GPIO_DC will be called*/u8x8_gpio_SetDC(u8x8, arg_int);break;case U8X8_MSG_BYTE_START_TRANSFER:/* Select slave, U8X8_MSG_GPIO_CS will be called */u8x8_gpio_SetCS(u8x8, u8x8->display_info->chip_enable_level);sleep_ms(2);break;case U8X8_MSG_BYTE_END_TRANSFER:sleep_ms(2);/* Insert codes to end SPI transmission */u8x8_gpio_SetCS(u8x8, u8x8->display_info->chip_disable_level);break;}return 1;
}

如果屏幕使用 I2C 接口,U8X8_MSG_BYTE_SEND 对应的是 I2C 数据发送函数,可以参考如下写法:

uint8_t u8x8_byte_stm32_hw_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
{/**u8g2/u8x8 will never send more than 32 bytes between START_TRANSFER and END_TRANSFER */static uint8_t buffer[32] = {0};static uint8_t buf_idx = 0;uint8_t * data = NULL;switch (msg) {case U8X8_MSG_BYTE_SEND:data = (uint8_t *) arg_ptr;while (arg_int > 0) {buffer[buf_idx++] = *data;data++;arg_int--;}break;case U8X8_MSG_BYTE_INIT:/*add your custom code to init i2c subsystem*/break;case U8X8_MSG_BYTE_SET_DC:break;case U8X8_MSG_BYTE_START_TRANSFER:buf_idx = 0;break;case U8X8_MSG_BYTE_END_TRANSFER:HAL_I2C_Master_Transmit(_I2C_DEV, (DEV_ADDR << 1), buffer, buf_idx, TX_TIMEOUT);break;}return 1;
}

8.3 初始化外设

如果数据发送是通过单片机外设硬件实现实现的,初始化 u8g2 前先初始化外设和对应的 GPIO,例如这里初始化 SPI 接口,还有相应 GPIO。

void oled_spi3_init(void)
{/* USER CODE BEGIN SPI3_Init 0 *//* USER CODE END SPI3_Init 0 *//* USER CODE BEGIN SPI3_Init 1 *//* USER CODE END SPI3_Init 1 */hspi3.Instance = SPI3;hspi3.Init.Mode = SPI_MODE_MASTER;hspi3.Init.Direction = SPI_DIRECTION_2LINES;hspi3.Init.DataSize = SPI_DATASIZE_8BIT;hspi3.Init.CLKPolarity = SPI_POLARITY_LOW;hspi3.Init.CLKPhase = SPI_PHASE_1EDGE;hspi3.Init.NSS = SPI_NSS_SOFT;hspi3.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;hspi3.Init.FirstBit = SPI_FIRSTBIT_MSB;hspi3.Init.TIMode = SPI_TIMODE_DISABLE;hspi3.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;hspi3.Init.CRCPolynomial = 10;if (HAL_SPI_Init(&hspi3) != HAL_OK){Error_Handler();}/* USER CODE BEGIN SPI3_Init 2 *//* USER CODE END SPI3_Init 2 */
}

8.4 初始化 u8g2

u8g2 没有对象初始化函数,自定义 u8g2 对象初始化函数,函数名称可以自定义,在初始化函数调用显示初始化及对应的屏幕配置函数,如下。

void u8g2_init(u8g2_t *u8g2)
{u8g2_Setup_ssd1312_128x64_noname_f(u8g2, U8G2_R2, u8x8_byte_stm32_hw_spi, u8x8_stm32_gpio_and_delay);u8g2_SetPowerSave(u8g2, 1);u8g2_InitDisplay(u8g2);u8g2_ClearDisplay(u8g2);u8g2_ClearBuffer(u8g2);u8g2_SetPowerSave(u8g2, 0);
}

可以看到这个就是前面讲解屏幕的配置函数,如下。

void u8g2_Setup_ssd1312_128x64_noname_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);

该函数的 4 个参数含义:

(1) u8g2,指定待初始化的 u8g2 对象,即 u8g2 结构体。
(2) rotation,配置屏幕旋转方向,支持 U8G2_R0,U8G2_R1,U8G2_R2,U8G2_R3 四种旋转方向。
(3) byte_cb,注册数据通信发送函数。
(4) gpio_and_delay_cb:注册屏幕 GPIO 控制函数。

8.5 总结

把对接屏幕驱动用到的这些自定义函数统一编写到一个文件中,文件可自行命名,例如命名为 u8g2_stm32.c,并添加到 u8g2 之外的用户目录。

9. 测试函数

移植完成后编写应用程序测试 u8g2 是否正常,调用 u8g2 绘图函数在显存绘制内容,在 main 函数调用初始化 SPI 和 u8g2,注意在主循环中调用 u8g2 显存发送函数 u8g2_SendBuffer 将显存内容更新至屏幕,在此附上 u8g2 测试程序。

#include "u8g2.h"static u8g2_t u8g2 = {0};void draw(u8g2_t * u8g2_p)
{u8g2_SetFontMode(u8g2_p, 1);u8g2_SetFontDirection(u8g2_p, 0);u8g2_SetFont(u8g2_p, u8g2_font_inb24_mf);u8g2_DrawStr(u8g2_p, 0, 20, "U");u8g2_SetFontDirection(u8g2_p, 1);u8g2_SetFont(u8g2_p, u8g2_font_inb30_mn);u8g2_DrawStr(u8g2_p, 21, 8, "8");u8g2_SetFontDirection(u8g2_p, 0);u8g2_SetFont(u8g2_p, u8g2_font_inb24_mf);u8g2_DrawStr(u8g2_p, 51, 30, "g");u8g2_DrawStr(u8g2_p, 67, 30,"\xb2");u8g2_DrawHLine(u8g2_p, 2, 35, 47);u8g2_DrawHLine(u8g2_p, 3, 36, 47);u8g2_DrawVLine(u8g2_p, 45, 32, 12);u8g2_DrawVLine(u8g2_p, 46, 33, 12);u8g2_SetFont(u8g2_p, u8g2_font_4x6_tr);u8g2_DrawStr(u8g2_p, 1, 54, "github.com/olikraus/u8g2");
}void main()
{oled_spi_init();u8g2_init(&u8g2);for (;;) {u8g2_ClearBuffer(&u8g2);draw(&u8g2);u8g2_SendBuffer(&u8g2);}
}

10. 移植 C++ 版本

移植 C++ 版本基础步骤和前面小节介绍的步骤相同,除此之外现在继续在 Keil 项目管理器再新建一个 u8g2cpp 文件夹,然后添加 u8g2 目录 u8g2/cppsrc/ 下所有的 .cpp 文件。

请添加图片描述

10.1 u8g2 继承类

自定义 u8g2 对象初始化类,继承 U8G2 不是必须的。可以把类定义在 U8g2lib.h 文件中,或其他文件,类名称可以自定义。在类的构造函数调用对应的屏幕配置函数,例如调用 ssd1312 屏幕配置。

void u8g2_Setup_ssd1312_128x64_noname_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);

再自定义初始化函数 SSD1312::Init(),调用 u8g2 显示初始化来初始化 u8g2。

extern "C" uint8_t u8x8_stm32_gpio_and_delay(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
extern "C" uint8_t u8x8_byte_stm32_hw_spi(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);class SSD1312 : public U8G2 {
private:public: SSD1312(const u8g2_cb_t *rotation = U8G2_R2) : U8G2() {u8g2_Setup_ssd1312_128x64_noname_f(&u8g2, rotation, u8x8_byte_stm32_hw_spi, u8x8_stm32_gpio_and_delay);}bool Init() {/**note: call to u8x8_utf8_init is not required here, this is done in the setup procedures before*/setPowerSave(1); initDisplay(); clearDisplay(); clearBuffer(); setPowerSave(0);return 1;}
};

10.2 测试程序

调用 SSD1312 类对象方法,编写应用程序测试 u8g2 是否正常,调用 u8g2 绘图函数在显存绘制内容,初始化 u8g2 对象,在主循环中调用 sendBuffer 将显存内容更新至屏幕。

#include "U8g2lib.h"SSD1312 oled;void draw(SSD1312 * oled_p)
{oled_p->setFontMode(1);oled_p->setFontDirection(0);oled_p->setFont(u8g2_font_inb24_mf);oled_p->drawStr(0, 20, "U");oled_p->setFontDirection(1);oled_p->setFont(u8g2_font_inb30_mn);oled_p->drawStr(21, 8, "8");oled_p->setFontDirection(0);oled_p->setFont(u8g2_font_inb24_mf);oled_p->drawStr(51, 30, "g");oled_p->drawStr(67, 30,"\xb2");oled_p->drawHLine(2, 35, 47);oled_p->drawHLine(3, 36, 47);oled_p->drawVLine(45, 32, 12);oled_p->drawVLine(46, 33, 12);oled_p->setFont(u8g2_font_4x6_tr);oled_p->drawStr(1, 54, "github.com/olikraus/u8g2");
}void main()
{oled.Init();for (;;) {oled.clearBuffer();draw(&oled);oled.sendBuffer();}
}

详细查看:

https://blog.csdn.net/qq_51183186/article/details/120348070

http://www.dtcms.com/wzjs/273770.html

相关文章:

  • 上海政府网站的建设的评价电脑培训班有哪些科目
  • 比较靠谱的软件下载网站惠州关键词排名优化
  • 广西建设网人员查询网宁波seo网络推广
  • 平面设计工作室网站郑州专业seo首选
  • 香港做一楼一凤的网站合法吗抖音seo是什么
  • rp网站做多大seo对各类网站的作用
  • wordpress用户修改头像seo站内优化公司
  • 北京网站建设工作室哪家好域名搜索引擎入口
  • 天水网站建设优化分析
  • 南通企业网站怎么建设生成关键词的软件
  • 美食网站建设方案软文文案范文
  • 帮人做网站要怎么赚钱吗安卓手机优化大师官方下载
  • 设计网站流程包括哪些百度极速版下载
  • 网站前期基础建设 怎么写最新新闻热点事件2022
  • 顺企网网址seo怎么优化步骤
  • 网站建设 思维导图网站seo运营培训机构
  • 如何设置自己的网站seo咨询推广
  • 05网语文seo分析
  • 腾讯网静态网站建设关键词整站优化
  • 网站建设税点百度一下你就知道啦
  • 网页制作工具分哪两类seo收费标准多少
  • 百度网址大全网站百度seo优
  • wordpress显示注册人数网站排名优化培训
  • vps 用ip可以访问网站么营销型网站外包
  • 网站建设需用要什么seo交流论坛seo顾问
  • 微信代运营方案南京seo建站
  • 如何提升网站加载速度宣传推广渠道有哪些
  • 企业核名网站品牌推广和品牌营销
  • 深圳电子商务网站有哪些安卓优化大师hd
  • 免费咨询医生平台焦作seo公司