/* Monochrome Low-Power ST7302 Display Library v2 - see http://www.technoblogy.com/show?3YB0 David Johnson-Davies - www.technoblogy.com - 14th January 2024 CC BY 4.0 Licensed under a Creative Commons Attribution 4.0 International license: http://creativecommons.org/licenses/by/4.0/ */ #if defined(MEGATINYCORE) // ATtiny402/412 PORTA positions. Change these for the chip you're using int const dc = 7; int const mosi = 1; int const sck = 3; int const cs = 6; // ATtiny 0-, 1-, and 2-series port manipulations - assumes all pins in same port #define PORT_TOGGLE(x) PORTA.OUTTGL = (x) #define PORT_LOW(x) PORTA.OUTCLR = (x) #define PORT_HIGH(x) PORTA.OUTSET = (x) #define PORT_OUTPUT(x) PORTA.DIRSET = (x) #else // ATtiny45/85 PORTB positions. Change these for the chip you're using int const dc = 0; int const mosi = 1; int const sck = 2; int const cs = 3; // Classic ATtiny port manipulations - assumes all pins in same port #define PORT_TOGGLE(x) PINB = (x) #define PORT_LOW(x) PORTB = PORTB & ~((x)); #define PORT_HIGH(x) PORTB = PORTB | ((x)) #define PORT_OUTPUT(x) DDRB = (x) #endif typedef void *(circle_type)(int, int); // Character set for text - stored in program memory const uint8_t CharMap[96][5] PROGMEM = { { 0x00, 0x00, 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x5F, 0x00, 0x00 }, { 0x00, 0x07, 0x00, 0x07, 0x00 }, { 0x14, 0x7F, 0x14, 0x7F, 0x14 }, { 0x24, 0x2A, 0x7F, 0x2A, 0x12 }, { 0x23, 0x13, 0x08, 0x64, 0x62 }, { 0x36, 0x49, 0x56, 0x20, 0x50 }, { 0x00, 0x08, 0x07, 0x03, 0x00 }, { 0x00, 0x1C, 0x22, 0x41, 0x00 }, { 0x00, 0x41, 0x22, 0x1C, 0x00 }, { 0x2A, 0x1C, 0x7F, 0x1C, 0x2A }, { 0x08, 0x08, 0x3E, 0x08, 0x08 }, { 0x00, 0x80, 0x70, 0x30, 0x00 }, { 0x08, 0x08, 0x08, 0x08, 0x08 }, { 0x00, 0x00, 0x60, 0x60, 0x00 }, { 0x20, 0x10, 0x08, 0x04, 0x02 }, { 0x3E, 0x51, 0x49, 0x45, 0x3E }, { 0x00, 0x42, 0x7F, 0x40, 0x00 }, { 0x72, 0x49, 0x49, 0x49, 0x46 }, { 0x21, 0x41, 0x49, 0x4D, 0x33 }, { 0x18, 0x14, 0x12, 0x7F, 0x10 }, { 0x27, 0x45, 0x45, 0x45, 0x39 }, { 0x3C, 0x4A, 0x49, 0x49, 0x31 }, { 0x41, 0x21, 0x11, 0x09, 0x07 }, { 0x36, 0x49, 0x49, 0x49, 0x36 }, { 0x46, 0x49, 0x49, 0x29, 0x1E }, { 0x00, 0x00, 0x14, 0x00, 0x00 }, { 0x00, 0x40, 0x34, 0x00, 0x00 }, { 0x00, 0x08, 0x14, 0x22, 0x41 }, { 0x14, 0x14, 0x14, 0x14, 0x14 }, { 0x00, 0x41, 0x22, 0x14, 0x08 }, { 0x02, 0x01, 0x59, 0x09, 0x06 }, { 0x3E, 0x41, 0x5D, 0x59, 0x4E }, { 0x7C, 0x12, 0x11, 0x12, 0x7C }, { 0x7F, 0x49, 0x49, 0x49, 0x36 }, { 0x3E, 0x41, 0x41, 0x41, 0x22 }, { 0x7F, 0x41, 0x41, 0x41, 0x3E }, { 0x7F, 0x49, 0x49, 0x49, 0x41 }, { 0x7F, 0x09, 0x09, 0x09, 0x01 }, { 0x3E, 0x41, 0x41, 0x51, 0x73 }, { 0x7F, 0x08, 0x08, 0x08, 0x7F }, { 0x00, 0x41, 0x7F, 0x41, 0x00 }, { 0x20, 0x40, 0x41, 0x3F, 0x01 }, { 0x7F, 0x08, 0x14, 0x22, 0x41 }, { 0x7F, 0x40, 0x40, 0x40, 0x40 }, { 0x7F, 0x02, 0x1C, 0x02, 0x7F }, { 0x7F, 0x04, 0x08, 0x10, 0x7F }, { 0x3E, 0x41, 0x41, 0x41, 0x3E }, { 0x7F, 0x09, 0x09, 0x09, 0x06 }, { 0x3E, 0x41, 0x51, 0x21, 0x5E }, { 0x7F, 0x09, 0x19, 0x29, 0x46 }, { 0x26, 0x49, 0x49, 0x49, 0x32 }, { 0x03, 0x01, 0x7F, 0x01, 0x03 }, { 0x3F, 0x40, 0x40, 0x40, 0x3F }, { 0x1F, 0x20, 0x40, 0x20, 0x1F }, { 0x3F, 0x40, 0x38, 0x40, 0x3F }, { 0x63, 0x14, 0x08, 0x14, 0x63 }, { 0x03, 0x04, 0x78, 0x04, 0x03 }, { 0x61, 0x59, 0x49, 0x4D, 0x43 }, { 0x00, 0x7F, 0x41, 0x41, 0x41 }, { 0x02, 0x04, 0x08, 0x10, 0x20 }, { 0x00, 0x41, 0x41, 0x41, 0x7F }, { 0x04, 0x02, 0x01, 0x02, 0x04 }, { 0x40, 0x40, 0x40, 0x40, 0x40 }, { 0x00, 0x03, 0x07, 0x08, 0x00 }, { 0x20, 0x54, 0x54, 0x78, 0x40 }, { 0x7F, 0x28, 0x44, 0x44, 0x38 }, { 0x38, 0x44, 0x44, 0x44, 0x28 }, { 0x38, 0x44, 0x44, 0x28, 0x7F }, { 0x38, 0x54, 0x54, 0x54, 0x18 }, { 0x00, 0x08, 0x7E, 0x09, 0x02 }, { 0x18, 0xA4, 0xA4, 0x9C, 0x78 }, { 0x7F, 0x08, 0x04, 0x04, 0x78 }, { 0x00, 0x44, 0x7D, 0x40, 0x00 }, { 0x20, 0x40, 0x40, 0x3D, 0x00 }, { 0x7F, 0x10, 0x28, 0x44, 0x00 }, { 0x00, 0x41, 0x7F, 0x40, 0x00 }, { 0x7C, 0x04, 0x78, 0x04, 0x78 }, { 0x7C, 0x08, 0x04, 0x04, 0x78 }, { 0x38, 0x44, 0x44, 0x44, 0x38 }, { 0xFC, 0x18, 0x24, 0x24, 0x18 }, { 0x18, 0x24, 0x24, 0x18, 0xFC }, { 0x7C, 0x08, 0x04, 0x04, 0x08 }, { 0x48, 0x54, 0x54, 0x54, 0x24 }, { 0x04, 0x04, 0x3F, 0x44, 0x24 }, { 0x3C, 0x40, 0x40, 0x20, 0x7C }, { 0x1C, 0x20, 0x40, 0x20, 0x1C }, { 0x3C, 0x40, 0x30, 0x40, 0x3C }, { 0x44, 0x28, 0x10, 0x28, 0x44 }, { 0x4C, 0x90, 0x90, 0x90, 0x7C }, { 0x44, 0x64, 0x54, 0x4C, 0x44 }, { 0x00, 0x08, 0x36, 0x41, 0x00 }, { 0x00, 0x00, 0x77, 0x00, 0x00 }, { 0x00, 0x41, 0x36, 0x08, 0x00 }, { 0x00, 0x06, 0x09, 0x06, 0x00 }, // degree symbol = '~' { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } }; // Monochrome display ********************************************** int const CASET = 0x2A; // Define column address int const RASET = 0x2B; // Define row address int const RAMWR = 0x2C; // Write to display RAM int const RAMRD = 0x2E; // Read from display RAM // Current plot position and colours uint8_t xpos, ypos; uint8_t scale = 1; // Text scale boolean smooth = true; boolean exor = false; // Plotting mode const uint8_t xsize = 250, ysize = 122; // Send a byte to the display void Data (uint8_t d) { for (uint8_t bit = 0x80; bit; bit >>= 1) { PORT_TOGGLE(1<>16); Data(block>>8); Data(block); PORT_TOGGLE(1<>mosi & 1); PORT_TOGGLE(1< -dy) { err = err - dy; xpos = xpos + sx; } if (e2 < dx) { err = err + dx; ypos = ypos + sy; } } PlotPoint(255, 0); // Flush } void DrawRect (uint8_t w, uint8_t h) { uint8_t x = xpos, y = ypos; MoveTo(x, y); DrawTo(x+w-1, y); DrawTo(x+w-1, y+h-1); DrawTo(x, y+h-1); DrawTo(x, y); } void FillRect (uint8_t w, uint8_t h) { uint8_t x = xpos, y = ypos; for (uint8_t i=x; i= y) { fun1(x1+x, y1-y); fun2(x1+x, y1+y); //4 fun1(x1+y, y1-x); fun2(x1+y, y1+x); //3 fun1(x1-y, y1-x); fun2(x1-y, y1+x); //2 fun1(x1-x, y1-y); fun2(x1-x, y1+y); //1 if (err > 0) { x = x - 1; dx = dx + 2; err = err - (radius<<1) + dx; } else { y = y + 1; err = err + dy; dy = dy + 2; } } xpos = x1; ypos = y1; } void DrawCircle (uint8_t radius) { DoCircle(radius, PlotPoint, PlotPoint); } void FillCircle (uint8_t radius) { DoCircle(radius, MoveTo, DrawTo); } // Converts bit pattern abcdefgh into a0b0c0d0e0f0g0h uint16_t Stretch (uint16_t x) { x = (x & 0xF0)<<4 | (x & 0x0F); x = (x<<2 | x) & 0x3333; x = (x<<1 | x) & 0x5555; return x<<1 | x; } void WriteColumn (uint8_t pixels, uint8_t x, uint8_t y) { for (uint8_t i=0x80; i; i = i>>1, y++) { if (pixels & i) PlotPoint(x, y); } } void WriteColumns (uint16_t left, uint16_t right, uint8_t x, uint8_t y) { WriteColumn(left, x, y+8); WriteColumn(left>>8, x, y); WriteColumn(right, x+1, y+8); WriteColumn(right>>8, x+1, y); } // Plot character void PlotChar (char c) { uint8_t x = xpos, y = ypos; uint8_t col0 = pgm_read_byte(&CharMap[c-32][0]); uint16_t 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) WriteColumn(col0, x+col-1, y); // 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); } } } } WriteColumns(col0L, col0R, x+col*2-2, y); col0L = col1L; col0R = col1R; } col0 = col1; } if (scale == 1) WriteColumn(col0, x+4, y); else WriteColumns(col0L, col0R, x+8, y); PlotPoint(255, 0); // Flush xpos = xpos + 6*scale; } // Plot text from a char array starting at the current plot position void PlotChars (char *s) { while (*s) PlotChar(*s++); } // Plot text from PROGMEM starting at the current plot position void PlotText (PGM_P p) { while (1) { char c = pgm_read_byte(p++); if (c == 0) return; PlotChar(c); } } void PlotInt (int n) { bool lead = false; for (int d=10000; d>0; d = d/10) { char j = (n/d) % 10; if (j!=0 || lead || d==1) { PlotChar(j + '0'); lead = true; } } } // Demo ********************************************** const int top = 56; const int bot = 535; void DrawStopwatch () { const int x0 = 125, y0 = 61, radius = 60; MoveTo(x0, y0); FillCircle(radius); scale = 1; exor = true; int x = 0, y = radius*bot; for (int i=0; i<60; i++) { // Hours and hour marks if (i%5 == 0) { MoveTo(x0+(x/bot), y0+(y/bot)); DrawTo(x0 + ((x/bot)*15/16), y0 + ((y/bot)*15/16)); MoveTo(x0 + ((x/bot)*13/16) - 3*(1+(i==0)), y0 + ((y/bot)*13/16) - 4); if (i==0) PlotInt(60); else PlotInt(i); } x = x + y/bot*top; y = y - x/bot*top; } } void TickStopwatch () { const int x0 = 125, y0 = 61, radius = 60; static int x = 0, y = radius*bot; MoveTo(x0, y0); DrawTo(x0+(x/bot), y0+(y/bot)); delay(1000); MoveTo(x0, y0); DrawTo(x0+(x/bot), y0+(y/bot)); x = x + y/bot*top; y = y - x/bot*top; } void DemoPanels () { MoveTo(0,61); DrawTo(65,61); scale = 1; MoveTo(15, 108); PlotText(PSTR("Input")); scale = 2; MoveTo(0, 86); PlotText(PSTR("15.0V")); MoveTo(0, 66); PlotText(PSTR("0.35A")); scale = 1; MoveTo(12, 48); PlotText(PSTR("Output")); scale = 2; MoveTo(0, 26); PlotText(PSTR("12.3V")); MoveTo(0, 6); PlotText(PSTR("0.30A")); scale = 1; MoveTo(184, 108); PlotText(PSTR("Temperature")); scale = 2; MoveTo(190, 86); PlotText(PSTR("21.3~")); MoveTo(181,81); DrawTo(249,81); scale = 1; MoveTo(199, 68); PlotText(PSTR("Battery")); scale = 2; MoveTo(194, 46); DrawRect(44, 16); MoveTo(238, 50); FillRect(6, 8); MoveTo(196, 48); FillRect(30, 12); MoveTo(181,41); DrawTo(249,41); scale = 1; MoveTo(208, 28); PlotText(PSTR("Time")); } // Setup ********************************************** void setup() { InitDisplay(); } void loop () { int start = millis(); DemoPanels(); DrawStopwatch(); start = millis() - start; scale = 2; MoveTo(190, 6); PlotInt(start); PlotText(PSTR("ms")); for (;;) TickStopwatch(); }