Those little OLED displays might just work:
The U8X8 driver produces those double-size bitmap characters; the default 8×8 matrix seem pretty much unreadable on a 0.96 inch OLED at any practical distance from a benchtop instrument. They might be workable on a 1.3 inch white OLED, minus the attractive yellow highlight for the frequency in the top line.
The OLED uses an SPI interface, although the U8X8 library clobbers my (simpleminded) SPI configuration for the AD9850 DDS and I’ve dummied out the DDS outputs. A soon-to-arrive I²C OLED should resolve that problem; changing the interface from SPI to I²C involves changing the single line of code constructing the driver object, so It Should Just Work.
The U8X8 driver writes directly to the display, thus eliminating the need for a backing buffer in the Arduino’s painfully limited RAM. I think the library hauls in all possible fonts to support font selection at runtime, even though I need at most two fonts, so it may be worthwhile to hack the unneeded ones from the library (or figure out if I misunderstand the situation and the Flash image includes only the fonts actually used). Each font occupies anywhere from 200 to 2000 bytes, which I’d rather have available for program code. Chopping out unused functions would certainly be less useful.
The display formatting is a crude hack just to see what the numbers look like:
int ln = 0; u8x8.draw2x2String(0,ln,Buffer); ln += 2; TestFreq.fx_64 = ScanTo.fx_64 - ScanFrom.fx_64; PrintFixedPtRounded(Buffer,TestFreq,1); u8x8.draw2x2String(0,ln,"W "); u8x8.draw2x2String(2*(8-strlen(Buffer)),ln,Buffer); ln += 2; PrintFixedPtRounded(Buffer,ScanStep,3); u8x8.draw2x2String(0,ln,"S "); u8x8.draw2x2String(2*(8-strlen(Buffer)),ln,Buffer); ln += 2; TestFreq.fx_32.high = SCAN_SETTLE; // milliseconds TestFreq.fx_32.low = 0; TestFreq.fx_64 /= KILO; // to seconds PrintFixedPtRounded(Buffer,TestFreq,3); u8x8.draw2x2String(0,ln,"T "); u8x8.draw2x2String(2*(8-strlen(Buffer)),ln,Buffer); ln += 2;
Updating the display produces a noticeable and annoying flicker, which isn’t too surprising, so each value should have an “update me” flag to avoid gratuitous writes. Abstracting the display formatting into a table-driven routine might be appropriate, when I need more than one layout, but sheesh.
I calculate the actual frequency from the 32 bit integer delta phase word written to the DDS, rather than use the achingly precise fixed point value, so a tidy 0.100 Hz frequency step doesn’t produce neat results. Instead, the displayed value will be within ±0.0291 Hz (the frequency resolution) of the desired frequency, which probably makes more sense for the very narrow bandwidths involved in a quartz crystal test gadget.
Computing the frequency step size makes heavy use of 64 bit integers:
// ScanStep.fx_64 = One.fx_64 / 4; // 0.25 Hz = 8 or 9 tuning register steps ScanStep.fx_64 = One.fx_64 / 10; // 0.1 Hz = 3 or 4 tuning register steps // ScanStep.fx_64 = One.fx_64 / 20; // 0.05 Hz = 2 or 3 tuning register steps // ScanStep = HzPerCt; // smallest possible frequency step
The fixed point numbers resulting from those divisions will be accurate to nine decimal places; good enough for what I need.
The sensible way of handling discrete scan width / step size / settling time options is through menus showing the allowed choices, with joystick / joyswitch navigation & selection, rather than keyboard entry. An analog joystick has the distinct advantage of using two analog inputs, not four digital pins, although the U8X8 driver includes a switch-driven menu handler.
There’s a definite need to log all the values through the serial output for data collection without hand transcription.
The Arduino source code as a GitHub Gist: