4 Digit LED clock, DS1307 RTC and DS18B20 Temperature sensor.

Hi Guys,

I’m relatively new to this and thought I’d share my first useful (sorta) sketch.

I’m building a HUGE LED clock, but so far I’ve only built a small display on a breadboard for testing. I’m working on getting the code done first.

I know a clock isn’t particularly exciting or original, but I wanted to do mine without the use of external driver or decoder ICs. I’ve seen lots of videos on youtube of people driving led displays with these ICs and usually doing a fairly useless count up from 0 to 9999.

I have common anode LED modules, the segment cathodes are driven directly by the arduino IO pins. The anodes are also driven by the arduino but via 4 transistors because the current would overload the arduino pins. (Each segment uses about 20mA.)

The multiplexing and INT > BCD > 7 Segment conversion is all done by the arduino so no external ICs (apart from the RTC and DS18B20 temp sensor).

I bought the RTC module via eBay from Hong Kong and it works a treat, and for less than £5 I’m not complaining.

This is still a work in progress so there’s more to come.

Things it does now:
-4 Digit multiplexing
-Reads time from RTC and displays in 24 hour format.
-Reads temperature from DS18B20 and displays in Celsius every 30 seconds.

Things to come:
-Ability to set the RTC via buttons.
-Make temperature scroll on and off the display (to hide the short blank while temperature is being read).
-Light sensor to turn off display at night.
-LCD module to show date and other info.
-Automatic adjustment for DST.

Here’s a youtube video of it working http://www.youtube.com/watch?v=BuRdddTZRdU&list=UUaTyVrg9zu-nz1CJBfIt6EA&index=1&feature=plcp

I don’t know if anyone will find this useful but I thought i’d post it anyway.

Here’s the code. I haven’t done a circuit diagram yet but will at some point. It’s simple anyway so you should be able to work it out.

#include <DallasTemperature.h> // http://www.milesburton.com/?title=Dallas_Temperature_Control_Library
#include <OneWire.h> // http://www.pjrc.com/teensy/td_libs_OneWire.html
#include <SimpleTimer.h>  // http://www.arduino.cc/playground/Code/SimpleTimer
#include <Wire.h>  //Included with Arduino IDE

#define DS1307_ADDRESS 0x68  //RTC Module Address
#define ONE_WIRE_BUS 14      //DS18B20 temperature sensor connected to analog pin 0.

byte digits[15] = {  //Bit pattern for 7 segment display
// -AFBGEDC            Segments labelled as per datasheet for Kingbright DA56-11EW dual common anode LED display module.
  B10001000,  // 0     1 represents segment OFF, 0 is ON
  B11011011,  // 1     the MSB is not used.
  B10010100,  // 2
  B10010001,  // 3
  B11000011,  // 4
  B10100001,  // 5
  B10100000,  // 6
  B10011011,  // 7
  B10000000,  // 8
  B10000001,  // 9
  B10000111,  // Degree symbol
  B10101100,  // Letter C
  B10100100,  // Letter E
  B10100110,  // Letter F
  B11110111  // - Symbol
};

int anodes[4] = {2,3,4,5};  //Common anodes for 7 segment displays connected to these digital outputs via NPN transistors
                            //Pin 2 is first digit, 3 is second and so on.
int cathodes[7] = {6,7,8,9,10,11,12};  //Cathodes for each segment all tied together and connected to these digital outputs.
                  //Segment to pin assignment
                  //6>C, 7>D, 8>E, 9>G, 10>B, 11>F, 12>A
int data[4];  //4 byte array stores value to be displayed.
int startAddress = 0; //Data start address on the DS1307

byte bcdToDec(byte val)  {
// Convert binary coded decimal to normal decimal numbers
  return ( (val/16*10) + (val%16) );
}

SimpleTimer timer;               //Set up timer instance.
OneWire oneWire(ONE_WIRE_BUS);   //Start the oneWire bus
DallasTemperature sensors(&oneWire);  //Create Dallas Temperature library instance.

void setup()
{
  for (int i = 0; i < 4; i++)  //Set anode pins mode to output and put them LOW.
  {
    pinMode(anodes[i], OUTPUT);
    digitalWrite(anodes[i], LOW);
  }
  
  for (int i = 0; i < 8; i++)  //Set cathode pins mode to output and put them HIGH.
  {
    pinMode(cathodes[i], OUTPUT);
    digitalWrite(cathodes[i], HIGH);
  }
  
  Wire.begin();  // Start the I2C bus.
  
  sensors.begin();  //Start the Dallas Temperature library.
  
  timer.setInterval(30000, showTemp);  //Set to diaplay temperature every 30 seconds.
}



void loop()
{
  readTime();
  outputDisplay(data);
  timer.run();
}  

void outputDigit(int seg)    //Outputs segment data for an individual digit.
{
  for (int s = 0; s < 7; s++)  //Read a bit at a time from the selected digit in the digits array and output it to the correct
  {                            //pin
    boolean bitState = bitRead(digits[seg], s);  //Read the current bit.
    digitalWrite(cathodes[s], bitState);         //and output it.
  }
}

void outputDisplay(int dig[4])        //Scan the display once with the 4 digit int array passed in.
{
  for (int d = 0; d < 4; d++)
  {
  outputDigit(dig[d]);                //Set up the segment pins with the correct data.
  digitalWrite(anodes[d], HIGH);      //Turn on the digit.
  delay(2);                           //Hold it on for 2ms to improve brightness.
  digitalWrite(anodes[d], LOW);       //And turn it off again before looping untl all digits have been displayed.
  }
}

void showTemp()
{
  sensors.requestTemperatures();  //Request temperature from the sensor.
  float temp = (sensors.getTempCByIndex(0));  //Read temperature from the first (only) sensor on the bus.
  int t = (int) temp;                         //Convert the temperature to int for display
  int starttime = millis();                   
  int endtime = starttime;                    //Store the internal timer counter value to make this loop run for a set period.  
  while ((endtime - starttime) <=5000) // do this loop for 5000mS
  {
  data[0] = (t / 10);                  //Calculate and store temperature 10s value
  data[1] = (t % 10);                  //Calculate and store temperature 1s value.
  data[2] = 10;                        //Degree symbol
  data[3] = 11;                        //Letter C for Celcius
  outputDisplay(data);                 //Send to diaplay.
  endtime = millis();                  //Read internal timer counter to see how long this loop has been running.
  }
}

void readTime()
{
    // Reset the register pointer
  Wire.beginTransmission(DS1307_ADDRESS);
  Wire.send(startAddress);
  Wire.endTransmission();

  Wire.requestFrom(DS1307_ADDRESS, 7);

  int second = bcdToDec(Wire.receive());
  int minute = bcdToDec(Wire.receive());
  int hour = bcdToDec(Wire.receive() & 0b111111); //24 hour time
  data[0] = (hour / 10);
  data[1] = (hour % 10);
  data[2] = (minute / 10);
  data[3] = (minute % 10);
}

Nice job. Lot of wires there!

I can't tell - do you have current limit resistors between arduino pins and the segments for the 20mA limit?

Yes, I forgot to mention that. I have a 220 ohm resistor for each segment. The actual current it a bit less than 20mA with that value but it's still bright enough. A 180 ohm resistor would have been more suitable but I didn't have any.

I’ve added the scrolling to help disguise the 750ms delay when reading the temperature.

It actually adds more delays, but I think it looks better.

Here’s a video:

And the code:

#include <DallasTemperature.h> // http://www.milesburton.com/?title=Dallas_Temperature_Control_Library
#include <OneWire.h> // http://www.pjrc.com/teensy/td_libs_OneWire.html
#include <SimpleTimer.h>  // http://www.arduino.cc/playground/Code/SimpleTimer
#include <Wire.h>  //Included with Arduino IDE

#define DS1307_ADDRESS 0x68  //RTC Module Address
#define ONE_WIRE_BUS 14      //DS18B20 temperature sensor connected to analog pin 0.

byte digits[16] = {  //Bit pattern for 7 segment display
// -AFBGEDC            Segments labelled as per datasheet for Kingbright DA56-11EW dual common anode LED display module.
  B10001000,  // 0     1 represents segment OFF, 0 is ON
  B11011011,  // 1     the MSB is not used.
  B10010100,  // 2
  B10010001,  // 3
  B11000011,  // 4
  B10100001,  // 5
  B10100000,  // 6
  B10011011,  // 7
  B10000000,  // 8
  B10000001,  // 9
  B10000111,  // Degree symbol
  B10101100,  // Letter C
  B10100100,  // Letter E
  B10100110,  // Letter F
  B11110111,  // - Symbol
  B11111111   // Blank (OFF)
};

int anodes[4] = {2,3,4,5};  //Common anodes for 7 segment displays connected to these digital outputs via NPN transistors
                            //Pin 2 is first digit, 3 is second and so on.
int cathodes[7] = {6,7,8,9,10,11,12};  //Cathodes for each segment all tied together and connected to these digital outputs.
                  //Segment to pin assignment
                  //6>C, 7>D, 8>E, 9>G, 10>B, 11>F, 12>A
int data[4];  //4 byte array stores value to be displayed.
int startAddress = 0; //Data start address on the DS1307

byte bcdToDec(byte val)  {
// Convert binary coded decimal to normal decimal numbers
  return ( (val/16*10) + (val%16) );
}

SimpleTimer timer;               //Set up timer instance.
OneWire oneWire(ONE_WIRE_BUS);   //Start the oneWire bus
DallasTemperature sensors(&oneWire);  //Create Dallas Temperature library instance.

void setup()
{
  for (int i = 0; i < 4; i++)  //Set anode pins mode to output and put them LOW.
  {
    pinMode(anodes[i], OUTPUT);
    digitalWrite(anodes[i], LOW);
  }
  
  for (int i = 0; i < 8; i++)  //Set cathode pins mode to output and put them HIGH.
  {
    pinMode(cathodes[i], OUTPUT);
    digitalWrite(cathodes[i], HIGH);
  }
  
  Wire.begin();  // Start the I2C bus.
  
  sensors.begin();  //Start the Dallas Temperature library.
  
  timer.setInterval(30000, showTemp);  //Set to diaplay temperature every 30 seconds.
}



void loop()
{
  readTime();
  outputDisplay(data);
  timer.run();
}  

void outputDigit(int seg)    //Outputs segment data for an individual digit.
{
  for (int s = 0; s < 7; s++)  //Read a bit at a time from the selected digit in the digits array and output it to the correct
  {                            //pin
    boolean bitState = bitRead(digits[seg], s);  //Read the current bit.
    digitalWrite(cathodes[s], bitState);         //and output it.
  }
}

void outputDisplay(int dig[4])        //Scan the display once with the 4 digit int array passed in.
{
  for (int d = 0; d < 4; d++)
  {
  outputDigit(dig[d]);                //Set up the segment pins with the correct data.
  digitalWrite(anodes[d], HIGH);      //Turn on the digit.
  delay(2);                           //Hold it on for 2ms to improve brightness.
  digitalWrite(anodes[d], LOW);       //And turn it off again before looping untl all digits have been displayed.
  }
}

void showTemp()
{
  scrollOut(data);
  sensors.requestTemperatures();  //Request temperature from the sensor.
  float temp = (sensors.getTempCByIndex(0));  //Read temperature from the first (only) sensor on the bus.
  int t = (int) temp;                         //Convert the temperature to int for display
  data[0] = (t / 10);                  //Calculate and store temperature 10s value
  data[1] = (t % 10);                  //Calculate and store temperature 1s value.
  data[2] = 10;                        //Degree symbol
  data[3] = 11;                        //Letter C for Celcius
  int starttime = millis();                   
  int endtime = starttime;                    //Store the internal timer counter value to make this loop run for a set period.  
  scrollIn(data);
  while ((endtime - starttime) <=5000) // do this loop for 5000mS
  {
  outputDisplay(data);                 //Send to diaplay.
  endtime = millis();                  //Read internal timer counter to see how long this loop has been running.
  }
  scrollOut(data);
  delay(750);
  readTime();
  scrollIn(data);
}

void readTime()
{
    // Reset the register pointer
  Wire.beginTransmission(DS1307_ADDRESS);
  Wire.send(startAddress);
  Wire.endTransmission();

  Wire.requestFrom(DS1307_ADDRESS, 7);

  int second = bcdToDec(Wire.receive());
  int minute = bcdToDec(Wire.receive());
  int hour = bcdToDec(Wire.receive() & 0b111111); //24 hour time
  data[0] = (hour / 10);
  data[1] = (hour % 10);
  data[2] = (minute / 10);
  data[3] = (minute % 10);
}

void scrollIn(int sDig[4])    //Scrolls data on to the display from blank.
{
  int scrollBuffer[8];        //Stores the entire set of data that will be shifted along the display.
  scrollBuffer[0] = 15;       //15 represents a blank digit.
  scrollBuffer[1] = 15;
  scrollBuffer[2] = 15;
  scrollBuffer[3] = 15;
  scrollBuffer[4] = sDig[0];
  scrollBuffer[5] = sDig[1];
  scrollBuffer[6] = sDig[2];
  scrollBuffer[7] = sDig[3];
  
  for (int st=0; st < 4; st++)  //Loop 4 times and read from next entry in the array each time.
  {
    int sData[4] = {scrollBuffer[(0 + st)], scrollBuffer[(1 + st)], scrollBuffer[(2 + st)], scrollBuffer[(3 + st)]};
    for (int sc=0; sc < 10; sc++)  //Refresh the display 10 times after each shift to give the illusion of scrolling.
    {
      outputDisplay(sData);
    }
  }
}

void scrollOut(int sDig[4])   //Scrolls data off the display to blank
{    
  int scrollBuffer[8];        //Stores the entire set of data that will be shifted along the display.
  scrollBuffer[0] = sDig[0];  
  scrollBuffer[1] = sDig[1];
  scrollBuffer[2] = sDig[2];
  scrollBuffer[3] = sDig[3];
  scrollBuffer[4] = 15;        //15 represents a blank digit.
  scrollBuffer[5] = 15;
  scrollBuffer[6] = 15;
  scrollBuffer[7] = 15;
  
  for (int st=0; st < 4; st++)  //Loop 4 times and read from next entry in the array each time.
  {
    int sData[4] = {scrollBuffer[(0 + st)], scrollBuffer[(1 + st)], scrollBuffer[(2 + st)], scrollBuffer[(3 + st)]};
    for (int sc=0; sc < 10; sc++)  //Refresh the display 10 times after each shift to give the illusion of scrolling.
    {
      outputDisplay(sData);
    }
  }
}

I've received a Samsung VFD Module (Model: 20t202da2ja).

I'm going to be adding this to the project so here is a video of me testing it out.

I used the Adafruid SPI VFD library for this test. I may use it in my project or I might come up with my own, we'll see how lazy I'm feeling.

http://www.youtube.com/watch?v=SezSJd0n0wU

Another little update with testing the VFD.

Once I've tidied up the code I'll post it here.

https://www.youtube.com/watch?v=E1JV6KoSfd4&feature=youtube_gdata_player

"I know a clock isn't particularly exciting or original, but I wanted to do mine without the use of external driver or decoder ICs"

Ah ha! Now you've gone & cheated on your original goals! The new screen does look sharp tho.

good job, I like the VFD