Should I use bitmask to separate bits in a byte ??

Hi,

I´m trying to build a digital clock, using a DS1307 chip and 6 pcs of 7-segment displays to show seconds, minutes and hours. The displays are connected to my arduino via 2pcs of 74HC595. One of the shiftregister handles the common cathode at the displays, the other one handles the segments at the displays. The code to start the DS1307 chip have I found in the forum and is working fine.

:-/My problem is that when the value of seconds, minutes or hours comes up to 10 or more, does the displays flip out totally. I want to separate the lower four bits and the upper bits in each byte (second, minute and hour). I think that bitmask is the correct way of doing this, but I can´t get it running.

Can someone guide me to get this work, because I haven´t found anything helpful about bitmask, that I understand???? :slight_smile:

Another issue, is my 10-hour display is brighter than the rest. Probably because this one is the last in the loop and is light up longer, has someone any good idea??

Here is the code:

// ******************************** Code that someone else has done *******************
#include "Wire.h"

#define DS1307_I2C_ADDRESS 0x68

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

// Convert binary coded decimal to normal decimal numbers
byte bcdToDec(byte val)
{
  return ( (val/16*10) + (val%16) );
}
// 1) Sets the date and time on the ds1307
// 2) Starts the clock
// 3) Sets hour mode to 24 hour clock
// Assumes you're passing in valid numbers
void setDateDs1307
(
byte second,        // 0-59
byte minute,        // 0-59
byte hour,          // 1-23
byte dayOfWeek,     // 1-7
byte dayOfMonth,    // 1-28/29/30/31
byte month,         // 1-12
byte year           // 0-99
)          
{
  Wire.beginTransmission(DS1307_I2C_ADDRESS);
  Wire.send(0);
  Wire.send(decToBcd(second));    // 0 to bit 7 starts the clock
  Wire.send(decToBcd(minute));
  Wire.send(decToBcd(hour));      // If you want 12 hour am/pm you need to set
  // bit 6 (also need to change readDateDs1307)
  Wire.send(decToBcd(dayOfWeek));
  Wire.send(decToBcd(dayOfMonth));
  Wire.send(decToBcd(month));
  Wire.send(decToBcd(year));
  Wire.endTransmission();
}

// Gets the date and time from the ds1307
void getDateDs1307
(byte *second,
byte *minute,
byte *hour,
byte *dayOfWeek,
byte *dayOfMonth,
byte *month,
byte *year)
{
  // Reset the register pointer
  Wire.beginTransmission(DS1307_I2C_ADDRESS);
  Wire.send(0);
  Wire.endTransmission();

  Wire.requestFrom(DS1307_I2C_ADDRESS, 7);

  // A few of these need masks because certain bits are control bits
  *second     = bcdToDec(Wire.receive() & 0x7f);
  *minute     = bcdToDec(Wire.receive());
  *hour       = bcdToDec(Wire.receive() & 0x3f);  // Need to change this if 12 hour am/pm
  *dayOfWeek  = bcdToDec(Wire.receive());
  *dayOfMonth = bcdToDec(Wire.receive());
  *month      = bcdToDec(Wire.receive());
  *year       = bcdToDec(Wire.receive());
}

// ******************************** Code for shiftout numbers at displays *******************
//Pin connected to ST_CP of 74HC595
int latchPin = 8;
//Pin connected to SH_CP of 74HC595
int clockPin = 12;
////Pin connected to DS of 74HC595
int dataPin = 11;

byte Number1S;
byte Number10S;
byte Number1M;
byte Number10M;
byte Number1h;
byte Number10h;
byte numberArray[10];



// ******************************** Code that someone else has done *******************
void setup()
{
  byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
  Wire.begin();
  Serial.begin(9600);

  // Change these values to what you want to set your clock to.
  // You probably only want to set your clock once and then remove
  // the setDateDs1307 call.
  second = 0;
  minute = 2;
  hour = 9;
  dayOfWeek = 6;
  dayOfMonth = 1;
  month = 5;
  year = 10;
  setDateDs1307(second, minute, hour, dayOfWeek, dayOfMonth, month, year);



// ******************************** Code for shiftout numbers at displays *******************
  //set pins to output because they are addressed in the main loop
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
  
  numberArray[0] = 63;  //Value to light up segments showing "0"
  numberArray[1] = 6;   //Value to light up segments showing "1"
  numberArray[2] = 91;  //Value to light up segments showing "2"
  numberArray[3] = 79;  //Value to light up segments showing "3"
  numberArray[4] = 102; //Value to light up segments showing "4"
  numberArray[5] = 109; //Value to light up segments showing "5"
  numberArray[6] = 125; //Value to light up segments showing "6"
  numberArray[7] = 7;   //Value to light up segments showing "7"
  numberArray[8] = 127; //Value to light up segments showing "8"
  numberArray[9] = 111; //Value to light up segments showing "9"
}
void loop()
{
  byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
  getDateDs1307(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year);
  



// ******************************** Code for shiftout numbers at displays *******************
// Show numbers at 1S display

    Number1S = numberArray[second];

    //ground latchPin and hold low for as long as transmitting
    digitalWrite(latchPin, LOW);
    shiftOut(dataPin, clockPin, MSBFIRST, 1);  
    // "1" is the value to show the number at "1 second display"    
    shiftOut(dataPin, clockPin, MSBFIRST, Number1S);
    //Send out value for 1 second digit
    digitalWrite(latchPin, HIGH);
    //delay(20);


// Show numbers at 10S display

    Number10S = numberArray[second/10];

    //ground latchPin and hold low for as long as transmitting
    digitalWrite(latchPin, LOW);
    shiftOut(dataPin, clockPin, MSBFIRST, 2);  
    // "2" is the value to show the number at "10 second display"   
    shiftOut(dataPin, clockPin, MSBFIRST, Number10S);
    //Send out value for 10 second digit
    digitalWrite(latchPin, HIGH);
    //delay(20);

// Show numbers at 1M display

    Number1M = numberArray[minute];

    //ground latchPin and hold low for as long as transmitting
    digitalWrite(latchPin, LOW);
    shiftOut(dataPin, clockPin, MSBFIRST, 4);  
    // "4" is the value to show the number at "1 Minute display"    
    shiftOut(dataPin, clockPin, MSBFIRST, Number1M);
    //Send out value for 1 minute digit
    digitalWrite(latchPin, HIGH);
    //delay(20);



// Show numbers at 10M display

    Number10M = numberArray[minute/10];

    //ground latchPin and hold low for as long as transmitting
    digitalWrite(latchPin, LOW);
    shiftOut(dataPin, clockPin, MSBFIRST, 8);  
    // "8" is the value to show the number at "10 Minute display"   
    shiftOut(dataPin, clockPin, MSBFIRST, Number10M);
    //Send out value for 10 minute digit
    digitalWrite(latchPin, HIGH);
    //delay(20);

// Show numbers at 1h display

    Number1h = numberArray[hour];

    //ground latchPin and hold low for as long as transmitting
    digitalWrite(latchPin, LOW);
    shiftOut(dataPin, clockPin, MSBFIRST, 16);  
    // "16" is the value to show the number at "1 hour display"    
    shiftOut(dataPin, clockPin, MSBFIRST, Number1h);
    //Send out value for 1 hour digit
    digitalWrite(latchPin, HIGH);
    //delay(20);

// Show numbers at 10h display

    Number10h = numberArray[hour/10];

    //ground latchPin and hold low for as long as transmitting
    digitalWrite(latchPin, LOW);
    shiftOut(dataPin, clockPin, MSBFIRST, 32);  
    // "32" is the value to show the number at "10 hour display"    
    shiftOut(dataPin, clockPin, MSBFIRST, Number10h);
    //Send out value for 10 hour digit
    digitalWrite(latchPin, HIGH);
    //delay(20);




}

My problem is that when the value of seconds, minutes or hours comes up to 10 or more, does the displays flip out totally. I want to separate the lower four bits and the upper bits in each byte (second, minute and hour).

The tens value is not the upper 4 bits, with the ones value in the lower 4 bits. So, this is not going to work.

Number1S = numberArray[second % 10];

This will result in an index of 0 to 9, which will most likely solve your problem.

What PaulS is saying is correct, but an even simpler way of dealing with the decimal digits is to leave them as BCD (Binary Coded Decimal), which is what the clock device works in.

Every time you read the clock in "getDateDs1307" you're converting from BCD to decimal; if you just left it as it was, you could simply say:

Number1S = numberArray[second & 0x0F];

Number10S = numberArray[second >> 4]

Thanks Paul!!
Your help was really useful, it worked directly.

Number1S = numberArray[second % 10];

My 10S, 10M and 10h was already working with this code.

   Number10h = numberArray[hour/10];

My question to you is what did the code with [second % 10] ?? What means with the %, is this arduino or C language?

I tested GROOVEs code example, but it didn´t work. the 1s worked just a few seconds, it seems like it didn´t match the numberArray.
The 10S was only shifting from 0 to 1 after 16 seconds, and from 1 to 2 after 32 seconds, and from 2 to 3 after 48 seconds. Strange for me.

Once again thanks for your help! I´m sure that I will be back with more questions :sunglasses:

/Vertol_p

The % operator is the modulo operator. What is means is to return the remainder of the division by the specified value.

If seconds = 42, then seconds/10 returns 4. Seconds divided by 10 is 4 with a remainder of 2, so seconds % 10 returns 2.

I tested GROOVEs code example, but it didn´t work. the 1s worked just a few seconds, it seems like it didn´t match the numberArray.
The 10S was only shifting from 0 to 1 after 16 seconds, and from 1 to 2 after 32 seconds, and from 2 to 3 after 48 seconds.

Did you remove all the BCD to decimal conversion from "getDate?

A BCD value of, say 35 decimal is represented as 0x35, so the shift and mask should work.
If, however, you convert 0x35 to decimal, it is stored as 0x23.
If you try to shift and mask this, it won't work.