but a microcontroller would be much simpler.
Also, why 2 threads on same subject ?
Also, why 2 threads on same subject ?
quite an astute observation the answer is i have a very bad internet speed and it glitched so i made them not so the same seeing as how it wouldnt let me delete one, this one is specifically about ways to make it work as a clock display while the other is just in general. Back to the arduino i have no clue how to set a com port and none of those links tell me directly how to turn standard usb to com
It's a lot easier (and more likely to work) to use VFD driver chips like MAX6932 instead of rolling your own drivers.
Controlling them with a microcontroller (or using programmable logic) is very easy since they use a pretty normal 4-wire interface.
Identifying the pins on the VFD goes like:
1. identify the filament pins. usually there are a group on each side of the display that have a pretty low resistance between them. Use continuity mode on your DMM
2. from those remaining, identify the grids and anodes. You can tell them apart because when multiple grids are powered together with one anode pin, the same segment will be lit in more than one character. And vice-versa when you power multiple anodes and one grid pin.
i think i have the power supply figured out, nothing stops me from using multiple transformers of which i have plenty, i also made my own chip out of transistors (schematic/explanation below)If you're going for discrete transistor solution, then you'll need help from others on this forum as I'm not an EE, more programmer !
the arduino code that makes my plan work for those into that kinda thing (tested, not on the vfd yet but ive yet to find any faults in my design or plan)
<snip>
thank you freddy for that part number, but overall what do you think of my solution?
i think i have the power supply figured out, nothing stops me from using multiple transformers of which i have plenty, i also made my own chip out of transistors (schematic/explanation below)If you're going for discrete transistor solution, then you'll need help from others on this forum as I'm not an EE, more programmer !
the arduino code that makes my plan work for those into that kinda thing (tested, not on the vfd yet but ive yet to find any faults in my design or plan)
<snip>
thank you freddy for that part number, but overall what do you think of my solution?
my experience of VFD's is from this project (http://www.johngineer.com/blog/?p=1595) which I reproduced
I can't see a schematic so it's not really possible to put the code you posted into context
Your level shifting and digit and segment drive circuits don't make any sense.
Draw ONE segment and ONE digit's circuit in full with all transistor symbols, all resistors, all component values and part no.s, and named input and outputs e.g, from the same segment in other digits, from the 4026 chip for the segment signal and from the multiplexing pulse generator for the digit select signal and to one each of the VFD's digit grid and segment anode pins.
My best guess is, depending on the transistor arrray types, your current schematic will either do nothing or blow the 4026 chips and multiplexing pulse generator immediately on switch-on! |O
what is sdo?SDO is serial data out, a SPI signal. The names MOSI for master SDO and MISO for slave SDO are preferred as that way you know the same name signal wires straight through (except when daisychaining). (MOSI stands for Master Out Slave In, and MISO for Master In Slave Out)
i am officially lost i have no clue what any of this does or how its meant to work, but then again my confusion is probably a good sign
only 8 grids,Sure it would work, if your firmware (sketch) fiddles the bits into the correct order before calling SPItransfer(). However the code will be much easier to write if you put ALL the grids in order on the first chip in the chain starting from OUT0 and going up to OUT7. That way you simply send the following codes in the last byte to select the grid to activate:
chip 1 out0 grid 1, out 2 grid 2, out 4 grid 3, out 6 grid 4,
chip 2 out0 grid 5, out 2 grid 6, out 4 grid 7, out 6 grid 8
out 11 A, out 10 B, out 9 C, out 8 D, out 7 E, out 5 F, out 3 G
would this work? also i have no clue how it knows WHAT to display but i assume it has to have something to do with serial in. and i have no clue how to even program for this
i am officially lost i have no clue what any of this does or how its meant to work, but then again my confusion is probably a good sign
ah i get it now its a computer chip (paraphrase please dont persecute me because that how i see it) so its all binary, im beginning to comprehend it now i think (the hardware not the programming and buriedcode with all due respect i have done enough small things ive build 3 amplifiers out of old electronics im bored of small things i need something like this to engage me and i try google but i dont have much of a talent for finding complex answers
as i understand it i need to write a program that takes asciii translates each character to a set out of 14 possible segments so that each letter a-z numbers 0-9 + - = * and space are all represented as products of the 14 segments, if it is how i understand i give the pins of the maxim6920 designations in binarycorrect, you will effectively need to set up a font definition of sorts
#define VFD_DIGIT_1 (1<<6) // Digit 1
#define VFD_DIGIT_2 (1<<10)
#define VFD_DIGIT_3 (1<<4)
#define VFD_DIGIT_4 (1<<0)
#define VFD_DIGIT_DP (1<<7) // Decimal Point
#define VFD_SEG_A (1<<1) // Segments
#define VFD_SEG_B (1<<3)
#define VFD_SEG_C (1<<11)
#define VFD_SEG_D (1<<5)
#define VFD_SEG_E (1<<9)
#define VFD_SEG_F (1<<2)
#define VFD_SEG_G (1<<8)
// VFD Numbers
#define VFD_NO_0 ((uint16_t) VFD_SEG_A|VFD_SEG_B|VFD_SEG_C|VFD_SEG_D|VFD_SEG_E|VFD_SEG_F)
#define VFD_NO_1 ((uint16_t) VFD_SEG_B|VFD_SEG_C)
#define VFD_NO_2 ((uint16_t) VFD_SEG_A|VFD_SEG_B|VFD_SEG_D|VFD_SEG_E|VFD_SEG_G)
#define VFD_NO_3 ((uint16_t) VFD_SEG_A|VFD_SEG_B|VFD_SEG_C|VFD_SEG_D|VFD_SEG_G)
etc
uint16_t VFD_numbers[] = {
VFD_NO_0, VFD_NO_1, VFD_NO_2, VFD_NO_3, VFD_NO_4, VFD_NO_5, VFD_NO_6, VFD_NO_7, VFD_NO_8, VFD_NO_9
};
as i understand it i need to write a program that takes asciii translates each character to a set out of 14 possible segments so that each letter a-z numbers 0-9 + - = * and space are all represented as products of the 14 segments, if it is how i understand i give the pins of the maxim6920 designations in binaryYes, that's right. I know of a couple of Starburst14 'font' tables that have been made public, but I'm not sure about the segment bit order. They are in Hex, so are a P.I.T.A to check manually compared to one defined in binary.
nb: MAX6920 can only control 12 segments so you will need at leat 3 of these to get close to the number of segments on your VFDI think you've made a mistake there. Neo's VFD only has 25 pins. Subtract 2 for the filament and you have 23 other electrodes so he only needs TWO MAX6920 chips.
@Freddy,oh OKnb: MAX6920 can only control 12 segments so you will need at leat 3 of these to get close to the number of segments on your VFDI think you've made a mistake there. Neo's VFD only has 25 pins. Subtract 2 for the filament and you have 23 other electrodes so he only needs TWO MAX6920 chips.
Quote from: Ian.M@Freddy,oh OKnb: MAX6920 can only control 12 segments so you will need at leat 3 of these to get close to the number of segments on your VFDI think you've made a mistake there. Neo's VFD only has 25 pins. Subtract 2 for the filament and you have 23 other electrodes so he only needs TWO MAX6920 chips.
thought 40+ was mentioned earlier in the thread, but have been keepin up - in that case 2 is ideal :)
// C source for font
// Generated by Ian.M's
// 14 segment font editor
unsigned int font[]={
0x2000, // 0x00 NUL
0x1000, // 0x01 SOH
0x0800, // 0x02 STX
0x0400, // 0x03 ETX
0x0200, // 0x04 EOT
0x0100, // 0x05 ENQ
0x0080, // 0x06 ACK
0x0040, // 0x07 BEL
0x0020, // 0x08 BS
0x0010, // 0x09 HT
0x0008, // 0x0A LF
0x0004, // 0x0B VT
0x0002, // 0x0C FF
0x0001, // 0x0D CR
0x0000, // 0x0E SO
0x0000, // 0x0F SI
0x3FFF, // 0x10 DLE
0x00FF, // 0x11 DC1
0x3FFF, // 0x12 DC2
0x3FFF, // 0x13 DC3
0x3FFF, // 0x14 DC4
0x3FFF, // 0x15 NAK
0x3FFF, // 0x16 SYN
0x3FFF, // 0x17 ETB
0x3FFF, // 0x18 CAN
0x3FFF, // 0x19 EM
0x3FFF, // 0x1A SUB
0x3FFF, // 0x1B ESC
0x3FFF, // 0x1C FS
0x3FFF, // 0x1D GS
0x3FFF, // 0x1E RS
0x3FFF, // 0x1F US
0x0000, // 0x20 Space
0x3FFF, // 0x21 '!'
0x0120, // 0x22 '"'
0x07AA, // 0x23 '#'
0x2DAA, // 0x24 '$'
0x0911, // 0x25 '%'
0x06CC, // 0x26 '&'
0x0020, // 0x27 '''
0x0041, // 0x28 '('
0x0014, // 0x29 ')'
0x00DD, // 0x2A '*'
0x00AA, // 0x2B '+'
0x0001, // 0x2C ','
0x0088, // 0x2D '-'
0x3FFF, // 0x2E '.'
0x0011, // 0x2F '/'
0x3F11, // 0x30 '0'
0x1800, // 0x31 '1'
0x3688, // 0x32 '2'
0x3C08, // 0x33 '3'
0x1988, // 0x34 '4'
0x2D88, // 0x35 '5'
0x2F88, // 0x36 '6'
0x2012, // 0x37 '7'
0x3F88, // 0x38 '8'
0x3D88, // 0x39 '9'
0x3FFF, // 0x3A ':'
0x3FFF, // 0x3B ';'
0x000C, // 0x3C '<'
0x0488, // 0x3D '='
0x0081, // 0x3E '>'
0x300A, // 0x3F '?'
0x3F0A, // 0x40 '@'
0x3B88, // 0x41 'A'
0x3C2A, // 0x42 'B'
0x2700, // 0x43 'C'
0x3C22, // 0x44 'D'
0x2780, // 0x45 'E'
0x2380, // 0x46 'F'
0x2F08, // 0x47 'G'
0x1B88, // 0x48 'H'
0x2422, // 0x49 'I'
0x1E00, // 0x4A 'J'
0x0394, // 0x4B 'K'
0x0700, // 0x4C 'L'
0x1B50, // 0x4D 'M'
0x1B44, // 0x4E 'N'
0x3F00, // 0x4F 'O'
0x3388, // 0x50 'P'
0x3F04, // 0x51 'Q'
0x338C, // 0x52 'R'
0x2D88, // 0x53 'S'
0x2022, // 0x54 'T'
0x1F00, // 0x55 'U'
0x0311, // 0x56 'V'
0x1B05, // 0x57 'W'
0x0055, // 0x58 'X'
0x0052, // 0x59 'Y'
0x2411, // 0x5A 'Z'
0x2441, // 0x5B '['
0x0044, // 0x5C '\'
0x2414, // 0x5D ']'
0x0140, // 0x5E '^'
0x0400, // 0x5F '_'
0x0040, // 0x60 '`'
0x3B88, // 0x61 'a'
0x3C2A, // 0x62 'b'
0x2700, // 0x63 'c'
0x3C22, // 0x64 'd'
0x2780, // 0x65 'e'
0x2380, // 0x66 'f'
0x2F08, // 0x67 'g'
0x1B88, // 0x68 'h'
0x2422, // 0x69 'i'
0x1E00, // 0x6A 'j'
0x0394, // 0x6B 'k'
0x0700, // 0x6C 'l'
0x1B50, // 0x6D 'm'
0x1B44, // 0x6E 'n'
0x3F00, // 0x6F 'o'
0x3388, // 0x70 'p'
0x3F04, // 0x71 'q'
0x338C, // 0x72 'r'
0x2D88, // 0x73 's'
0x2022, // 0x74 't'
0x1F00, // 0x75 'u'
0x0311, // 0x76 'v'
0x1B05, // 0x77 'w'
0x0055, // 0x78 'x'
0x0052, // 0x79 'y'
0x2411, // 0x7A 'z'
0x0094, // 0x7B '{'
0x0322, // 0x7C '|'
0x0049, // 0x7D '}'
0x0944, // 0x7E '~'
0x3FFF // 0x7F DEL
};
That's a usable 7 bit ASCII character set with some lamp test segment patterns down in the control codes. Notable ommissions are . ; : ! and of course the lower case alphabet is in upper case. const unsigned int font[]={
unless you arre using the C99 fixed width types from stdint.h, in which case you'd use:const uint16_t font[]={
i should note at this point to trying to learn how to program and do microcontrollers but only if i can actually do it and not stare at a screen for 3 hours trying to tell my computer that there is an arduino attached and failing. so as more eloquently put im open to it so long as i can do it without hitting a brick wall just trying to set it up.
i just realized something, won't the grid pins work at ground potential? that is to say when i tested it to map it out they were and it worked, if they can function as ground then it becomes much simpler AND saves io/driver chip pinsDepends what you mean by 'work' Inactive grids or anodes at 0V = OFF. The VFD tube acts as an AND gate - the specific segment only lights if both its grid and anode are positive.
One display and its led to 4 pages of theories, i have no clue how to code and apparently im a stumbling idiot everywhere else also. Every idea i come up with either leads to more than i can afford or nothing at all (or at least nothing i know how to do).
One display and its led to 4 pages of theories, i have no clue how to code and apparently im a stumbling idiot everywhere else also. Every idea i come up with either leads to more than i can afford or nothing at all (or at least nothing i know how to do).I couldn't really find the MM58342 here in the UK, but prices seems to hover around $20. Which is steep.
Arduino Uno 74HC595
MOSI (11) => DS (14) - first chip only
SCK (13) => SH_CP (11)
SS (10) => ST_CP (12) - SPI /CS
Other '595 connections
+5V => /MR (10) - reset disabled
Gnd => /OE (13) - outputs on
Q7' (9) => DS (14) of next chip
+5V => Vcc (16)
Gnd => Gnd (8 )
if((millis()-ms)>ONE_SEC){
ms+=ONE_SEC;
BCDtime++;
fixHMS();
}
by keeping a running count of 'milliseconds' and adding 1000 to it whenever it lags by more than 1000. There seem to be a lot of reports of problems with millis() accuracy. . . .
You already have a 16MHz crystal for the ATmega16U2 running the USB interface, so why not tap into that accurate clock for the main ATmega328P MCU instead of fitting a s--tty resonator?
No wonder Arduinos have such a rep for crappy timekeeping. :palm:
#define ONE_SEC 997784UL // micros() in one second trimmed for resonator.
which was calculated based on the time lost during a 15 hour run, and:int main() {
uint32_t t; // temp for digit extraction
uint8_t d; // extracted digit, then its font
uint32_t ms; // tick counter to sync to system micros count.
setup(); // initialisation
ms=micros();
while(1){ // Superloop
flags.bMode=!digitalRead(BTNMODE);
flags.bSet=!digitalRead(BTNSET);
if((micros()-ms)>ONE_SEC){
ms+=ONE_SEC;
BCDtime++;
fixHMS();
}
switch(flags.bSet<<1|flags.bMode){
case 0b00: //Normal
display(BCDtime>>8);
VFDsymbWrite(VFD_SYMB_DOT,(BCDtime&1)); //Flashing dot
break;
case 0b01: //Mode pressed
display(BCDtime&0xFFFFUL);
VFDsymbWrite(VFD_SYMB_DOT,0); //No dot
break;
case 0b10: //Set pressed
BCDtime+=0x000100UL; //Increment only minutes
if((BCDtime&0x00FF00UL)==0x005A00UL) BCDtime&=0xFF00FFUL; //Wrap 60 to 00
goto doSet;
case 0b11: //Set + Mode pressed
BCDtime+=0x010000UL; //Increment hours
doSet:
BCDtime&=0xFFFF00UL; //Clear seconds
ms=micros();
fixHMS();
display(BCDtime>>8);
VFDsymbWrite(VFD_SYMB_DOT,1); //Fixed dot
delay(80);
break;
}
delay(20);
} //endWhile(1)
}//endFn main
which is how I'm keeping time in my main() function (I've got a dummy .ino file so I can program it in real GCC C++ without the IDE mangling it before compilation).#define ONE_SEC 999187UL // micros() in one second trimmed for resonator.
and is tracking a NNTP corrected PC clock to better than 2 seconds a day. To do any better, I'd have to either write a sketch to automate the clock setting and error measurement, or use a *good* frequency meter. $b = "
int SER_Pin = 11; //pin 14 on the 75HC595
int RCLK_Pin = 10; //pin 12 on the 75HC595
int SRCLK_Pin = 13; //pin 11 on the 75HC595
//How many of the shift registers - change this
#define number_of_74hc595s 1
//do not touch
#define numOfRegisterPins number_of_74hc595s * 8
boolean registers[numOfRegisterPins];
void setup(){
pinMode(SER_Pin, OUTPUT);
pinMode(RCLK_Pin, OUTPUT);
pinMode(SRCLK_Pin, OUTPUT);
//reset all register pins
clearRegisters();
writeRegisters();
}
//set all register pins to LOW
void clearRegisters(){
for(int i = numOfRegisterPins - 1; i >= 0; i--){
registers[i] = HIGH;
}
}
//Set and display registers
//Only call AFTER all values are set how you would like (slow otherwise)
void writeRegisters(){
digitalWrite(RCLK_Pin, LOW);
for(int i = numOfRegisterPins - 1; i >= 0; i--){
digitalWrite(SRCLK_Pin, LOW);
int val = registers[i];
digitalWrite(SER_Pin, val);
digitalWrite(SRCLK_Pin, HIGH);
}
digitalWrite(RCLK_Pin, HIGH);
}
//set an individual pin HIGH or LOW
void setRegisterPin(int index, int value){
registers[index] = value;
}
void loop(){
setRegisterPin(1, HIGH);
setRegisterPin(2, HIGH);
setRegisterPin(3, HIGH);
setRegisterPin(4, HIGH);
setRegisterPin(5, HIGH);
setRegisterPin(6, HIGH);
setRegisterPin(7, HIGH);
setRegisterPin(8, LOW);
writeRegisters(); //MUST BE CALLED TO DISPLAY CHANGES
//Only call once after the values are set how you need.
}
";
echo $b;
A-1.2kOhm-15 ; I assume this is the LED --- '595 wiring
B-1.2kOhm-1
C-1.2kOhm-2
D-1.2kOhm-3
E-1.2kOhm-4
F-1.2kOhm-5
G-1.2kOhm-6
H-1.2kOhm-7
GND-8
+5V-16
Arduino11 - 595,14
Arduino10 - 595,12
Arduino13 - 595,11
595,10
595,13
595,14 all NC ; ?????? you've already listed '595.14 -- Arduino.11
void loop(){
// Display segments for "3"
setRegisterPin(0, LOW); //a
setRegisterPin(1, LOW); //b
setRegisterPin(2, LOW); //c
setRegisterPin(3, LOW); //d
setRegisterPin(4, HIGH); //e
setRegisterPin(5, HIGH); //f
setRegisterPin(6, LOW); //g
setRegisterPin(7, HIGH); //d.p.
writeRegisters(); //MUST BE CALLED TO DISPLAY CHANGES
//Only call once after the values are set how you need.
delay(2);
}
Remember for common anode displays, LOW = ON ;)
const uint8_t SER_Pin = 11; // MOSI - pin 14 on the 75HC595, data in
const uint8_t RCLK_Pin = 10; // /SS - pin 12 on the 75HC595, store clk
const uint8_t SRCLK_Pin = 13; // SCLK - pin 11 on the 75HC595, shift clock
//How many of the shift registers - change this
#define number_of_74hc595s 1
#define ON LOW
#define OFF HIGH
//// uncomment for Ian's segment ordering
//#define SCRAMBLE
//const uint8_t scramble[]={ 6,5,4,3,2,1,0,7 }; //Map Neo's segment order to mine.
//do not touch
#define numOfRegisterPins number_of_74hc595s * 8
uint8_t registers[number_of_74hc595s];
void setup(){
// Setup pins as output
pinMode(SER_Pin, OUTPUT);
pinMode(RCLK_Pin, OUTPUT);
pinMode(SRCLK_Pin, OUTPUT);
//reset all register pins
clearRegisters();
writeRegisters();
}
//set all register pins to OFF
void clearRegisters(){
for(uint8_t i = 0; i<sizeof(registers); i++){
registers[i] = OFF?0xFF:0;
}
}
//Set and display registers
//Only call AFTER all values are set how you would like (slow otherwise)
void writeRegisters(){
digitalWrite(RCLK_Pin, LOW);
for(uint8_t i = sizeof(registers); i--;){ //loop from N-1 to zero inclusive
uint8_t t=registers[i];
for(uint8_t j = 8; j--;){
digitalWrite(SRCLK_Pin, LOW);
// // Extract bit value and output the simple way
// bool val = !!(t&128);
// digitalWrite(SER_Pin, val);
// Extract bit value and output the fast way
if(!!(t&128)) digitalWrite(SER_Pin, HIGH); else digitalWrite(SER_Pin, LOW);
//delayMicroseconds(10); // dont exceed 100 KHz!
digitalWrite(SRCLK_Pin, HIGH);
t<<=1; //shift to next bit.
}
}
digitalWrite(RCLK_Pin, HIGH);
}
//set an individual pin HIGH or LOW
void setRegisterPin(uint8_t index, bool value){
const uint8_t BitMasks[]={1,2,4,8,16,32,64,128}; // convert bit position to single '1' mask
#ifdef SCRAMBLE
index=(index&0xF8)|scramble[index&7];
#endif
if(value) registers[index>>3]|=BitMasks[index&7]; else registers[index>>3]&=~BitMasks[index&7];
}
void loop(){
// Display segments for "3"
setRegisterPin(0, ON); //a
setRegisterPin(1, ON); //b
setRegisterPin(2, ON); //c
setRegisterPin(3, ON); //d
setRegisterPin(4, OFF); //e
setRegisterPin(5, OFF); //f
setRegisterPin(6, ON); //g
setRegisterPin(7, OFF); //d.p.
writeRegisters(); //MUST BE CALLED TO DISPLAY CHANGES
//Only call once after the values are set how you need.
delay(2);
}
Sketch is called 'Neo1e'.595,14 all NC ; ?????? you've already listed '595.14 -- Arduino.11
If you are too cheap to get a USB<=>logic level serial cable, once youv'e stuffed a bootloader in there, you could even use a Uno with RESET tied low and tap its RX and TX pins to the equivalent pins on the PDIP, then pulse its RESET low manually to trigger the bootloader.there is a difference between cheap and practically broke, ill look into the bus strips the breadboard itself is a very old one i got from the same place i got the crystal
CH340G breakout boards can be found for as little as $2, or hack a really old cellphone data cable. If its cheaper than a couple of bottles of pop, drink only water for a week to pay for it.. . . . At this point I should note that my ancestry comes from two groups with reputations for being the tightest with money in Western Europe so min-maxing every purchasing decision is nearly instinctive for me.If you are too cheap to get a USB<=>logic level serial cable, once youv'e stuffed a bootloader in there, you could even use a Uno with RESET tied low and tap its RX and TX pins to the equivalent pins on the PDIP, then pulse its RESET low manually to trigger the bootloader.there is a difference between cheap and practically broke
now im confused you say transistor but a transistor cannot output more than its base, also im not hacking my arduino it works and i like it that way, knowing my luck if i touched it that fact would soon change
Truth Table
===========
NPN PNP
----- -----
E B C E B C
0 0 Z 0 0 0*
0 1 0 0 1 Z
1 0 Z 1 0 1
1 1 1* 1 1 Z
i believe there was a misunderstanding i have no intention to use the transistor as a 2 input device what i mean was to combine outputs, likebelowabove (reply#193)
would this work for that octal buffer http://www.ti.com/lit/ds/symlink/sn74hct541.pdf (http://www.ti.com/lit/ds/symlink/sn74hct541.pdf) though im not entirely sure what you you mean by decoded counter? perhaps a part number would help
However if you want to put the segment 'font' diode matrix ROM between the tristate buffers and the MIC2981, you'd do better to use 74HC241 which gets you two digits worth of 4 bit tristate buffers in one chip. One is active high OE ahd the other active low, so you also need three screaming fast inverters (74AC series) to avoid overlapping the active low enable signals with the adjacent timeslot active high signals. It would probably be safer to not use two timeslots, (Q0 and Q4), and group all the active high enables in slots Q1-Q3, and active low in /Q5-Q7 using Q8 for reset. Then you could use ordinary inverters rather than 74AC ones. That would also mean you might need to bump up the multiplexing frequency a bit as the frame rate @512Hz clock would only be 64Hz.or alternatively i could just accept that my "font" would be best on leds where it isnt already ludicrously complex
i believe there was a misunderstanding i have no intention to use the transistor as a 2 input device what i mean was to combine outputs, likebelowabove (reply#193)
That looks like two signals per transistor to me. You've got an [An]signal and an [IOn] signal to each transistor then you are paralleling the emitters which cant ever work properly.
Try this:
(https://www.eevblog.com/forum/projects/vacuum-fluorescent-display-multiplexing-problem/?action=dlattach;attach=263079;image)
I've attached the LTSPICE circuit in case you want to extend it or add pulsed sources ground etc. and simulate it
as i understand it theres the 5v logic signal that turns it on (saturation) then from there until it is turned off it acts as a short circuitOK, lets give you a sim to poke around in and hope it 'clicks' for you.
but as you said i dont grok transistors so im merely explaining why i thought that and now arguing for it