Для OLED I2C 128 x 32.
#include <avr/io.h>
#include <util/delay.h>
#define I2C_SDA PB4
#define I2C_SCL PB3
#define I2C_SDA_HIGH() DDRB &= ~(1<<I2C_SDA)
#define I2C_SDA_LOW() DDRB |= (1<<I2C_SDA)
#define I2C_SCL_HIGH() DDRB &= ~(1<<I2C_SCL)
#define I2C_SCL_LOW() DDRB |= (1<<I2C_SCL)
int main(void) {
OLED_init();
OLED_clear();
while(1) {
OLED_printC(0,0,0);
OLED_printC(11,0,1);
OLED_printC(22,0,2);
OLED_printC(33,0,3);
OLED_printC(44,0,4);
OLED_printC(55,0,5);
OLED_printC(66,0,6);
OLED_printC(77,0,7);
OLED_printC(88,0,8);
OLED_printC(99,0,9);
OLED_printC(110,0,10);
OLED_printC(121,0,11);
}}
///// I2C ///////////////////////////////////////////////////////
void I2C_init(void) {DDRB &= ~((1<<I2C_SDA)|(1<<I2C_SCL)); PORTB &= ~((1<<I2C_SDA)|(1<<I2C_SCL));}
void I2C_write(uint8_t data) {
for(uint8_t i = 8; i; i--) {I2C_SDA_LOW();
if (data & 0x80) I2C_SDA_HIGH();I2C_SCL_HIGH();data<<=1;I2C_SCL_LOW();}
I2C_SDA_HIGH();I2C_SCL_HIGH();asm("nop");I2C_SCL_LOW();
}
void I2C_start(uint8_t addr) {I2C_SDA_LOW();I2C_SCL_LOW();I2C_write(addr);}
void I2C_stop(void) {I2C_SDA_LOW();I2C_SCL_HIGH();I2C_SDA_HIGH();}
///// OLED ///////////////////////////////////
#define OLED_ADDR 0x78
#define OLED_CMD_MODE 0x00
#define OLED_DAT_MODE 0x40
#define OLED_INIT_LEN 12
// OLED init settings
const uint8_t OLED_INIT_CMD[] PROGMEM = {
0xA8, 0x1F, // 0x1F for 128x32, 0x3F for 128x64
0x22, 0x00, 0x03,
0x20, 0x00,
0xDA, 0x02,
0x8D, 0x14,
0xAF,
0xA1, 0xC8
};
// Standard ASCII 5x8 font (adapted from Neven Boyanov and Stephen Denne)
const uint8_t OLED_FONT[] PROGMEM = {
0x00,0xF0,0xFC,0xFE,0x06,0x02,0x06,0xFE,0xFC,0xF0,0x00, // 0
0x00,0x07,0x1F,0x3F,0x30,0x20,0x30,0x3F,0x1F,0x07,0x00,
0x00,0x00,0x08,0x0C,0xFC,0xFE,0xFE,0x00,0x00,0x00,0x00, // 1
0x00,0x20,0x20,0x20,0x3F,0x3F,0x3F,0x20,0x20,0x20,0x00,
0x00,0x0C,0x0E,0x06,0x02,0x02,0x86,0xFE,0x7C,0x38,0x00, // 2
0x00,0x30,0x38,0x3C,0x36,0x33,0x31,0x30,0x30,0x38,0x00,
0x00,0x0C,0x0E,0x86,0x82,0x82,0xC6,0xFE,0x7C,0x38,0x00, // 3
0x00,0x18,0x38,0x30,0x20,0x20,0x31,0x3F,0x1F,0x0E,0x00,
0x00,0x00,0xC0,0x20,0x18,0x04,0xFE,0xFE,0xFE,0x00,0x00, // 4
0x00,0x03,0x02,0x02,0x02,0x22,0x3F,0x3F,0x3F,0x22,0x02,
0x00,0x00,0x7E,0x7E,0x46,0x46,0xC6,0xC6,0x86,0x00,0x00, // 5
0x00,0x18,0x38,0x30,0x20,0x20,0x30,0x3F,0x1F,0x0F,0x00,
0x00,0xC0,0xF0,0xF8,0xFC,0x4C,0xC6,0xC2,0x82,0x00,0x00, // 6
0x00,0x0F,0x1F,0x3F,0x30,0x20,0x30,0x3F,0x1F,0x0F,0x00,
0x00,0x06,0x06,0x06,0x06,0x06,0xC6,0xF6,0x3E,0x0E,0x00, // 7
0x00,0x00,0x00,0x30,0x3C,0x0F,0x03,0x00,0x00,0x00,0x00,
0x00,0x38,0x7C,0xFE,0xC6,0x82,0xC6,0xFE,0x7C,0x38,0x00, // 8
0x00,0x0E,0x1F,0x3F,0x31,0x20,0x31,0x3F,0x1F,0x0E,0x00,
0x00,0x78,0xFC,0xFE,0x86,0x02,0x86,0xFE,0xFC,0xF8,0x00, // 9
0x00,0x00,0x00,0x21,0x21,0x31,0x1D,0x1F,0x0F,0x03,0x00,
0xF0,0xF8,0x0C,0x06,0x02,0x02,0x02,0x02,0x0E,0x0C,0x00, // C //10
0x03,0x07,0x0C,0x18,0x10,0x10,0x10,0x10,0x1C,0x0C,0x00,
0x00,0x1C,0x22,0x22,0x22,0x1C,0x00,0x00,0x00,0x00,0x00,// degrees // 11
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
};
void OLED_init(void) {
I2C_init();
I2C_start(OLED_ADDR);
I2C_write(OLED_CMD_MODE);
for (uint8_t i = 0; i < OLED_INIT_LEN; i++) I2C_write(pgm_read_byte(&OLED_INIT_CMD[i]));
I2C_stop();
}
void OLED_printC(uint8_t x, uint8_t y,char ch) {
OLED_cursor(x,y);
I2C_start(OLED_ADDR);
I2C_write(OLED_DAT_MODE);
for(uint8_t i=0; i<11; i++){
I2C_write(pgm_read_byte(&OLED_FONT[(ch*22+i)])); }
I2C_stop();
OLED_cursor(x,y+1);
I2C_start(OLED_ADDR);
I2C_write(OLED_DAT_MODE);
for(uint8_t i=11; i<22; i++){
I2C_write(pgm_read_byte(&OLED_FONT[(ch*22+i)])); }
I2C_stop();
}
void OLED_cursor(uint8_t xpos, uint8_t ypos) {
I2C_start(OLED_ADDR);
I2C_write(OLED_CMD_MODE);
I2C_write(xpos & 0x0F);
I2C_write(0x10 | (xpos >> 4));
I2C_write(0xB0 | (ypos & 0x07));
I2C_stop();
}
void OLED_clear(void) {
OLED_cursor(0, 0);
I2C_start(OLED_ADDR);
I2C_write(OLED_DAT_MODE);
for(uint16_t i=512; i; i--) I2C_write(0x00);
I2C_stop();
}
Attiny85 + OLED I2C 128 x 32 Плавный шрифт.
/*
David Johnson-Davies - www.technoblogy.com - 21st October 2020
ATtiny85 @ 1 MHz (internal oscillator; BOD disabled)
*/
#include <Wire.h>
//SCL - PB2 -7
//SDA - PB0 - 5
// OLED I2C 128 x 32 monochrome display **********************************************
const int OLEDAddress = 0x3C;
// Initialisation sequence for OLED module
int const InitLen = 15;
const unsigned char Init[InitLen] PROGMEM = {
0xA8, // Set multiplex
0x1F, // for 32 rows
0x8D, // Charge pump
0x14,
0x20, // Memory mode
0x01, // Vertical addressing
0xA1, // 0xA0/0xA1 flip horizontally
0xC8, // 0xC0/0xC8 flip vertically
0xDA, // Set comp ins
0x02,
0xD9, // Set pre charge
0xF1,
0xDB, // Set vcom deselect
0x40,
0xAF // Display on
};
const int data = 0x40;
const int single = 0x80;
const int command = 0x00;
void InitDisplay () {
Wire.beginTransmission(OLEDAddress);
Wire.write(command);
for (uint8_t c=0; c<InitLen; c++) Wire.write(pgm_read_byte(&Init[c]));
Wire.endTransmission();
}
void DisplayOnOff (int On) {
Wire.beginTransmission(OLEDAddress);
Wire.write(command);
Wire.write(0xAE + On);
Wire.endTransmission();
}
// Graphics **********************************************
int Scale = 1;
boolean Smooth = false;
// Character set for text - stored in program memory
const uint8_t CharMap[96][6] PROGMEM = {
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },//(space)
{ 0x00, 0x00, 0x5F, 0x00, 0x00, 0x00 },
{ 0x00, 0x07, 0x00, 0x07, 0x00, 0x00 },
{ 0x14, 0x7F, 0x14, 0x7F, 0x14, 0x00 },
{ 0x24, 0x2A, 0x7F, 0x2A, 0x12, 0x00 },
{ 0x23, 0x13, 0x08, 0x64, 0x62, 0x00 },
{ 0x36, 0x49, 0x56, 0x20, 0x50, 0x00 },
{ 0x00, 0x08, 0x07, 0x03, 0x00, 0x00 },
{ 0x00, 0x1C, 0x22, 0x41, 0x00, 0x00 },
{ 0x00, 0x41, 0x22, 0x1C, 0x00, 0x00 },
{ 0x2A, 0x1C, 0x7F, 0x1C, 0x2A, 0x00 },
{ 0x08, 0x08, 0x3E, 0x08, 0x08, 0x00 },
{ 0x00, 0x80, 0x70, 0x30, 0x00, 0x00 },
{ 0x08, 0x08, 0x08, 0x08, 0x08, 0x00 },
{ 0x00, 0x00, 0x60, 0x60, 0x00, 0x00 },
{ 0x20, 0x10, 0x08, 0x04, 0x02, 0x00 },
{ 0x3E, 0x41, 0x41, 0x41, 0x3E, 0x00 }, //0 48
{ 0x00, 0x42, 0x7F, 0x40, 0x00, 0x00 },
{ 0x72, 0x49, 0x49, 0x49, 0x46, 0x00 },
{ 0x21, 0x41, 0x49, 0x4D, 0x33, 0x00 },
{ 0x18, 0x14, 0x12, 0x7F, 0x10, 0x00 },
{ 0x27, 0x45, 0x45, 0x45, 0x39, 0x00 },
{ 0x3C, 0x4A, 0x49, 0x49, 0x31, 0x00 },
{ 0x41, 0x21, 0x11, 0x09, 0x07, 0x00 },
{ 0x36, 0x49, 0x49, 0x49, 0x36, 0x00 },
{ 0x46, 0x49, 0x49, 0x29, 0x1E, 0x00 }, //9
{ 0x00, 0x00, 0x14, 0x00, 0x00, 0x00 },
{ 0x00, 0x40, 0x34, 0x00, 0x00, 0x00 },
{ 0x00, 0x08, 0x14, 0x22, 0x41, 0x00 },
{ 0x14, 0x14, 0x14, 0x14, 0x14, 0x00 },
{ 0x00, 0x41, 0x22, 0x14, 0x08, 0x00 },
{ 0x02, 0x01, 0x59, 0x09, 0x06, 0x00 },
{ 0x3E, 0x41, 0x5D, 0x59, 0x4E, 0x00 },
{ 0x7C, 0x12, 0x11, 0x12, 0x7C, 0x00 },
{ 0x7F, 0x49, 0x49, 0x49, 0x36, 0x00 },
{ 0x3E, 0x41, 0x41, 0x41, 0x22, 0x00 },
{ 0x7F, 0x41, 0x41, 0x41, 0x3E, 0x00 },
{ 0x7F, 0x49, 0x49, 0x49, 0x41, 0x00 },
{ 0x7F, 0x09, 0x09, 0x09, 0x01, 0x00 },
{ 0x3E, 0x41, 0x41, 0x51, 0x73, 0x00 },
{ 0x7F, 0x08, 0x08, 0x08, 0x7F, 0x00 },
{ 0x00, 0x41, 0x7F, 0x41, 0x00, 0x00 },
{ 0x20, 0x40, 0x41, 0x3F, 0x01, 0x00 },
{ 0x7F, 0x08, 0x14, 0x22, 0x41, 0x00 },
{ 0x7F, 0x40, 0x40, 0x40, 0x40, 0x00 },
{ 0x7F, 0x02, 0x1C, 0x02, 0x7F, 0x00 },
{ 0x7F, 0x04, 0x08, 0x10, 0x7F, 0x00 },
{ 0x3E, 0x41, 0x41, 0x41, 0x3E, 0x00 },
{ 0x7F, 0x09, 0x09, 0x09, 0x06, 0x00 },
{ 0x3E, 0x41, 0x51, 0x21, 0x5E, 0x00 },
{ 0x7F, 0x09, 0x19, 0x29, 0x46, 0x00 },
{ 0x26, 0x49, 0x49, 0x49, 0x32, 0x00 },
{ 0x03, 0x01, 0x7F, 0x01, 0x03, 0x00 },
{ 0x3F, 0x40, 0x40, 0x40, 0x3F, 0x00 },
{ 0x1F, 0x20, 0x40, 0x20, 0x1F, 0x00 },
{ 0x3F, 0x40, 0x38, 0x40, 0x3F, 0x00 },
{ 0x63, 0x14, 0x08, 0x14, 0x63, 0x00 },
{ 0x03, 0x04, 0x78, 0x04, 0x03, 0x00 },
{ 0x61, 0x59, 0x49, 0x4D, 0x43, 0x00 },
{ 0x00, 0x7F, 0x41, 0x41, 0x41, 0x00 },
{ 0x02, 0x04, 0x08, 0x10, 0x20, 0x00 },
{ 0x00, 0x41, 0x41, 0x41, 0x7F, 0x00 },
{ 0x04, 0x02, 0x01, 0x02, 0x04, 0x00 },
{ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00 },
{ 0x00, 0x03, 0x07, 0x08, 0x00, 0x00 },
{ 0x20, 0x54, 0x54, 0x78, 0x40, 0x00 },
{ 0x7F, 0x28, 0x44, 0x44, 0x38, 0x00 },
{ 0x38, 0x44, 0x44, 0x44, 0x28, 0x00 },
{ 0x38, 0x44, 0x44, 0x28, 0x7F, 0x00 },
{ 0x38, 0x54, 0x54, 0x54, 0x18, 0x00 },
{ 0x00, 0x08, 0x7E, 0x09, 0x02, 0x00 },
{ 0x18, 0xA4, 0xA4, 0x9C, 0x78, 0x00 },
{ 0x7F, 0x08, 0x04, 0x04, 0x78, 0x00 },
{ 0x00, 0x44, 0x7D, 0x40, 0x00, 0x00 },
{ 0x20, 0x40, 0x40, 0x3D, 0x00, 0x00 },
{ 0x7F, 0x10, 0x28, 0x44, 0x00, 0x00 },
{ 0x00, 0x41, 0x7F, 0x40, 0x00, 0x00 },
{ 0x7C, 0x04, 0x78, 0x04, 0x78, 0x00 },
{ 0x7C, 0x08, 0x04, 0x04, 0x78, 0x00 },
{ 0x38, 0x44, 0x44, 0x44, 0x38, 0x00 },
{ 0xFC, 0x18, 0x24, 0x24, 0x18, 0x00 },
{ 0x18, 0x24, 0x24, 0x18, 0xFC, 0x00 },
{ 0x7C, 0x08, 0x04, 0x04, 0x08, 0x00 },
{ 0x48, 0x54, 0x54, 0x54, 0x24, 0x00 },
{ 0x04, 0x04, 0x3F, 0x44, 0x24, 0x00 },
{ 0x3C, 0x40, 0x40, 0x20, 0x7C, 0x00 },
{ 0x1C, 0x20, 0x40, 0x20, 0x1C, 0x00 },
{ 0x3C, 0x40, 0x30, 0x40, 0x3C, 0x00 },
{ 0x44, 0x28, 0x10, 0x28, 0x44, 0x00 },
{ 0x4C, 0x90, 0x90, 0x90, 0x7C, 0x00 },
{ 0x44, 0x64, 0x54, 0x4C, 0x44, 0x00 },
{ 0x00, 0x08, 0x36, 0x41, 0x00, 0x00 },
{ 0x00, 0x00, 0x77, 0x00, 0x00, 0x00 },
{ 0x00, 0x41, 0x36, 0x08, 0x00, 0x00 },
{ 0x02, 0x01, 0x02, 0x04, 0x02, 0x00 },//~ 78
{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }
};
void ClearDisplay () {
Wire.beginTransmission(OLEDAddress);
Wire.write(command);
// Set column address range
Wire.write(0x21); Wire.write(0); Wire.write(127);
// Set page address range
Wire.write(0x22); Wire.write(0); Wire.write(3);
Wire.endTransmission();
// Write the data in 26 20-byte transmissions
for (int i = 0 ; i < 26; i++) {
Wire.beginTransmission(OLEDAddress);
Wire.write(data);
for (int i = 0 ; i < 20; i++) Wire.write(0);
Wire.endTransmission();
}
}
// Converts bit pattern abcdefgh into aabbccddeeffgghh
int Stretch (int x) {
x = (x & 0xF0)<<4 | (x & 0x0F);
x = (x<<2 | x) & 0x3333;
x = (x<<1 | x) & 0x5555;
return x | x<<1;
}
// Plots a character; line = 0 to 3; column = 0 to 131
void PlotChar(int c, int line, int column) {
Wire.beginTransmission(OLEDAddress);
Wire.write(command);
// Set column address range
Wire.write(0x21); Wire.write(column); Wire.write(column + Scale*6 - 1);
// Set page address range
Wire.write(0x22); Wire.write(line); Wire.write(line + Scale - 1);
Wire.endTransmission();
Wire.beginTransmission(OLEDAddress);
Wire.write(data);
uint8_t col0 = pgm_read_byte(&CharMap[c-32][0]);
int col0L, col0R, col1L, col1R;
col0L = Stretch(col0);
col0R = col0L;
for (uint8_t col = 1 ; col < 5; col++) {
uint8_t col1 = pgm_read_byte(&CharMap[c-32][col]);
col1L = Stretch(col1);
col1R = col1L;
if (Scale == 1) Wire.write(col0);
// Smoothing
else {
if (Smooth) {
for (int i=6; i>=0; i--) {
for (int j=1; j<3; j++) {
if (((col0>>i & 0b11) == (3-j)) && ((col1>>i & 0b11) == j)) {
col0R = col0R | 1<<((i*2)+j);
col1L = col1L | 1<<((i*2)+3-j);
}
}
}
}
Wire.write(col0L); Wire.write(col0L>>8);
Wire.write(col0R); Wire.write(col0R>>8);
col0L = col1L; col0R = col1R;
}
col0 = col1;
}
if (Scale == 1) Wire.write(col0);
else {
Wire.write(col0L); Wire.write(col0L>>8);
Wire.write(col0R); Wire.write(col0R>>8);
}
Wire.endTransmission();
}
// Plot text starting at the current plot position
void PlotText(PGM_P s, int line, int column) {
int p = (int)s;
while (1) {
char c = pgm_read_byte(p++);
if (c == 0) return;
PlotChar(c, line, column);
column = column + Scale*6;
}
}
void setup() {
Wire.begin();
InitDisplay();
ClearDisplay();
Scale = 2;
}
void loop() {
byte t=0;
Smooth = true;// Smooth = false;
PlotChar(t+48,0,0);
PlotText(PSTR("RCL-RADIO"), 2, 0);
delay(1000);
}