Saving pins for Arduino. Single wire shift register control 74HC595

Whatever you do on the microcontroller, you still end up with a clock. And for projects on Arduino, the weather station is undoubtedly the apogee. And now, having weighed the board with all kinds of sensors, quite often fans of microcontrollers have a problem with a lack of pins.

Typically, to expand the input / output ports use shift registers such as 74HC595. But to control them, it takes three conclusions! Incredible waste, isn’t it? After all, you can do everything ONE! All those for whom two additional free ports are vital, I invite you under cat.


Good idea and bad implementation

Quite by chance, such a toy fell into my hands – a module with four seven-segment indicators from an ampere. The device is a four-digit static seven-segment display based on the 74HC595 shift registers.

By the way, ampere often sins with circuitry, and this module is no exception. That’s probably why it’s been taken off the market a long time ago. It came to me by accident, apparently lying around in warehouse residues, and was sent by mistake.

An interesting circuit for switching the inputs of the module. It is made using two RC circuits at the inputs for clocking and controlling the output latch and allows you to control the outputs of the shift registers with just one wire instead of three. And here lies a couple of nuances, which we will analyze further.

Since the module has not been produced for a long time, it was not easy to find the original circuit. But I also did not want to copy it from the board. And for the analysis it was important to have an exact scheme, so as not to be unfounded.


Immediately there are questions about the connection diagram of the indicators. The current limiting resistors are rated at 220 ohms, this creates an “eye burn” effect and overloads the indicators. Such a current value could be suitable for dynamic indication, but in static the brightness is too high. In the next revisions of the board, the resistors were replaced with 510 Ohm, but for me this is a lot. I replaced them with 620 ohms, with the current for the segment set to about 5mA.

Next, we will deal with the connection of control signals. The clock input 11 of the SHIFR shift register is connected directly to the microcontroller port. Data input 14 “DATA” is connected to the same line through an RC circuit R1C1, the charge time of which is approximately 20-25 µs. The latch control input 12 “LATCH” is connected through the R2C2 RC circuit, which charges in about 250 µs.

The control principle is quite simple. If a very short pulse of about 1 μS is applied to the display input, then the RC chains do not have time to charge, and since the shift register has a sufficiently high speed, the data has time to move into the register. Thus, the duration of the pulse can be controlled by the charge of the capacitors and the required voltage level at the data and latch inputs can be set.


The transfer of a logical unit is carried out by applying a pulse with a duration of approximately 25 μS and a short pause of no more than 1 μS. The pulse will charge the capacitor at the data input to a logic one level, and a short pause will not have time to discharge it. The edge of the next pulse will hit the clock input and write a unit to the register.

To write a logical zero to the shift register, it is necessary, on the contrary, to first give a pause of approximately 30 µS. This will discharge the data input capacitor to logic zero if it was charged in the previous period. And then we give a short pulse of about 1 μS so that its front writes zero to the register.

At the end of the transfer of 24 bits of data to fill 4 shift registers, a pulse of 250 µs duration should be applied to set the latch control signal. The written data will go to the outputs of the shift registers and will be held there until the next edge of the LATCH signal. Now the capacitor should be discharged, for this we set the input of the circuit to a low level for at least 250 μS before submitting new data.

This could have ended, if not for the very nuances in the operation of the circuit. I was alarmed by the fact that RC chains have a charge time difference of only one order of magnitude. From this it turns out that the capacitor at the input of the latch can be fully charged if you apply 10 units in a row. And taking into account the fact that the level of a logical unit for 74NS595 starts from a voltage of 3.15V, it is enough to apply about 6 logical units in a row to fully charge the capacitor.

The circuit uses indicators with a common anode, to disable the segments of which it is necessary to write units at the output of the register. It turns out that when the number 1 is turned on on the indicator, it is necessary to transmit the binary code 11001111, which just contains 6 units.

If you turn on two units in a row on a seven-segment display, then we will just get six pulses in a row, transmitting logical units. This combination has time to charge the capacitor at the input of the LATCH latch. As a result, at the time of updating the display, a short “wink” is observed.


The graphs show that the “LATCH” signal at the shift register latch control input, after the transmission of the first seven-segment unit code, is charged almost to the level of a logical unit. As a result, after each such code transmission cycle for one register, the entire display is updated. This leads to a short-term appearance of “garbage” – the seven-segment code falls into the wrong positions.

If such a circuit controls the indicators, then a short “wink” of the display may not be critical. But this is clearly not suitable for controlling a relay or something like that.

As soon as I did not try to reduce the duration of the high-level pulses and increase the pauses, this glitch could not be completely eliminated.

The problem was solved by replacing the resistor R2 from 33KΩ to 100KΩ. The charge time of the RC chain has increased several times. The indicator began to work better. But still, the difference between the charge time of the data-input capacitors and the latch was not enough to display four units on the display. Yes, and it will not work to include more than four shift registers in a row with such a scheme, because. capacitor C2 can still have time to charge up to the level of a logical unit.

Finalization of the scheme

To finalize the circuit, you need to add one, and preferably two, Schottky diodes. This will accelerate the discharge of capacitor C2 and charge C1. Also, this refinement reduces the overall time required to update the display. Resistors R3R4 are added to limit the discharge current of the capacitors.


If we compare the results of the circuit with diodes (left graph) and without them (right graph), it becomes clear that the pulse edges at the DATA input and the pulse cutoff at the LATCH control input have become much steeper. And, most importantly, the capacitor C2 at the latch control input has time to discharge in a short write pulse. Now you can not deny yourself anything and connect almost any number of shift registers.


The text of the test program was written in CodeVisionAVR. This is an excellent compiler, it works well even on very weak computers. Able to directly upload firmware to Arduino. It has a convenient wizard for automatic configuration of peripherals, as well as a large number of ready-made libraries for various sensors, displays and other things. Working with I / O ports was done directly through registers, which later added a little more fuss. In the hardware, I just finalized the module, cut the tracks a little, added the missing components and jumpers.


Arduino version

An attempt to repeat the same thing in the Arduino IDE led to a crash. The digitalWrite function works very slowly with ports, and it is simply not possible to achieve a pause of less than 1 µs between pulses while maintaining the arduino programming paradigm. The best time is 4µs. In this case, the capacitor C1 has time to discharge to the very border of the logical unit, and the stability of the circuit is still lost.

I assembled the final scheme in Proteus 8.6. Found a library with Arduino models on GitHub. Not the most convenient library, contacts of the virtual model do not fall into the grid. And I had to re-select the ratings of the circuit, at which the operation of the registers would be stable.


The text of the program is as follows. To control registers on a single wire, you can use the “shiftRegisterEntry” function, its input parameters are explained in the comments.

//Выход для управления индикацией

//Массив для хранения семисегментных кодов
#define MAX_DISPL 4
uint8_t displ[MAX_DISPL]=
  //семисегментные коды цифр 1,2,3,4
  {0b10011001, 0b00001101, 0b00100101, 0b10011111};

//Функция для управления сдвиговым регистром по одному проводу
//uint8_t *data - указатель на массив с данными, 
//                которые выводятся в регистр
//uint8_t amount - количество байт для записи в регистр
void shiftRegisterEntry(uint8_t *data, uint8_t amount){
  //перебираем байты, которые нужно записать в регистры
  for(uint8_t num = 0; num < amount; ++num)
    //записываем отдельные биты из каждого байта
    for(uint8_t bitNum = 0; bitNum < 8; ++bitNum){
      //график сигнала для записи логической единицы
        digitalWrite(SERIAL_DATA_PORT, HIGH);
        digitalWrite(SERIAL_DATA_PORT, LOW);
        digitalWrite(SERIAL_DATA_PORT, HIGH);
      //график сигнала для записи логического нуля
        digitalWrite(SERIAL_DATA_PORT, HIGH);
        digitalWrite(SERIAL_DATA_PORT, LOW);
        digitalWrite(SERIAL_DATA_PORT, HIGH);

  //формируем сигнал переключения защелки
  digitalWrite(SERIAL_DATA_PORT, LOW);

void setup() {
  //настройка выхода для управления регистром

void loop() {
  //обновляем дисплей с интервалом 100мС
  shiftRegisterEntry(displ, MAX_DISPL);

Capacitor C1 is charged through an open diode D1 and resistor R3. This provides enough offset between the SHIFT clock and the rising DATA input to write to the logic zero register.


The discharge of the capacitor C1 is carried out through the resistor R1. Its resistance is much higher, and the capacitor does not have time to discharge to the logical unit boundary if the write pulse is produced using the “digitalWrite” function. But the time of full discharge also increases significantly.



The average filling time for four shift registers on one wire on the Arduino was 3ms. This is quite a long time by the standards of the microcontroller. But if you don’t need to update the outputs often, then this method may be quite acceptable.

I can’t say that I’m ready to apply this control method in some of my real projects, but it’s quite suitable for warming up the brain. Although, if you do something on a tiny13 or similar microcontroller, write a program in C and access the port registers directly, the register write time will be reduced by about 4 times … but there are a lot of “ifs”.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *