1

I'm using an Arduino Nano, a UNL2803 IC, and three 2N3904 transistors to drive three seven-segment vacuum fluorescent display tubes (IV-6) in a multiplex configuration. The UNL2803 is used to drive the segments: when an Arduino pin is pulled low, 25V is sent to the corresponding segment. The 2N3904 transistors are used to drive each of the digits: when the Arduino pin is high, 25V is sent to the digit's grid, thereby activating the digit.

The problem: the tubes aren't showing the correct segments, and the displays aren't being activated with correct timing. I have checked each segment connection to make sure it is connected to the correct segment. By slowing down the time interval between digits, I can see that the second and third digits (the 10s and 1s) are being displayed sequentially with the correct interval, but the first digit (the 100s) comes on with the second digit and stays on for twice the interval time. It also appears that some of the digits are attempting to display more than one number (sequentially) while activated.

The code:

// Pin assignments for segments
const int SEG_A = 2;
const int SEG_B = 3;
const int SEG_C = 4;
const int SEG_D = 6;
const int SEG_E = 5;
const int SEG_F = 7;
const int SEG_G = 8;

// Pin assignments for digits
const int DIG1 = 9;
const int DIG2 = 10;
const int DIG3 = 11;

int digit = 1;
int dig_number = 0;
unsigned int number = 321;    

void setup() {

  Serial.begin(9600);
  
  // Set segment pins as outputs
  pinMode(SEG_A, OUTPUT);
  pinMode(SEG_B, OUTPUT);
  pinMode(SEG_C, OUTPUT);
  pinMode(SEG_D, OUTPUT);
  pinMode(SEG_E, OUTPUT);
  pinMode(SEG_F, OUTPUT);
  pinMode(SEG_G, OUTPUT);
  
  // Set digit pins as outputs
  pinMode(DIG1, OUTPUT);
  pinMode(DIG2, OUTPUT);
  pinMode(DIG3, OUTPUT);

  // Turn off digits
  digitalWrite(DIG1, LOW);
  digitalWrite(DIG2, LOW);
  digitalWrite(DIG3, LOW);
}

void loop() {
      if (digit == 1) {
        digitalWrite(DIG1, HIGH);
        digitalWrite(DIG2, LOW);
        digitalWrite(DIG3, LOW);
        dig_number = number / 100;
        if (number < 100) {      // to disable the digit if it's not being used
          dig_number == 99;      // triggers 'default' in switch/case
          display_number(dig_number); 
        } else {
          display_number(dig_number);
        }
        digit = 2;
        Serial.println("The first digit is: ");
        Serial.print(dig_number);
        delay (250);
      }  

      if (digit == 2) {
        digitalWrite(DIG1, LOW);
        digitalWrite(DIG2, HIGH);
        digitalWrite(DIG3, LOW);
        dig_number = (number / 10) % 10;
        if (dig_number == 0 && number < 10) {       // to disable the digit if it's not being used
          dig_number == 99;        // triggers 'default' in switch/case
          display_number(dig_number);          
        } else {
          display_number(dig_number);
        }
        digit = 3;
        Serial.println("The second digit is: ");
        Serial.print(dig_number);
        delay (250);
      }

      if (digit == 3) {
        digitalWrite(DIG1, LOW);
        digitalWrite(DIG2, LOW);
        digitalWrite(DIG3, HIGH);
        dig_number = number % 10;    
        display_number(dig_number);
        digit = 1;
        Serial.println("The third digit is: ");
        Serial.print(dig_number);
        delay (250);
      }
}

void display_number(int dig_number) {

    switch (dig_number) {
        case 0:
        digitalWrite(SEG_A, LOW);   
        digitalWrite(SEG_B, LOW);
        digitalWrite(SEG_C, LOW);
        digitalWrite(SEG_D, LOW);
        digitalWrite(SEG_E, LOW);
        digitalWrite(SEG_F, LOW);
        digitalWrite(SEG_G, HIGH);
        break;
        
    case 1:
        digitalWrite(SEG_A, HIGH);
        digitalWrite(SEG_B, LOW);
        digitalWrite(SEG_C, LOW);
        digitalWrite(SEG_D, HIGH);
        digitalWrite(SEG_E, HIGH);
        digitalWrite(SEG_F, HIGH);
        digitalWrite(SEG_G, HIGH);
        break;
        
    case 2:
        digitalWrite(SEG_A, LOW);
        digitalWrite(SEG_B, LOW);
        digitalWrite(SEG_C, HIGH);
        digitalWrite(SEG_D, LOW);
        digitalWrite(SEG_E, LOW);
        digitalWrite(SEG_F, HIGH);
        digitalWrite(SEG_G, LOW);
        break;
        
    case 3:
        digitalWrite(SEG_A, LOW);
        digitalWrite(SEG_B, LOW);
        digitalWrite(SEG_C, LOW);
        digitalWrite(SEG_D, LOW);
        digitalWrite(SEG_E, HIGH);
        digitalWrite(SEG_F, HIGH);
        digitalWrite(SEG_G, LOW);
        break;
        
    case 4:
        digitalWrite(SEG_A, HIGH);
        digitalWrite(SEG_B, LOW);
        digitalWrite(SEG_C, LOW);
        digitalWrite(SEG_D, HIGH);
        digitalWrite(SEG_E, HIGH);
        digitalWrite(SEG_F, LOW);
        digitalWrite(SEG_G, LOW);
        break;
        
    case 5:
        digitalWrite(SEG_A, LOW);
        digitalWrite(SEG_B, HIGH);
        digitalWrite(SEG_C, LOW);
        digitalWrite(SEG_D, LOW);
        digitalWrite(SEG_E, HIGH);
        digitalWrite(SEG_F, LOW);
        digitalWrite(SEG_G, LOW);
        break;
        
    case 6:
        digitalWrite(SEG_A, LOW);
        digitalWrite(SEG_B, HIGH);
        digitalWrite(SEG_C, LOW);
        digitalWrite(SEG_D, LOW);
        digitalWrite(SEG_E, LOW);
        digitalWrite(SEG_F, LOW);
        digitalWrite(SEG_G, LOW);
        break;
        
    case 7:
        digitalWrite(SEG_A, LOW);
        digitalWrite(SEG_B, LOW);
        digitalWrite(SEG_C, LOW);
        digitalWrite(SEG_D, HIGH);
        digitalWrite(SEG_E, HIGH);
        digitalWrite(SEG_F, HIGH);
        digitalWrite(SEG_G, HIGH);
        break;
        
    case 8:
        digitalWrite(SEG_A, LOW);
        digitalWrite(SEG_B, LOW);
        digitalWrite(SEG_C, LOW);
        digitalWrite(SEG_D, LOW);
        digitalWrite(SEG_E, LOW);
        digitalWrite(SEG_F, LOW);
        digitalWrite(SEG_G, LOW);
        break;
        
    case 9:
        digitalWrite(SEG_A, LOW);
        digitalWrite(SEG_B, LOW);
        digitalWrite(SEG_C, LOW);
        digitalWrite(SEG_D, LOW);
        digitalWrite(SEG_E, HIGH);
        digitalWrite(SEG_F, LOW);
        digitalWrite(SEG_G, LOW);
        break;
    
    default:
        digitalWrite(SEG_A, HIGH);
        digitalWrite(SEG_B, HIGH);
        digitalWrite(SEG_C, HIGH);
        digitalWrite(SEG_D, HIGH);
        digitalWrite(SEG_E, HIGH);
        digitalWrite(SEG_F, HIGH);
        digitalWrite(SEG_G, HIGH);
        break;
    }
}

The circuit diagram:

enter image description here

I have heard rumor that using delay() instead of millis() for multiplexing can be problematic. Is that what's going on here?

Many thanks in advance for considering this problem!

4
  • The way you have wired ìt, when you are switching a digit on, you need to send a LOW to its corresponding pin and a HIGH to the other two digit pins. You have this inverted. I'm guessing that the wire connecting R9, R10 and R11 goes all the way to 25 volts. Base resistors on the transistors would be nice.
    – 6v6gt
    Jan 19, 2023 at 1:11
  • Thank you. My understanding of using the 2N3904 transistor as a switch is that a high pin is needed on the base in order to "open" the switch and allow current to flow from collector to emitter. Please help me understand the need for a low pin on the base for this to work. I am new to transistors. :) Jan 20, 2023 at 18:20
  • This is correct but, in your case, switching the transistors on pulls the grids to ground thus switching off the displays. I have added a more complete explanation below as an answer.
    – 6v6gt
    Jan 21, 2023 at 6:10
  • For future searchers, you can check out the final project here. Many thanks to those who commented——your feedback was extremely helpful. Jan 31, 2023 at 15:33

3 Answers 3

0

Your code appears to invert the switching pattern of the digits. Instead of switching the selected digit on and the other two off, you are doing the opposite.

The grid of a VFD tube has to have a voltage applied to it to illuminate the selected segments. Those segments are also selected by having a voltage applied. The circuit you have shown, by default, powers both the grids and the segments via 10k resistors connected to the 25 volt power rail. The transistors, also in the uln2803, when switched on, pull the grids and segments to ground, thus switching those elements off. This arrangement reduces the complexity of the circuit by eliminating the need for high side switching but "wastes" power.

A simple code correction should solve the problem:

// Turn off digits 
   digitalWrite(DIG1, HIGH);  // high turns the grid off.
   digitalWrite(DIG2, HIGH); 
   digitalWrite(DIG3, HIGH);
 }
if (digit == 1) { 
   digitalWrite(DIG1, LOW);  // digit one ON
   digitalWrite(DIG2, HIGH); // digit two OFF 
   digitalWrite(DIG3, HIGH); // digit three OFF
}

Do the equivalent for digits 2 and 3.

Use resistors (say 1k) in series with the transistor bases to limit the current and protect the arduino pins. See https://learn.sparkfun.com/tutorials/transistors/applications-i-switches

You still have to confirm if the wire connecting R9, R10 and R11 goes to all the way to the +25 volt rail. This is not clear from the schematic.

3
  • Thanks so much for this explanation! I eventually replaced the 2N3904 transistors with a ULN2803, and that fixed the problem. All is working as it should now, except for one small quirk: I have set up a simple counter to cycle through numbers, and I can see very faint illumination on segments that are not energized while the count is underway. A "ghosting" effect, so to speak, on all the digits. Very low voltage is somehow getting to pins that are not selected. Any idea where this might be coming from? Jan 21, 2023 at 9:52
  • @ThomasBurns If you get ghosting, then before switching one digit on, first switch the other two off, then set up the segments (by calling display_number() ) and wait say 1ms. Then switch the selected digit on. Also, speed up your multiplexing. Probably display each digit for about 5ms to avoid noticeable flicker but without incurring too much of a switching loss penalty. This means a small restructuring of your code.
    – 6v6gt
    Jan 21, 2023 at 10:06
  • Yes this worked (had to tinker with it for a few minutes). Many thanks for the feedback! Jan 21, 2023 at 10:36
2

I made a VFD clock using some really cool old DG10B tubes from an early calculator a year or so ago. I had a heck of a time getting it to work, until I decided try tackling one problem at a time, and then put it all together.

In my clock I used the MAX6921 VFD driver IC, a DS3231 RTC with super cap, and a XIAO for the brains. The VFD driver chip is controlled by pwm/serial (data, load, clock) and the RTC is over I2c.

Instead of trying to multiplex them, I just got them all working at once, I did a nice slow count of all digits being on and displaying the same digits. This helped me detect a couple wiring faults, and helped me figure out which segments needed to be lit for each number I wanted displayed. (the digits on my tubes are quite unique!)

tube pinout DG10b tubes

once I had my "fonts" figured out and a case for each digit, I created a simple loop that counted through 0-9 on all digits with all four of them on. 4444, 5555, etc

Then I started trying to get just one digit lit at a time. (this helped me find another wiring issue) // [pihgfedcba------1234}; //this is what the data stream looks like when sent to the driver // ...where the first 10 digits are the segments, and the last 4 are the grids for each digit from left to right 1-4. // The rest are currently unused and should be padded with zero's or 1's)

Next I made a loop that would check the time, and print out the digits. I DO use delay() in my code, in order to deliberately flicker my tubes (for the antique steampunk effect) But here's the thing, I believe my code checks the time for each individual digit. the loop says for each digits 1-4 (check time, display digit)

there was a lot more involved, and it's been a while since I worked on it so I am not sure I am being helpful here. I just wanted to suggest you follow a good troubleshooting process. (smaller problems are easier to solve)

my vfd clock

3
  • 1
    This was extremely helpful. Your approach led me to discover that I was using an incorrect pinout for the UNL2803 chip. Correcting this solved my segment problems. Still working on figuring out what's going on with the digits. Thank you! Also wanted to quickly say that your breadboard technique is inspiring—mine looks considerably less organized. Jan 20, 2023 at 18:21
  • Haha, yeah, my bread boarding is a little obsessive. -and I'm glad I was able to help. Vfd displays are so fascinating. Hope your project turns out how your want envision it. :) Jan 20, 2023 at 23:47
  • I'd love to get my hands on some of those VFD tubes with their rough, handwritten style fonts. But, I know, such odd ball displays are difficult to get hold of and probably well outside any reasonable hobby budget.
    – 6v6gt
    Jan 21, 2023 at 18:16
0

For future searchers, I finally got this circuit going using two ULN2803 transistor arrays, instead of discrete transistors for the digit connections. Here's the final schematic:

enter image description here

You can check out more about the final project here. Many thanks to those who commented——your feedback was very helpful!

2
  • your final schematic has still errors. You fixed the missing GND to the ULN2803 drivers. But the COM inputs (pin 10) and the three resistors for the grid shall be connected to +24V!
    – Landroval
    Feb 19, 2023 at 14:42
  • @Landroval Thanks for pointing this out! I've exchanged the schematic for the corrected version. Feb 22, 2023 at 12:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.