The problem
The instrument cluster is how a rider sees what the vehicle is doing. On a small display, information has to be laid out clearly, updated without flicker and prioritised so a fault is never hidden behind a speed reading. Entry-level EVs use simple segment or character displays, so good design on limited hardware matters.
Objectives
- Drive the 16×2 LCD efficiently in 4-bit mode with custom characters
- Show speed, SOC bar, drive mode and a fault indicator on one screen
- Read speed from the potentiometer, mode from the keypad and SOC from the cell voltage
- Show faults with priority over normal information and confirm them with the buzzer and LEDs
What you need
From the EV Embedded Development Kit
- STM32F103C8T6 microcontroller unit (main controller)
- 16×2 LCD with contrast control
- Analog potentiometer input
- 4×3 matrix keypad
- 1S battery with connector and T-sense input
- RGB LEDs and a buzzer
Software
- STM32CubeIDE with HAL drivers
- Embedded C
- Proteus (optional, for LCD simulation)
Extra parts
None. Everything this project needs is on the kit.
This project uses the kit's lithium cell. Respect polarity, never short the terminals, and don't leave the cell charging unattended.
Key concepts
- HD44780-style character LCD
- A controller that shows 2 lines of 16 characters and accepts up to eight user-defined 5×8 characters stored in its CGRAM.
- 4-bit mode
- Sending each byte as two nibbles over four data lines, saving GPIO pins at the cost of slightly longer writes.
- Custom bar graph
- Using custom characters with 1 to 5 filled columns to draw a smooth SOC bar with five steps per character cell.
- Display buffering
- Building the screen in a RAM buffer and writing only changed characters, which avoids flicker and saves time.
Step-by-step guide
- 1
Plan the layout
Sketch the 32 character cells. A typical layout puts speed in large digits on the left of line 1, the drive mode such as ECO, NORM or SPORT on the right, and an SOC bar with a percentage on line 2. Decide where the fault indicator goes and how a fault message takes over. List the update rates: speed 4–5 times a second, SOC once a second.
Checkpoint: A drawn layout for normal and fault screens agreed by the team.
- 2
Board setup
Enable the DIP switches for the LCD, potentiometer, keypad, LEDs, buzzer and battery blocks. In CubeMX set SYSCLK to 72 MHz, configure the LCD data and control pins as outputs, ADC1 on the potentiometer and cell voltage channels with DMA, keypad rows as outputs and columns as inputs with pull-ups, and a 10 ms timer tick. Adjust the LCD contrast until characters are clear.
Checkpoint: A test string appears on both lines of the LCD.
- 3
LCD driver
Write an LCD driver with initialisation for 4-bit mode, command and data writes, cursor positioning and CGRAM loading. Use a microsecond delay from a timer for the enable pulse and command timings in the datasheet. Add a RAM frame buffer of 32 characters and a refresh routine that writes only characters that changed. Keep the driver in its own source file with a small public interface so the cluster code never touches the LCD pins directly.
Checkpoint: A counter updating 10 times a second shows no flicker and the refresh routine's time is measured.
- 4
Custom characters
Design custom characters: five bar fills for the SOC bar, a battery outline, a warning triangle and a plug symbol. Since only eight can be loaded at once, choose them carefully. Load them at start-up and test each one. Draw each character on a 5×8 grid first, then convert the rows to bytes. Keep the battery and warning symbols simple, since fine detail is lost on a character LCD.
Checkpoint: All custom characters display correctly and the SOC bar can show any value smoothly.
- 5
Inputs: speed and mode
Map the averaged potentiometer reading to 0–80 km/h with a small dead zone at zero, and state that speed is emulated. Scan the keypad with debounce and map keys to drive modes. Show the mode change immediately. Filter the potentiometer reading with a short moving average so the speed digits do not flicker between two values. Remember the selected mode in flash so it is restored at power-up, as a real cluster does.
Checkpoint: Turning the potentiometer moves the speed smoothly and pressing mode keys changes the mode shown.
- 6
SOC from cell voltage
Read the cell voltage, calibrated against a multimeter using the divider ratio on the schematic. Convert to SOC with a simple voltage-to-SOC lookup table from the cell datasheet or a measured curve, and filter it so the bar does not jump when loads change. Note that voltage-based SOC is approximate under load. Cell safety: check polarity and never short the cell.
Checkpoint: The SOC bar reflects the cell's charge and changes slowly and smoothly.
- 7
Faults and priority
Define faults such as low SOC, high cell temperature and over-speed. When a fault is active, show the warning symbol, flash the fault message on line 2 and drive the red LED and buzzer. When several faults are active, show the most severe and cycle through the rest. Clear the indication when the fault clears. Keep the fault list in a table so new faults can be added easily.
Checkpoint: Triggering two faults together shows the more severe one first, then cycles through both.
- 8
Integration and timing
Combine everything in a simple scheduler driven by the 10 ms tick: keypad scan every 10 ms, inputs every 50 ms, display refresh every 200 ms and SOC every second. Measure loop timing with a GPIO and an oscilloscope or logic analyser if available, or with a timer count printed over UART. Make sure no task blocks: replace busy-wait delays in the LCD driver with short timed waits where possible.
Checkpoint: All tasks meet their periods and the display remains smooth under all inputs.
- 9
Testing and report
Write test cases for every screen state and fault. Ask a few people to read the display at a glance and note what they misread. Improve the layout and document the design, the driver and the results. Include photographs of each screen state, the custom character designs and a timing table, and explain any layout changes made after the readability test and why they helped.
Checkpoint: A test table and a short readability study are in the report.
Testing & validation
- Every screen and fault state shown correctly
- No visible flicker during fast speed changes
- SOC reading compared with a multimeter-based calculation
- Glance readability test with several users
Expected results
A working character-LCD cluster showing speed, SOC, drive mode and prioritised faults, with a reusable LCD driver and custom-character set.
Take it further
- Receive speed and SOC over CAN instead of local inputs
- Add an odometer and trip meter stored in flash
- Add an energy-flow indicator for regenerative braking
- Build a Hindi-language version with custom characters
Viva and review questions
Why write only changed characters?
LCD writes are slow, and clearing and rewriting the whole screen causes flicker. Updating only changed cells is faster and smoother.
How many custom characters can the LCD hold?
Eight at a time in CGRAM, so the set has to be chosen for each screen.
Why is the SOC from voltage approximate?
Under load the voltage sags because of internal resistance, so voltage-based SOC reads low while loaded; filtering and resting readings reduce the effect.