Battery icon with U8x8

Hello
I have a project that uses a small OLED screen, and an Arduino mini pro. Due to extreme shortages of RAM space, I have to use the U8X8 library with its limited fonts, and even then I don't have space for the larger fonts.
I want to include a battery level icon, which I guess is really four icons. I can't actually see this as an option even in the extended fonts. I have seen tutorials that explain how to write a bitmap to the screen but they assume you want to write to the whole screen rather than just a small fraction.
What is the most memory-efficient way of doing what I want, assuming it's even possible?

Even the u8x8 has a drawTile() function for a bitmap.
Can you show your sketch, maybe we have tips to reduce RAM usage.
Can you show the bitmaps for the battery level ? I think that drawing a line is not possible with u8x8, so you might need a few bitmaps.
If you have seen something, can you give a link to it ?

That drawTile() function intrigued me.

// u8x8_tiles.ino
//
// For: https://forum.arduino.cc/t/battery-icon-with-u8x8/1006207
//
// Testing the bitmap of the U8x8 library
// The library "U8g2" is added to the project, but only the U8x8 part is used.
// Battery bitmap: my own design
//
// Version 1, 24 June 2022, by Koepel
//   It amazes me how ugly this sketch turned out to be. 
//   It only works for this specific bitmap, and the code is not nice.
//

#include <U8x8lib.h>

U8X8_SSD1306_128X64_NONAME_HW_I2C u8x8(U8X8_PIN_NONE);   // I2C bus, no reset pin

// Four tiles for a battery icon of 16x16.
// The bitmap for the tiles is vertical!
//    The first byte are the pixels on the left.
//    The lowest bit is the pixel on top.
const byte batteryTile[] = 
{ 
  // The upper-left 8x8 pixels:
  0x00, 0x00, 0xF8, 0x0C, 0x04, 0x02, 0x02, 0x02, 
  // The upper-right 8x8 pixels:
  0x02, 0x02, 0x02, 0x04, 0x0C, 0xF8, 0x00, 0x00, 
  // The lower-left 8x8 pixels:
  0x00, 0x00, 0x7F, 0x40, 0x40, 0x40, 0x40, 0x40, 
  // The lower-right 8x8 pixels:
  0x40, 0x40, 0x40, 0x40, 0x40, 0x7F, 0x00, 0x00, 
};

const int potPin = A0;

const int batX = 12;     // the 'x' (column) of the upper-left of the battery
const int batY = 3;     // the 'y' (row) of the upper-left of the battery


void setup(void)
{
  u8x8.begin();
  u8x8.setFont(u8x8_font_chroma48medium8_r);
  u8x8.drawString(0, 4, "Battery");
  u8x8.drawString(8, 4, "  0%");   // allow text up to 100%

  u8x8.drawTile( batX, batY,   2, batteryTile);
  u8x8.drawTile( batX, batY+1, 2, (char *) batteryTile + 16);
}


void loop(void)
{
  int rawADC = analogRead( potPin);
  int percent = rawADC / 10;         
  percent = constrain( percent, 0, 100);
  char buffer[10];
  snprintf( buffer, sizeof( buffer), "%3d", percent);
  u8x8.drawString(8, 4, buffer);
  showBattery( percent);
  delay(100);
}


void showBattery( int percentage)
{
  // copy the battery tiles to a temporary "work" tile.
  byte tiles[32];
  memcpy(tiles, batteryTile, 32);

  // There are 12 lines to draw inside the battery.
  // Zero lines is also an option, so there are 13 possible levels.
  // There are 6 lines in the lower part and 6 lines in the upper part
  int lines = percentage / 8;        // might need some tuning near 0% and 100%
  lines = constrain( lines, 0, 12);  // for safety
  int lowerlines = min( 6, lines);   // 0...6 lines in the lower part
  int upperlines = 0;                
  if( lines > 6)
    upperlines = lines - 6;          


  // The lines are over 4 bytes, and the tiles are vertical.
  // I can not think of any good code, so I just put down what it should do.

  // lower-left
  for( int i=3; i<8; i++)
  {
    for( int j=0; j<lowerlines; j++)
      bitSet( tiles[i+16], 7-(j+2));
  }

  // lower-right
  for( int i=0; i<5; i++)
  {
    for( int j=0; j<lowerlines; j++)
      bitSet( tiles[i+24], 7-(j+2));
  }

  // upper-left
  for( int i=3; i<8; i++)
  {
    for( int j=0; j<upperlines; j++)
      bitSet( tiles[i], 7-j);
  }

  // upper-right
  for( int i=0; i<5; i++)
  {
    for( int j=0; j<upperlines; j++)
      bitSet( tiles[i+8], 7-j);
  }

  u8x8.drawTile( batX, batY,   2, tiles);
  u8x8.drawTile( batX, batY+1, 2, (char *) tiles + 16);
}

The sketch in Wokwi:

Ah, thank you! I hadn't noticed drawTile - I will try your code.

OK so this was very cool, but as I suspected it made the code too big for the Arduino. I've already done most of the memory-saving things like putting strings into PROGMEM, so I doubt there's a way round this. Also, even when I removed portions of my sketch to make it fit, it took a good 10 seconds before setup() got going, presumably because of the large byte declaration.
I think the way forward is a just to use a number of "I" characters to create a makeshift battery display.

Yeah, I could put the battery 32 bytes in PROGMEM and use 8 bytes to build the level.

Large byte declarations do not even take 1 millisecond. Without seeing your sketch, I don't know if there is room for improvement.

If you select a font with more character definitions, then perhaps you can use the graphical bars. I don't know if the u8x8 has UTF-8 definitions for the 8 bars.

██
█▉
█▊
█▋
█▌
█▎
█▏






[ADDED]
I could not find such a font of the U8x8 library, there is a font for old ASCII with the full bar and half a bar.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.