So the MCU is an STC15W204S which is an 8051 compatible chip and I compiled everything with SDCC. There wasn't a good header file for it so I just wrote stc15.h myself, it just defines all the SFR addresses. No external libraries anywhere, every single part of the firmware is written from scratch.
The LCD is a standard HD44780 16x2 running in 4-bit mode and honestly getting that working was annoying because the data pins aren't on one port, they're split across P1 and P3 which means every single write has to manually pull out each bit and send it to the right pin. I wrote the whole driver myself. It's three functions, one for routing the bits, one for commands, one for character data. The display state lives in a buffer and gets flushed to the LCD every frame.
Timekeeping is done with Timer0 in 16-bit mode. The ISR just chains five software counters together, each one overflowing into the next, to build out a MM:SS timer. It starts the moment you pick an operation and stops after question 10. If it somehow hits 99 minutes it just shows OVER instead of the time.
The rotary encoder CLK goes straight to INT0 so every edge fires an interrupt. There's a short busy-loop at the top to debounce it and then DT gets sampled for direction. I also added a speed counter in the main loop so if you spin it fast the step size doubles, otherwise scrolling to big numbers takes forever.
Before any problem shows up the firmware checks the operand pair against the operation and throws out anything that would give a negative result, a non-integer, or something too big to display. New operands also get pre-generated right after each answer so there's no gap between questions.
Bohan Xu
Muth
Jorj Bauer
Stephen Holdaway
Actually you just need to add the additional SFRs the stc15 has which are not in the base set defined by <8052.h>. I did so for the I/O pin types, which are an improvement on the 8051 quasi-pullup pins.