HEF4094B Shift Registers - Unexpected Output

Hi there!

I've recently started working on a custom spa pool controller, to allow WiFi control of temperatures, blowers, and automatic heating / filtration cycles. The bulk of the project is done at this stage, but I've run into an issue whilst reverse engineering the existing control panel of the spa to integrate with my custom controller.

The control panel has three LEDs, one Bi-Colour LED, and a triple 7-segment display, all of which are controlled by two HEF4094B Shift Registers. I took the time to go through each of the parallel outputs on the shift registers, to figure out which outputs controlled which regions of the display:

U1 - Data wire connected to U2 serial output
--
QP0 - Display segment G
QP1 - Display segment C
QP2 - Display DP
QP3 - Display segment D
QP4 - Display segment B
QP5 - Display segment F
QP6 - Display segment E
QP7 - Display segment A

U2 - Data wire connected to Arduino
--
QP0 - Bi-colour LED (Green)
QP1 - Red LED
QP2 - Yellow LED
QP3 - Bi-colour LED (Red)
QP4 - Green LED
QP5 - Display digit 1 select
QP6 - Display digit 3 select
QP7 - Display digit 2 select

Based on this, I tried a quick test (based on an example found here) to iterate through the outputs on U2, setting an individual bit high every 500ms:

const byte COL_COUNT = 9;
//array to hold the data
unsigned char sequence[COL_COUNT] = {B00000000, B00000001, B00000010, B00000100, B00001000, B00010000, B00100000, B01000000, B10000000};
//unsigned char sequence[COL_COUNT] = {1, 2, 4, 8, 16, 32, 64, 128};
//unsigned char sequence[COL_COUNT] = {0x01, 0x02, 0x04, 0x8, 0x10, 0x20, 0x40, 0x80};
//Define which pins will be used for the shift register control
//can be any digital pin on the Arduino
int latchPin = 8;  //Pin connected to STR(pin 1) of HEF4094
int clockPin = 12; //Pin connected to CP(pin 3) of HEF4094
int dataPin = 11;  //Pin connected to D(pin 2) of HEF4094
 
void setup() {    
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
}
 
void loop() 
{ 
  for (int col = 0; col < COL_COUNT; col++)   
  {
    digitalWrite(latchPin, HIGH); //Pull latch HIGH to send data
    shiftOut(dataPin, clockPin, MSBFIRST, sequence[col]); //Send the data
    digitalWrite(latchPin, LOW); // Pull latch LOW to stop sending data
    delay(500);
  }
}

The output on the display panel after running this example was not as I expected. I did expect the 7-segment displays to output garbage, but I would have expected the LEDs to turn on in the order listed above (i.e QP0, QP1, QP2, QP3 etc). This was instead the output I got, with the input binary listed below each state:

This is my first time using shift registers in a project, and I wonder if I am misunderstanding how they work here. If anyone can figure out why the register is outputting multiple bits high at once, and not setting outputs high in any sort of coherent order, your input would be much appreciated!

Cheers.

Send a single value (i.e. controlled by Serial) and use your DMM to see what are the outputs doing.

1 Like

LEDs (etc.) can be wired to light up on high or low. For 7 segment displays this means common cathode or anode. And a transistor may be inserted as an inverting amplifier for higher current source/sink.

I only can guess that you may have used a wrong pin mapping for the shift register chips.

I'd extend the program to shift out 16 bits, for control of all 16 output pins, and cycle both a single 0 or 1 to find out the polarity of each LED or segment.

1 Like

Aren’t you supposed to flick the latch AFTER you shifted data in?

That doesn't matter for the final output. The latch should be used to suppress changed bits while shifting.

Explain please? The doc sheet says data is presented at outputs on HIGH

From what I see:
The single color LEDs and display segments are active LOW.
The bicolor LED and display digits are active HIGH.
You have the photos in reverse order but otherwise the order matches description.
The sequence is shifted by one: photo marked as 0x01 shows the latch displaying 0x00.

2 Likes

Data is loaded into the output registers on STR HIGH.

If you can’t be bothered to explain what you mean don’t bother to reply to me, please.

Thank you all for your input!

Smajdalf - you were right in saying that the LEDs and display segments are active LOW, and the bicolour LED and display digits are active HIGH. Using this information, and the suggestion from DrDiettrich to extended the program to shift out 16-bits, I am now able to set the state of individual LEDs and write numbers to the display.

I also discovered that interestingly, the second byte I write controls U2, which is the first IC in the chain. The first byte controls U1, which is connected to the serial out of U2.

Using the below code, I turn on all the LEDs (bicolour LED set to red), and write "123" to the display:

int latchPin = 8;  //Pin connected to STR(pin 1) of HEF4094
int clockPin = 12; //Pin connected to CP(pin 3) of HEF4094
int dataPin = 11;  //Pin connected to D(pin 2) of HEF4094
 
void setup() { 
  // Set latch, clock and data pins to output   
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
}
 
void loop() 
{ 
  while ( 1 )   
  {
    // Write the first digit
    digitalWrite(latchPin, HIGH); //Pull latch HIGH to send data
    shiftOut(dataPin, clockPin, MSBFIRST, B11101101); // Select the display segments (1)
    shiftOut(dataPin, clockPin, MSBFIRST, B00111101); // Select the 1st display digit, turn on all LEDs
    digitalWrite(latchPin, LOW); // Pull latch LOW to stop sending data

    // Delay between sending data
    delay(4);

    // Write the second digit
    digitalWrite(latchPin, HIGH); //Pull latch HIGH to send data
    shiftOut(dataPin, clockPin, MSBFIRST, B00100110); // Select the display segments (2)
    shiftOut(dataPin, clockPin, MSBFIRST, B10001000); // Select the 2nd display digit, don't change LED states
    digitalWrite(latchPin, LOW); // Pull latch LOW to stop sending data
    
    delay(4);

    // Write the third digit
    digitalWrite(latchPin, HIGH); //Pull latch HIGH to send data
    shiftOut(dataPin, clockPin, MSBFIRST, B01100100); // Select the display segments (3)
    shiftOut(dataPin, clockPin, MSBFIRST, B01011101); // Select the 2nd display digit, don't change LED states
    digitalWrite(latchPin, LOW); // Pull latch LOW to stop sending data

    // Delay between sending data
    delay(4);
  }
}

Thanks again for everyone's help / advice, very much appreciated :slight_smile:

Maybe you have missed this:

According to the datasheed the data are latched while the latch pin is HIGH. So you are driving the pin in the wrong direction: you should take it LOW before shifting in the new data and drive it HIGH after the shifting is done. (Or simply pulse it for a short period after each shift.) Otherwise you can see flickering of the LEDs during the data transfer.
Since it seems the Latch input is level sensitive (unlike HC595) you can tie it permanently HIGH and free one Arduino pin if you don't mind the flickering.

2 Likes

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.