Display control code

This commit is contained in:
2026-02-07 01:38:05 -05:00
parent 2e9004ee34
commit 52ff24e649
21 changed files with 797 additions and 86 deletions

159
components/oled/Oled.cpp Normal file
View File

@@ -0,0 +1,159 @@
#include <string>
#include "driver/gpio.h"
#include "driver/i2c.h"
#include "esp_err.h"
#include "esp_log.h"
#include "Oled.h"
#include "font8x8_basic.h"
#include "ssd1306.h"
#define TAG "OLED"
// 128x64 pixels
// 8 pixels per byte
// 128 bytes per page -> ((128*64)/8)/128 = 8 pages.
#define DISPLAY_WIDTH 128
#define DISPLAY_HEIGHT 64
#define PAGE_SIZE 128
#define PAGE_COUNT 8
#define I2C_PORT I2C_NUM_0
void Oled::init(uint8_t sda_pin, uint8_t scl_pin) {
i2c_config_t i2c_config = {
.mode = I2C_MODE_MASTER,
.sda_io_num = sda_pin,
.scl_io_num = scl_pin,
.sda_pullup_en = GPIO_PULLUP_ENABLE,
.scl_pullup_en = GPIO_PULLUP_ENABLE,
.master = {
.clk_speed = 1000000
},
.clk_flags = 0,
};
i2c_param_config(I2C_PORT, &i2c_config);
i2c_driver_install(I2C_PORT, I2C_MODE_MASTER, 0, 0, 0);
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (OLED_I2C_ADDRESS << 1) | I2C_MASTER_WRITE, true);
i2c_master_write_byte(cmd, OLED_CONTROL_BYTE_CMD_STREAM, true);
i2c_master_write_byte(cmd, OLED_CMD_SET_CHARGE_PUMP, true);
i2c_master_write_byte(cmd, 0x14, true);
i2c_master_write_byte(cmd, OLED_CMD_SET_SEGMENT_REMAP, true);
i2c_master_write_byte(cmd, OLED_CMD_SET_COM_SCAN_MODE, true);
i2c_master_write_byte(cmd, OLED_CMD_DISPLAY_ON, true);
i2c_master_stop(cmd);
if (ESP_OK != i2c_master_cmd_begin(I2C_PORT, cmd, 10 / portTICK_PERIOD_MS)) {
ESP_LOGE(TAG, "configuration failed");
}
i2c_cmd_link_delete(cmd);
clear_display();
}
void Oled::clear_display() {
ESP_LOGI(TAG, "clear_display");
i2c_cmd_handle_t cmd;
uint8_t page[PAGE_SIZE] = {0};
for (uint8_t i = 0; i < PAGE_COUNT; i++) {
cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (OLED_I2C_ADDRESS << 1) | I2C_MASTER_WRITE, true);
i2c_master_write_byte(cmd, OLED_CONTROL_BYTE_CMD_SINGLE, true);
i2c_master_write_byte(cmd, 0xB0 | i, true);
i2c_master_write_byte(cmd, OLED_CONTROL_BYTE_DATA_STREAM, true);
i2c_master_write(cmd, page, PAGE_SIZE, true);
i2c_master_stop(cmd);
i2c_master_cmd_begin(I2C_PORT, cmd, 10 / portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd);
}
}
void Oled::set_contrast(uint8_t contrast) {
i2c_cmd_handle_t cmd;
cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (OLED_I2C_ADDRESS << 1) | I2C_MASTER_WRITE, true);
i2c_master_write_byte(cmd, OLED_CONTROL_BYTE_CMD_STREAM, true);
i2c_master_write_byte(cmd, OLED_CMD_SET_CONTRAST, true);
i2c_master_write_byte(cmd, contrast, true);
i2c_master_stop(cmd);
i2c_master_cmd_begin(I2C_NUM_0, cmd, 10 / portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd);
}
void Oled::display_text(const std::string& text) {
ESP_LOGI(TAG, "display_text %s", text.c_str());
i2c_cmd_handle_t cmd;
uint8_t cur_page = 0;
uint8_t col = 0;
auto col_width = DISPLAY_WIDTH / 8; // using an 8x8 font
auto num_rows = DISPLAY_HEIGHT / 8; // using an 8x8 font
auto max_size = col_width * num_rows;
cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (OLED_I2C_ADDRESS << 1) | I2C_MASTER_WRITE, true);
i2c_master_write_byte(cmd, OLED_CONTROL_BYTE_CMD_STREAM, true);
i2c_master_write_byte(cmd, 0x00, true); // reset column
i2c_master_write_byte(cmd, 0x10, true);
i2c_master_write_byte(cmd, 0xB0 | cur_page, true); // reset page
i2c_master_stop(cmd);
i2c_master_cmd_begin(I2C_NUM_0, cmd, 10 / portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd);
for (uint8_t i = 0; i < text.size() && i < max_size; i++) {
ESP_LOGI(TAG, "%d: %c", i, text[i]);
if (text[i] == '\n' || col >= col_width) {
ESP_LOGI(TAG, "new line");
cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (OLED_I2C_ADDRESS << 1) | I2C_MASTER_WRITE, true);
i2c_master_write_byte(cmd, OLED_CONTROL_BYTE_CMD_STREAM, true);
i2c_master_write_byte(cmd, 0x00, true); // reset column
i2c_master_write_byte(cmd, 0x10, true);
i2c_master_write_byte(cmd, 0xB0 | ++cur_page, true); // increment page
i2c_master_stop(cmd);
i2c_master_cmd_begin(I2C_NUM_0, cmd, 10/portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd);
col = 0;
} else {
cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (OLED_I2C_ADDRESS << 1) | I2C_MASTER_WRITE, true);
i2c_master_write_byte(cmd, OLED_CONTROL_BYTE_DATA_STREAM, true);
uint8_t rotated[8];
rotate8x8((uint8_t*)font8x8_basic[(uint8_t)text[i]], rotated);
i2c_master_write(cmd, rotated, 8, true);
i2c_master_stop(cmd);
i2c_master_cmd_begin(I2C_NUM_0, cmd, 10/portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd);
col++;
}
}
}
void Oled::rotate8x8(uint8_t in[8], uint8_t out[8]) {
for (int x = 0; x < 8; x++) {
out[x] = 0;
for (int y = 0; y < 8; y++) {
if (in[y] & (1 << x)) {
out[x] |= (1 << (7 - y));
}
}
}
}