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
英文地址,請注明出處:http://en.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)…