625 lines
31 KiB
Arduino
625 lines
31 KiB
Arduino
// ============================================================================
|
||||
|
|
// VQC10 driver
|
|||
|
|
// ----------------------------------------------------------------------------
|
|||
|
|
// Drives 8x VQC10 tubes/modules, each a 5x7 dot-matrix (LED or VFD-style)
|
|||
|
|
// character display (see Datasheets/VQC10_Funkamateur.pdf and
|
|||
|
|
// "VQC10 timing.jpeg" for the original hardware reference - VQC10 is an
|
|||
|
|
// Eastern-European 5x7 dot-matrix indicator tube, not a classic 7-segment
|
|||
|
|
// Nixie/VFD tube). Because each character cell is a dot matrix rather than
|
|||
|
|
// a fixed set of segments, this driver renders full ASCII text (via the
|
|||
|
|
// bitmap _font[] table below) instead of just digits.
|
|||
|
|
//
|
|||
|
|
// Wiring / protocol: the 8 character cells are driven through a chain of
|
|||
|
|
// 74HC595 serial-in/parallel-out shift registers (latchPin=RCK/STCP,
|
|||
|
|
// clockPin=SCK/SHCP, dataPin=DIN/SER - classic 3-wire SPI-like shift-out,
|
|||
|
|
// no MISO). Unlike most other drivers in this project (which multiplex
|
|||
|
|
// digit-by-digit), the VQC10 hardware is scanned ROW-by-ROW: for every one
|
|||
|
|
// of the NUMROWS=7 dot-rows, the column data for all NUMDIGITS=8 characters
|
|||
|
|
// is shifted out and latched digit-by-digit, then a single row-select line
|
|||
|
|
// is pulsed on for a PWM-timed on-period before moving to the next row.
|
|||
|
|
// Refresh timing is fully cooperative/blocking (see writeDisplay2() below)
|
|||
|
|
// rather than driven from the hardware timer ISR - see the note above
|
|||
|
|
// writeDisplay() for why.
|
|||
|
|
//
|
|||
|
|
// Used by clocks.h configuration(s): CLOCK_71 ("2x VQC10 clock by UNFI").
|
|||
|
|
// ============================================================================
|
|||
|
|
#ifdef VQC10
|
|||
|
|
char tubeDriver[] = "VQC10";
|
|||
|
|
#define NUMDIGITS 8
|
|||
|
|
int maxDigits = NUMDIGITS;
|
|||
|
|
|
|||
|
|
//Please, set the pin numbers in clock.h!
|
|||
|
|
//#define latchPin 5 //D2 RCK
|
|||
|
|
//#define clockPin 4 //D1 SCK
|
|||
|
|
//#define dataPin 2 //D4 DIN
|
|||
|
|
//#define ledOffpin 0 //D5
|
|||
|
|
//#define D5pin 14
|
|||
|
|
|
|||
|
|
|
|||
|
|
#define NUMCOLS 5 // font glyph width in dots (columns per character cell)
|
|||
|
|
#define NUMROWS 7 // font glyph height in dots (rows per character cell) - also the number of physical row-select lines scanned in writeDisplay2()
|
|||
|
|
|
|||
|
|
boolean _upsidedown = false; // flips the dot-matrix rendering 180 degrees (for tubes mounted upside down); never set to true anywhere in this codebase - effectively dead/unused, kept for parity with wordclock.ino which shares this same font/transpose code
|
|||
|
|
byte row[NUMROWS]; // scratch buffer filled by show()/transposePattern(): one row-bitmap per dot-row for the character currently being rendered
|
|||
|
|
|
|||
|
|
// Maps the shared digit[]/newDigit[] buffer codes (see core file: 0-9=digit, 10=BLANK,
|
|||
|
|
// 11=minus, 12=decimal point, 13+=driver-specific extra glyphs) to an index into the
|
|||
|
|
// ASCII-ordered _font[] table below, i.e. this converts the generic "digit code" alphabet
|
|||
|
|
// used by the core firmware into actual character codes this driver can render.
|
|||
|
|
char asciiConvert[] = "0123456789 -.APC~%oIF";
|
|||
|
|
char DPchar = 0xFF; //decimal point - index of the dedicated 1-dot "decimal point" glyph appended at the very end of _font[] (see 0xFF entry below)
|
|||
|
|
|
|||
|
|
char cDigit[NUMDIGITS+1] = "76543210"; // NOTE: declared/initialized but never referenced anywhere else in this file or the project - dead code (candidate for removal)
|
|||
|
|
byte dat[NUMDIGITS][NUMROWS]; // final row-bitmaps actually shifted out to hardware (post-animation-blend result)
|
|||
|
|
byte oldDat[NUMDIGITS][NUMROWS]; // row-bitmaps for the outgoing (old) character, built fresh each writeDisplaySingle() call
|
|||
|
|
byte newDat[NUMDIGITS][NUMROWS]; // row-bitmaps for the incoming (new) character, built fresh each writeDisplaySingle() call
|
|||
|
|
|
|||
|
|
// standard ascii 5x7 font incl. the IBM-PC extension:
|
|||
|
|
// already defined in DotMatrx5x7.h
|
|||
|
|
// Format: NUMCOLS(5) bytes per glyph, indexed as glyph_code*NUMCOLS in show() above; each
|
|||
|
|
// byte is one column of the cell, with dot rows packed in its low NUMROWS(7) bits (bit0=row0
|
|||
|
|
// top .. bit6=row6 bottom in normal orientation). Glyph 0xFF at the very end of the table is
|
|||
|
|
// repurposed as a dedicated "decimal point" glyph (see DPchar above) rather than a real
|
|||
|
|
// character, so it only lights a single dot instead of a printable symbol.
|
|||
|
|
//#define aUML "\x84" // ä = 0x84
|
|||
|
|
//#define oUML "\x94" // ö = 0x94
|
|||
|
|
//#define uUML "\x81" // ü = 0x81
|
|||
|
|
//#define sZET "\xE1" // ß = 0xE1
|
|||
|
|
//#define AUML "\x8E" // Ä = 0x8E
|
|||
|
|
//#define OUML "\x99" // Ö = 0x99
|
|||
|
|
//#define UUML "\x9A" // Ü = 0x9A
|
|||
|
|
|
|||
|
|
byte _font[] = {
|
|||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, // 0x00 empty
|
|||
|
|
0x3E, 0x5B, 0x4F, 0x5B, 0x3E, // 0x01 sad
|
|||
|
|
0x3E, 0x6B, 0x4F, 0x6B, 0x3E, // 0x02 happy
|
|||
|
|
0x1C, 0x3E, 0x7C, 0x3E, 0x1C, // 0x03 heart
|
|||
|
|
0x18, 0x3C, 0x7E, 0x3C, 0x18, // 0x04 diamond
|
|||
|
|
0x1C, 0x57, 0x7D, 0x57, 0x1C, // 0x05 clover
|
|||
|
|
0x1C, 0x5E, 0x7F, 0x5E, 0x1C, // 0x06 spade
|
|||
|
|
0x00, 0x18, 0x3C, 0x18, 0x00, // 0x07 small full circle
|
|||
|
|
0xFF, 0xE7, 0xC3, 0xE7, 0xFF, // 0x08 inverted small circle
|
|||
|
|
0x06, 0x09, 0x06, 0x00, 0x00, // 0x09 small empty circle //old: 0x00, 0x18, 0x24, 0x18, 0x00, // 0x09 small empty circle
|
|||
|
|
0xFF, 0xE7, 0xDB, 0xE7, 0xFF, // 0x0A block (linefeed)
|
|||
|
|
0x30, 0x48, 0x3A, 0x06, 0x0E, // 0x0B male
|
|||
|
|
0x26, 0x29, 0x79, 0x29, 0x26, // 0x0C female
|
|||
|
|
0x40, 0x7F, 0x05, 0x05, 0x07, // 0x0D note (carriage return)
|
|||
|
|
0x40, 0x7F, 0x05, 0x25, 0x3F, // 0x0E two notes
|
|||
|
|
0x5A, 0x3C, 0xE7, 0x3C, 0x5A, // 0x0F sun
|
|||
|
|
0x7F, 0x3E, 0x1C, 0x1C, 0x08, // 0x10 right triangle
|
|||
|
|
0x08, 0x1C, 0x1C, 0x3E, 0x7F, // 0x11 left triangle
|
|||
|
|
0x14, 0x22, 0x7F, 0x22, 0x14, // 0x12 up/down arrow
|
|||
|
|
0x5F, 0x5F, 0x00, 0x5F, 0x5F, // 0x13 double exclamation mark
|
|||
|
|
0x06, 0x09, 0x7F, 0x01, 0x7F, // 0x14 paragraph end sign (pilcrow)
|
|||
|
|
// 0x00, 0x66, 0x89, 0x95, 0x6A, // 0x15 paragraph sign original
|
|||
|
|
0x00, 0x26, 0x49, 0x55, 0x28, // 0x15 paragraph sign
|
|||
|
|
0x60, 0x60, 0x60, 0x60, 0x60, // 0x16 double underline
|
|||
|
|
0x54, 0x62, 0x7F, 0x62, 0x54, // 0x17 up/down arrow with underline
|
|||
|
|
0x08, 0x04, 0x7E, 0x04, 0x08, // 0x18 up arrow
|
|||
|
|
0x10, 0x20, 0x7E, 0x20, 0x10, // 0x19 down arrow
|
|||
|
|
0x08, 0x08, 0x2A, 0x1C, 0x08, // 0x1A right arrow
|
|||
|
|
0x08, 0x1C, 0x2A, 0x08, 0x08, // 0x1B left arrow
|
|||
|
|
0x14, 0x3E, 0x55, 0x41, 0x22, // 0x1C euro
|
|||
|
|
0x63, 0x75, 0x69, 0x75, 0x63, // 0x1D timer
|
|||
|
|
0x30, 0x38, 0x3E, 0x38, 0x30, // 0x1E up triangle
|
|||
|
|
0x06, 0x0E, 0x3E, 0x0E, 0x06, // 0x1F down triangle
|
|||
|
|
0x00, 0x00, 0x00, 0x00, 0x00, // 0x20 space
|
|||
|
|
0x00, 0x00, 0x5F, 0x00, 0x00, // 0x21 !
|
|||
|
|
0x00, 0x07, 0x00, 0x07, 0x00, // 0x22 "
|
|||
|
|
0x14, 0x7F, 0x14, 0x7F, 0x14, // 0x23 #
|
|||
|
|
0x24, 0x2A, 0x7F, 0x2A, 0x12, // 0x24 $
|
|||
|
|
0x23, 0x13, 0x08, 0x64, 0x62, // 0x25 %
|
|||
|
|
0x36, 0x49, 0x56, 0x20, 0x50, // 0x26 &
|
|||
|
|
0x00, 0x08, 0x07, 0x03, 0x00, // 0x27 ´
|
|||
|
|
0x00, 0x1C, 0x22, 0x41, 0x00, // 0x28 (
|
|||
|
|
0x00, 0x41, 0x22, 0x1C, 0x00, // 0x29 )
|
|||
|
|
0x2A, 0x1C, 0x7F, 0x1C, 0x2A, // 0x2A *
|
|||
|
|
0x08, 0x08, 0x3E, 0x08, 0x08, // 0x2B +
|
|||
|
|
0x00, 0x80, 0x70, 0x30, 0x00, // 0x2C ,
|
|||
|
|
0x08, 0x08, 0x08, 0x08, 0x08, // 0x2D -
|
|||
|
|
0x00, 0x00, 0x60, 0x60, 0x00, // 0x2E .
|
|||
|
|
0x20, 0x10, 0x08, 0x04, 0x02, // 0x2F /
|
|||
|
|
0x3E, 0x51, 0x49, 0x45, 0x3E, // 0x30 0
|
|||
|
|
0x00, 0x42, 0x7F, 0x40, 0x00, // 0x31 1
|
|||
|
|
0x72, 0x49, 0x49, 0x49, 0x46, // 0x32 2
|
|||
|
|
0x21, 0x41, 0x49, 0x4D, 0x33, // 0x33 3
|
|||
|
|
0x18, 0x14, 0x12, 0x7F, 0x10, // 0x34 4
|
|||
|
|
0x27, 0x45, 0x45, 0x45, 0x39, // 0x35 5
|
|||
|
|
0x3C, 0x4A, 0x49, 0x49, 0x31, // 0x36 6
|
|||
|
|
0x41, 0x21, 0x11, 0x09, 0x07, // 0x37 7
|
|||
|
|
0x36, 0x49, 0x49, 0x49, 0x36, // 0x38 8
|
|||
|
|
0x46, 0x49, 0x49, 0x29, 0x1E, // 0x39 9
|
|||
|
|
0x00, 0x00, 0x14, 0x00, 0x00, // 0x3A :
|
|||
|
|
0x00, 0x40, 0x34, 0x00, 0x00, // 0x3B ;
|
|||
|
|
0x00, 0x08, 0x14, 0x22, 0x41, // 0x3C <
|
|||
|
|
0x14, 0x14, 0x14, 0x14, 0x14, // 0x3D =
|
|||
|
|
0x00, 0x41, 0x22, 0x14, 0x08, // 0x3E >
|
|||
|
|
0x02, 0x01, 0x59, 0x09, 0x06, // 0x3F ?
|
|||
|
|
0x3E, 0x41, 0x5D, 0x59, 0x4E, // 0x40 @
|
|||
|
|
0x7C, 0x12, 0x11, 0x12, 0x7C, // 0x41 A
|
|||
|
|
0x7F, 0x49, 0x49, 0x49, 0x36, // 0x42 B
|
|||
|
|
0x3E, 0x41, 0x41, 0x41, 0x22, // 0x43 C
|
|||
|
|
0x7F, 0x41, 0x41, 0x41, 0x3E, // 0x44 D
|
|||
|
|
0x7F, 0x49, 0x49, 0x49, 0x41, // 0x45 E
|
|||
|
|
0x7F, 0x09, 0x09, 0x09, 0x01, // 0x46 F
|
|||
|
|
0x3E, 0x41, 0x41, 0x51, 0x73, // 0x47 G
|
|||
|
|
0x7F, 0x08, 0x08, 0x08, 0x7F, // 0x48 H
|
|||
|
|
0x00, 0x41, 0x7F, 0x41, 0x00, // 0x49 I
|
|||
|
|
0x20, 0x40, 0x41, 0x3F, 0x01, // 0x4A J
|
|||
|
|
0x7F, 0x08, 0x14, 0x22, 0x41, // 0x4B K
|
|||
|
|
0x7F, 0x40, 0x40, 0x40, 0x40, // 0x4C L
|
|||
|
|
0x7F, 0x02, 0x1C, 0x02, 0x7F, // 0x4D M
|
|||
|
|
0x7F, 0x04, 0x08, 0x10, 0x7F, // 0x4E N
|
|||
|
|
0x3E, 0x41, 0x41, 0x41, 0x3E, // 0x4F O
|
|||
|
|
0x7F, 0x09, 0x09, 0x09, 0x06, // 0x50 P
|
|||
|
|
0x3E, 0x41, 0x51, 0x21, 0x5E, // 0x51 Q
|
|||
|
|
0x7F, 0x09, 0x19, 0x29, 0x46, // 0x52 R
|
|||
|
|
0x26, 0x49, 0x49, 0x49, 0x32, // 0x53 S
|
|||
|
|
0x03, 0x01, 0x7F, 0x01, 0x03, // 0x54 T
|
|||
|
|
0x3F, 0x40, 0x40, 0x40, 0x3F, // 0x55 U
|
|||
|
|
0x1F, 0x20, 0x40, 0x20, 0x1F, // 0x56 V
|
|||
|
|
0x3F, 0x40, 0x38, 0x40, 0x3F, // 0x57 W
|
|||
|
|
0x63, 0x14, 0x08, 0x14, 0x63, // 0x58 X
|
|||
|
|
0x03, 0x04, 0x78, 0x04, 0x03, // 0x59 Y
|
|||
|
|
0x61, 0x59, 0x49, 0x4D, 0x43, // 0x5A Z
|
|||
|
|
0x00, 0x7F, 0x41, 0x41, 0x41, // 0x5B [
|
|||
|
|
0x02, 0x04, 0x08, 0x10, 0x20, // 0x5C '\'
|
|||
|
|
0x00, 0x41, 0x41, 0x41, 0x7F, // 0x5D ]
|
|||
|
|
0x04, 0x02, 0x01, 0x02, 0x04, // 0x5E ^
|
|||
|
|
0x40, 0x40, 0x40, 0x40, 0x40, // 0x5F _
|
|||
|
|
0x00, 0x03, 0x07, 0x08, 0x00, // 0x60 `
|
|||
|
|
0x20, 0x54, 0x54, 0x78, 0x40, // 0x61 a
|
|||
|
|
0x7F, 0x28, 0x44, 0x44, 0x38, // 0x62 b
|
|||
|
|
0x38, 0x44, 0x44, 0x44, 0x00, // 0x63 c
|
|||
|
|
0x38, 0x44, 0x44, 0x28, 0x7F, // 0x64 d
|
|||
|
|
0x38, 0x54, 0x54, 0x54, 0x18, // 0x65 e
|
|||
|
|
0x00, 0x08, 0x7E, 0x09, 0x02, // 0x66 f
|
|||
|
|
// 0x18, 0xA4, 0xA4, 0x9C, 0x78, // 0x67 g (old)
|
|||
|
|
0x0C, 0x52, 0x52, 0x4E, 0x3C, // 0x67 g
|
|||
|
|
0x7F, 0x08, 0x04, 0x04, 0x78, // 0x68 h
|
|||
|
|
0x00, 0x44, 0x7D, 0x40, 0x00, // 0x69 i
|
|||
|
|
0x20, 0x40, 0x40, 0x3D, 0x00, // 0x6A j
|
|||
|
|
0x7F, 0x10, 0x28, 0x44, 0x00, // 0x6B k
|
|||
|
|
0x00, 0x41, 0x7F, 0x40, 0x00, // 0x6C l
|
|||
|
|
0x7C, 0x04, 0x78, 0x04, 0x78, // 0x6D m
|
|||
|
|
0x7C, 0x08, 0x04, 0x04, 0x78, // 0x6E n
|
|||
|
|
0x38, 0x44, 0x44, 0x44, 0x38, // 0x6F o
|
|||
|
|
0xFC, 0x18, 0x24, 0x24, 0x18, // 0x70 p
|
|||
|
|
// 0x18, 0x24, 0x24, 0x18, 0xFC, // 0x71 q (old)
|
|||
|
|
0x0C, 0x12, 0x12, 0x0C, 0x7E, // 0x71 q
|
|||
|
|
0x7C, 0x08, 0x04, 0x04, 0x08, // 0x72 r
|
|||
|
|
0x48, 0x54, 0x54, 0x54, 0x24, // 0x73 s
|
|||
|
|
0x04, 0x04, 0x3F, 0x44, 0x24, // 0x74 t
|
|||
|
|
0x3C, 0x40, 0x40, 0x20, 0x7C, // 0x75 u
|
|||
|
|
0x1C, 0x20, 0x40, 0x20, 0x1C, // 0x76 v
|
|||
|
|
0x3C, 0x40, 0x30, 0x40, 0x3C, // 0x77 w
|
|||
|
|
0x44, 0x28, 0x10, 0x28, 0x44, // 0x78 x
|
|||
|
|
0x0C, 0x10, 0x10, 0x50, 0x3C, // 0x79 y
|
|||
|
|
0x44, 0x64, 0x54, 0x4C, 0x44, // 0x7A z
|
|||
|
|
0x00, 0x08, 0x36, 0x41, 0x00, // 0x7B {
|
|||
|
|
0x00, 0x00, 0x7F, 0x00, 0x00, // 0x7C |
|
|||
|
|
0x00, 0x41, 0x36, 0x08, 0x00, // 0x7D }
|
|||
|
|
0x02, 0x01, 0x02, 0x04, 0x02, // 0x7E ~
|
|||
|
|
0x3C, 0x26, 0x23, 0x26, 0x3C, // 0x7F house
|
|||
|
|
0x1E, 0xA1, 0xA1, 0x61, 0x12, // 0x81
|
|||
|
|
0x3A, 0x40, 0x40, 0x20, 0x7A, // 0x81 ü
|
|||
|
|
0x38, 0x54, 0x54, 0x55, 0x59, // 0x82
|
|||
|
|
0x21, 0x55, 0x55, 0x79, 0x41, // 0x83
|
|||
|
|
0x21, 0x54, 0x54, 0x78, 0x41, // 0x84 ä
|
|||
|
|
0x21, 0x55, 0x54, 0x78, 0x40, // 0x85
|
|||
|
|
0x20, 0x54, 0x55, 0x79, 0x40, // 0x86
|
|||
|
|
0x0C, 0x1E, 0x52, 0x72, 0x12, // 0x87
|
|||
|
|
0x39, 0x55, 0x55, 0x55, 0x59, // 0x88
|
|||
|
|
0x39, 0x54, 0x54, 0x54, 0x59, // 0x89
|
|||
|
|
0x39, 0x55, 0x54, 0x54, 0x58, // 0x8A
|
|||
|
|
0x00, 0x00, 0x45, 0x7C, 0x41, // 0x8B
|
|||
|
|
0x00, 0x02, 0x45, 0x7D, 0x42, // 0x8C
|
|||
|
|
0x00, 0x01, 0x45, 0x7C, 0x40, // 0x8D
|
|||
|
|
0xF0, 0x29, 0x24, 0x29, 0xF0, // 0x8E Ä
|
|||
|
|
0xF0, 0x28, 0x25, 0x28, 0xF0, // 0x8F
|
|||
|
|
0x7C, 0x54, 0x55, 0x45, 0x00, // 0x90
|
|||
|
|
0x20, 0x54, 0x54, 0x7C, 0x54, // 0x91
|
|||
|
|
0x7C, 0x0A, 0x09, 0x7F, 0x49, // 0x92
|
|||
|
|
0x32, 0x49, 0x49, 0x49, 0x32, // 0x93
|
|||
|
|
0x32, 0x48, 0x48, 0x48, 0x32, // 0x94 ö
|
|||
|
|
0x32, 0x4A, 0x48, 0x48, 0x30, // 0x95
|
|||
|
|
0x3A, 0x41, 0x41, 0x21, 0x7A, // 0x96
|
|||
|
|
0x3A, 0x42, 0x40, 0x20, 0x78, // 0x97
|
|||
|
|
0x00, 0x9D, 0xA0, 0xA0, 0x7D, // 0x98
|
|||
|
|
//0x39, 0x44, 0x44, 0x44, 0x39, // 0x99 Ö (old)
|
|||
|
|
0x3D, 0x42, 0x42, 0x42, 0x3D, // 0x99 Ö
|
|||
|
|
0x3D, 0x40, 0x40, 0x40, 0x3D, // 0x9A Ü
|
|||
|
|
0x3C, 0x24, 0xFF, 0x24, 0x24, // 0x9B cent
|
|||
|
|
0x48, 0x7E, 0x49, 0x43, 0x66, // 0x9C pound
|
|||
|
|
0x2B, 0x2F, 0xFC, 0x2F, 0x2B, // 0x9D
|
|||
|
|
0xFF, 0x09, 0x29, 0xF6, 0x20, // 0x9E
|
|||
|
|
0xC0, 0x88, 0x7E, 0x09, 0x03, // 0x9F
|
|||
|
|
0x20, 0x54, 0x54, 0x79, 0x41, // 0xA0
|
|||
|
|
0x00, 0x00, 0x44, 0x7D, 0x41, // 0xA1
|
|||
|
|
0x30, 0x48, 0x48, 0x4A, 0x32, // 0xA2
|
|||
|
|
0x38, 0x40, 0x40, 0x22, 0x7A, // 0xA3
|
|||
|
|
0x00, 0x7A, 0x0A, 0x0A, 0x72, // 0xA4
|
|||
|
|
0x7D, 0x0D, 0x19, 0x31, 0x7D, // 0xA5
|
|||
|
|
0x26, 0x29, 0x29, 0x2F, 0x28, // 0xA6
|
|||
|
|
0x26, 0x29, 0x29, 0x29, 0x26, // 0xA7
|
|||
|
|
0x30, 0x48, 0x4D, 0x40, 0x20, // 0xA8
|
|||
|
|
0x38, 0x08, 0x08, 0x08, 0x08, // 0xA9
|
|||
|
|
0x08, 0x08, 0x08, 0x08, 0x38, // 0xAA
|
|||
|
|
0x2F, 0x10, 0xC8, 0xAC, 0xBA, // 0xAB
|
|||
|
|
0x2F, 0x10, 0x28, 0x34, 0xFA, // 0xAC
|
|||
|
|
0x00, 0x00, 0x7B, 0x00, 0x00, // 0xAD exclamation mark upside down
|
|||
|
|
0x08, 0x14, 0x2A, 0x14, 0x22, // 0xAE less less
|
|||
|
|
0x22, 0x14, 0x2A, 0x14, 0x08, // 0xAF greater greater
|
|||
|
|
0xAA, 0x00, 0x55, 0x00, 0xAA, // 0xB0
|
|||
|
|
0xAA, 0x55, 0xAA, 0x55, 0xAA, // 0xB1
|
|||
|
|
0xAA, 0x55, 0xAA, 0x55, 0xAA, // 0xB2
|
|||
|
|
0x00, 0x00, 0x00, 0xFF, 0x00, // 0xB3
|
|||
|
|
0x10, 0x10, 0x10, 0xFF, 0x00, // 0xB4
|
|||
|
|
0x14, 0x14, 0x14, 0xFF, 0x00, // 0xB5
|
|||
|
|
0x10, 0x10, 0xFF, 0x00, 0xFF, // 0xB6
|
|||
|
|
0x10, 0x10, 0xF0, 0x10, 0xF0, // 0xB7
|
|||
|
|
0x14, 0x14, 0x14, 0xFC, 0x00, // 0xB8
|
|||
|
|
0x14, 0x14, 0xF7, 0x00, 0xFF, // 0xB9
|
|||
|
|
0x00, 0x00, 0xFF, 0x00, 0xFF, // 0xBA
|
|||
|
|
0x14, 0x14, 0xF4, 0x04, 0xFC, // 0xBB
|
|||
|
|
0x14, 0x14, 0x17, 0x10, 0x1F, // 0xBC
|
|||
|
|
0x10, 0x10, 0x1F, 0x10, 0x1F, // 0xBD
|
|||
|
|
0x14, 0x14, 0x14, 0x1F, 0x00, // 0xBE
|
|||
|
|
0x10, 0x10, 0x10, 0xF0, 0x00, // 0xBF
|
|||
|
|
0x00, 0x00, 0x00, 0x1F, 0x10, // 0xC0
|
|||
|
|
0x10, 0x10, 0x10, 0x1F, 0x10, // 0xC1
|
|||
|
|
0x10, 0x10, 0x10, 0xF0, 0x10, // 0xC2
|
|||
|
|
0x00, 0x00, 0x00, 0xFF, 0x10, // 0xC3
|
|||
|
|
0x10, 0x10, 0x10, 0x10, 0x10, // 0xC4
|
|||
|
|
0x10, 0x10, 0x10, 0xFF, 0x10, // 0xC5
|
|||
|
|
0x00, 0x00, 0x00, 0xFF, 0x14, // 0xC6
|
|||
|
|
0x00, 0x00, 0xFF, 0x00, 0xFF, // 0xC7
|
|||
|
|
0x00, 0x00, 0x1F, 0x10, 0x17, // 0xC8
|
|||
|
|
0x00, 0x00, 0xFC, 0x04, 0xF4, // 0xC9
|
|||
|
|
0x14, 0x14, 0x17, 0x10, 0x17, // 0xCA
|
|||
|
|
0x14, 0x14, 0xF4, 0x04, 0xF4, // 0xCB
|
|||
|
|
0x00, 0x00, 0xFF, 0x00, 0xF7, // 0xCC
|
|||
|
|
0x14, 0x14, 0x14, 0x14, 0x14, // 0xCD
|
|||
|
|
0x14, 0x14, 0xF7, 0x00, 0xF7, // 0xCE
|
|||
|
|
0x14, 0x14, 0x14, 0x17, 0x14, // 0xCF
|
|||
|
|
0x10, 0x10, 0x1F, 0x10, 0x1F, // 0xD0
|
|||
|
|
0x14, 0x14, 0x14, 0xF4, 0x14, // 0xD1
|
|||
|
|
0x10, 0x10, 0xF0, 0x10, 0xF0, // 0xD2
|
|||
|
|
0x00, 0x00, 0x1F, 0x10, 0x1F, // 0xD3
|
|||
|
|
0x00, 0x00, 0x00, 0x1F, 0x14, // 0xD4
|
|||
|
|
0x00, 0x00, 0x00, 0xFC, 0x14, // 0xD5
|
|||
|
|
0x00, 0x00, 0xF0, 0x10, 0xF0, // 0xD6
|
|||
|
|
0x10, 0x10, 0xFF, 0x10, 0xFF, // 0xD7
|
|||
|
|
0x14, 0x14, 0x14, 0xFF, 0x14, // 0xD8
|
|||
|
|
0x10, 0x10, 0x10, 0x1F, 0x00, // 0xD9
|
|||
|
|
0x00, 0x00, 0x00, 0xF0, 0x10, // 0xDA
|
|||
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0xDB
|
|||
|
|
0xF0, 0xF0, 0xF0, 0xF0, 0xF0, // 0xDC
|
|||
|
|
0xFF, 0xFF, 0xFF, 0x00, 0x00, // 0xDD
|
|||
|
|
0x00, 0x00, 0x00, 0xFF, 0xFF, // 0xDE
|
|||
|
|
0x0F, 0x0F, 0x0F, 0x0F, 0x0F, // 0xDF
|
|||
|
|
0x38, 0x44, 0x44, 0x38, 0x44, // 0xE0 alpha
|
|||
|
|
0x7C, 0x2A, 0x2A, 0x3E, 0x14, // 0xE1 beta / ß
|
|||
|
|
0x7E, 0x02, 0x02, 0x06, 0x06, // 0xE2 Gamma
|
|||
|
|
0x02, 0x7E, 0x02, 0x7E, 0x02, // 0xE3 Pi
|
|||
|
|
0x63, 0x55, 0x49, 0x41, 0x63, // 0xE4 Sigma
|
|||
|
|
0x38, 0x44, 0x44, 0x3C, 0x04, // 0xE5 sigma
|
|||
|
|
0x40, 0x7E, 0x20, 0x1E, 0x20, // 0xE6 mu
|
|||
|
|
0x06, 0x02, 0x7E, 0x02, 0x02, // 0xE7 tau
|
|||
|
|
0x99, 0xA5, 0xE7, 0xA5, 0x99, // 0xE8 Phi
|
|||
|
|
0x1C, 0x2A, 0x49, 0x2A, 0x1C, // 0xE9 theta
|
|||
|
|
0x4C, 0x72, 0x01, 0x72, 0x4C, // 0xEA Omega
|
|||
|
|
0x30, 0x4A, 0x4D, 0x4D, 0x30, // 0xEB delta
|
|||
|
|
0x30, 0x48, 0x78, 0x48, 0x30, // 0xEC phi?
|
|||
|
|
0xBC, 0x62, 0x5A, 0x46, 0x3D, // 0xED empty set
|
|||
|
|
0x3E, 0x49, 0x49, 0x49, 0x00, // 0xEE epsilon
|
|||
|
|
0x7E, 0x01, 0x01, 0x01, 0x7E, // 0xEF
|
|||
|
|
0x2A, 0x2A, 0x2A, 0x2A, 0x2A, // 0xF0 equivalence
|
|||
|
|
0x44, 0x44, 0x5F, 0x44, 0x44, // 0xF1 plus minus
|
|||
|
|
0x40, 0x51, 0x4A, 0x44, 0x40, // 0xF2 greater or equal
|
|||
|
|
0x40, 0x44, 0x4A, 0x51, 0x40, // 0xF3 less or equal
|
|||
|
|
0x00, 0x00, 0xFF, 0x01, 0x03, // 0xF4
|
|||
|
|
0xE0, 0x80, 0xFF, 0x00, 0x00, // 0xF5
|
|||
|
|
0x08, 0x08, 0x6B, 0x6B, 0x08, // 0xF6 divided by
|
|||
|
|
0x36, 0x12, 0x36, 0x24, 0x36, // 0xF7 approx
|
|||
|
|
0x06, 0x0F, 0x09, 0x0F, 0x06, // 0xF8 degree
|
|||
|
|
0x00, 0x00, 0x18, 0x18, 0x00, // 0xF9 big dot
|
|||
|
|
0x00, 0x00, 0x10, 0x10, 0x00, // 0xFA small dot
|
|||
|
|
0x30, 0x40, 0xFF, 0x01, 0x01, // 0xFB square root
|
|||
|
|
0x00, 0x1F, 0x01, 0x01, 0x1E, // 0xFC
|
|||
|
|
0x00, 0x19, 0x1D, 0x17, 0x12, // 0xFD power of two
|
|||
|
|
0x00, 0x3C, 0x3C, 0x3C, 0x3C, // 0xFE blob
|
|||
|
|
//0x00, 0x00, 0x00, 0x60, 0x60, // 0xFF: Decimal point: 4 points
|
|||
|
|
0x00, 0x00, 0x00, 0x00, 0x40, // 0xFF: Decimal point, only 1 point
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
void setup_pins() {
|
|||
|
|
DPRINTLN("VQC10 Clock - setup 74HC595 pins");
|
|||
|
|
pinMode(latchPin, OUTPUT); regPin(latchPin,"latchPin");
|
|||
|
|
pinMode(dataPin,OUTPUT); regPin(dataPin,"dataPin");
|
|||
|
|
pinMode(clockPin,OUTPUT); regPin(clockPin,"clockPin");
|
|||
|
|
pinMode(D5pin,INPUT); regPin(D5pin,"D5pin"); // NOTE: configured and registered but never read anywhere in this driver or the core file - purpose (spare sensor/button input?) is undocumented, see open questions
|
|||
|
|
digitsOnly = false; // this driver can render full ASCII text (dot-matrix font), not just 0-9, so let the core firmware know
|
|||
|
|
asciiConvert[16] = 9; // runtime override: digit-buffer code 16 (originally mapped to '~' above) is remapped to raw font index 9 ("small empty circle" glyph, see _font table) for a driver-specific extra symbol
|
|||
|
|
// Deliberately does NOT call startTimer() here (unlike most other drivers): the hardware
|
|||
|
|
// timer ISR (writeDisplay(), see below) is intentionally a no-op for VQC10, and indeed
|
|||
|
|
// startTimer() is never invoked anywhere for this driver in the whole project. All actual
|
|||
|
|
// refresh work happens cooperatively via writeDisplay2(), called repeatedly from loop()/
|
|||
|
|
// Fdelay() in the core file - see the comment above writeDisplay() for why.
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void inline shiftOutForward(byte myDataOut) {
|
|||
|
|
// This shifts 8 bits out MSB first, on the rising edge of the clock, clock idles low
|
|||
|
|
// Used for the "digit select" (Z) and "row select" shift-register bytes, whose bit
|
|||
|
|
// order must match how those select lines are physically wired to the 74HC595 outputs.
|
|||
|
|
for (int i=7; i>=0; i--) {
|
|||
|
|
digitalWrite(clockPin, 0);
|
|||
|
|
digitalWrite(dataPin, myDataOut & (1<<i)); //register shifts bits on upstroke of clock pin
|
|||
|
|
digitalWrite(clockPin, 1);
|
|||
|
|
digitalWrite(dataPin, 0);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void inline shiftOutReverse(byte myDataOut) {
|
|||
|
|
// This shifts 8 bits out LSB first, on the rising edge of the clock, clock idles low
|
|||
|
|
// Used for the pixel/column DATA byte only - the opposite bit order from
|
|||
|
|
// shiftOutForward() is required here because the data byte travels through the same
|
|||
|
|
// shift-register chain but ends up latched onto a different (mirrored) set of output
|
|||
|
|
// pins than the select bytes; using the wrong helper here would mirror the glyph.
|
|||
|
|
for (int i=0; i<8; i++) {
|
|||
|
|
digitalWrite(clockPin, 0);
|
|||
|
|
digitalWrite(dataPin, myDataOut & (1<<i)); //register shifts bits on upstroke of clock pin
|
|||
|
|
digitalWrite(clockPin, 1);
|
|||
|
|
digitalWrite(dataPin, 0);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
#define PWMrefresh 8000l // NOTE: defined but not referenced anywhere in this file - dead macro (leftover from an earlier PWM implementation?)
|
|||
|
|
|
|||
|
|
// Required interface stub only: the hardware timer ISR that drives every other driver's
|
|||
|
|
// multiplex refresh is intentionally left EMPTY for VQC10. The real refresh (writeDisplay2()
|
|||
|
|
// below) needs delayMicroseconds() calls per row for PWM brightness dimming, which is far too
|
|||
|
|
// slow/blocking to run safely inside a timer ISR context. Instead, writeDisplay2() is called
|
|||
|
|
// cooperatively from the main loop() and from Fdelay() in the core file. Consistent with this,
|
|||
|
|
// setup_pins() above never calls startTimer(), so this ISR is in fact never even attached for
|
|||
|
|
// this driver - it exists purely to satisfy the common driver interface (extern declaration in
|
|||
|
|
// the core file, and the VQC10 special-case in changeDigit()'s animation code).
|
|||
|
|
void ICACHE_RAM_ATTR writeDisplay() {}
|
|||
|
|
|
|||
|
|
|
|||
|
|
int PWM_min = 0;
|
|||
|
|
int PWM_max = 800; // row on-time ceiling in microseconds, at full brightness (see PWMtimeBrightness below)
|
|||
|
|
|
|||
|
|
// Blocking, cooperative multiplex refresh for the whole 8x5x7 display - one full call
|
|||
|
|
// scans every row once. Called repeatedly from loop()/Fdelay() in the core file (NOT from
|
|||
|
|
// an ISR - see the note above writeDisplay()). Brightness is implemented as simple PWM: each
|
|||
|
|
// row is held "on" for PWMtimeBrightness microseconds out of a PWM_max budget, then forced
|
|||
|
|
// off for the remainder, so total per-row time is constant regardless of brightness (keeps
|
|||
|
|
// the row scan rate/refresh flicker frequency stable while only the mark/space ratio changes).
|
|||
|
|
void writeDisplay2() {
|
|||
|
|
static int PWMtimeBrightness;
|
|||
|
|
//static uint32_t refresh = 0;
|
|||
|
|
//static uint32_t runtim = 0;
|
|||
|
|
//static uint32_t laststart = 0;
|
|||
|
|
boolean offState;
|
|||
|
|
int brightness;
|
|||
|
|
int iRow,loopMax;
|
|||
|
|
|
|||
|
|
|
|||
|
|
//refresh = millis()-laststart;
|
|||
|
|
//laststart = millis();
|
|||
|
|
//runtim = laststart;
|
|||
|
|
|
|||
|
|
brightness = displayON ? prm.dayBright : prm.nightBright;
|
|||
|
|
if (brightness>MAXBRIGHTNESS) brightness = MAXBRIGHTNESS; //only for safety
|
|||
|
|
|
|||
|
|
if (autoBrightness && displayON) {
|
|||
|
|
PWMtimeBrightness = max(PWM_min,PWM_max*lx/MAXIMUM_LUX); // ambient-light-driven dimming: scale row on-time by measured lux vs. MAXIMUM_LUX
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
PWMtimeBrightness = max(PWM_min,PWM_max*brightness/MAXBRIGHTNESS); // manual brightness: scale row on-time by configured day/night brightness level
|
|||
|
|
|
|||
|
|
iRow = 0;
|
|||
|
|
// FIXED (was "loopMax = maxDigits;", i.e. NUMDIGITS=8): this loop indexes dot-matrix ROWS, which
|
|||
|
|
// only range 0..NUMROWS-1 (NUMROWS=7, i.e. dat[i] is sized [NUMROWS]=[7]), not digit columns. The
|
|||
|
|
// old bound made the loop run iRow = 0..7 (8 iterations) instead of 0..6 (7 iterations), so on the
|
|||
|
|
// last iteration (iRow==7) "dat[i][iRow]" below read one element past the end of each digit's
|
|||
|
|
// 7-byte row array - for i<NUMDIGITS-1 this silently read dat[i+1][0] (the next digit's row-0
|
|||
|
|
// data, due to row-major layout) instead of a real row-7 pattern, and for the last digit
|
|||
|
|
// (i==NUMDIGITS-1) it read out of the whole `dat` array into whatever memory followed it
|
|||
|
|
// (oldDat[0][0]). It also drove a nonexistent 8th row-select line via shiftOutForward(~(1<<iRow))
|
|||
|
|
// below. Net effect was an extra, garbage 8th "row" scanned on every refresh - flicker/ghosting
|
|||
|
|
// risk and a stolen slice of the row-time PWM budget.
|
|||
|
|
loopMax = NUMROWS;
|
|||
|
|
do {
|
|||
|
|
// NOTE: the "iRow == maxDigits" term here can never be true (maxDigits==NUMDIGITS==8, but iRow now
|
|||
|
|
// only ever reaches up to NUMROWS-1==6 before the loop exits via `while(iRow<loopMax)`) - it looks
|
|||
|
|
// like it was meant to add an extra "sync/blank" row at the end of each sweep, but as written it's
|
|||
|
|
// dead weight in the OR. Left as-is (not an out-of-bounds/indexing issue, just an inert condition).
|
|||
|
|
offState = ( (brightness == 0) || (!radarON) || (iRow == maxDigits));
|
|||
|
|
|
|||
|
|
for (int i=0;i<NUMDIGITS;i++) { //fill one line with dots
|
|||
|
|
// Two-phase shift+latch per digit: first phase asserts this digit's select line
|
|||
|
|
// together with its row data; the second phase re-latches the SAME data but with
|
|||
|
|
// ALL digit-select lines forced back off (0xFF = all deselected, active-low select).
|
|||
|
|
// This immediately blanks the just-lit digit again before the loop moves on to the
|
|||
|
|
// next one, which prevents the still-settling row data from bleeding/ghosting onto
|
|||
|
|
// the previously selected digit while the next digit's select+data is being shifted
|
|||
|
|
// in (VFD/tube grids can retain enough charge to glow briefly if left selected while
|
|||
|
|
// data changes underneath them).
|
|||
|
|
shiftOutForward(0xFF); //deselect Z
|
|||
|
|
shiftOutForward(~(1<<i)); //select digit
|
|||
|
|
shiftOutReverse(offState ? 0 : dat[i][iRow]); // set data line
|
|||
|
|
digitalWrite(latchPin, HIGH); //Write shift register to latch
|
|||
|
|
digitalWrite(latchPin, LOW);
|
|||
|
|
asm volatile ("nop");
|
|||
|
|
|
|||
|
|
//Finish latching
|
|||
|
|
shiftOutForward(0xFF); //deselect Z
|
|||
|
|
shiftOutForward(0xFF); //All digit select lines are HIGH
|
|||
|
|
shiftOutReverse(offState ? 0 : dat[i][iRow]); //keep data line
|
|||
|
|
digitalWrite(latchPin, HIGH); //Write shift register to latch
|
|||
|
|
digitalWrite(latchPin, LOW);
|
|||
|
|
asm volatile ("nop");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// All 8 digits now hold row iRow's column data latched into their driver ICs (but with
|
|||
|
|
// digit-select left off from the blanking step above). Now pulse on the single row-select
|
|||
|
|
// line for this row - this is what actually makes the row iRow of every digit light up
|
|||
|
|
// simultaneously - for a PWM-timed on-period, implementing brightness control.
|
|||
|
|
shiftOutForward(~(1<<iRow)); //enable row
|
|||
|
|
shiftOutForward(0xFF); //All digit select lines are HIGH
|
|||
|
|
shiftOutForward(0); //anything
|
|||
|
|
digitalWrite(latchPin, HIGH); //Write shift register to latch
|
|||
|
|
digitalWrite(latchPin, LOW);
|
|||
|
|
if (!offState)
|
|||
|
|
delayMicroseconds(PWMtimeBrightness);
|
|||
|
|
else
|
|||
|
|
delayMicroseconds(PWM_max-PWMtimeBrightness);
|
|||
|
|
|
|||
|
|
iRow++;
|
|||
|
|
} while(iRow<loopMax);
|
|||
|
|
|
|||
|
|
//runtim = millis()-runtim;
|
|||
|
|
//DPRINT(refresh); DPRINT("/"); DPRINTLN(runtim);
|
|||
|
|
yield(); // hand control back to the RTOS/WiFi stack between refresh passes - important since this whole function runs blocking on the main loop, not in an ISR
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
// Looks up character c's glyph in the column-major _font[] table (5 bytes per glyph, one
|
|||
|
|
// byte per column, each byte's low 7 bits = one dot per row) and converts it into the
|
|||
|
|
// row-major representation (row[NUMROWS], one byte per row, one bit per column) that the
|
|||
|
|
// row-scanned hardware needs. c is a plain ASCII code (0x00-0xFF), already translated from
|
|||
|
|
// the core firmware's digit-buffer code via asciiConvert[] by the caller.
|
|||
|
|
void show(byte c){
|
|||
|
|
byte loccol[NUMCOLS];
|
|||
|
|
for (byte i=0; i < NUMCOLS; i++)
|
|||
|
|
loccol[i] = _font[c*NUMCOLS+i];
|
|||
|
|
transposePattern(loccol,row);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Transposes a column-major 5x7 glyph (cols[NUMCOLS], one bit per row within each column
|
|||
|
|
// byte) into a row-major bitmap (rows[NUMROWS], one bit per column within each row byte).
|
|||
|
|
// Each output row byte ends up with its NUMCOLS=5 column bits packed into bits [2..6]
|
|||
|
|
// (via the final "<< (7-NUMCOLS)" shift), bit0/bit1/bit7 left as 0 - this alignment must
|
|||
|
|
// match how those bits are wired through the 74HC595 chain to the physical column drivers.
|
|||
|
|
// When _upsidedown is set, both the row scan direction (cmask shifted right instead of
|
|||
|
|
// left, starting from bit6 instead of bit0) and the column read order are reversed, giving
|
|||
|
|
// a full 180-degree flip for tubes mounted upside down (see _upsidedown declaration above -
|
|||
|
|
// currently unused/dead in this project, always false).
|
|||
|
|
void transposePattern(byte cols[], volatile byte rows[]){
|
|||
|
|
byte cmask;
|
|||
|
|
cmask = (_upsidedown ? 0x40 : 1);
|
|||
|
|
for (byte r=0; r < NUMROWS; r++) {
|
|||
|
|
rows[r] = 0;
|
|||
|
|
for (byte c=0; c < NUMCOLS; c++) {
|
|||
|
|
if (cmask&cols[(_upsidedown ? (NUMCOLS-c-1) : c)]) rows[r] |= 1;
|
|||
|
|
rows[r] = rows[r] << 1;
|
|||
|
|
}
|
|||
|
|
if (_upsidedown) cmask = cmask >> 1;
|
|||
|
|
else cmask = cmask << 1;
|
|||
|
|
rows[r] = rows[r] << (7-NUMCOLS);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Debug helper: prints one byte as 8 ASCII '0'/'1' characters (MSB first).
|
|||
|
|
void bPrint(byte in) {
|
|||
|
|
for (int i=7;i>=0;i--) {
|
|||
|
|
boolean b = in & (1<<i);
|
|||
|
|
DPRINT(b ? '1' : '0');
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Debug helper: dumps the current dat[][] buffer (the exact bitmap about to be scanned out
|
|||
|
|
// by writeDisplay2()) to Serial as ASCII art, for bring-up/troubleshooting. Not called in
|
|||
|
|
// normal operation (see the commented-out call at the end of writeDisplaySingle() below).
|
|||
|
|
void printBitmap() { //print bitmap for testing
|
|||
|
|
for (int j=0;j<NUMROWS;j++) {
|
|||
|
|
for (int i=0;i<NUMDIGITS;i++) {
|
|||
|
|
bPrint(dat[i][j]); Serial.print(" ");
|
|||
|
|
}
|
|||
|
|
DPRINTLN(" ");
|
|||
|
|
}
|
|||
|
|
DPRINTLN("__________________________________");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
// No-op: unlike several other drivers, VQC10 has no dedicated "all outputs off" hardware
|
|||
|
|
// shortcut here - blanking a digit position is instead achieved through the normal buffer
|
|||
|
|
// path by writing digit-buffer code 10 (BLANK) into digit[]/newDigit[], which asciiConvert[]
|
|||
|
|
// maps to a space character (empty glyph). The core .ino no longer calls clearTubes() from
|
|||
|
|
// anywhere at all (its former caller, disableDisplay(), has been removed entirely as dead code),
|
|||
|
|
// so this stub is purely for interface compliance at this point.
|
|||
|
|
void clearTubes() {}
|
|||
|
|
|
|||
|
|
// Blocking, one-shot render: rebuilds oldDat[]/newDat[] (bitmaps for the outgoing and
|
|||
|
|
// incoming character of every digit position) from the shared digit[]/newDigit[] buffers,
|
|||
|
|
// then blends them into dat[] according to each position's animMask[] wipe-animation
|
|||
|
|
// progress. dat[] is what writeDisplay2() actually scans out to the hardware - this
|
|||
|
|
// function does not touch the hardware itself.
|
|||
|
|
void writeDisplaySingle() {
|
|||
|
|
char dispChar;
|
|||
|
|
// Physical-to-logical digit position remapping: the 8 cells are wired/driven as two
|
|||
|
|
// groups of 4 in reverse order (3,2,1,0 then 7,6,5,4), consistent with two physical
|
|||
|
|
// VQC10 modules (see CLOCK_71 "2x VQC10 clock") each internally mirrored/chained back to
|
|||
|
|
// front relative to the logical left-to-right digit[]/newDigit[] buffer order.
|
|||
|
|
byte tubeShift[] = {3,2,1,0,7,6,5,4};
|
|||
|
|
byte a;
|
|||
|
|
for (int i=0;i<NUMDIGITS;i++) { //generate new line -- NOTE: comment says "new" but this loop actually builds oldDat[] (the OUTGOING/current character) from digit[]; see the next loop for newDat[]/newDigit[]. Comment/variable naming appears swapped from actual old/new roles, though the logic itself is correct (oldDat<-digit[], newDat<-newDigit[] matches the core file's old/new buffer convention).
|
|||
|
|
dispChar = digit[tubeShift[i]];
|
|||
|
|
if (dispChar<sizeof(asciiConvert)) dispChar = asciiConvert[(byte)dispChar]; // translate digit-buffer code to ASCII via asciiConvert[]; note dispChar is signed char compared against unsigned sizeof() - harmless here since digit-buffer codes are always small non-negative values, but a latent signed/unsigned mismatch
|
|||
|
|
show(dispChar);
|
|||
|
|
for (int k=0;k<NUMROWS;k++) {
|
|||
|
|
oldDat[i][k] = row[k];
|
|||
|
|
}
|
|||
|
|
if (digitDP[tubeShift[i]]) {
|
|||
|
|
show(DPchar); // overlay the decimal-point/separator dot glyph
|
|||
|
|
for (int k=0;k<NUMROWS;k++) {
|
|||
|
|
oldDat[i][k] |= row[k]; // OR the DP dot pattern onto the character pattern so both render together in the same cell
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
for (int i=0;i<NUMDIGITS;i++) { //generate old line -- NOTE: comment says "old" but this loop builds newDat[] (the INCOMING/target character) from newDigit[]; see note on the previous loop.
|
|||
|
|
dispChar = newDigit[tubeShift[i]];
|
|||
|
|
if (dispChar<sizeof(asciiConvert)) dispChar = asciiConvert[(byte)dispChar];
|
|||
|
|
show(dispChar);
|
|||
|
|
for (int k=0;k<NUMROWS;k++) {
|
|||
|
|
newDat[i][k] = row[k];
|
|||
|
|
}
|
|||
|
|
if (digitDP[tubeShift[i]]) {
|
|||
|
|
show(DPchar);
|
|||
|
|
for (int k=0;k<NUMROWS;k++) {
|
|||
|
|
newDat[i][k] |= row[k];
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Vertical wipe/scroll transition: blend oldDat[] and newDat[] into dat[] based on
|
|||
|
|
// animMask[] (set by the core file's changeDigit() animation state machine, incrementing
|
|||
|
|
// roughly 1..19 over the transition - see the VQC10 special-case in that function). a=0
|
|||
|
|
// means no animation in progress yet (show old character unchanged); as a increases
|
|||
|
|
// (halved and capped to NUMROWS-1=7 dot-rows) the display effectively scrolls the old
|
|||
|
|
// character's rows upward out of view while the new character's rows scroll in from the
|
|||
|
|
// bottom, row-by-row, producing a smooth vertical wipe rather than an instant character
|
|||
|
|
// swap (this is the driver-specific animation timing referenced by the VQC10 special-case
|
|||
|
|
// in the core file's changeDigit()).
|
|||
|
|
for (int i=0;i<NUMDIGITS;i++) { //combine animation
|
|||
|
|
a = animMask[tubeShift[i]]/2; if (a>7) a=7;
|
|||
|
|
for (int k=0;k<NUMROWS;k++) {
|
|||
|
|
if (a==0) dat[i][k] = oldDat[i][k];
|
|||
|
|
else { //Animation!!!
|
|||
|
|
if ((a+k)<NUMROWS) {
|
|||
|
|
dat[i][k] = oldDat[i][k+a]; // still within old character's remaining (not yet scrolled out) rows
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
dat[i][k] = newDat[i][(k+a)-NUMROWS]; // wrapped past the bottom: pull in rows of the new character instead
|
|||
|
|
}
|
|||
|
|
} //endif Animation!!
|
|||
|
|
} //end for i
|
|||
|
|
} //end for
|
|||
|
|
//printBitmap();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#endif
|