How to Create a Menu on a 128x32 COG LCD Display
To create a menu on a 128x32 COG LCD display, you need to manage the limited pixel space—128 columns by 32 rows—by designing a text-based or icon-based interface that scrolls or pages through options. The display is small, so you’ll typically use a monochrome graphic library like Adafruit_GFX with a controller like SSD1306 or ST7565, which are common for these COG (Chip-On-Glass) panels. Start by defining a menu structure in code: an array of strings (e.g., “Option 1”, “Option 2”) with a maximum of 3-4 characters per line due to the 32-pixel height. A 5x7 font gives you about 21 characters per line horizontally, but vertical space limits you to 4 lines at most (32 pixels / 8 pixels per line = 4 lines, with no spacing). For readability, use 2 lines with larger fonts or 3 lines with small fonts, and implement a cursor or highlight via inverse video. The key is to handle user input (e.g., buttons or rotary encoder) to navigate, updating the display buffer with
display.display() after each change. This approach works for embedded systems like Arduino or ESP32, where you can store menu items in PROGMEM to save RAM. For a concrete example, a
128x32 cog lcd display with SPI interface lets you send data at 8 MHz, achieving refresh rates under 10 ms per frame, which is fast enough for real-time menu scrolling.
Understanding the Hardware Constraints
The 128x32 COG LCD display uses a chip-on-glass design where the driver IC is bonded directly to the glass, reducing thickness to about 1.2 mm and weight to under 5 grams. This is critical for portable devices like handheld meters or wearable prototypes. The display’s resolution is 128x32 pixels, which means 4096 total pixels, each driven by a single transistor in the COG package. The SPI interface typically operates at 3.3V logic, with a maximum clock speed of 10 MHz, but most libraries default to 4 MHz for stability. Power consumption is around 0.5 mA during active use and 0.1 mA in sleep mode, making it suitable for battery-powered projects. The display’s contrast ratio is about 2000:1, and the viewing angle is 120 degrees, but the 32-pixel height means you’ll see only 4 lines of 5x7 text (if you use 8-pixel line spacing) or 3 lines with 10-pixel spacing. For menus, you must decide between scrolling text (e.g., a single line that moves horizontally) or paging (e.g., showing 2-3 options per page). The COG architecture also limits the number of backlight options—most use a single LED with a current draw of 20 mA, so you can control brightness via PWM on a transistor.
Menu Data Structures and Memory Management
When writing menu code, you need to store items in a way that fits the 128x32 COG LCD display’s limited buffer. The display buffer is 512 bytes (128x32 / 8 bits per byte), so you can pre-render menu screens as bitmaps or generate them on the fly. For a typical menu with 10 items, use a struct array: each item has a name (char array of 16 bytes), a function pointer (2 bytes), and a flags byte (e.g., for submenu or action). This totals 19 bytes per item, so 10 items use 190 bytes of RAM—critical on an Arduino Uno with 2 KB RAM. To save space, store strings in PROGMEM (flash memory) using
F() macro, which reduces RAM usage to 0 bytes for strings. For example, a menu item like “Temp” can be stored as
const char menu1[] PROGMEM = "Temp"; and accessed via
strcpy_P(buffer, menu1);. The display’s SPI communication uses a 3-wire interface (SCLK, MOSI, CS) plus a DC pin for data/command, and you must send commands like 0xAF (display on) and 0x40 (set start line) to initialize. The typical initialization sequence takes 10-15 commands, each 1 byte, and you can set contrast via command 0x81 followed by a value from 0x00 to 0xFF (default 0x7F). For menus, you’ll also need to handle button debouncing—use a 50 ms delay or a state machine to avoid false triggers.
Rendering Text and Graphics on 128x32
To render a menu on the 128x32 COG LCD display, you must choose a font that balances readability and information density. The Adafruit_GFX library includes a 5x7 font (5 pixels wide, 7 pixels tall) that fits 25 characters per line (128/5 = 25.6, but you lose 1 pixel per character for spacing, so 21 characters). With 32 pixels height, you get 4 lines (32/8 = 4), but you need at least 1 pixel line spacing, so 3 lines is practical. For a menu, use a 8x13 font (like the one in the U8g2 library) to get 16 characters per line and 2 lines (32/13 = 2.46, so 2 lines with 6 pixels spacing). This gives you a clear, bold look for option names. Alternatively, use custom bitmaps for icons—each icon is 16x16 pixels (256 bits = 32 bytes), and you can store 4 icons per page (128/16 = 8 icons horizontally, but you need spacing, so 6 icons per row). For a menu, combine text and icons: for example, a “Settings” icon (16x16) followed by “Set” text (3 characters). The rendering speed depends on the SPI clock: at 4 MHz, a full frame (512 bytes) takes 1.024 ms (512 bytes * 8 bits / 4 MHz = 1.024 ms), plus overhead for command setup, so total refresh is about 2-3 ms. This is fast enough for scrolling menus with 10 items per second.
Navigation Logic and User Input Handling
Creating a menu on a 128x32 COG LCD display requires a navigation system that works with the small screen. Use a state machine with states like MENU_MAIN, MENU_SUB, and MENU_ACTION. For input, common options are two buttons (up/down) or a rotary encoder with a push button. With two buttons, implement a simple loop: read button states, debounce with a 50 ms timer, then update a cursor index (e.g.,
currentItem) that wraps around the menu array. For a rotary encoder, use interrupts to count pulses and detect direction—each detent corresponds to one menu item. The display updates only when the cursor changes, using
display.clearDisplay() and
display.setCursor() to redraw the menu. For example, highlight the selected item by inverting pixels:
display.setTextColor(WHITE, BLACK) for normal, and
display.setTextColor(BLACK, WHITE) for selected. To save processing, pre-calculate the y-coordinate for each line: if you have 3 items per page, set y = 0, 11, 22 (with 11-pixel spacing). For longer menus (e.g., 20 items), implement paging: show 3 items per page, and use a page index. The total number of pages is
ceil(numItems / 3). When the user scrolls past the last item, advance to the next page. This approach uses minimal RAM—just a few bytes for the cursor and page index.
Performance Optimization and Data Tables
To optimize performance on the 128x32 COG LCD display, you can use a frame buffer that you modify in memory before sending to the display. The buffer is 512 bytes, so you can write to it using
display.drawPixel() or
display.drawBitmap() without SPI overhead. For menus, pre-render static elements (like title bar or icons) into the buffer once, then only update the text area. For example, if you have a fixed header “Menu:” at the top (y=0), you can draw it once and only redraw lines 2-4. This reduces SPI transactions by 25% (128 bytes for the header vs. 512 bytes for the full frame). You can also use hardware acceleration: many COG displays support vertical scrolling via command 0x40 (set display start line), which lets you scroll the entire display without redrawing—useful for a scrolling list. For data, here’s a table comparing font options:
| Font Type | Character Width | Characters per Line | Lines per Screen | RAM per Character |
|-----------|----------------|---------------------|------------------|-------------------|
| 5x7 | 5 pixels | 21 | 4 | 5 bytes |
| 8x13 | 8 pixels | 16 | 2 | 13 bytes |
| 12x16 | 12 pixels | 10 | 2 | 24 bytes |
| Custom | Variable | 6-12 | 1-3 | Depends on design |
The 5x7 font is best for dense menus (e.g., 4 options), while 8x13 is better for readability with 2 options. For a 128x32 COG LCD display, the 8x13 font gives a good balance: 16 characters per line, 2 lines, with 6 pixels padding between lines. This leaves 2 pixels at the top and bottom for a border or cursor.
Real-World Implementation Example
Consider a temperature monitor with a 128x32 COG LCD display. The menu has three items: “Temp”, “Humidity”, and “Settings”. Each item triggers a function to read a sensor. The code structure is:
typedef struct {
const char* name;
void (*action)();
} MenuItem;
MenuItem menu[] = {
{"Temp", readTemp},
{"Humidity", readHum},
{"Settings", configMenu}
};
The display shows one item at a time due to the 32-pixel height, using a 12x16 font (10 characters per line). The user presses a button to cycle through items. When selected, the action function clears the display and shows a value (e.g., “23.5 C”). The SPI communication sends 512 bytes per frame, taking 1.3 ms at 4 MHz (512 * 8 / 4e6 = 1.024 ms, plus command overhead). The total response time from button press to display update is under 10 ms, including debounce (50 ms) and rendering (2 ms). This is fast enough for human interaction. For a more complex menu with submenus, use a stack: push the current menu state onto a stack (e.g., 10 levels deep), and pop when the user backs out. Each level stores the current item index and page number, using 4 bytes per level (40 bytes total for 10 levels). This fits in the Arduino’s 2 KB RAM easily.
Power Management and Sleep Modes
The 128x32 COG LCD display can be put into sleep mode to save power, which is essential for battery-operated devices. Use command 0xAE to turn off the display, and 0xAF to turn it on. The sleep current is 0.1 mA, compared to 0.5 mA active. For menus, you can implement a timeout: if no button is pressed for 30 seconds, clear the display and enter sleep. When a button is pressed, wake up and reinitialize the display (send the init sequence again, which takes about 5 ms). This reduces average power consumption by 80% if the device is idle 90% of the time. You can also dim the display by reducing contrast via command 0x81 (set contrast) to a lower value like 0x20, which cuts power to the LED backlight by 50% (from 20 mA to 10 mA). For a menu, you can dim the display when idle and brighten it on button press—this is a common UX trick. The COG architecture also allows you to disable the internal charge pump (command 0xAD with 0x8B) to save 0.2 mA, but this reduces contrast, so only use it in low-light conditions.
Debugging and Testing the Menu System
When debugging a menu on a 128x32 COG LCD display, use a serial monitor to print the current menu state (e.g., “Item 2, Page 0”). This helps verify navigation logic without relying on the display. Test the display’s response to SPI commands: send a test pattern (e.g., all pixels on) to check for dead pixels or wiring issues. The typical failure mode is a blank screen due to incorrect initialization—check that the CS pin is asserted low and the DC pin is set correctly for data (high) vs. commands (low). Use an oscilloscope to measure SPI timing: the clock should be clean with no glitches, and the data lines should settle before the clock edge. For the menu, test edge cases: wrap-around at the last item, empty menu (0 items), and long strings that exceed the 21-character limit. The display will truncate text, so ensure your menu items are short. For example, “Temperature” is too long (11 characters) for a 5x7 font with 21 characters per line, but “Temp” (4 characters) fits. If you need longer names, use a scrolling text effect: shift the text left by 1 pixel every 100 ms, but this adds complexity and uses more CPU time (about 1 ms per frame for scrolling).