Go Down

Topic: Driving 4 daisy chained 32 bit shift registers (Read 826 times) previous topic - next topic

kevina96

You are trying to display "+.1212121212". What result are you getting on the display?

So when I run the following code:

Code: [Select]
#define PIN_LE    10 //Shift Register Latch Enable
#define PIN_CLK   13  //Shift Register Clock
#define PIN_DATA  11  //Shift Register Data
#define PIN_BL    9  //Shift Register Blank (0=display off     1=display on)


// shift register positions
// --------------------------HV5530 #1--------------------------
// Controls 9 Dots (One cathode each), Plus/Minus tube (2 cathodes), One 10 digit tube (10 cathodes)

// Dots are first
//      Dot   1  2  3  4  5  6  7  8  9
int dots[] = {0, 1, 2, 3, 4, 5, 6, 7, 8};

//HV5530 #1 Pin 10 (HVOUT20) is not used
//Bit 9 not used
int blank1[] = {9};
// Plus/minus tube  +   -
int plusminus[] = {10, 11};

// Rightmost numeric tube (Tube 1)
//        Digit  0   1   2   3   4   5   6   7   8   9
//  NL840 Pin #  13  5   7   10  6   2   8   1   3   9
int tube1[] =  {15, 16, 18, 21, 17, 13, 19, 12, 14, 20};         
//Pins 35-44 (HVOUT1 - HVOUT10) are not used

// --------------------------HV5530 #2,3,4--------------------------
//HV5530#2,3,4 each control three (3) numeric tubes each (10 cathodes each, 30 cathodes total)
//Connections are similarly numbered between each set of tubes and HV chip for chips 2,3,4
//Pins 21 and 22 (HVOUT31 and HVOUT32) are not used

// Next 3 tubes from right to left (Tubes 2,3,4)
//       Digit  0   1   2   3   4   5   6   7   8   9
// NL840 Pin #  13  5   7   10  6   2   8   1   3   9
int tube2[] =  {35, 36, 38, 41, 37, 33, 39, 32, 34, 40};
int tube3[] =  {45, 46, 48, 51, 47, 43, 49, 42, 44, 50};
int tube4[] =  {57,  58, 60, 63, 59, 55, 61, 54, 56, 62}; 

//       Digit  0   1   2   3   4   5   6   7   8   9
// NL840 Pin #  13  5   7   10  6   2   8   1   3   9
int tube5[] =  {67, 68, 70, 73, 69, 65, 71, 64, 66, 72};
int tube6[] =  {77,  78, 80, 83, 79, 75, 81, 74, 76, 82};
int tube7[] =  {89,  90, 92, 95, 91, 87, 93, 86, 88, 94};

//       Digit  0   1   2   3   4   5   6   7   8   9
// NL840 Pin #  13  5   7   10  6   2   8   1   3   9
int tube8[] =  {99,100,102,105,101,97,103,96,98,104};
int tube9[] =  {109,110,112,115,111,107,113,106,108,114}; 
int tube10[] =  {121,122,124,127,123,119,125,118,120,126};


void setup() {
  pinMode(PIN_LE,  OUTPUT);
  pinMode(PIN_BL,  OUTPUT);
  pinMode(PIN_DATA,OUTPUT);
  pinMode(PIN_CLK, OUTPUT);
  digitalWrite(PIN_BL, HIGH);
  BlankDisplay();
}


unsigned long previousSRMillis = 0;    // keeping track last time shift register values were clocked in

void loop() {
  boolean srBuffer[128] = {0};
  unsigned long currentMillis = millis();
 
  if (currentMillis - previousSRMillis >= 250) {  // clocking in 4 times a second
   
    previousSRMillis = currentMillis;

    boolean srBuffer[128] = {0};

    // doing the lookups for what number to display then
    // looking up which shift register position
    // for each tube
    // "10" from the lookup table indicates to blank the tube since it is out of range.
   
    srBuffer[dots[1]] = 1; //light up dot 1
    srBuffer[plusminus[1]] = 1; //light up plus
    srBuffer[tube1[1]] = 1; //light up number 1 on tube 1
    srBuffer[tube2[2]] = 1; //light up number 2 on tube 2
    srBuffer[tube3[1]] = 1; //light up number 1 on tube 3
    srBuffer[tube4[2]] = 1; //light up number 2 on tube 4
    srBuffer[tube5[1]] = 1; //light up number 1 on tube 5
    srBuffer[tube6[2]] = 1; //light up number 2 on tube 6
    srBuffer[tube7[1]] = 1; //light up number 1 on tube 7
    srBuffer[tube8[2]] = 1; //light up number 2 on tube 8
    srBuffer[tube9[1]] = 1; //light up number 1 on tube 9
    srBuffer[tube10[2]] = 1; //light up number 2 on tube 10


    digitalWrite(PIN_LE, LOW);

    for(int i = 0; i < 128; i++){
     
      digitalWrite(PIN_DATA,srBuffer[i]);
      digitalWrite(PIN_CLK,HIGH);
      delayMicroseconds(5);
      digitalWrite(PIN_CLK,LOW);
      delayMicroseconds(5);
    }

    digitalWrite(PIN_LE, HIGH);
  }

}


void BlankDisplay()
{
  // Disconnect shift register from data latches:
  digitalWrite(PIN_LE, LOW);


  // Set the data to LOW
  digitalWrite  (PIN_DATA,  LOW);


  //  Clock in the LOW 128 times
  for (uint8_t i = 0; i < 128; i++)
  {
    digitalWrite(PIN_CLK, LOW);   // Clock in one data bit
    digitalWrite(PIN_CLK, HIGH);
  }
}


I get this result:

https://youtu.be/RrND7-T2LgE

I have no idea why this does not work. From what I can tell, I should be shifting in 128 bits, each assigned to the proper register and pin from my physical board layout. There has to be some sort of fundamental mistake I'm not seeing.

johnwasser

The BlankDisplay() seems to work and the clocking there is different in two ways:
  • Put the "digitalWrite(PIN_CLK, LOW);" BEFORE the "digitalWrite(PIN_CLK, HIGH);"
  • I would take out the "delayMicroseconds(5);" calls.




You have two variables named srBuffer[] and the first one (line 67) is not used.  Take out that line.

The "digitalWrite(PIN_LE, HIGH);" at the end of BlankDisplay() is missing.  Please put it back in.
Send Bitcoin tips to: 1G2qoGwMRXx8az71DVP1E81jShxtbSh5Hp

kevina96

Hi guys. Finally, after a lot of sweat and frustration, I've developed a robust code to drive my display. It deals with decimal numbers as well. Essentially, it takes a char array input from the serial port and creates the appropriate 128 bit boolean array which is then clocked out to the 4 HV chips. It was a bit challenging (no pun intended) to deal with decimal numbers, but nevertheless it works! The code is quite long so I'll upload it in a separate message. Lots of it is just bit mapping, but I tried to make it as clear as possible for the sake of my own understanding. Hopefully this will also be useful to someone else one day.

kevina96

See the attached .ino if you are interested; code exceeded post character length (again, not pretty but it works well).

kevina96

#19
Oct 16, 2018, 06:56 am Last Edit: Oct 16, 2018, 06:58 am by kevina96
I'm a firm believer in "seeing is believing": https://youtu.be/Pbq0HJ7vn24

johnwasser

One way to make the code more efficient is to use arrays instead of cascaded 'if' statements:
Code: [Select]
void tube1(char x)
{
  const byte tube1[10] = {25, 26, 28, 31, 27, 23, 29, 22, 24, 30}; // 0 - 9


  if (isDigit(x))
    srBuffer[tube1[x - '0']] = 1;
}


void tube2(char x)
{
  const byte tube2[10] = {38, 37, 35, 32, 36, 40, 34, 41, 39, 33}; // 0 - 9


  if (isDigit(x))
    srBuffer[tube2[x - '0']] = 1;
}


void tube3(char x)
{
  const byte tube3[10] = {45, 46, 48, 51, 47, 43, 49, 42, 44, 50}; // 0 - 9


  if (isDigit(x))
    srBuffer[tube3[x - '0']] = 1;
}


void tube4(char x)
{
  const byte tube4[10] = {55, 56, 58, 61, 57, 53, 59, 52, 54, 60}; // 0 - 9


  if (isDigit(x))
    srBuffer[tube4[x - '0']] = 1;
}


void tube5(char x)
{
  const byte tube5[10] = {70, 69, 67, 64, 68, 72, 66, 73, 71, 65}; // 0 - 9


  if (isDigit(x))
    srBuffer[tube5[x - '0']] = 1;
}


void tube6(char x)
{
  const byte tube6[10] = {77, 78, 80, 83, 79, 75, 81, 74, 76, 82}; // 0 - 9


  if (isDigit(x))
    srBuffer[tube6[x - '0']] = 1;
}


void tube7(char x)
{
  const byte tube7[10] = {87, 88, 90, 93, 89, 85, 91, 84, 86, 92}; // 0 - 9


  if (isDigit(x))
    srBuffer[tube7[x - '0']] = 1;


}


void tube8(char x)
{
  const byte tube8[10] = {102, 101, 99, 96, 100, 104, 98, 105, 103, 97}; // 0 - 9


  if (isDigit(x))
    srBuffer[tube8[x - '0']] = 1;
}


void tube9(char x)
{
  const byte tube9[10] = {109, 110, 112, 115, 111, 107, 113, 106, 108, 114};  // 0 - 9


  if (isDigit(x))
    srBuffer[tube9[x - '0']] = 1;
}


void tube10(char x)
{
  const byte tube10[10] = {119, 120, 122, 125, 121, 117, 123, 116, 118, 124};  // 0 - 9


  if (isDigit(x))
    srBuffer[tube10[x - '0']] = 1;
}



I think this will do the same as your 'numbers' function:
Code: [Select]
void numbers(char x[])
{
  //Read input string and pass output to dot and plus/minus tube


  //Read input string, remove decimal if it exists, and pass output to numberic tubes 1-10
  removeChar(x, '.');


  byte count = strlen(x) - 1;


  switch (count)
  {
    default:   // Length is more
    case 10:    tube10(x[count - 10]);
    case 9:     tube9(x[count - 9]);
    case 8:     tube8(x[count - 8]);
    case 7:     tube7(x[count - 7]);
    case 6:     tube6(x[count - 6]);
    case 5:     tube5(x[count - 5]);
    case 4:     tube4(x[count - 4]);
    case 3:     tube3(x[count - 3]);
    case 2:     tube2(x[count - 2]);
    case 1:     tube1(x[count - 1]);
    case 0:
  }
}
Send Bitcoin tips to: 1G2qoGwMRXx8az71DVP1E81jShxtbSh5Hp

darrob

That's pretty Cool :) I've always loved Nixie tubes.
How happy are you?

kevina96

Thanks again John. I like the streamlined approach. I'll give this a try over the weekend (when I'm home from work travel) and see how it cleans things up.

One way to make the code more efficient is to use arrays instead of cascaded 'if' statements:
Code: [Select]
void tube1(char x)
{
  const byte tube1[10] = {25, 26, 28, 31, 27, 23, 29, 22, 24, 30}; // 0 - 9


  if (isDigit(x))
    srBuffer[tube1[x - '0']] = 1;
}


void tube2(char x)
{
  const byte tube2[10] = {38, 37, 35, 32, 36, 40, 34, 41, 39, 33}; // 0 - 9


  if (isDigit(x))
    srBuffer[tube2[x - '0']] = 1;
}


void tube3(char x)
{
  const byte tube3[10] = {45, 46, 48, 51, 47, 43, 49, 42, 44, 50}; // 0 - 9


  if (isDigit(x))
    srBuffer[tube3[x - '0']] = 1;
}


void tube4(char x)
{
  const byte tube4[10] = {55, 56, 58, 61, 57, 53, 59, 52, 54, 60}; // 0 - 9


  if (isDigit(x))
    srBuffer[tube4[x - '0']] = 1;
}


void tube5(char x)
{
  const byte tube5[10] = {70, 69, 67, 64, 68, 72, 66, 73, 71, 65}; // 0 - 9


  if (isDigit(x))
    srBuffer[tube5[x - '0']] = 1;
}


void tube6(char x)
{
  const byte tube6[10] = {77, 78, 80, 83, 79, 75, 81, 74, 76, 82}; // 0 - 9


  if (isDigit(x))
    srBuffer[tube6[x - '0']] = 1;
}


void tube7(char x)
{
  const byte tube7[10] = {87, 88, 90, 93, 89, 85, 91, 84, 86, 92}; // 0 - 9


  if (isDigit(x))
    srBuffer[tube7[x - '0']] = 1;


}


void tube8(char x)
{
  const byte tube8[10] = {102, 101, 99, 96, 100, 104, 98, 105, 103, 97}; // 0 - 9


  if (isDigit(x))
    srBuffer[tube8[x - '0']] = 1;
}


void tube9(char x)
{
  const byte tube9[10] = {109, 110, 112, 115, 111, 107, 113, 106, 108, 114};  // 0 - 9


  if (isDigit(x))
    srBuffer[tube9[x - '0']] = 1;
}


void tube10(char x)
{
  const byte tube10[10] = {119, 120, 122, 125, 121, 117, 123, 116, 118, 124};  // 0 - 9


  if (isDigit(x))
    srBuffer[tube10[x - '0']] = 1;
}



I think this will do the same as your 'numbers' function:
Code: [Select]
void numbers(char x[])
{
  //Read input string and pass output to dot and plus/minus tube


  //Read input string, remove decimal if it exists, and pass output to numberic tubes 1-10
  removeChar(x, '.');


  byte count = strlen(x) - 1;


  switch (count)
  {
    default:   // Length is more
    case 10:    tube10(x[count - 10]);
    case 9:     tube9(x[count - 9]);
    case 8:     tube8(x[count - 8]);
    case 7:     tube7(x[count - 7]);
    case 6:     tube6(x[count - 6]);
    case 5:     tube5(x[count - 5]);
    case 4:     tube4(x[count - 4]);
    case 3:     tube3(x[count - 3]);
    case 2:     tube2(x[count - 2]);
    case 1:     tube1(x[count - 1]);
    case 0:
  }
}



kevina96

That's pretty Cool :) I've always loved Nixie tubes.
How happy are you?
Very happy :D

It was a huge learning experience to design a board from scratch and make it all happen the way I envisioned. A humbling experience, and it really makes you appreciate the level of technology we take for granted in today's world. I'm looking to make my work bigger and better all the time now!

johnwasser

Very happy :D

It was a huge learning experience to design a board from scratch and make it all happen the way I envisioned. A humbling experience, and it really makes you appreciate the level of technology we take for granted in today's world. I'm looking to make my work bigger and better all the time now!
I must say, the the display looks really cool in the video.
Send Bitcoin tips to: 1G2qoGwMRXx8az71DVP1E81jShxtbSh5Hp

kevina96

I must say, the the display looks really cool in the video.
Thanks John! If you think this was cool, I happened to score 2 nimo tubes on eBay today. Google them; they were mini CRT tubes intended to compete with nixies. Planning on making a 2 tube Nimo clock with an arduino or esp after this! I've also got a pal with more than 2; so I've got some ideas in the works that have never been done before and will look cool as ever. Stay tuned

johnwasser

#26
Oct 18, 2018, 01:37 am Last Edit: Oct 18, 2018, 01:39 am by johnwasser
I've seen NIMO tubes on Fran Blanche's "FranLab" YouTube channel. 

The NIMO Tube: Rarest And Most Dangerous Digital Display Of All Time
https://www.youtube.com/watch?v=xmWg7CtN0Ac

NIMO Tube Shootout! + X-Rays??
https://www.youtube.com/watch?v=fRRgKwwxYjo
Send Bitcoin tips to: 1G2qoGwMRXx8az71DVP1E81jShxtbSh5Hp

kevina96

#27
Oct 20, 2018, 11:00 pm Last Edit: Oct 20, 2018, 11:04 pm by kevina96
I've seen NIMO tubes on Fran Blanche's "FranLab" YouTube channel.  
Look what came in the mail today! I think this will be the first arduino controlled Nimo tube project.



kevina96

Thanks again John. I like the streamlined approach. I'll give this a try over the weekend (when I'm home from work travel) and see how it cleans things up.

Just tried your changes John, they work great and clean things up a bit!

Go Up