0

I have two 74HC595 driving two 7 segment LED displays and I wrote a simple C program to either display a specified number (00-99) from argv or count from 00 to 99.

When specifying a value from the command line, it always works perfectly, even in a loop (edit: actually if I remove the clear from init() then it fails intermittently in a shell loop). However, if I just run with no argv, which make it just count from 00 to 99 with 300ms between iterations, every now an then an led will not be lit, or the DP will be lit. I'm always shifting 8 bits two times so I'm not sure why there would be missing or extra bits.

Example debug out:

cur val: 15
shifting: 109
cur: 0
cur: 1
cur: 1
cur: 0
cur: 1
cur: 1
cur: 0
cur: 1
shifting: 6
cur: 0
cur: 0
cur: 0
cur: 0
cur: 0
cur: 1
cur: 1
cur: 0

In this case the left vertical of the 5 was missing (i.e. the most significant 1 in 109) even though the bits I sent to the DS were correct as show above.

Code:

#include <wiringPi.h>
#include <stdlib.h>
#include <stdio.h>

#define   SDI   0   //serial data input
#define   RCLK  1   //memory clock input(STCP)
#define   SRCLK 2   //shift register clock input(SHCP)

unsigned char SegCode[11] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x00};

void write_to_dual(int value);

void init(void)
{
  pinMode(SDI, OUTPUT); //make P0 output
  pinMode(RCLK, OUTPUT); //make P0 output
  pinMode(SRCLK, OUTPUT); //make P0 output

  write_to_dual(-1);

  digitalWrite(SDI, LOW);
  digitalWrite(RCLK, LOW);
  digitalWrite(SRCLK, LOW);
}

void shift_data()
{
  digitalWrite(SRCLK, HIGH);
  delay(1);
  digitalWrite(SRCLK, LOW);
}

void write_data()
{
  digitalWrite(RCLK, HIGH);
  delay(1);
  digitalWrite(RCLK, LOW);
}

void hc595_shift(unsigned char dat)
{
  int i;
  printf("shifting: %d\n", dat);
  for(i=0;i<8;i++){
    /* unsigned int to_write = (0x80 & (dat << i)); */
    unsigned int to_write = (0x80 & (dat << i)) >> 7;
    printf("cur: %d\n", to_write);
    digitalWrite(SDI, to_write);
    shift_data();
    digitalWrite(SDI, LOW);
  }
}

unsigned char *calc_2byte_base10(int value)
{
  unsigned char *bytes = malloc(2 * sizeof(unsigned char));
  if (value == -1) {
    bytes[0] = 11;
    bytes[1] = 11;
  } else {
    int ones = value % 10;
    int tens = (value / 10) % 10;
    bytes[0] = ones;
    bytes[1] = tens;
  }
  return bytes;
}

void write_to_dual(int value)
{
  unsigned char *bytes;
  bytes = calc_2byte_base10(value);
  hc595_shift(SegCode[bytes[0]]);
  hc595_shift(SegCode[bytes[1]]);
  write_data();
  free(bytes);
}

int main(int argc, char **argv)
{
  int i;

  if(wiringPiSetup() == -1){
    printf("setup wiringPi failed !");
    return 1;
  }

  init();

  if (argc > 1) {
    int value = atoi(argv[1]);
    write_to_dual(value);
  } else {
    int i;
    for (i = 0; i < 100; i++) {
      printf("cur val: %d\n", i);
      write_to_dual(i);
      delay(600);
    }
  }

  return 0;
}

Given that it works if I run it on individual values (init() clears the two displays) or if I add write_to_dual(-1); at the end of every loop iteration, it works fine, it seems that not clearing the displays is somehow leaving some cruft or something. Is anyone seeing anything obvious in this code (largely borrowed from the Sunfounder source (https://github.com/sunfounder/Sunfounder_SuperKit_C_code_for_RaspberryPi/blob/master/11_Segment/segment1.c) or could one of the shift registers be busted?

EDIT: if I remove write_to_dual(-1); from init() then I do get intermittent issues whether it be individual invocations or in a shell loop. It must be the code.

4
  • Are you powering the chip from 3V3 or 5V. I think there may be problems if you use 5V as the Pi's 3V3 GPIO won't be reliably seen as low/high.
    – joan
    Commented Dec 16, 2016 at 9:32
  • Ahhh yes, the shift registers are powered by 5V. I'll try 3.3 tonight, thanks.
    – jshort
    Commented Dec 16, 2016 at 16:41
  • That was it, thanks! I suppose I can use a resistor less than 1kOhm with 3.3V because the LEDs were much more dim.
    – jshort
    Commented Dec 17, 2016 at 3:53
  • Yes, you will need to use a smaller resistor for the same brightness for LEDs.
    – joan
    Commented Dec 17, 2016 at 9:00

1 Answer 1

1

As Joan pointed out, I should use 3.3V input to the 74HC595 instead of 5V like the Sunfounder documentation mentioned. The same code resulted in no missed LEDs in the fast counting (without the need of zeroing out all 16 outputs).

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.