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.