/* * HPLJvfd.ino * Test a HP LaserJet 4MPlus vacuum fluorescent display interface board * Arduino Uno/Nano sketch * Version: March 4, 2025 * Author: G. Forrest Cook, www.solorb.com/elect * Released under the GPL V3 license * Some code borrowed from LCDtest1.ino * * The board uses a Mitsubishi M66004SP IC to control the VF display, * a 74HC595 to control the 3 LEDs and a 74HC165 to input the 8 pushbuttons. * * All 3 interface ICs use the SPI SCK clock (D13), the M66004SP and HC595 * use the MOSI output (D11) for serial data in. * The HC165 Qh output goes to the MISO input (D12). * The HC165 serial Din connects to the HC595 Qh output for some reason.. * Pins on the display board: 1 and 2:Gnd, 8 and 9:+5V, 3:HC165 Serial Dout, * 4:HC595 Latch and HC165 !Load, 5:M66004 !Load, 6:Shared Clock, * 7:M66004 and HC595 Serial Din * Button values top L->R and bot L->R: 40,20,10,08, 80,02,04,01 * * The M66004SP uses (D9) as the !load line, the 74HC595 uses (D8) as the * positive output latch pin and the 74HC165 uses (D10) for the !parallel load * pin. Also, the '595 QH output connects to the '165 Din pin, not used here. * The character ROM's extra characters are European and misc stuff instead * of the Japanese Kanji chars shown in the data sheet. 0xB3 is degree char. * Custom RAM chars are at addresses 0x90 thru 0x9F. */ #include #define loadHCttl 8 // HC595 latch (pos) and HC165 load (neg) pin #define loadVFD 9 // M66004SP load data pin (neg) #define VFDCHARS 16 // number of characters on the VFD #define VFDCLOCK 250000 // VFD clock speed (Hz) #define TTLCLOCK 1000000 // HC TTL clock speed (Hz) #define VFDSETTLE 20 // VFD settling time after SPI transfer (uSec) #define LEDSOFF 0xE0 byte Ledouts[]={0xE0, 0xC0, 0xA0, 0x80, 0x60, 0x40, 0x20, 0x00}; char Scrollstr[VFDCHARS+1]; byte LEDstate=0; void setup() { byte i; SPI.begin(); // SPI initializes port B. pinMode (loadHCttl, OUTPUT); pinMode (loadVFD, OUTPUT); digitalWrite(loadHCttl, HIGH); digitalWrite(loadVFD, HIGH); vfdcontrol(0x07); // low 3 bits set display width (16 digits) vfdcontrol(0x0B); // brightness in low 3 bits (08-0F) vfdcontrol(0xF7); // last bit is 128/fosc or 256/fosc vfdcontrol(0xF4); // Auto increment off in last bit vfdcontrol(0xF3); // Display test: all digits full-on delay(250); vfdcontrol(0xF1); // Normal operation, display test off vfdcontrol(0xF8); // turn off both M66004SP output ports for (i=0; i<16; i++) vfdcontrol(0x80+i); // turn all cursor positions off spiInOut(LEDSOFF); // turn off the LEDs } void loop() { byte i; byte buttons; int count; vfdstring(0, "Hello World VFD!"); delay (1000); vfdclear(); vfdstring(0, "Scrolling String:"); delay (700); clearscrollstr(); scrollstring(250, "Testing one two three four five six."); delay (700); vfdstring(0, "Button: LED:"); for (i=0; i<8; i++) { buttons=spiInOut(Ledouts[i&0x07]); vfdhexbyte(7, buttons); vfdhexbyte(14, i); delay (700); } spiInOut(LEDSOFF); // turn off the LEDs vfdclear(); delay (700); vfdstring(0, "Cursor On:"); for (i=0; i<16; i++) { vfdcontrol(0x10+i); // cursor on + addr delay (60); } vfdstring(0, "Cursor Off:"); for (i=0; i<16; i++) { vfdcontrol(0x80+i); // cursor off + addr delay (60); } vfdclear(); delay (700); vfdstring(0, "Brightness:"); delay (200); for (i=0; i<8; i++) { vfdcontrol(i+8); // brightness in low 3 bits (08-0F) vfdhexbyte(12, i); delay (800); } vfdcontrol(0x0B); // brightness in low 3 bits (08-0F) vfdclear(); delay (700); vfdstring(0x00, "Integer:"); for (count=-110; count<111; count++) { vfdnum_clear(11, 4); // clear the digits and - sign vfdinteger(11, count); delay(50); } vfdclear(); delay (700); vfdstring(0, "Hex Byte:"); delay (200); for (i=0; i<31; i++) { vfdhexbyte(10, i); delay (100); } vfdclear(); delay (700); vfdstring(0, "Hex Word:"); vfdhexword(10, 0x1234); delay (1500); vfdclear(); delay (700); vfdstring(0, "Custom Char:"); // Make a smiley face vfdcontrol(0xFC); // Custom Char vfdcontrol(0x00); // Char Addr (- 0x90) vfdcontrol(0xC4); // Column 1, bits 7-1 vfdcontrol(0xC2); // Column 2 vfdcontrol(0x1A); // Column 3 vfdcontrol(0xC2); // Column 4 vfdcontrol(0xC4); // Column 5 vfdchar(0x0D, 0x90); delay (1500); vfdclear(); vfdstring(0, "Chars:"); // display one column of chars delay (200); for (i=0; i<16; i++) { vfdhexbyte(0x07, i+0xA0); vfdchar(0x0A, i+0xA0); delay (500); } vfdclear(); delay (700); } // Write an integer to the VFD with variable character width. // addr is for the right digit // this doesn't overwrite the higher digits, // call lcdnum_clear first to clear the previous digits. void vfdinteger(byte addr, int val) { if (val >= 0) // check for negative numbers vfdintegerdigs(addr, val, 0); else vfdintegerdigs(addr, 0-val, 1); } // recursively display integer digits void vfdintegerdigs(byte addr, int val, byte neg) { int dividend; vfdchar(addr, val%10 + '0'); dividend = val / 10; if (dividend > 0) vfdintegerdigs(addr-1, dividend, neg); // recurse else if (neg) // deal with the minus sign vfdchar(--addr, '-'); } // clear a specified number of counter digits (integer or hex) // starting with the right-most character and moving left void vfdnum_clear(byte addr, byte digits) { do { vfdchar(addr--, 0x20); digits--; } while (digits); } // Write a 4 digit hexadecimal value to the VFD. void vfdhexword(byte addr, unsigned int val) // addr is MSD position { vfdhexbyte(addr, (byte)(val>>8)); vfdhexbyte(addr+2, (byte)val); } // Write a 2 digit hexadecimal value to the VFD. void vfdhexbyte(byte addr, byte val) // addr is MSD position { byte nibble; nibble = val >> 4; if (nibble < 10) nibble += '0'; else nibble += '7'; vfdchar(addr, nibble); nibble = val & 0x0F; if (nibble < 10) nibble += '0'; else nibble += '7'; vfdchar(addr+1, nibble); } void vfdclear() // clear the VFD { byte i; for (i=0; i= VFDCHARS) break; } } // scroll a string across the VFD void scrollstring(int dtime, char *str) { while (*str) { scrollline (Scrollstr, *str++); // fill the line delay(dtime); } } // Scroll chars R->L on one line, output the line. void scrollline(char *scrollstr, char inchr) { byte i; for (i=0; i