【 声明版权所有欢迎转载请勿用于商业用途。 联系信箱feixiaoxing 163.com】前面我们说过spi屏幕也说过1602的液晶屏幕其实还有一种屏幕也是用的很多的。这种屏幕就是oled小屏幕。市面上很多0.96寸的小屏幕都是这种而且都是128*64的分辨率驱动芯片也大都是ssd1306今天正好来看看oled怎么驱动。1、屏幕接口和1602液晶屏幕一样这种oled屏幕也是iic接口。所以总共四根线即可一根是电源一根是gnd还有两个就是iic总线。2、连线连线的话电源和地按常规走线电源选择3.3v和5v均可。iic的话scl选择接d22sda选择接d21这样就可以了。3、简单的显示原理不管是iic屏幕还是spi屏幕显示的本质都是mcu和屏幕驱动ic沟通。只不过刚好沟通的协议是iic或者是spi而已。这里mcu不选择mipi主要还是成本、功耗和市场定位的考虑和技术本身无关。4、生成代码代码部分还是和以前一样选用deepseek或者是chatgpt生成即可。因为ssd1306用的非常多所以基本上告诉ai用esp-idf生成一个oled iic 0.96寸的驱动代码它就知道如何去生成代码了。下面是我这边生成的一份代码。#include stdio.h #include string.h #include freertos/FreeRTOS.h #include freertos/task.h #include driver/i2c_master.h #include esp_log.h #define TAG OLED // I2C configuration, driver ic is SSD1306, 128*64 #define I2C_MASTER_NUM I2C_NUM_0 #define I2C_MASTER_SDA_IO 21 // Modify according to your wiring #define I2C_MASTER_SCL_IO 22 // Modify according to your wiring #define I2C_MASTER_FREQ_HZ 400000 // OLED configuration #define OLED_ADDR 0x3C // I2C address, could be 0x3D #define OLED_WIDTH 128 #define OLED_HEIGHT 64 // Complete 5x7 font (ASCII 32-127) static const uint8_t font5x7[96][5] { {0x00, 0x00, 0x00, 0x00, 0x00}, // 32 Space {0x00, 0x00, 0x5F, 0x00, 0x00}, // 33 ! {0x00, 0x07, 0x00, 0x07, 0x00}, // 34 {0x14, 0x7F, 0x14, 0x7F, 0x14}, // 35 # {0x24, 0x2A, 0x7F, 0x2A, 0x12}, // 36 $ {0x23, 0x13, 0x08, 0x64, 0x62}, // 37 % {0x36, 0x49, 0x55, 0x22, 0x50}, // 38 {0x00, 0x05, 0x03, 0x00, 0x00}, // 39 {0x00, 0x1C, 0x22, 0x41, 0x00}, // 40 ( {0x00, 0x41, 0x22, 0x1C, 0x00}, // 41 ) {0x14, 0x08, 0x3E, 0x08, 0x14}, // 42 * {0x08, 0x08, 0x3E, 0x08, 0x08}, // 43 {0x00, 0x50, 0x30, 0x00, 0x00}, // 44 , {0x08, 0x08, 0x08, 0x08, 0x08}, // 45 - {0x00, 0x60, 0x60, 0x00, 0x00}, // 46 . {0x20, 0x10, 0x08, 0x04, 0x02}, // 47 / {0x3E, 0x51, 0x49, 0x45, 0x3E}, // 48 0 {0x00, 0x42, 0x7F, 0x40, 0x00}, // 49 1 {0x42, 0x61, 0x51, 0x49, 0x46}, // 50 2 {0x21, 0x41, 0x45, 0x4B, 0x31}, // 51 3 {0x18, 0x14, 0x12, 0x7F, 0x10}, // 52 4 {0x27, 0x45, 0x45, 0x45, 0x39}, // 53 5 {0x3C, 0x4A, 0x49, 0x49, 0x30}, // 54 6 {0x01, 0x71, 0x09, 0x05, 0x03}, // 55 7 {0x36, 0x49, 0x49, 0x49, 0x36}, // 56 8 {0x06, 0x49, 0x49, 0x29, 0x1E}, // 57 9 {0x00, 0x36, 0x36, 0x00, 0x00}, // 58 : {0x00, 0x56, 0x36, 0x00, 0x00}, // 59 ; {0x08, 0x14, 0x22, 0x41, 0x00}, // 60 {0x14, 0x14, 0x14, 0x14, 0x14}, // 61 {0x00, 0x41, 0x22, 0x14, 0x08}, // 62 {0x02, 0x01, 0x51, 0x09, 0x06}, // 63 ? {0x32, 0x49, 0x79, 0x41, 0x3E}, // 64 {0x7E, 0x11, 0x11, 0x11, 0x7E}, // 65 A {0x7F, 0x49, 0x49, 0x49, 0x36}, // 66 B {0x3E, 0x41, 0x41, 0x41, 0x22}, // 67 C {0x7F, 0x41, 0x41, 0x22, 0x1C}, // 68 D {0x7F, 0x49, 0x49, 0x49, 0x41}, // 69 E {0x7F, 0x09, 0x09, 0x09, 0x01}, // 70 F {0x3E, 0x41, 0x49, 0x49, 0x7A}, // 71 G {0x7F, 0x08, 0x08, 0x08, 0x7F}, // 72 H {0x00, 0x41, 0x7F, 0x41, 0x00}, // 73 I {0x20, 0x40, 0x41, 0x3F, 0x01}, // 74 J {0x7F, 0x08, 0x14, 0x22, 0x41}, // 75 K {0x7F, 0x40, 0x40, 0x40, 0x40}, // 76 L {0x7F, 0x02, 0x0C, 0x02, 0x7F}, // 77 M {0x7F, 0x04, 0x08, 0x10, 0x7F}, // 78 N {0x3E, 0x41, 0x41, 0x41, 0x3E}, // 79 O {0x7F, 0x09, 0x09, 0x09, 0x06}, // 80 P {0x3E, 0x41, 0x51, 0x21, 0x5E}, // 81 Q {0x7F, 0x09, 0x19, 0x29, 0x46}, // 82 R {0x46, 0x49, 0x49, 0x49, 0x31}, // 83 S {0x01, 0x01, 0x7F, 0x01, 0x01}, // 84 T {0x3F, 0x40, 0x40, 0x40, 0x3F}, // 85 U {0x1F, 0x20, 0x40, 0x20, 0x1F}, // 86 V {0x3F, 0x40, 0x38, 0x40, 0x3F}, // 87 W {0x63, 0x14, 0x08, 0x14, 0x63}, // 88 X {0x07, 0x08, 0x70, 0x08, 0x07}, // 89 Y {0x61, 0x51, 0x49, 0x45, 0x43}, // 90 Z {0x00, 0x7F, 0x41, 0x41, 0x00}, // 91 [ {0x02, 0x04, 0x08, 0x10, 0x20}, // 92 backslash {0x00, 0x41, 0x41, 0x7F, 0x00}, // 93 ] {0x04, 0x02, 0x01, 0x02, 0x04}, // 94 ^ {0x40, 0x40, 0x40, 0x40, 0x40}, // 95 _ {0x00, 0x01, 0x02, 0x04, 0x00}, // 96 {0x20, 0x54, 0x54, 0x54, 0x78}, // 97 a {0x7F, 0x48, 0x44, 0x44, 0x38}, // 98 b {0x38, 0x44, 0x44, 0x44, 0x20}, // 99 c {0x38, 0x44, 0x44, 0x48, 0x7F}, // 100 d {0x38, 0x54, 0x54, 0x54, 0x18}, // 101 e {0x08, 0x7E, 0x09, 0x01, 0x02}, // 102 f {0x0C, 0x52, 0x52, 0x52, 0x3E}, // 103 g {0x7F, 0x08, 0x04, 0x04, 0x78}, // 104 h {0x00, 0x44, 0x7D, 0x40, 0x00}, // 105 i {0x20, 0x40, 0x44, 0x3D, 0x00}, // 106 j {0x7F, 0x10, 0x28, 0x44, 0x00}, // 107 k {0x00, 0x41, 0x7F, 0x40, 0x00}, // 108 l {0x7C, 0x04, 0x18, 0x04, 0x78}, // 109 m {0x7C, 0x08, 0x04, 0x04, 0x78}, // 110 n {0x38, 0x44, 0x44, 0x44, 0x38}, // 111 o {0x7C, 0x14, 0x14, 0x14, 0x08}, // 112 p {0x08, 0x14, 0x14, 0x18, 0x7C}, // 113 q {0x7C, 0x08, 0x04, 0x04, 0x08}, // 114 r {0x48, 0x54, 0x54, 0x54, 0x20}, // 115 s {0x04, 0x3F, 0x44, 0x40, 0x20}, // 116 t {0x3C, 0x40, 0x40, 0x20, 0x7C}, // 117 u {0x1C, 0x20, 0x40, 0x20, 0x1C}, // 118 v {0x3C, 0x40, 0x30, 0x40, 0x3C}, // 119 w {0x44, 0x28, 0x10, 0x28, 0x44}, // 120 x {0x0C, 0x50, 0x50, 0x50, 0x3C}, // 121 y {0x44, 0x64, 0x54, 0x4C, 0x44}, // 122 z {0x00, 0x08, 0x36, 0x41, 0x00}, // 123 { {0x00, 0x00, 0x7F, 0x00, 0x00}, // 124 | {0x00, 0x41, 0x36, 0x08, 0x00}, // 125 } {0x10, 0x08, 0x08, 0x10, 0x08}, // 126 ~ {0x00, 0x00, 0x00, 0x00, 0x00} // 127 DEL }; // Global variables static uint8_t *display_buffer NULL; static i2c_master_dev_handle_t i2c_dev_handle NULL; // OLED Low-Level Driver Functions // Write command to OLED static esp_err_t oled_write_cmd(uint8_t cmd) { uint8_t data[] {0x00, cmd}; return i2c_master_transmit(i2c_dev_handle, data, sizeof(data), -1); } // Write data to OLED static esp_err_t oled_write_data(uint8_t *data, size_t len) { uint8_t *buf malloc(len 1); if (!buf) return ESP_ERR_NO_MEM; buf[0] 0x40; memcpy(buf 1, data, len); esp_err_t ret i2c_master_transmit(i2c_dev_handle, buf, len 1, -1); free(buf); return ret; } // Refresh display static void oled_display(void) { oled_write_cmd(0x21); // Column address mode oled_write_cmd(0); // Start column oled_write_cmd(127); // End column oled_write_cmd(0x22); // Page address mode oled_write_cmd(0); // Start page oled_write_cmd(7); // End page (64/88 pages, 0-7) oled_write_data(display_buffer, OLED_WIDTH * OLED_HEIGHT / 8); } // Clear screen static void oled_clear(void) { memset(display_buffer, 0, OLED_WIDTH * OLED_HEIGHT / 8); } // Draw a pixel static void oled_draw_pixel(int x, int y, int color) { if (x 0 || x OLED_WIDTH || y 0 || y OLED_HEIGHT) return; if (color) { display_buffer[x (y / 8) * OLED_WIDTH] | (1 (y % 8)); } else { display_buffer[x (y / 8) * OLED_WIDTH] ~(1 (y % 8)); } } // Draw a character static void oled_draw_char(int x, int y, char c, int color) { unsigned char uc (unsigned char)c; if (uc 32 || uc 127) return; uc - 32; // Boundary check if (x 0 || x OLED_WIDTH - 5 || y 0 || y OLED_HEIGHT - 7) return; for (int i 0; i 5; i) { uint8_t line font5x7[uc][i]; for (int j 0; j 7; j) { if (line (1 j)) { oled_draw_pixel(x i, y j, color); } } } } // Draw a string static void oled_draw_string(int x, int y, const char *str, int color) { int cursor_x x; int cursor_y y; while (*str) { if (*str \n) { cursor_x x; cursor_y 8; } else if (*str \r) { cursor_x x; } else { // Check if line wrap is needed if (cursor_x 5 OLED_WIDTH) { cursor_x x; cursor_y 8; } oled_draw_char(cursor_x, cursor_y, *str, color); cursor_x 6; // Each character takes 6 pixels (5px width 1px spacing) } str; } } // Initialize OLED static void oled_init(void) { vTaskDelay(pdMS_TO_TICKS(100)); oled_write_cmd(0xAE); // Display off oled_write_cmd(0xD5); // Set display clock divide oled_write_cmd(0x80); oled_write_cmd(0xA8); // Set multiplex ratio oled_write_cmd(0x3F); oled_write_cmd(0xD3); // Set display offset oled_write_cmd(0x00); oled_write_cmd(0x40); // Set display start line oled_write_cmd(0x8D); // Charge pump oled_write_cmd(0x14); oled_write_cmd(0x20); // Memory addressing mode oled_write_cmd(0x00); oled_write_cmd(0xA1); // Segment remap oled_write_cmd(0xC8); // COM scan direction oled_write_cmd(0xDA); // COM pins configuration oled_write_cmd(0x12); oled_write_cmd(0x81); // Contrast oled_write_cmd(0xCF); oled_write_cmd(0xD9); // Pre-charge period oled_write_cmd(0xF1); oled_write_cmd(0xDB); // VCOM detecter level oled_write_cmd(0x40); oled_write_cmd(0xA4); // Resume to RAM content display oled_write_cmd(0xA6); // Normal display oled_write_cmd(0xAF); // Display on ESP_LOGI(TAG, OLED initialized); } // Main Function void app_main(void) { ESP_LOGI(TAG, Starting OLED Demo...); // Initialize I2C bus i2c_master_bus_config_t i2c_bus_cfg { .i2c_port I2C_MASTER_NUM, .sda_io_num I2C_MASTER_SDA_IO, .scl_io_num I2C_MASTER_SCL_IO, .clk_source I2C_CLK_SRC_DEFAULT, .glitch_ignore_cnt 7, .flags.enable_internal_pullup true, }; i2c_master_bus_handle_t bus_handle; ESP_ERROR_CHECK(i2c_new_master_bus(i2c_bus_cfg, bus_handle)); ESP_LOGI(TAG, I2C bus initialized); // Add I2C device i2c_device_config_t i2c_dev_cfg { .device_address OLED_ADDR, .scl_speed_hz I2C_MASTER_FREQ_HZ, }; ESP_ERROR_CHECK(i2c_master_bus_add_device(bus_handle, i2c_dev_cfg, i2c_dev_handle)); ESP_LOGI(TAG, I2C device added at address 0x%02X, OLED_ADDR); // Allocate display buffer int buffer_size OLED_WIDTH * OLED_HEIGHT / 8; display_buffer malloc(buffer_size); if (!display_buffer) { ESP_LOGE(TAG, Failed to allocate display buffer); return; } memset(display_buffer, 0, buffer_size); // Initialize OLED oled_init(); oled_clear(); oled_display(); // Display test int counter 0; char str_buffer[32]; while (1) { oled_clear(); // Use different Y coordinates for each line to avoid overlap // Line 1: Title (y0) oled_draw_string(0, 0, ESP32 OLED Demo, 1); // Line 2: Separator line (y10) oled_draw_string(0, 10, ----------------, 1); // Line 3: Count (y20) snprintf(str_buffer, sizeof(str_buffer), Count: %d, counter%100); oled_draw_string(0, 20, str_buffer, 1); // Line 4: Time (y30) snprintf(str_buffer, sizeof(str_buffer), Time: %d, counter); oled_draw_string(0, 30, str_buffer, 1); // Line 5: Progress bar (y42) oled_draw_string(0, 42, Progress:, 1); int bar_width (counter % 100) * 70 / 100; // Maximum 70 pixels wide for (int i 0; i bar_width; i) { oled_draw_pixel(60 i, 47, 1); // Y coordinate 47 } // Line 6: Status (y55) oled_draw_string(0, 55, Running..., 1); oled_display(); counter; vTaskDelay(pdMS_TO_TICKS(100)); if (counter 999) counter 0; } }5、编译、连接和测试用esp核心板、杜邦线和屏幕连接好之后需要确认下电源是不是对的这是最主要的。接着就是编译代码、生成image确认没问题就可以download image。接着继续看看屏幕有没有点亮内容有没有更新和我们预期的是否一致。需要注意的是这里真正显示的函数是oled_display这一点需要注意下。这一切都没有问题之后就可以回头看看流程为下一步的使用打下基础。