How to display a battery icon on a 1.77 inch TFT?
How to Display a Battery Icon on a 1.77 Inch TFT
To display a battery icon on a 1.77 inch TFT, you need to draw a bitmap image of a battery outline and fill it dynamically based on the battery level, using a microcontroller like an STM32 or ESP32 with SPI communication. The 1.77 inch spi mcu rgb tft display typically has a resolution of 128x160 pixels and uses the ST7735 driver, which supports 16-bit color (RGB565). Start by initializing the display with the correct SPI clock speed (usually 4-8 MHz for reliable operation) and set the orientation to portrait or landscape depending on your layout. For a battery icon, you can create a 32x16 pixel bitmap (or larger, like 48x24) in a tool like LCD Image Converter, then store it as a const unsigned char array in your code. The icon should include a rectangular body with a small tab on the right side (positive terminal) and a border of 1-2 pixels. To show the charge level, you’ll draw a filled rectangle inside the body, with the width proportional to the battery percentage—for example, at 50% charge, fill half the interior width. Use the fillRect() function from the TFT library, passing the x, y, width, height, and color (e.g., green for >50%, yellow for 20-50%, red for <20%). For a smooth update, clear only the interior area before redrawing, not the entire screen, to avoid flicker. The refresh rate should be at least 30 Hz for real-time updates, but you can throttle it to 1 Hz for battery monitoring to save power. The display’s SPI bus can handle up to 10 Mbps, so drawing a 32x16 icon takes less than 1 ms. You’ll need to map the battery level from an ADC reading (e.g., from a voltage divider on a Li-ion cell) to the pixel width. For a 3.7V Li-ion battery, the ADC range is 0-4095 on a 12-bit ADC, corresponding to 2.7V (empty) to 4.2V (full). Map this to 0-100% using a lookup table or linear interpolation, then compute the fill width as fillWidth = (batteryPercent * (iconWidth - 2*border)) / 100. If you’re using a 1.77 inch TFT with the ST7735 driver, the pixel coordinates start at (0,0) in the top-left corner. Place the battery icon at a fixed position, like (48, 10) for a 128x160 screen, leaving room for text or other UI elements. The display’s SPI interface requires 4 pins: CS, DC, MOSI, SCLK, plus a reset pin. Typical initialization sequence includes a software reset, sleep-out command, and display-on command. For the battery icon, you can also add a percentage text next to it using the setCursor() and print() functions, with a font size of 1 or 2 (5x7 or 8x13 pixels). The total memory for a 32x16 bitmap is 1024 bytes (32*16*2 bytes for 16-bit color), which is fine for most MCUs with 32KB+ RAM. If you’re short on memory, compress the bitmap to RLE (run-length encoding) or use a smaller icon like 24x12. To ensure accurate color, use the RGB565 format: for example, green is 0x07E0, yellow is 0xFFE0, red is 0xF800, and gray for the border is 0x8410. The display’s backlight can be controlled via PWM on a separate pin, typically at 100 Hz to avoid visible flicker, and you can dim it to 50% brightness to save power, which is useful for battery-powered devices. For a real-world example, an ESP32 with a 1.77 inch TFT can read battery voltage through an ADC pin, average 10 samples to reduce noise, and update the icon every 5 seconds to minimize CPU load. The code should include a drawBatteryIcon() function that takes the percentage as input, clears the previous fill with the background color (e.g., black 0x0000), then draws the new fill. Test the icon on the display by simulating different levels—0%, 25%, 50%, 75%, 100%—to verify the fill width matches. Also, handle edge cases like a disconnected battery (ADC reading 0) by showing a red empty icon with a warning symbol. The display’s viewing angle is 6 o’clock (typical for TN panels), so place the icon where it’s easily visible, like the top-right corner. For multi-color icons, you can use a 16-bit color palette with 65,536 colors, but limit to 4-5 colors for simplicity. The SPI bus timing is critical: set the clock polarity to 0 (CPOL=0) and phase to 0 (CPHA=0) for the ST7735, with data sent MSB first. The display’s resolution of 128x160 means you have 20,480 pixels total, so a battery icon takes up 0.5% of the screen area—enough to be clear without obscuring other data. If you’re using a library like Adafruit_ST7735, the drawBitmap() function can render the icon directly, but you’ll need to handle the fill manually. For a more advanced approach, use a sprite buffer in RAM to draw the icon off-screen, then blit it to the display in one go, reducing SPI traffic. The sprite buffer for a 32x16 icon is 1024 bytes, and you can update it in 0.1 ms at 10 Mbps. The battery icon’s border should be 1 pixel thick to avoid aliasing, and the tab should be 4x2 pixels on the right side. For a 3D effect, add a highlight line on the top edge using a lighter color like 0xFFFF (white). The fill should start 1 pixel from the left border and end 1 pixel from the right, leaving a 1-pixel gap for the border. For a 48x24 icon, the fill width at 50% is 23 pixels (48-2 borders = 46, half is 23). The display’s gamma correction is fixed, so colors appear slightly different—test with a multimeter to verify the actual voltage. The battery icon can also include a lightning bolt symbol for charging, which you can draw as a small 8x8 bitmap. To detect charging, read a GPIO pin connected to a charger detection circuit (e.g., a voltage divider on the USB VBUS). The charger status can be indicated by a blinking icon (toggle every 500 ms) or a static symbol. The display’s SPI bus can be shared with other devices like an SD card, but you’ll need separate CS pins. For a 1.77 inch TFT, the typical power consumption is 20-30 mA with backlight on, and 5-10 mA with backlight off. To save power, turn off the backlight when the battery is below 10% and only update the icon every 10 seconds. The ADC reading should be calibrated with a known voltage reference, like the internal 1.1V reference on an ESP32. The battery level mapping can be linearized using a polynomial or a lookup table with 10-20 points. For a Li-ion cell, the voltage curve is nonlinear: 4.2V (100%), 3.7V (50%), 3.2V (10%), 2.7V (0%). Use a 10-point lookup table with interpolation to get accurate percentages. The display’s pixel clock is 16 MHz max, but 8 MHz is stable for long wires. The battery icon should be drawn after the display is fully initialized, which takes about 50 ms (including a 120 ms delay for sleep-out). The SPI transaction should be wrapped in beginTransaction() and endTransaction() to avoid conflicts with interrupts. The icon’s background color should match the screen’s background (e.g., black), so it appears seamless. For a 128x160 screen, you can place multiple battery icons for different devices, but keep them at least 10 pixels apart to avoid overlap. The fill color can be gradient from green to red using a color map, but that requires more computation. For a simple implementation, use a single color and change it based on the level. The display’s command set includes CASET and RASET to define a window, which you can use to update only the fill area, reducing SPI traffic. For example, set the column range to (iconX+1, iconX+iconWidth-2) and the row range to (iconY+1, iconY+iconHeight-2), then write the fill pixels in a loop. This is faster than using fillRect() for large areas. The fill pixels can be written in a single SPI transaction with a buffer of 256 bytes. The battery icon’s aspect ratio should be 2:1 (width:height) for a realistic look, like 32x16 or 48x24. The tab should be 4 pixels wide and 2 pixels tall, centered vertically on the right side. The border should be 1 pixel thick, with a color of 0x8410 (gray) for a neutral look. The interior fill should be 2 pixels away from the border on all sides. For a 32x16 icon, the interior width is 28 pixels (32-2-2), and the interior height is 12 pixels (16-2-2). At 50% charge, the fill width is 14 pixels. The fill rectangle’s x-coordinate is iconX+2, y-coordinate is iconY+2, width is fillWidth, height is 12. The fill color can be green (0x07E0) for 50-100%, yellow (0xFFE0) for 20-50%, and red (0xF800) for 0-20%. The display’s color depth is 16-bit, so each pixel is 2 bytes. For a 28x12 fill area, you need to send 672 bytes (28*12*2) per update. At 8 MHz SPI, this takes 0.84 ms. The total update time for the icon is under 2 ms, leaving plenty of CPU time for other tasks. The battery icon can be animated by drawing a small moving dot inside the body to indicate charging, but this adds complexity. For a static icon, the bitmap can be stored in PROGMEM to save RAM on AVR-based MCUs. On an ESP32, store it in flash memory using const uint8_t arrays. The icon’s bitmap should be generated with a tool like GIMP or LCD Assistant, which outputs a C array in the format {0x00, 0x01, ...}. The array size is (width*height*2) bytes. For a 32x16 icon, this is 1024 bytes. The display’s driver IC (ST7735) supports 262K colors, but the 16-bit mode is the most common for 8-bit MCUs. The SPI command for writing pixels is 0x2C, followed by the pixel data. The initialization sequence for the ST7735 includes commands like 0x11 (sleep-out), 0x3A (set pixel format to 0x05 for 16-bit), 0x36 (set orientation), and 0x29 (display-on). The orientation can be set to 0x00 for portrait (default) or 0x60 for landscape (rotation 90 degrees). For a battery icon in landscape mode, place it at (10, 10) for a 160x128 screen. The display’s refresh rate is 60 Hz, but you can update the icon at a lower rate to save power. The battery voltage should be read with a 10-bit ADC (0-1023) on an ESP8266, or 12-bit (0-4095) on an ESP32. Use a voltage divider with two resistors (e.g., 100kΩ and 220kΩ) to scale the battery voltage to 0-3.3V. The formula is: Vbat = (adcValue / adcMax) * vRef * (R1+R2)/R2. For a 3.7V battery, set vRef = 3.3V, R1 = 100kΩ, R2 = 220kΩ, so the scaling factor is 1.454. The ADC reading at 4.2V is 4095 * 3.3 / 4.2 * 220/320 = 4095 * 0.7857 * 0.6875 = 2210. At 2.7V, the ADC reading is 4095 * 3.3 / 2.7 * 220/320 = 4095 * 1.222 * 0.6875 = 3440. This is inverted, so you need to invert the mapping. The battery percentage can be calculated as: percentage = (adcValue - adcEmpty) * 100 / (adcFull - adcEmpty), where adcEmpty = 3440 and adcFull = 2210. If the ADC reading is outside this range, clamp it to 0 or 100. The display’s backlight pin can be controlled with PWM at 1 kHz, using a duty cycle of 0-255. For a 50% brightness, set the duty cycle to 128. The battery icon should be drawn on a black background for contrast. The display’s pixel format is RGB565, meaning the first 5 bits are red, next 6 bits are green, last 5 bits are blue. For a green fill, use 0x07E0 (binary 0000011111100000). For yellow, use 0xFFE0 (1111111111100000). For red, use 0xF800 (1111110000000000). The border color can be 0x8410 (1000010000010000), which is a medium gray. The icon’s bitmap should be created with a 1-pixel border around the entire body, including the tab. The tab is a small rectangle on the right side, 4 pixels wide and 2 pixels tall, centered vertically. The body is 28x14 pixels (width 32 minus 4 for tab, height 16 minus 2 for border). The interior fill area is 26x12 pixels (body minus 1-pixel border on each side). The fill width is calculated as fillWidth = (percentage * 26) / 100. The fill height is always 12 pixels. The fill rectangle’s top-left corner is (iconX+2, iconY+2). The fill color is determined by the percentage. The display’s SPI bus should be initialized with a clock speed of 4 MHz for long wires (up to 10 cm) or 8 MHz for short wires (<5 cm). The CS pin should be pulled high when not in use. The DC pin is used to distinguish commands (low) and data (high). The reset pin should be pulled high with a 10kΩ resistor. The initialization sequence should include a 10 ms delay after reset, then a 120 ms delay after sleep-out. The display’s window mode can be set with CASET (0x2A) and RASET (0x2B) commands. For example, to update only the fill area, set the column range to (iconX+2, iconX+2+fillWidth-1) and the row range to (iconY+2, iconY+2+12-1). Then send the RAMWR command (0x2C) followed by the fill pixels. This reduces the amount of data sent. The fill pixels can be generated in a loop: for each row, for each column, send the 16-bit color value. The color value is stored as two bytes, low byte first (little-endian). For example, green 0x07E0 is sent as 0xE0, 0x07. The SPI transaction should be wrapped in a mutex if using FreeRTOS. The battery icon can be tested with a potentiometer simulating the battery voltage. Connect the potentiometer to the ADC pin, and adjust it to see the icon change. The icon should update within 10 ms of the ADC reading change. The display’s response time is 10-20 ms (typical for TN panels), so the icon will appear smooth. For a production device, use a hardware filter on the ADC input (e.g., a 100nF capacitor) to reduce noise. The battery icon can also include a text label like “BAT” above it, using a 5x7 font. The font data is stored in a bitmap array, and you can use a library like Adafruit_GFX to render text. The text color should be white (0xFFFF) for contrast. The icon’s position should be adjusted for different screen orientations. For a 128x160 screen in portrait mode, place the icon at (48, 10) for 32x16 size, or (40, 10) for 48x24 size. The text label “BAT” can be placed at (48, 0) for 32x16 icon, or (40, 0) for 48x24 icon. The font height is 7 pixels, so it fits above the icon. The display’s backlight can be turned off when the device is in sleep mode, and the battery icon can be updated only when the button is pressed. The battery level can be stored in RTC memory to persist across sleep cycles. The icon’s fill color can be animated to pulse when the battery is low, by toggling between red and black every 500 ms. This is done by alternating the fill color in the drawBatteryIcon() function. The icon’s border should remain static during animation. The display’s SPI bus can be shared with a touch controller if needed, but the touch controller’s CS pin must be separate. The battery icon can be combined with a voltage readout in millivolts, displayed as text next to the icon
The best product decisions are no longer the loudest in the room — they are the most evidenced.— Obivu Research Note, 2024
See your own customer signals, ranked.
Turn fragmented interviews, tickets, and verbatims into a single feed of validated insights. Full feature access, white-glove onboarding, no credit card.