Compound bitwise OR confusion

I nicked this sketch off a posted Nixie clock project here and changed a few things to adapt to my situation. I am driving 3 IN-1 tubes with HV5622 register and Uno controller. I want the program to one day call a single digit on each tube for time display. Someday I'll achieve this once my understanding improves.

My confusion lies in the x=x|y of the sketch at Var32|= in the doIndication() function.
Does this mean Var32=(Var32)|(ARRAY(N))? If so Var32 is always set to zero?

I've tried drawing out the 32 bits on paper according to 1st compound bitwise OR an relate it to the register pins and have not been successful.

Using the String toDisplay of 999 and 888 works on two of three tubes. The non-correct-displaying tube cycles between 0 and 1. I've tried to wrap my mind around it but cannot at this time. What am I missing to have the last tube display the correct number?

#include <SPI.h>
#define latchPin 10
String toDisplay="000";
//NX digit 2 display[ 1 ,  2 ,  3 ,  4 ,  5  ,  6  ,  7  ,  8  ,   9  ,   0  ]
uint32_t Symbol[10]={0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80, 0x100, 0x200};
void setup() {
  Serial.begin(9600);
  Serial.println(F("Starting"));
  pinMode(latchPin, OUTPUT);
  SPI.begin();
  SPI.setDataMode(SPI_MODE2);
  SPI.setClockDivider(SPI_CLOCK_DIV4); 
}

void loop() {
  toDisplay="888";
  Serial.println(toDisplay);
  doIndication();
  delay(3000);
  toDisplay="999";
  Serial.println(toDisplay);
  doIndication();
  delay(3000);
}
void doIndication()
{
  digitalWrite(latchPin, LOW);
  uint32_t Var32;
  uint32_t digits=toDisplay.toInt();
  Var32=0;
  Var32|=(uint32_t)(Symbol[digits/100])<<20;  //NX3 this one is correct
  digits=digits/10;
  Var32|=(uint32_t)(Symbol[digits/10])<<10;  //NX2 this one is correct
  digits=digits/10;
  Var32|=(uint32_t)(Symbol[digits]); //NX1 this one in incorrect
  //digits=digits/10; Has no effect as original code drives 6 tubes.
  SPI.transfer(Var32>>24);
  SPI.transfer(Var32>>16);
  SPI.transfer(Var32>>8);
  SPI.transfer(Var32);
  digitalWrite(latchPin, HIGH);
}

My confusion lies in the x=x|y of the sketch at Var32|= in the doIndication() function.
Does this mean Var32=(Var32)|(ARRAY(N))?
If so Var32 is always set to zero?

Exactly, although I don’t understand why you thing this results in zero?

I think you need to look at the truth table for bitwise OR...
0 | 0 = 0
0 | 1 = 1
1 | 0 = 1
1 | 1 = 1

Edit: also you maths for getting the digits looks completed borked to me...

   Var32|=(uint32_t)(Symbol[digits/100])<<20;  //NX3 this one is correct
  digits=digits/10;
  Var32|=(uint32_t)(Symbol[digits/10])<<10;  //NX2 this one is correct
  digits=digits/10;
  Var32|=(uint32_t)(Symbol[digits]); //NX1 this one in incorrect

Presumably this is meant to get hundreds, tens and units, but I can’t see how it gets anything other than the hundreds. Although I can’t see why it’s getting the last digit wrong. Try...

int huns = (digits / 100) % 10;
int tens = (digits / 10) % 10;
int unit = digits % 10;

pcbbc:
Exactly, although I don’t understand why you thing this results in zero?

I think you need to look at the truth table for bitwise OR...
0 | 0 = 0
0 | 1 = 1
1 | 0 = 1
1 | 1 = 1

Not the result of the compound bitwise OR of Var32 equaling zero. The insertion of Var32(uint32_t) into the bitwise OR being zero in the start of each calculation, is that always zero. The result for Var32 is going to be some binary number. Does that mean the result of the first calculation of Var32 is now passed to the next calculation?

pcbbc:
Edit: also you maths for getting the digits looks completed borked to me...

   Var32|=(uint32_t)(Symbol[digits/100])<<20;  //NX3 this one is correct

digits=digits/10;
 Var32|=(uint32_t)(Symbol[digits/10])<<10;  //NX2 this one is correct
 digits=digits/10;
 Var32|=(uint32_t)(Symbol[digits]); //NX1 this one in incorrect




Presumably this is meant to get hundreds, tens and units, but I can’t see how it gets anything other than the hundreds. Although I can’t see why it’s getting the last digit wrong. Try...


int huns = (digits / 100) % 10;
int tens = (digits / 10) % 10;
int unit = digits % 10;

Here is where I got the original sketch. Original
I used that person’s code with the first calculation being /10. I had really strange results. So I took 888 and divided it by 10 which it will return 88. I thought that can’t be right, so I divided it by 100 to return an 8.

goldbrick_gangboss:
Not the result of the compound bitwise OR of Var32 equaling zero. The insertion of Var32(uint32_t) into the bitwise OR being zero in the start of each calculation, is that always zero.

When you use a compount operator like '+=' or '|=' it is just a shorthand notation for writing var = var | var2.

This does not mean that the initial var is zero. It means you take the current value of 'var' bitwise OR it with var2 and store that result back into var.

goldbrick_gangboss:
The insertion of Var32(uint32_t) into the bitwise OR being zero in the start of each calculation, is that always zero.

No, it’s whatever the current value of Var32 was before the statement executed exactly as you described...

Var32=(Var32)|(ARRAY(N));

Here is where I got the original sketch. Original
I used that person’s code with the first calculation being /10. I had really strange results. So I took 888 and divided it by 10 which it will return 88. I thought that can’t be right, so I divided it by 100 to return an 8.

Their code is here...

Var32=0;
 
  Var32|=(unsigned long)(SymbolArray[digits%10])<<20; // s2
  digits=digits/10;

  Var32|=(unsigned long)(SymbolArray[digits%10])<<10; //s1
  digits=digits/10;

  Var32|=(unsigned long) (SymbolArray[digits%10]); //m2
  digits=digits/10;

As you can see it (correctly) uses the modulo operator (%) to get the remainder after dividing by 10 each step.

In the code you posted you have replaced the modulo operator with a divide for some reason. Why?

Perhaps you don’t understand modulo, or you just made a mistake. Regardless it has completely changed the meaning of that code.

888 is really bad choice of test data. You have no idea if the individual digits being output are obtained from the correct position, or even output in the correct order.

pcbbc:
No, it’s whatever the current value of Var32 was before the statement executed exactly as you described...

Var32=(Var32)|(ARRAY(N));

Their code is here...

Var32=0;

Var32|=(unsigned long)(SymbolArray[digits%10])<<20; // s2
  digits=digits/10;

Var32|=(unsigned long)(SymbolArray[digits%10])<<10; //s1
  digits=digits/10;

Var32|=(unsigned long) (SymbolArray[digits%10]); //m2
  digits=digits/10;



As you can see it (correctly) uses the modulo operator (%) to get the remainder after dividing by 10 each step.

In the code you posted you have replaced the modulo operator with a divide for some reason. Why?

Perhaps you don’t understand modulo, or you just made a mistake. Regardless it has completely changed the meaning of that code.

888 is really bad choice of test data. You have no idea if the individual digits being output are obtained from the correct position, or even output in the correct order.

Okay thank you both for the input. The operator (%) only returns the remainder correct? For example 123/10 will return 3.

goldbrick_gangboss:
Okay thank you both for the input. The operator (%) only returns the remainder correct? For example 123/10 will return 3.

I guess you mean :
For example 123%10 will return 3.

Nixie projects always fascinate me. The IN-18 tubes in that project you found are great. I’ve built a couple of clocks using the smaller front facing IN-12 tubes, one of which I published here:
https://forum.arduino.cc/index.php?topic=668279.0

I’ll also look seriously at the HV5122 32 bit low side high voltage driver chip for my next project.

6v6gt:
I guess you mean :
For example 123%10 will return 3.

Nixie projects always fascinate me. The IN-18 tubes in that project you found are great. I’ve built a couple of clocks using the smaller front facing IN-12 tubes, one of which I published here:
Six Digit Nixie Clock - Exhibition / Gallery - Arduino Forum

I’ll also look seriously at the HV5122 32 bit low side high voltage driver chip for my next project.

Yes my mistake. IN18 tubes are becoming more hard to find. I managed to gather a large number of IN1 tubes. Once I learn how to work with the Arduino I want to create an IV11 clock too.

I love gas tubes. I only wish I had the time to play with them. At one time I owned a National frequency counter, using a Nixie display. Things I regret throwing away...

aarg:
I love gas tubes. I only wish I had the time to play with them. At one time I owned a National frequency counter, using a Nixie display. Things I regret throwing away...

Ouch.

So I may have had an epiphany. Is it possible that the sketch is not ever calling the 0x1 in my array because the programming calls the second element in my array? Meaning the machine thinks that the array is written from 0 to 9 with the logical #1 being 0x2? I hope that makes sense I am not sure how to word my question for certain.

If I write my array as such will this make it better?

uint32_t Symbol[11]={0x0, 0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80, 0x100, 0x200}

If my String is set to “123” then it does 123%10, I get remainder of 3 which is calling 0x8 from the array yes? It takes 0x8 compares it to Var32, returns the OR’d value then bit shifts left 20 bits. I think I am losing sight of when the bit shifting occurs. In mathematics you perform everything in parenthesis or brackets first then do the things outside of the brackets. Is this not the case with the programming language?

goldbrick_gangboss:
Ouch.

So I may have had an epiphany. Is it possible that the sketch is not ever calling the 0x1 in my array because the programming calls the second element in my array? Meaning the machine thinks that the array is written from 0 to 9 with the logical #1 being 0x2? I hope that makes sense I am not sure how to word my question for certain.

If I write my array as such will this make it better?

uint32_t Symbol[11]={0x0, 0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80, 0x100, 0x200}

Yes, arrays are indexed from zero.

That means your original array had indexes 0..9.
Symbol[0] would get the value 0x01
Symbol[9] would get the value 0x200
That is correct.

The % 10 modulo operator returns a number in the range 0 to 9. Your new array won’t work with that because the indexes of your new array are 0..10, and index 0 isn’t populated but will be used.

Sorry pcbbc I was editing the previous post.

You appear, from the comments, to have a problem with only one tube.
Is it displaying an unexpected digit ? Anyway, you have to explain exactly what you mean by this:

"//NX1 this one in incorrect"

If only digit is incorrect, there is probably a wiring error if the other digits work.
Even if there is a wiring error (between the shift register and the "faulty" tube), it can probably be corrected by a mapping in software.

6v6gt:
You appear, from the comments, to have a problem with only one tube.
Is it displaying an unexpected digit ? Anyway, you have to explain exactly what you mean by this:

"//NX1 this one in incorrect"

If only digit is incorrect, there is probably a wiring error if the other digits work.
Even if there is a wiring error (between the shift register and the "faulty" tube), it can probably be corrected by a mapping in software.

I’ll go plug everything in and report back, I will also revise the sketch and post it. Stay tuned for an update.

goldbrick_gangboss:
Sorry pcbbc I was editing the previous post.

No the OR occurs last.

Compound operators always do everything on the right first, according to usual operator/bracket precedence.
Then finally the compound operation (in this case the OR operation) last on the value of the original variable:

//This...
Variable <op>= <expression>;
//Equivalent of...
Variable = Variable <op> ( <expression> );

1.Get the value from the array (element index 0..9 depending on the result of the modulo operator)
2. Cast that value to an unsigned long (actually it already is one as the array is uint32_t which IS same as unsigned long on most Arduino, but anyway)
3. Shift that number left by 20 bits
4. Or the shifted result into whatever the current value of Var32 is

I echo what 6v6gt says. If this is effecting only one of your tubes, then it’s a wiring problem. The code as presented on the website is 100% correct. It doesn’t require modification.

Got it pcbbc. Order of operations does follow mathematics.

Here is the link to my schematic. It may help clear some confusion when I refer to NX1, NX2, and NX3.
Schematic

Here is the revised code.

#include <SPI.h>
#define latchPin 10
String toDisplay="000";
//NX digit 2 display[ 1 ,  2 ,  3 ,  4 ,  5  ,  6  ,  7  ,  8  ,   9  ,   0  ]
uint32_t Symbol[10]={0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80, 0x100, 0x200};
void setup() {
  Serial.begin(9600);
  Serial.println(F("Starting"));
  pinMode(latchPin, OUTPUT);
  SPI.begin();
  SPI.setDataMode(SPI_MODE2);
  SPI.setClockDivider(SPI_CLOCK_DIV4); 
}

void loop() {
  toDisplay="123";
  Serial.println(toDisplay);
  doIndication();
  delay(3000);
  toDisplay="321";
  Serial.println(toDisplay);
  doIndication();
  delay(3000);
}
void doIndication()
{
  digitalWrite(latchPin, LOW);
  uint32_t Var32;
  uint32_t digits=toDisplay.toInt();
  Var32=0;
  Var32|=(uint32_t)(Symbol[digits%10])<<20;
  digits=digits/10;
  Var32|=(uint32_t)(Symbol[digits/10])<<10; 
  digits=digits/10;
  Var32|=(uint32_t)(Symbol[digits%10]);
  digits=digits/10;
  SPI.transfer(Var32>>24);
  SPI.transfer(Var32>>16);
  SPI.transfer(Var32>>8);
  SPI.transfer(Var32);
  digitalWrite(latchPin, HIGH);
}

When the Arduino is sending the String "123" I am getting this as an output on the nixies.
NX1 = 2
NX2 = 1
NX3 = 3
Then when it sends String "321"
NX1 = 4
NX2 = 3
NX3 = 1
My commenting in the original post of the sketch is quite possibly incorrect of labeling NX1-NX3. I had commented out those sections of the function and noted which tube was no longer displaying anything, hence why I labeled them as such in the original post sketch.
I've double checked the wiring, and it's as the schematic shows. This wiring is the same as I did for scrolling the numbers with an array. As reference here is that code.

#define NUM_LEADS    31
int clockPin = 0;
int latchPin = 1;
int dataPin = 2;
uint32_t sequence[31] = {0x1,    0x2,    0x4,    0x8,   0x10,   0x20,   0x40,   0x80,   0x100,   0x200,
                         0x400,  0x800,  0x1000,  0x2000, 0x4000,  0x8000,  0x10000,  0x20000,  0x40000, 0x80000,
                         0x100000,   0x200000,  0x400000,  0x800000,  0x1000000,  0x2000000,  0x4000000, 0x8000000, 0x10000000, 0x20000000,
                         0x40000000};


void setup() {
  pinMode(clockPin, OUTPUT);
  pinMode(latchPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
}

void loop() {
  for (int i = 0; i < NUM_LEADS; i++)
  {
    digitalWrite(latchPin, LOW);
    shiftOut(dataPin, clockPin, MSBFIRST, sequence[i] >> 24);
    shiftOut(dataPin, clockPin, MSBFIRST, sequence[i] >> 16);
    shiftOut(dataPin, clockPin, MSBFIRST, sequence[i] >> 8);
    shiftOut(dataPin, clockPin, MSBFIRST, sequence[i]);
    digitalWrite(latchPin, HIGH);
    delay(100);
  }
}

It worked fine other than I had to give 31 as input or it would cut off a single digit in the last nixie tube.

Edit: I think I may have worked it out why. I skipped pin 7/HVOUT 11 on the register. The shift needs to happen one more due to this. Not 100% sure just a thought

Another Edit: So I realized I did not use % in the second bitwise OR expression. I changed that from / to %. It was still doing what I said above with each NX. I then added >>1 on the last Var32 expression and it works! Never being satisfied of it's working I will be drawing out the 32 bits on paper as I want to understand why it's working.

Var32|=(uint32_t)(Symbol[digits%10])<<20;  //NX3
  digits=digits/10;
  Var32|=(uint32_t)(Symbol[digits%10])<<10;  //NX2
  digits=digits/10;
  Var32|=(uint32_t)(Symbol[digits%10]>>1); //NX1
  //digits=digits/10;

That right shift will mean digit 0 won’t work. The entry 0x01 at index 0 of the array will be shifted right one bit and become 0x00.

Edit: We don’t have access rights to your google docs to view your schematic.
Please add as an attachment so we can all see it.

If you want to really understand the difference between these:

  a += b ;

  a = a + b ;

Then you need to substitute something with side-effects for a, such as:

  *p++ += b ;
  *p++ = *p++ + b ;

// or

  *func() += b ;
  *func() = *func() + b ;   // func() returns a pointer...

They are not the same when side effects are involved, but then you always need to take
care in that situation...

To get technical = and += and such operators take an Lvalue and an Rvalue, whereas + takes 2 Rvalues.
Lvalues have to be variables - an Lvalue is basically the high-level view of a memory address.

I think I may have worked it out why. I skipped pin 7/HVOUT 11 on the register. The shift needs to happen one more due to this. Not 100% sure just a thought

Well, that will explain some strange behavior.
That shift register has 32 positions. You need 30 positions for 3 digits. So the whole thing will have slipped from a certain point. If you mix up pins, it will be possible to correct in software with an intermediate mapping table or a special function.

You must also change your testing routine so you systematically change the first digit, going through from 0 to 9, then the second, then the third. However, at the moment, that is likely to yield chaotic results because of the error.

Apologies on schematic thought I had made it public. It should work now.

I’ll attach later as I am responding from iPhone.

It sounds like I need to dig deeper and learn some other techniques. Baby steps for now.

NX Tester Counter (1).pdf (68 KB)