/** * @file OLED_SSD1306_ATY.c * * @param Project DEVICE_GENERAL_ATY_LIB * * @author ATY * * @copyright * - Copyright 2017 - 2026 MZ-ATY * - This code follows: * - MZ-ATY Various Contents Joint Statement - * * https://mengze.top/MZ-ATY_VCJS * - CC 4.0 BY-NC-SA - * * https://creativecommons.org/licenses/by-nc-sa/4.0/ * - Your use will be deemed to have accepted the terms of this statement. * * @brief Dev-style implementation for SSD1306 OLED display (I2C) * * @version * - 2_00_251112 > ATY * -# Refactor to Dev-style interface with platform-agnostic callbacks ******************************************************************************** */ #ifndef __OLED_SSD1306_ATY_C #define __OLED_SSD1306_ATY_C #include "OLED_SSD1306_ATY.h" /* ------------------------ Dev-style helpers & APIs ------------------------ */ static int _oled_write_cmd(OLED_SSD1306_ATY_Dev* dev, uint8_t cmd) { if(!dev || !dev->i2c_write) return -1; uint8_t buf[2] = {0x00, cmd}; return dev->i2c_write(dev->addr, buf, 2, dev->channel); } static int _oled_write_data(OLED_SSD1306_ATY_Dev* dev, const uint8_t* data, uint16_t len) { if(!dev || !dev->i2c_write || !data || len == 0) return -1; /* 简洁起见,逐字节发送(0x40 + data),兼容性强 */ for(uint16_t i = 0; i < len; i++) { uint8_t buf[2] = {0x40, data[i]}; int rc = dev->i2c_write(dev->addr, buf, 2, dev->channel); if(rc) return rc; } return 0; } void OLED_SSD1306_SetPosDev(OLED_SSD1306_ATY_Dev* dev, uint8_t x, uint8_t y) { if(!dev) return; _oled_write_cmd(dev, (uint8_t)(0xb0 + y)); _oled_write_cmd(dev, (uint8_t)(((x & 0xf0) >> 4) | 0x10)); _oled_write_cmd(dev, (uint8_t)((x & 0x0f) | 0x01)); } void OLED_SSD1306_FillScreenDev(OLED_SSD1306_ATY_Dev* dev, uint8_t fillData) { if(!dev) return; for(uint8_t y = 0; y < 8; y++) { _oled_write_cmd(dev, (uint8_t)(0xb0 + y)); _oled_write_cmd(dev, 0x01); _oled_write_cmd(dev, 0x10); for(uint8_t x = 0; x < X_WIDTH; x++) { _oled_write_data(dev, &fillData, 1); } } } void OLED_SSD1306_DrawChar8x16Dev(OLED_SSD1306_ATY_Dev* dev, uint8_t x, uint8_t y, const uint8_t symbol[]) { if(!dev || !symbol) return; if(x > 120) { x = 0; y += 2; } OLED_SSD1306_SetPosDev(dev, x, y); _oled_write_data(dev, symbol, 8); OLED_SSD1306_SetPosDev(dev, x, (uint8_t)(y + 1)); _oled_write_data(dev, symbol + 8, 8); } void OLED_SSD1306_DrawChar16x16Dev(OLED_SSD1306_ATY_Dev* dev, uint8_t x, uint8_t y, const uint8_t symbol[]) { if(!dev || !symbol) return; if(x > 120) { x = 0; y += 2; } OLED_SSD1306_SetPosDev(dev, x, y); _oled_write_data(dev, symbol, 16); OLED_SSD1306_SetPosDev(dev, x, (uint8_t)(y + 1)); _oled_write_data(dev, symbol + 16, 16); } void OLED_SSD1306_DrawString8x16Dev(OLED_SSD1306_ATY_Dev* dev, uint8_t x, uint8_t y, const char* str, const uint8_t* font) { if(!dev || !str || !font) return; uint8_t xi = x, yi = y; for(const char* p = str; *p; ++p) { if(xi > 120) { xi = 0; yi = (uint8_t)(yi + 2); } if(yi > 6) break; const uint8_t* glyph = font + (((uint8_t)(*p) - 32) * 16); OLED_SSD1306_DrawChar8x16Dev(dev, xi, yi, glyph); xi = (uint8_t)(xi + 8); } } int OLED_SSD1306_WriteCmdDev(OLED_SSD1306_ATY_Dev* dev, uint8_t cmd) { return _oled_write_cmd(dev, cmd); } int OLED_SSD1306_WriteDataDev(OLED_SSD1306_ATY_Dev* dev, const uint8_t* data, uint16_t len) { return _oled_write_data(dev, data, len); } void OLED_SSD1306_InitDev(OLED_SSD1306_ATY_Dev* dev, uint8_t addr, uint8_t channel) { if(!dev) return; dev->addr = addr; dev->channel = channel; if(dev->lock) dev->lock(1); /* 0.91" 128x32 init sequence */ _oled_write_cmd(dev, 0xAE); _oled_write_cmd(dev, 0x20); _oled_write_cmd(dev, 0x00); _oled_write_cmd(dev, 0xb0); _oled_write_cmd(dev, 0xc8); _oled_write_cmd(dev, 0x00); _oled_write_cmd(dev, 0x10); _oled_write_cmd(dev, 0x40); _oled_write_cmd(dev, 0x81); _oled_write_cmd(dev, 0xdf); _oled_write_cmd(dev, 0xa1); _oled_write_cmd(dev, 0xa6); _oled_write_cmd(dev, 0xa8); _oled_write_cmd(dev, 0x1F); _oled_write_cmd(dev, 0xa4); _oled_write_cmd(dev, 0xd3); _oled_write_cmd(dev, 0x00); _oled_write_cmd(dev, 0xd5); _oled_write_cmd(dev, 0xf0); _oled_write_cmd(dev, 0xd9); _oled_write_cmd(dev, 0x22); _oled_write_cmd(dev, 0xda); _oled_write_cmd(dev, 0x12); _oled_write_cmd(dev, 0xdb); _oled_write_cmd(dev, 0x20); _oled_write_cmd(dev, 0x8d); _oled_write_cmd(dev, 0x14); _oled_write_cmd(dev, 0xDA); _oled_write_cmd(dev, 0x02); _oled_write_cmd(dev, 0xaf); OLED_SSD1306_FillScreenDev(dev, 0x00); OLED_SSD1306_SetPosDev(dev, 0, 0); if(dev->lock) dev->lock(0); } /* ------------------------ Legacy implementation (disabled) ------------------------ */ #if 0 void OLED_WriteData(uint8_t oledData) { I2C_Start(); I2C_WriteByte(0x78); //Slave address,SA0=0 I2C_WriteByte(0x40); I2C_WriteByte(oledData); I2C_Stop(); } void OLED_WriteCmd(uint8_t oledCmd) { I2C_Start(); I2C_WriteByte(0x78); //Slave address,SA0=0 I2C_WriteByte(0x00); I2C_WriteByte(oledCmd); I2C_Stop(); } void OLED_SetPos(uint8_t x, uint8_t y) { OLED_WriteCmd(0xb0 + y); OLED_WriteCmd(((x & 0xf0) >> 4) | 0x10); OLED_WriteCmd((x & 0x0f) | 0x01); } void OLED_FillScreen(uint8_t fillData) { uint8_t y, x; for(y = 0; y < 8; y++) { OLED_WriteCmd(0xb0 + y); OLED_WriteCmd(0x01); OLED_WriteCmd(0x10); for(x = 0; x < X_WIDTH; x++) OLED_WriteData(fillData); } } void OLED_Init(void) { // uint16_t i = 0; // for(i = 0; i < 5000; i++){} // DelayNms(50); // OLED_WriteCmd(0xae); // Turn off oled panel // OLED_WriteCmd(0x00); // Set low column address // OLED_WriteCmd(0x10); // Set high column address // OLED_WriteCmd(0x40); // Set start line address, Set Mapping RAM Display Start Line (0x00~0x3F) // OLED_WriteCmd(0x81); // Set contrast control register // OLED_WriteCmd(BRIGHTNESS); // Set SEG Output Current Brightness // OLED_WriteCmd(0xa1); // Set SEG/Column Mapping, 0xa0 reverse x, 0xa1 normal x // OLED_WriteCmd(0xc8); // Set COM/Row Scan Direction, 0xc0 reverse y, 0xc8 normal y // OLED_WriteCmd(0xa6); // Set normal display // OLED_WriteCmd(0xa8); // Set multiplex ratio(1 to 64) // OLED_WriteCmd(0x3f); // 1/64 duty // OLED_WriteCmd(0xd3); // Set display offset Shift Mapping RAM Counter (0x00~0x3F) // OLED_WriteCmd(0x00); // Not offset // OLED_WriteCmd(0xd5); // Set display clock divide ratio/oscillator frequency // OLED_WriteCmd(0x80); // Set divide ratio, Set Clock as 100 Frames/Sec // OLED_WriteCmd(0xd9); // Set pre-charge period // OLED_WriteCmd(0xf1); // Set Pre-Charge as 15 Clocks & Discharge as 1 Clock // OLED_WriteCmd(0xda); // Set com pins hardware configuration // OLED_WriteCmd(0x12); // OLED_WriteCmd(0xdb); // Set vcomh // OLED_WriteCmd(0x40); // Set VCOM Deselect Level // OLED_WriteCmd(0x20); // Set Page Addressing Mode (0x00/0x01/0x02) // OLED_WriteCmd(0x02); // // OLED_WriteCmd(0x8d); // Set Charge Pump enable/disable // OLED_WriteCmd(0x14); // Set(0x10) disable // OLED_WriteCmd(0xa4); // Disable Entire Display On (0xa4/0xa5) // OLED_WriteCmd(0xa6); // Disable Inverse Display On (0xa6/a7) // OLED_WriteCmd(0xaf); // Turn on oled panel // OLED_FillScreen(0x00); // Clear screen // OLED_SetPos(0, 0); // Reset origin // 0.91 OLED_WriteCmd(0xAE); OLED_WriteCmd(0x20); OLED_WriteCmd(0x00); OLED_WriteCmd(0xb0); OLED_WriteCmd(0xc8); OLED_WriteCmd(0x00); OLED_WriteCmd(0x10); OLED_WriteCmd(0x40); OLED_WriteCmd(0x81); OLED_WriteCmd(0xdf); OLED_WriteCmd(0xa1); OLED_WriteCmd(0xa6); OLED_WriteCmd(0xa8); OLED_WriteCmd(0x1F); OLED_WriteCmd(0xa4); OLED_WriteCmd(0xd3); OLED_WriteCmd(0x00); OLED_WriteCmd(0xd5); OLED_WriteCmd(0xf0); OLED_WriteCmd(0xd9); OLED_WriteCmd(0x22); OLED_WriteCmd(0xda); OLED_WriteCmd(0x12); OLED_WriteCmd(0xdb); OLED_WriteCmd(0x20); OLED_WriteCmd(0x8d); OLED_WriteCmd(0x14); OLED_WriteCmd(0xDA); OLED_WriteCmd(0x02); OLED_WriteCmd(0xaf); OLED_FillScreen(0x00); // Clear screen OLED_SetPos(0, 0); // Reset origin } void OLED_DrawChar8x16(uint8_t x, uint8_t y, uint8_t symbol[]) { uint8_t i = 0; if(x > 120) // If x large than max width, then move to next line begining { x = 0; y += 2; } OLED_SetPos(x, y); for(i = 0; i < 8; i++) { OLED_WriteData(symbol[i]); } OLED_SetPos(x, y + 1); for(i = 0; i < 8; i++) { OLED_WriteData(symbol[i + 8]); } } void OLED_DrawChar16x16(uint8_t x, uint8_t y, uint8_t symbol[]) { uint8_t i = 0; if(x > 120) // If x large than max width, then move to next line begining { x = 0; y += 2; } OLED_SetPos(x, y); for(i = 0; i < 16; i++) { OLED_WriteData(symbol[i]); } OLED_SetPos(x, y + 1); for(i = 0; i < 16; i++) { OLED_WriteData(symbol[i + 16]); } } // void OLED_DrawString8x16(uint8_t x, uint8_t y, uint8_t* str, uint8_t len, uint8_t* font) // { // uint8_t i = 0; // for(i = 0; i < len; i++) // { // if(x > 120) // { // x = 0; // y += 2; // } // if(y > 6) // break; // OLED_DrawChar8x16(x, y, font + ((str[i] - 32) * 16)); // x += 8; // } // } uint8_t NumToChar(uint8_t num) { if(num >= 0 && num <= 9) return num + 32 + 16; return num; // Not a number between 0-9 } void OLED_DisNumber(uint8_t x, uint8_t y, uint8_t disData) { OLED_SetPos(x, y); OLED_DrawChar8x16(x, y, FontSongTi8x16 + ((NumToChar(disData) - 32) * 16)); } void OLED_DisValue(uint8_t x, uint8_t y, uint8_t* disData, uint8_t disLength) { uint8_t i = 0; for(i = 0; i < disLength; i++) { OLED_SetPos(x, y); OLED_DrawChar8x16(x, y, FontSongTi8x16 + ((NumToChar(disData[i]) - 32) * 16)); x += 8; } } void OLED_Dis_Welcom(void) { uint8_t beginX = 28, beginY = 2; OLED_DrawString8x16(0, 0, "I. Astrol", FontSongTi8x16); // OLED_DrawString8x16(0, 16, "HT", 2, FontSongTi8x16); } // todo: not tested #endif /* legacy implementation disabled in Dev refactor */ #endif /* __OLED_SSD1306_ATY_C */