Tiny RTC module + 7 segment display issue (0000)

hello everyone,
i'm a complete beginner on arduino, and I was trying to make a clock with 4 single digit 7 segment display with common anode with, a tiny RTC module and a 74HC595. I did it like this:

After coding several hours all I can get is 4 "zero" displayed on the 7 segments displays and the 2 LEDs correctly flicking. Here is my code:

// Date and time functions using a DS1307 RTC connected via I2C and Wire lib
#include <Wire.h>
#include <RTClib.h>

// set shift register pins
#define data_pin 13
#define latch_pin 12
#define clock_pin 11

// set digit segments 5V pins
#define d1_pin 1
#define d2_pin 2
#define d3_pin 3
#define d4_pin 4
#define dot_pin 7

#define rotation_cycles 6 // set number of rotation cycles per digit in 'rotation' effect mode
#define mux_delay 3 // set delay between switching display of digits
#define num_digits 10

// define digits, 0 - on, 1 - off
byte segments[10] = {
  0b00000001, // 0
  0b01100111, // 1
  0b00010010, // 2
  0b01000010, // 3
  0b01100100, // 4
  0b01001000, // 5
  0b00001000, // 6
  0b01100011, // 7
  0b00000000, // 8
  0b01000000  // 9
};

byte segments_off = 0b01111111;

// set variables that will keep previous values for minutes and hours to be compared with current values at next run
int prev_minutes = 0;
int prev_hours = 0;
int max_cycles = rotation_cycles * num_digits - 1;
int cycles_remaining = max_cycles; // variable to count remaining cycles for 'rotation' effect
int mod_digit = 0; // digit to be modified during 'rotation'
boolean hide_first_hour = false; // tell the display function whether to show or hide leading zero for hours
boolean first_run = true;
// variables indicating which digit changed
boolean m1_change = false;
boolean h2_change = false;
boolean h1_change = false;

// create RTC object for clock
RTC_DS1307 RTC;


// HELPER FUNCTIONS

// clears digits on display by turning power off
void clearDisplay() {
  digitalWrite(d1_pin, LOW);
  digitalWrite(d2_pin, LOW);
  digitalWrite(d3_pin, LOW);
  digitalWrite(d4_pin, LOW);
}

// display single digit
void displayDigit(int digit_pin, int number) {
  // using shift register to light up required led segments
  digitalWrite(latch_pin, LOW);
  shiftOut(data_pin, clock_pin, LSBFIRST, segments[number]);
  digitalWrite(latch_pin, HIGH);
  // blank display
  clearDisplay();
  // light up required digit
  digitalWrite(digit_pin, HIGH); 
}

// display time
void displayTime(int hours, int minutes) {
  int h1, h2, m1, m2;
  h2 = hours % 10;
  h1 = ((hours % 100) - h1) / 10;
  m2 = minutes % 10;
  m1 = ((minutes % 100) - m1) / 10;
  
  if (hide_first_hour == true) {
    clearDisplay(); // diplay first hour digit only if it is greater than 0
  }
  else
  {
    displayDigit(d1_pin, h1);
  }
  delay(mux_delay);
  displayDigit(d2_pin, h2);
  delay(mux_delay);
  displayDigit(d3_pin, m1);
  delay(mux_delay);
  displayDigit(d4_pin, m2);
  delay(mux_delay);
}

// blink dot
void blinkDot(int seconds) {
  if ( (seconds % 2) == 0 ) {
    clearDisplay();
    digitalWrite(latch_pin, LOW);
    shiftOut(data_pin, clock_pin, LSBFIRST, segments_off);
    digitalWrite(latch_pin, HIGH);
    digitalWrite(d2_pin, HIGH);    
    digitalWrite(dot_pin, LOW);
  } else {
    clearDisplay();
    digitalWrite(dot_pin, HIGH);
  }
  delay(mux_delay);
}

// modify single digit for 'rotation' effect
int modifyDigit(int digit) {
  // int cycle = (cycles_remaining - (cycles_remaining % num_digits)) / rotation_cycles;
  int cycle = cycles_remaining / rotation_cycles;
  digit += (num_digits-cycle-1);
  digit %= 10;
  
  return digit;
}

// modify time for 'rotation' effect
void modifyTime(int *time2display) {
  
  int h2 = time2display[0] % 10;
  int h1 = int(time2display[0] / 10);
  int m2 = time2display[1] % 10;
  int m1 = int(time2display[1] / 10);
  
  // modify digit whose turn it is as determined by mod_digit   
  switch (mod_digit) {
  case 4:
    m2 = modifyDigit(m2); 
    break;
  case 3:
    m1_change = false;
    m1 = modifyDigit(m1);
    break;
  case 2:
    h2_change = false;
    h2 = modifyDigit(h2);
    break;
  case 1:
    h1_change = false;   
    h1 = modifyDigit(h1);
    break;
  default:
    break;
  }
 
  // keep higher digits from changing while lower digits 'rotate' by reducing them by one
  if (mod_digit != 0) {
    if (m1_change == true) {
      m1 = (m1 + 10 - 1) % 10; // add ten before reducing by one to avoid going negative, then get remainder to avoid number higher than ten
      m1 = min(m1, 5); // higher minute digit cannot be greater than 5
    }
    if (h2_change == true) {
      h2 = (h2 + 10 - 1) % 10;
      // set h2 to 2 instead of 9 at midnight
      if (h1_change && h1==0) {
        h2 = min(h2, 2);
      }
    }
    if (h1_change == true) {
      h1 = (h1 + 10 - 1) % 10;
      h1 = min(h1, 2); // higher hour digit cannot be greater than 2
    }
  }   
  
  m2 %= 10;
  m1 %= 10;
  h2 %= 10;
  h1 %= 10;
  
  // modify time array directly as it was passed to this function by reference - nothing to return
  time2display[0] = h1*10 + h2;
  time2display[1] = m1*10 + m2;
}


// MAIN PROGRAM BODY

void setup() {

  // set pin modes
  pinMode(data_pin, OUTPUT);
  pinMode(latch_pin, OUTPUT);
  pinMode(clock_pin, OUTPUT);
  pinMode(d1_pin, OUTPUT);
  pinMode(d2_pin, OUTPUT);
  pinMode(d3_pin, OUTPUT);
  pinMode(d4_pin, OUTPUT);
  pinMode(dot_pin, OUTPUT);
  
  // start connection with clock and the clock itself
  Wire.begin();
  RTC.begin();
  
  // set the clock to current system time - uncomment when need to set time then comment again
  RTC.adjust(DateTime(__DATE__, __TIME__));
}

void loop() {
  
  // read time
  DateTime now = RTC.now();
  int hours = now.hour();
  int minutes = now.minute();
  int seconds = now.second();
  int days = now.day();
  int months = now.month();
  int hours2display, minutes2display;
    
  // check if any of time digits (except lower minutes) changed and if yes mark them as subjected to correction during 'rotation'
  if ( ( int(minutes/10) != int(prev_minutes)/10 ) && !first_run ) {
    m1_change = true;
  }
  if ( ( (hours % 10) != (prev_hours % 10) ) && !first_run ) {
    h2_change = true;
  }
  if ( ( int(hours/10) != int(prev_hours)/10 ) && !first_run ) {
    h1_change = true;
  }
  
  // determine whether to hide or display leading hour digit
  if (hours < 10) {
    hide_first_hour = true; 
  }
  else if (hours == 10 && h1_change == true) {
    hide_first_hour = true;
  }
  else 
  {
    hide_first_hour = false;
  }

    // display time
    displayTime(hours2display, minutes2display);
    blinkDot(seconds); // blink divider dot
  }

I was thinking that this was due to a problem on the RTC, but when I deplug it, LEDs stop flicking, so I assume that this part of code is right, but I really don't understand why it dosen't show anything else than 4 zeros.

I really tried everything I could, but I have no solution, that's why i'm posting here today :frowning:
Anyone got any advice?

Cheers!

Alex

P.S. This is the tiny RTC module i have. Do I have to place a PNP component on it ?

Thanks for answer.

Haven't looked at the code yet.

Your 595 can only provide 6ma sinking per pin you are trying to take 17+ ma.
You should have decoupling on the 595.
Your two leds are not wired correctly.
The Arduino output can source 20ma safely, you are trying to source 7*17=119ma.
You should not use D1 TX, try a different pin.

Is this your code?

Hey, thanks for your answer,

I get the code from a tutorial on fritzing and modified it to fit with my project.

When you say that I should have decoupled on the 595, you mean: I plug the 7 segments on the first one, and all the VCC on the other one to drive them thru the 595 right ?

thanks!

For decoupling, you should have a 100nF capacitor across the VCC to GND pins of the register.

Step back a bit and run a simple sketch that prints the RTC time out to the serial monitor.
This will prove the RTC is OK.

This is an extremely poor cct. for your application as both the Arduino and shift register are being over loaded and can be damaged by this.

Also, as mentioned, do not use D1 as it is the TX pin.

Suggest you use MAX7221/19
http://playground.arduino.cc/Main/MAX72XXHardware

.

See, Connecting a 7-segment LED at Gammon Forum : Electronics : Microprocessors : Interfacing LED displays with the MAX7219 driver

For the moment, I tried a simple sketch to see if the RTC time was printing out the serial monitor and it works. So, the RTC is perfectly clean. Once I plug it with the 4 single 7 segments, it says in the serial monitor that the RTC is not working!

I don't see in your sketch where it can identify the RTC is not working.

Several important design failures have not been addressed.

.

Hello!

Following what you posted, i'll try to do it with a MAX7219 instead of 595.
I learned that MAX7219 is working better with cathode so I plan to buy some 4x 20mm single 7 segment display with common cathode to make it easy.

As you explained about capacitors, and what I read here: Arduino Playground - MAX72XXHardware

I made this sketch:

Due to the number of elements, I want to put a 10K resistor on ISET pin, and I placed the blinking leds (for seconds display) as the fifth digit on the "DIG4".

I also placed, as you said and what i read on playground arduino, a 100n and a 100uf capacitors

Do you think this wire is correct and efficient for this project?
If so, i'll try to do something with the led control library for MAX7219

cheers!
Alex

Here is what I used for a project a while back.
Use SPI to simplify sending data to the 7219.

Edit
D4 is not used
.

Your two LEDs should be in series, I would put them on DP.

.

Sample counting sketch:

//Nick Gammon
#include <SPI.h>
//const byte SS = 10;  // omit this line for Arduino 1.0 onwards

const byte MAX7219_REG_NOOP        = 0x0;
// codes 1 to 8 are digit positions 1 to 8
const byte MAX7219_REG_DECODEMODE  = 0x9;
const byte MAX7219_REG_INTENSITY   = 0xA;
const byte MAX7219_REG_SCANLIMIT   = 0xB;
const byte MAX7219_REG_SHUTDOWN    = 0xC;
const byte MAX7219_REG_DISPLAYTEST = 0xF;

void sendByte (const byte reg, const byte data)
{
  digitalWrite (SS, LOW);
  SPI.transfer (reg);
  SPI.transfer (data);
  digitalWrite (SS, HIGH);
}  // end of sendByte

void setup ()
{
  SPI.begin ();
  sendByte (MAX7219_REG_SCANLIMIT, 3);      // show 4 digits
  sendByte (MAX7219_REG_DECODEMODE, 0xFF);  // use digits (not bit patterns)
  sendByte (MAX7219_REG_DISPLAYTEST, 0);    // no display test
  sendByte (MAX7219_REG_INTENSITY, 7);      // character intensity: range: 0 to 15
  sendByte (MAX7219_REG_SHUTDOWN, 1);       // not in shutdown mode (ie. start it up)
}   // end of setup

void number (const int num)
{

  char buf [5];
  sprintf (buf, "%4i", num);

  // send all 4 digits
  for (byte digit = 0; digit < 4; digit++)
  {
    byte c = buf [digit];
    if (c == ' ' )
      c = 0xF;  // code for a blank
    else
      c -= '0';
    //sendByte (4 - digit, c);
    sendByte (1+ digit, c);
  }
}  // end of number

int i;

void loop ()
{
  number(i++);
  i = i % 10000; // reset at 9999 + 1
  delay (10);
}  // end of loop

Thanks for sharing this!

Ok for series LED as DP
I understand why there's a resistor on pin 18, but why putting a 6.8K on the load pin ?

I followed this schema and it didn't mention this:

Regards,

You only need the 6.8K (pull-down) if your 7219 is on a PCB that can be unplugged from the UNO PCB.

You can omit it if the pins are wired permanently.

Edit:
However, since pins are inputs at power up, the 'load' pin will be floating until made an output.
Better keep the 'load' pin with a pull-down installed.

.