ESP32_u8g2移植

前言
U8g2 是一个用于嵌入式设备的单色图形库。U8g2支持单色OLED和LCD,并支持如SSD1306 SSD1315等多种类型的OLED驱动,几乎市面上常见都支持。
U8g2源码 download:https://github.com/olikraus/u8g2
在这里插入图片描述
1:环境
ESP32 S3(ESP32-S3-DevKitC-1 44pin)
vscdoe+idf5.4.1

2: 在vscode 创建个工程 模块helloworld就行

3:增加组件
idf.py create-component -C components/u8g2
会创建u8g2 目录 里面有还有include目录(u8g2.h)于u8g2.c cmakefile
1>把 u8g2-master\csrc
.h 文件拷贝到 工程/components/u8g2/include 4个文件 u8g2.h覆盖就好
u8g2.c 移动到src 目录
2> 删除多余文件
u8x8_d_*****.c 这里只保留u8x8_d_ssd1306_128x64_noname.c 与 u8x8_d_ssd1315_128x64_noname.c
其他都删除了,这里保留2个,可能还会用到1315 所以先保留下来
在这里插入图片描述

3>u8g2_d_setup.c
以128*64 为例
_f 全缓冲(Full) 128×64÷8 = 1024 字节 一次性渲染全屏幕,速度最快 内存充足的设备(如 ESP32)
_1 单页缓冲(Page 1) 128×8÷8 = 128 字节 逐页渲染,需循环处理 8 页 内存紧张的设备(如 Arduino Uno)
_2 双页缓冲(Page 2) 128×16÷8 = 256 字节 逐页渲染,减少页切换频率 内存有限但需稍快速度
只保留了2个函数

/* ssd1306 f */
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)
{uint8_t tile_buf_height;uint8_t *buf;u8g2_SetupDisplay(u8g2, u8x8_d_ssd1306_128x64_noname, u8x8_cad_ssd13xx_fast_i2c, 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);
}
/* ssd1315 f */
void u8g2_Setup_ssd1315_i2c_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_ssd1315_128x64_noname, u8x8_cad_ssd13xx_fast_i2c, 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);
}

4>修改u8g2_d_memory.c
只保留上面2个函数用到的 函数(默认情况下 全是静态变量,内存如果足够大,这个文件可以不修改,全保留)

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
}

5>修改 components/u8g2的cmakefile

#idf_component_register(SRCS "u8g2.c"
#                   INCLUDE_DIRS "include")
# 定义变量,存储所有 .c 文件路径
file(GLOB MY_C_FILES "src/*.c")  # "src/" 是目标目录,"*.c" 匹配所有 .c 文件
## 递归匹配 "src" 目录及所有子目录下的 .c 文件
#file(GLOB_RECURSE MY_C_FILES "src/*.c")
# 在 ESP-IDF 中,将文件添加到组件编译(如果是 main 组件)
idf_component_register(SRCS ${MY_C_FILES}  # 通过变量引用所有 .c 文件INCLUDE_DIRS "include"    # 包含目录(根据实际情况修改)
)
# 排除 "src/test" 目录下的 .c 文件
#file(GLOB_RECURSE MY_C_FILES 
#    "src/*.c"
#   PATTERN "src/test/*" EXCLUDE  # 排除指定路径
#)

在这里插入图片描述

6>其他配置
在这里插入图片描述
在这里插入图片描述

4:上main.c

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/i2c_master.h"
#include "driver/gpio.h"
#include "u8g2.h"
#include "driver/i2c.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include <xtensa/xtruntime.h>
#include "esp_log.h"// 日志标签
static const char *TAG = "OLED_EXAMPLE";// 引脚定义(SCL: GPIO9, SDA: GPIO10)
#define BOARD_I2C_SDA         47
#define BOARD_I2C_SCL         21#define OLED_SCL_GPIO BOARD_I2C_SCL
#define OLED_SDA_GPIO BOARD_I2C_SDA
// 可选:LED引脚(如果需要)
#define LED_GPIO 38 //or  48  需要锡焊下,这里就免了// 函数声明
void OLED_W_SCL(uint8_t BitValue);
void OLED_W_SDA(uint8_t BitValue);
void OLED_GPIO_Init(void);
void led_init(void);
void LED(uint8_t state);
void LED_TOGGLE(void);// 微秒级延时(ESP32内置函数)
#define ets_delay_us(us) ({ \uint32_t _count = (us) * (XTAL_CLK_FREQ / 1000000) / 2; \while (_count--) { \__asm__ __volatile__("nop"); \} \
})// 自定义延时函数(纳秒级,近似)
void ns_delay(int ns) {// 1ns约对应XTAL时钟的1/40(ESP32默认40MHz XTAL)int nop_count = ns / 25; for (int i = 0; i < nop_count; i++) {__asm__ __volatile__("nop");}
}// U8g2的GPIO和延时回调函数
uint8_t u8g2_gpio_and_delay_esp32(U8X8_UNUSED u8x8_t *u8x8, U8X8_UNUSED uint8_t msg, U8X8_UNUSED uint8_t arg_int, U8X8_UNUSED void *arg_ptr) {switch(msg) {case U8X8_MSG_DELAY_MILLI:  // 毫秒级延时vTaskDelay(pdMS_TO_TICKS(arg_int));break;case U8X8_MSG_DELAY_10MICRO:  // 10微秒延时(修正原10ms错误)ets_delay_us(10);break;case U8X8_MSG_DELAY_100NANO:  // 100纳秒延时ns_delay(100);break;case U8X8_MSG_GPIO_I2C_CLOCK:  // I2C时钟线控制OLED_W_SCL(arg_int);break;case U8X8_MSG_GPIO_I2C_DATA:  // I2C数据线控制OLED_W_SDA(arg_int);break;default:return 0;  // 未实现的消息}return 1;  // 成功处理
}// 绘制圆形任务
void draw_circle_fun(u8g2_t* u8g2) {u8g2_ClearBuffer(u8g2);  // 清空缓冲区// 1. 绘制完整圆形轮廓(圆心(64,32),半径20)u8g2_DrawCircle(u8g2, 64, 32, 20, U8G2_DRAW_ALL);// 2. 绘制填充圆形(圆心(30,30),半径15)//u8g2_DrawFilledEllipse(u8g2, 30, 30, 15, U8G2_DRAW_ALL);u8g2_DrawFilledEllipse(u8g2,       // U8g2实例30, 30,      // 中心坐标(x0=64, y0=32),对应128x64屏幕的中心15, 15,      // rx=40(水平半径),ry=20(垂直半径)U8G2_DRAW_ALL  // 绘制完整椭圆);// 3. 绘制部分圆弧(右上象限,圆心(100,30),半径10)u8g2_DrawCircle(u8g2, 100, 30, 10, U8G2_DRAW_UPPER_RIGHT);u8g2_DrawBox(u8g2, 100, 30,20,20);u8g2_SendBuffer(u8g2);  // 将缓冲区内容发送到屏幕vTaskDelay(pdMS_TO_TICKS(1000));  // 每秒刷新一次}void app_main(void) {esp_err_t ret;// 初始化NVS(非易失性存储)
// 需要调用 nvs_flash_init() 的场景
// 如果你的应用程序使用了以下功能,必须初始化 NVS:
// WiFi / 蓝牙功能:WiFi 的连接凭证(SSID、密码)、蓝牙的配对信息等默认存储在 NVS 中,不初始化会导致 WiFi / 蓝牙无法正常工作。
// OTA 升级:OTA 相关的状态信息(如当前固件版本、升级标志)需要 NVS 存储。
// 分区表中的 NVS 分区:默认的 ESP-IDF 分区表包含 nvs 分区(用于用户数据)和 nvs_keys 分区(用于加密密钥),若需使用这些分区存储自定义数据(如设备配置),必须初始化。
// 其他依赖 NVS 的组件:如 esp_http_client 的缓存、esp_https_ota 的状态记录等,底层可能依赖 NVS。ret = nvs_flash_init();if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {ESP_ERROR_CHECK(nvs_flash_erase());ret = nvs_flash_init();}ESP_ERROR_CHECK(ret);// 初始化LED(可选,用于调试)led_init();// 初始化OLED引脚(SCL/SDA)OLED_GPIO_Init();// 初始化U8g2u8g2_t u8g2;// 配置SSD1306 128x64,全屏缓冲,软件I2Cu8g2_Setup_ssd1306_i2c_128x64_noname_f(&u8g2, U8G2_R0, u8x8_byte_sw_i2c,  // 软件I2C发送函数u8g2_gpio_and_delay_esp32);  // 回调函数u8g2_InitDisplay(&u8g2);  // 初始化显示器u8g2_SetPowerSave(&u8g2, 0);  // 唤醒显示器u8g2_ClearBuffer(&u8g2);  // 清空缓冲区// 绘制十字线u8g2_DrawLine(&u8g2, 0, 0, 127, 63);u8g2_DrawLine(&u8g2, 127, 0, 0, 63);u8g2_SendBuffer(&u8g2);  // 发送缓冲区数据到屏幕// 主循环while (1) {LED_TOGGLE();  // 闪烁LED表示程序运行vTaskDelay(pdMS_TO_TICKS(500));  // 延时500msdraw_circle_fun(&u8g2);}
}// 控制SCL引脚电平
void OLED_W_SCL(uint8_t BitValue) {gpio_set_level(OLED_SCL_GPIO, BitValue);ets_delay_us(2);  // 小延时保证I2C时序稳定
}// 控制SDA引脚电平
void OLED_W_SDA(uint8_t BitValue) {gpio_set_level(OLED_SDA_GPIO, BitValue);ets_delay_us(2);  // 小延时保证I2C时序稳定
}// 初始化OLED的SCL和SDA引脚(开漏输出+上拉)
void OLED_GPIO_Init(void) {gpio_config_t gpio_init_struct = {.intr_type = GPIO_INTR_DISABLE,  // 禁用中断.mode = GPIO_MODE_OUTPUT_OD,     // 开漏输出(I2C必需).pull_up_en = GPIO_PULLUP_ENABLE,  // 使能上拉(I2C无外部上拉时).pull_down_en = GPIO_PULLDOWN_DISABLE,.pin_bit_mask = (1ULL << OLED_SCL_GPIO) | (1ULL << OLED_SDA_GPIO)  // 配置SCL和SDA引脚};gpio_config(&gpio_init_struct);// 初始化为高电平(释放总线)OLED_W_SCL(1);OLED_W_SDA(1);vTaskDelay(pdMS_TO_TICKS(10));  // 等待引脚稳定
}// 初始化LED引脚(可选,用于调试)
void led_init(void) {gpio_config_t gpio_init_struct = {.intr_type = GPIO_INTR_DISABLE,.mode = GPIO_MODE_OUTPUT,.pull_up_en = GPIO_PULLUP_DISABLE,.pull_down_en = GPIO_PULLDOWN_DISABLE,.pin_bit_mask = 1ULL << LED_GPIO};gpio_config(&gpio_init_struct);LED(0);  // 初始关闭
}// 控制LED状态
void LED(uint8_t state) {gpio_set_level(LED_GPIO, state);
}// 翻转LED状态
void LED_TOGGLE(void) {uint8_t current = gpio_get_level(LED_GPIO);gpio_set_level(LED_GPIO, !current);
}

主要是2个回调函数
在这里插入图片描述
主要是 回调函数 u8x8_msg_cb,u8x8_msg_cb
typedef uint8_t (*u8x8_msg_cb)(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
u8x8_msg_cb 可以用uint8_t u8x8_byte_sw_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void arg_ptr) //现成的
/
ssd1306 f */
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_Setup_ssd1306_i2c_128x64_noname_f(
&u8g2, // U8g2 上下文结构体,保存配置和状态
U8G2_R0, // 屏幕旋转方向(U8G2_R0:不旋转;U8G2_R180:翻转180度等)
u8g2_esp32_i2c_byte_cb, // I2C 字节发送回调(底层实现 I2C 写操作)
u8g2_esp32_gpio_and_delay_cb // GPIO 控制和延时回调(处理复位、延时)
);

5: 测试结果 如果对你又帮助,麻烦点个赞,加个关注
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/92488.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/92488.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MCP实现:.Net实现MCP服务端 + Ollama ,MCP服务端工具调用

本文使用.Net编写MCP服务端 Ollama &#xff0c;实现简单MCP调用&#xff0c;代码仅实现基本演示功能。 文章目录一、Ollama如何安装使用二、创建.Net8项目&#xff0c;开发MCP服务端三、开发MCP客户端&#xff0c;并对接Ollama一、Ollama如何安装使用 请移步&#xff1a;htt…

Docker的安装使用以及常见的网络问题

一、什么是DockerDocker是一种容器化技术&#xff0c;用于快速打包、分发和运行程序。他的核心思想是"一次构建&#xff0c;到处运行"&#xff0c;通过将应用及其依赖的环境打包到一个轻量级、可移植的容器中&#xff0c;实现跨平台一致运行。二、Docker的安装1.Cent…

C++入门学习

1.命名空间的介绍首先我们看到如下的代码&#xff0c;在C语言中&#xff1a;#include <stdio.h> #include <stdlib.h> int rand 10; // C语言没办法解决类似这样的命名冲突问题&#xff0c;所以C提出了namespace来解决 int main() {printf("%d\n", rand…

解决python错误:playwright._impl._errors.TimeoutError: Timeout 30000ms exceeded.

from playwright.sync_api import sync_playwrightwith sync_playwright() as p:browser = p.chromium.launch(headless=False)page = browser.new_page() page.goto(url)page.wait_for_load_state(networkidle) 在Python环境中运行以上代码后报错: page.wait_for_load_…

爬虫逆向之雷池waf

本文章中所有内容仅供学习交流使用&#xff0c;不用于其他任何目的。否则由此产生的一切后果均与作者无关&#xff01; 雷池waf概念 雷池 WAF&#xff08;SafeLine&#xff09;是长亭科技开源的一款 Web 应用防火墙&#xff0c;部署在网站前面&#xff0c;把所有进来的 HTTP/…

23种设计模式解析--行为型

行为型模式&#xff08;协作的艺术&#xff09; 观察者模式 观察者模式详解 模式定义 观察者模式&#xff08;Observer Pattern&#xff09;是一种行为设计模式&#xff0c;用于建立对象间一对多的依赖关系。当一个对象&#xff08;Subject&#xff09;状态变化时&#xff0c;所…

Linux系统之lua 详解

命令简介 lua 是 Lua 语言的解释器&#xff0c;用于加载和执行 Lua 程序&#xff08;包括文本源码和预编译的二进制文件&#xff09;。它支持两种运行模式&#xff1a;批处理模式&#xff08;执行指定脚本文件&#xff09;和交互式模式&#xff08;逐行读取并执行输入的命令&am…

visual studio 无明显错误,但是无法编译成功解决—仙盟创梦IDE

往后面查看rror CS0246: 未能找到类型或命名空间名“SimpleClass”(是否缺少 using 指令或程序集引用?)修复阿雪技术观在科技发展浪潮中&#xff0c;我们不妨积极投身技术共享。不满足于做受益者&#xff0c;更要主动担当贡献者。无论是分享代码、撰写技术博客&#xff0c;还是…

《论文阅读》传统CoT方法和提出的CoT Prompting的区分

论文&#xff1a;Chain-of-Thought Prompting Elicits Reasoning in Large Language Models作者对传统CoT方法和本文提出的CoT Prompting的区分。1. 传统方法的局限性 (1) 基于微调的CoT&#xff08;Rationale-Augmented Training&#xff09; 实现方式&#xff1a;需人工标注大…

Minio 高性能分布式对象存储

1、什么是对象存储? 描述: 对象存储&#xff08;Object Storage&#xff09;是一种存储数据的计算机体系结构&#xff0c;它以对象的形式存储和管理数据。与传统的文件系统和块存储不同&#xff0c;对象存储将数据作为对象存储在分布式的存储集群中&#xff0c;每个对象都有一…

[深度学习] 大模型学习4-RAG技术全景解析

在大语言模型基础知识一文中&#xff0c;检索增强生成&#xff08;Retrieval-Augmented Generation&#xff0c;简称 RAG&#xff09;技术作为构建大语言模型&#xff08;Large Language Model&#xff0c;简称 LLM&#xff09;应用的一种方式已被简要提及&#xff0c;本文将详…

4G/5G无线电单元系统

4G/5G无线电单元系统 ADI公司的核心技术和领域专业知识帮助客户在全球范围内规划、设计、打造更出色的高性能通信系统。 我们的无线电单元(RU)设计平台利用新一代技术来提供高性能解决方案&#xff0c;帮助客户消除设计障碍、缩短产品开发周期&#xff0c;加快产品上市时间。 价…

HarvardX TinyML小笔记1(番外2:神经网络)

1 介绍 图片来自&#xff1a;https://zh.wikipedia.org/zh-cn/%E4%BA%BA%E5%B7%A5%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C 神经网络一直感觉挺神奇的&#xff0c;江湖也说可解释性很差&#xff0c;无论如何还是学学吧。借这次学习哈佛的TinyML&#xff0c;也就顺带弄了。 这里…

计算机网络 第2章通信基础(竟成)

第 2 章 物理层【考纲内容】1.通信基础 (1) 信道、信号、带宽、码元、波特、速率、信源与信宿等基本概念 (2) 奈奎斯特定理与香农定理 (3) 编码与调制 (4) 电路交换、报文交换与分组交换 (5) 数据报与虚电路2.传输介质 (1) 双绞线、同轴电缆、光纤与无线传输介质&#xff1b;(2…

2025-08-09通过授权码的方式给exe程序充值

2025-08-09通过授权码的方式给exe程序充值主要点&#xff1a; 一次性授权机制&#xff1a; 新增 .used_licenses 文件记录所有已使用的授权码 每次激活前检查授权码是否在已使用列表中 激活成功后立即将授权码标记为已使用 时效性验证&#xff1a; 授权码包含过期时间戳&#x…

工具类-高效集合差异计算工具DiffWrapper

集合差异工具类-DiffWrapper 原因 在编辑过程中&#xff0c;肯定会存在对于子表的更新操作&#xff0c;这种更新分为三种&#xff1a; 要加的&#xff0c; 要删的&#xff0c;要更新的&#xff0c;并且传参只有一个modifyVO的, 每一个都写有点过于冗余&#xff0c;故考虑提取一…

SimBA算法实现过程

文章目录添加噪声衡量扰动示例数值总结高级索引变量名代码总体代码添加噪声 操作&#xff1a;将频率扰动通过trans( )转为像素域扰动加到原始图像上&#xff08;trans返回频率域转换为像素域的结果&#xff09; expanded (images_batch[remaining_indices] # 原始图像&…

【面试题】cookie和session 的区别

文章目录一、核心定义与存储位置二、关键区别对比三、典型使用场景四、关联与依赖总结在Web开发中&#xff0c; Cookie和 Session是两种常用的状态管理机制&#xff0c;用于在无状态的HTTP协议中保存用户信息&#xff08;如登录状态、偏好设置等&#xff09;。二者的核心区别体…

【机器学习】算法调参的两种方式:网格搜索(枚举)、随机搜索

文章目录一、网格搜索&#xff1a;穷举式的最优解寻找1、数学推导过程1. 搜索空间的数学结构2. 优化问题的数学性质3. 收敛性分析4. 误差分析2、为什么网格搜索有效&#xff1f;1. 全局最优性保证2. 可重现性与稳定性3. 参数敏感性分析3、适用场景与局限性二、随机搜索&#xf…

免费PDF翻译 离线自建

https://github.com/Byaidu/PDFMathTranslate/blob/main/docs/README_zh-CN.md https://github.com/Byaidu/PDFMathTranslate/releases 方法 针对不同的使用案例&#xff0c;我们提供不同的方法来使用我们的程序&#xff1a;1. UV 安装 安装 Python (3.10 < 版本 < 3.12)…