608Views9Replies

Author Options:

Problem in arduino code... you'll have to run this one to understand - Word Clock? Answered

I have been writing this code for the Word clock. I am trying to customize the code to fit into an atmega8, and use DS1307 RTC. Both of these is fine, but what is wrong is that when I upload my code and try to set the time by using the buttons, the time is not setting properly. I can increment minutes with the minutes button to 16, but not further. Hours works fine, but if, lets say the time is 6:36 on the arduino, then If I press the hour button, I find that time changes to 7:31. Five minutes less than what I expected.
What am I overlooking here? 
I advise to run the code and understand the problem.

On the other hand Binary sketch size: 7164 bytes (of a 7168 byte maximum), this is just 4 bytes short of max. Can that be a part of the problem

Code:

#include <Wire.h>

// Display output pin assignments
#define MTEN  Display1=Display1 | (1<<0) 
#define HALF Display1=Display1 | (1<<1)
#define QUARTER Display1=Display1 | (1<<2)
#define TWENTY Display1=Display1 | (1<<3)
#define MFIVE Display1=Display1 | (1<<4)
#define MINUTES Display1=Display1 | (1<<5)
#define PAST Display1=Display1 | (1<<6)
#define UNUSED1 Display1=Display1 | (1<<7)

#define TO Display2=Display2 | (1<<0)
#define ONE Display2=Display2 | (1<<1)
#define TWO Display2=Display2 | (1<<2)
#define THREE Display2=Display2 | (1<<3)
#define FOUR Display2=Display2 | (1<<4)
#define HFIVE Display2=Display2 | (1<<5)
#define SIX Display2=Display2 | (1<<6)
#define UNUSED2 Display2=Display2 | (1<<7)

#define SEVEN Display3=Display3 | (1<<0)
#define EIGHT Display3=Display3 | (1<<1)
#define NINE Display3=Display3 | (1<<2)
#define HTEN Display3=Display3 | (1<<3)
#define ELEVEN Display3=Display3 | (1<<4)
#define TWELVE Display3=Display3 | (1<<5)
#define OCLOCK  Display3=Display3 | (1<<6)
#define UNUSED3 Display3=Display3 | (1<<7)

#define DS1307_I2C_ADDRESS 0x68  // This is the I2C address
#if defined(ARDUINO) && ARDUINO >= 100   // Arduino v1.0 and newer
  #define I2C_WRITE Wire.write
  #define I2C_READ Wire.read
#else                                   // Arduino Prior to v1.0
  #define I2C_WRITE Wire.send
  #define I2C_READ Wire.receive
#endif


int  hr=12, mn=00, scnd=0;
static unsigned long msTick =0;  // the number of Millisecond Ticks since we last
                                 // incremented the second counter
int  count;
boolean selftestmode;
boolean  DS1307Present=false;       // flag to indicate that the 1307 is there..    1 = present
char Display1=0, Display2=0, Display3=0;

// hardware constants
static unsigned int LEDClockPin=5;    //11 d5 ok
static unsigned int LEDDataPin=3;    //5 d3
static unsigned int LEDStrobePin=4;   //6 d4

static unsigned int MinuteButtonPin=6;  //d6 12
static unsigned int HourButtonPin=7;    //d7 13
static unsigned int PWMPin = 11;

char buf[50]; // time output string for debugging

byte decToBcd(byte b)
{  return ( ((b/10) << 4) + (b%10) );}

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

void getTime()
{
  //read from chip and store in hr, mn, scnd
  Wire.beginTransmission(DS1307_I2C_ADDRESS);
  I2C_WRITE((uint8_t) 0x00);
  Wire.endTransmission();
 
  Wire.requestFrom(DS1307_I2C_ADDRESS, 3);
  scnd = bcdToDec(I2C_READ());
  mn =  bcdToDec(I2C_READ());
  hr =  bcdToDec(I2C_READ());
}
void setTime()
{
  //to be paranoid, we're going to first stop the clock
  //to ensure we don't have rollovers while we're
  //writing:
  writeRTCreg(0,0x80);
  //now, we'll write everything *except* the second
  Wire.beginTransmission(DS1307_I2C_ADDRESS);
  I2C_WRITE((uint8_t) 0x01);
  I2C_WRITE(mn);
  I2C_WRITE(hr);

  Wire.endTransmission();
  //now, we'll write the seconds; we didn't have to keep
  //track of whether the clock was already running, because
  //scnd already knows what we want it to be. This
  //will restart the clock as it writes the new seconds value.
  writeRTCreg(0,scnd);
}
byte readRTCreg(byte adr)
{
   if(adr > 0x3F) { return 0xff; }
  Wire.beginTransmission(DS1307_I2C_ADDRESS);
  I2C_WRITE(adr);
  Wire.endTransmission();
  Wire.requestFrom(DS1307_I2C_ADDRESS, 1);
  return I2C_READ();
}
void writeRTCreg(byte adr, byte val)
{
if(adr > 0x3F) { return; }
   Wire.beginTransmission(DS1307_I2C_ADDRESS);
   I2C_WRITE(adr);
   I2C_WRITE(val);
   Wire.endTransmission();
}

void print_DS1307time()
{
  /* Format the time and date and insert into the temporary buffer */
  snprintf(buf, sizeof(buf), "RTC time: %02d:%02d:%02d",
  hr, mn, scnd);

  /* Print the formatted string to serial so we can see the time */
  Serial.println(buf);

}

void setup()
{
  // initialise the hardware
  // initialize the appropriate pins as outputs:
  pinMode(LEDClockPin, OUTPUT);
  pinMode(LEDDataPin, OUTPUT);
  pinMode(LEDStrobePin, OUTPUT);
 
 
  //pinMode(BrightnessPin, INPUT);
  pinMode(MinuteButtonPin, INPUT);
  pinMode(HourButtonPin, INPUT);
  digitalWrite(MinuteButtonPin, HIGH);  //set internal pullup
  digitalWrite(HourButtonPin, HIGH); //set internal pullup


  pinMode(PWMPin, OUTPUT);
 
  Serial.begin(9600);
  Wire.begin();
   // test whether the DS1302 is there
  Serial.print("Verifying DS1307 ");
  // start by verifying that the chip has a valid signature
  if (readRTCreg(0x20) == 0x55) {
    // Signature is there - set the present flag and mmove on
    DS1307Present=true;
    Serial.println("Valid Signature");
  }
  else
  {
    // Signature isnt there - may be a new chip -
    //   do a write to see if it will hold the signature
    writeRTCreg(0x20,0x55);
    if (readRTCreg(0x20) == 0x55) {
      // We can store data - assume that it is a new chip that needs initialisation
/*      // Start by clearing the clock halt flag.
          //"Bit 7 of register 0 is the clock halt (CH) bit.
          //When this bit is set to a 1, the oscillator is disabled."
            byte _reg0_sec = decToBcd(scnd);
            _reg0_sec = _reg0_sec & ~0x80;
            writeRTCreg(0,_reg0_sec);
*/
      // Set the time and date on the chip
      scnd = 0;
      mn = 0;
      hr = 12;
      setTime();
      // set the DS1302 present flag
      DS1307Present=true;
      Serial.println("present - new chip initialised.");
    }
    else  Serial.println("absent");
  } 


  msTick=millis();      // Initialise the msTick counter
    selftest();
  selftestmode=false;

  if (DS1307Present) {
    // Get the current time and date from the chip
   getTime();
    }
 
  displaytime();        // display the current time
}



void ledsoff(void) {
Display1=0;
Display2=0;
Display3=0;
}

void WriteLEDs(void) {
// Now we write the actual values to the hardware
shiftOut(LEDDataPin, LEDClockPin, MSBFIRST, Display3);
shiftOut(LEDDataPin, LEDClockPin, MSBFIRST, Display2);
shiftOut(LEDDataPin, LEDClockPin, MSBFIRST, Display1);
digitalWrite(LEDStrobePin,HIGH);
delay(2);
digitalWrite(LEDStrobePin,LOW);


}

void selftest(void){
  Serial.print("TEST");
  analogWrite(PWMPin, 255);
 
  ledsoff(); MTEN; WriteLEDs(); delay(500);
  ledsoff(); HALF; WriteLEDs(); delay(500);
  ledsoff(); QUARTER; WriteLEDs(); delay(500);
  ledsoff(); TWENTY; WriteLEDs(); delay(500);
  ledsoff(); MFIVE; WriteLEDs(); delay(500);
  ledsoff(); MINUTES; WriteLEDs(); delay(500);
  ledsoff(); PAST; WriteLEDs(); delay(500);
  ledsoff(); TO; WriteLEDs(); delay(500);
  ledsoff(); ONE; WriteLEDs(); delay(500);
  ledsoff(); TWO; WriteLEDs(); delay(500);
  ledsoff(); THREE; WriteLEDs(); delay(500);
  ledsoff(); FOUR; WriteLEDs(); delay(500);
  ledsoff(); HFIVE; WriteLEDs(); delay(500);
  ledsoff(); SIX; WriteLEDs(); delay(500);
  ledsoff(); SEVEN; WriteLEDs(); delay(500);
  ledsoff(); EIGHT; WriteLEDs(); delay(500);
  ledsoff(); NINE; WriteLEDs(); delay(500);
  ledsoff(); HTEN; WriteLEDs(); delay(500);
  ledsoff(); ELEVEN; WriteLEDs(); delay(500);
  ledsoff(); TWELVE; WriteLEDs(); delay(500);
  ledsoff(); OCLOCK; WriteLEDs(); delay(500);
}


void displaytime(void){

  // start by clearing the display to a known state
  ledsoff();
 
  Serial.print("It is ");

  // now we display the appropriate minute counter
  if ((mn>4) && (mn<10)) {
    MFIVE;
    MINUTES;
    Serial.print("Five Minutes ");
  }
  if ((mn>9) && (mn<15)) {
    MTEN;
    MINUTES;
    Serial.print("Ten Minutes ");
  }
  if ((mn>14) && (mn<20)) {
    QUARTER;
      Serial.print("Quarter ");
  }
  if ((mn>19) && (mn<25)) {
    TWENTY;
    MINUTES;
    Serial.print("Twenty Minutes ");
  }
  if ((mn>24) && (mn<30)) {
    TWENTY;
    MFIVE;
    MINUTES;
    Serial.print("Twenty Five Minutes ");
  } 
  if ((mn>29) && (mn<35)) {
    HALF;
    Serial.print("Half ");
  }
  if ((mn>34) && (mn<40)) {
    TWENTY;
    MFIVE;
    MINUTES;
    Serial.print("Twenty Five Minutes ");
  } 
  if ((mn>39) && (mn<45)) {
    TWENTY;
    MINUTES;
    Serial.print("Twenty Minutes ");
  }
  if ((mn>44) && (mn<50)) {
    QUARTER;
    Serial.print("Quarter ");
  }
  if ((mn>49) && (mn<55)) {
    MTEN;
    MINUTES;
    Serial.print("Ten Minutes ");
  }
  if (mn>54) {
    MFIVE;
    MINUTES;
    Serial.print("Five Minutes ");
  }



  if ((mn <5))
  {
    switch (hr) {
    case 1:
      ONE;
      Serial.print("One ");
      break;
    case 2:
      TWO;
      Serial.print("Two ");
      break;
    case 3:
      THREE;
      Serial.print("Three ");
      break;
    case 4:
      FOUR;
      Serial.print("Four ");
      break;
    case 5:
      HFIVE;
      Serial.print("Five ");
      break;
    case 6:
      SIX;
      Serial.print("Six ");
      break;
    case 7:
      SEVEN;
      Serial.print("Seven ");
      break;
    case 8:
      EIGHT;
      Serial.print("Eight ");
      break;
    case 9:
      NINE;
      Serial.print("Nine ");
      break;
    case 10:
      HTEN;
      Serial.print("Ten ");
      break;
    case 11:
      ELEVEN;
      Serial.print("Eleven ");
      break;
    case 12:
      TWELVE;
      Serial.print("Twelve ");
      break;
    }
  OCLOCK;
  Serial.println("O'Clock");
  }
  else
    if ((mn < 35) && (mn >4))
    {
      PAST;
      Serial.print("Past ");
      switch (hr) {
    case 1:
      ONE;
      Serial.println("One ");
      break;
    case 2:
      TWO;
      Serial.println("Two ");
      break;
    case 3:
      THREE;
      Serial.println("Three ");
      break;
    case 4:
      FOUR;
      Serial.println("Four ");
      break;
    case 5:
      HFIVE;
      Serial.println("Five ");
      break;
    case 6:
      SIX;
      Serial.println("Six ");
      break;
    case 7:
      SEVEN;
      Serial.println("Seven ");
      break;
    case 8:
      EIGHT;
      Serial.println("Eight ");
      break;
    case 9:
      NINE;
      Serial.println("Nine ");
      break;
    case 10:
      HTEN;
      Serial.println("Ten ");
      break;
    case 11:
      ELEVEN;
      Serial.println("Eleven ");
      break;
    case 12:
      TWELVE;
      Serial.println("Twelve ");
      break;
      }
    }
    else
    {
      // if we are greater than 34 minutes past the hour then display
      // the next hour, as we will be displaying a 'to' sign
      TO;
      Serial.print("To ");
      switch (hr) {
      case 1:
        TWO;
       Serial.println("Two ");
       break;
      case 2:
        THREE;
      Serial.println("Three ");
        break;
      case 3:
        FOUR;
      Serial.println("Four ");
        break;
      case 4:
        HFIVE;
      Serial.println("Five ");
        break;
      case 5:
        SIX;
      Serial.println("Six ");
        break;
      case 6:
        SEVEN;
      Serial.println("Seven ");
        break;
      case 7:
        EIGHT;
      Serial.println("Eight ");
        break;
      case 8:
        NINE;
      Serial.println("Nine ");
        break;
      case 9:
        HTEN;
      Serial.println("Ten ");
        break;
      case 10:
        ELEVEN;
      Serial.println("Eleven ");
        break;
      case 11:
        TWELVE;
      Serial.println("Twelve ");
        break;
      case 12:
        ONE;
      Serial.println("One ");
        break;
      }
    }



   WriteLEDs();
  
}


void incrementtime(void){
  // increment the time counters keeping care to rollover as required
  scnd=0;
  if (++mn >= 60) {
    mn=0;
    if (++hr == 13) {
      hr=1; 
    }
  } 
  // debug outputs
  Serial.println();
//  if (DS1307Present)
//  print_DS1307time();
//  else{
//  Serial.print("Arduino Time: " );
  Serial.print(hr);
  Serial.print(":");
  Serial.print(mn);
  Serial.print(":");
  Serial.println(scnd);
//  }

}


void loop(void)
{
 
  //selftest();
int aread = sq(analogRead(3)/4)+3;
  //Uncomment the following line and comment the next one in order to
  //  enable dimming via a potentiometer connected to pin 0:
  analogWrite(PWMPin, aread>255 ? 255:aread);
  //analogWrite(PWMPin, 255);
 
    // heart of the timer - keep looking at the millisecond timer on the Arduino
    // and increment the seconds counter every 1000 ms
    if ( millis() - msTick >999) {
        msTick=millis();
        scnd++;
/*        // Flash the onboard Pin13 Led so we know something is hapening!
        digitalWrite(13,HIGH);
        delay(100);
        digitalWrite(13,LOW);   
*/    }
   
   
   
    //test to see if we need to increment the time counters
    if (scnd==60)
    {
      incrementtime();
      displaytime();
    }
if (DS1307Present) {
    // Get the current time and date from the chip
     getTime();
    }
    // test to see if a forward button is being held down
    // for time setting
    if ( (digitalRead(MinuteButtonPin) ==0 ) && scnd!=1)
      // the forward button is down
      // and it has been more than one second since we
      // last looked
    {
      mn=(((mn/5)*5) +5);
      scnd=0;
      incrementtime();
      scnd++;  // Increment the second counter to ensure that the name
      // flash doesnt happen when setting time
      if (DS1307Present) {

      // Set the time on the chip
      setTime();
    }
    delay(100);
      displaytime();
    }

    // test to see if the back button is being held down
    // for time setting
    if ((digitalRead(HourButtonPin)==0 ) && scnd!=1)
    {
      /*
      minute=(((minute/5)*5) -5);
      second=0; // decrement the minute counter
      if (minute<0) {
        minute=55;
        if (--hour <0) hour=12;
      }
      */
     
      mn = (mn/5)*5;  //round minute down to previous 5 min interval
      if (++hr == 13) {
        hr=1; 
      }
      incrementtime();
      scnd++;  // Increment the second counter to ensure that the name
      // flash doesnt happen when setting time 
      if (DS1307Present) {
      // Set the time and date on the chip
      setTime();
    }
    delay(100);
      displaytime();
    }

}

Discussions

0
user
frollard

Best Answer 6 years ago

I can't compile it to give real advice;

debugging; you need to find exactly where it goes wrong. Is your time number correct and the word count wrong -- or is the time math wrong?

I'd write a nested for loop that goes through every possible time from 00:00 to 11:59, and outputs that number to serial monitor, and to the screen. perhaps add a delay to make it obvious whats happening. Increment the time with a procedure rather than just 'set time = x loop', so more like time = time++

If the time counting math is proper, and outputs to the serial and display correctly, then its a problem with your 'hour incrementing' procedure.

I have a hunch that:


minute=(((minute/5)*5) -5);
second=0; // decrement the minute counter
if (minute<0) {
minute=55;
if (--hour <0) hour=12;
}
*/

is causing the problem...right at the end -- are you making the minutes step by increments of 5 while setting the time? in which case it might prevent you from stepping above 16 for some ridiculous reason.

I would personally keep the minutes stored as proper minutes and only convert them during the 'output' calculations.

Yes, thats right, it increments five minutes at a time. But that part you just read is commented out, instead there's an increment function. I should probably post my code again after clearing it out a bit.. shall I?

Normal time increment is fine. When it is incrementing itself it runs well and good. Just when setting time using the 'minute' button, it goes wrong. Lately I realised that its not just for 16 but any value above 15...

0
user
pro2xy

6 years ago

Latest update! It worked... I flashed the AVR with the same code again and it worked fine :D but strange
thanks all... which one should I mark the best answer?

Glad you got it working, and thanks for the BA :)

Keep coding and if it works well -- post your iteration as an ible!

I will... Just waiting for a camera to take the pics.. :)

0
user
pro2xy

6 years ago

Forgot to add.. The code is a mix of a couple of codes found on the net. The base being Doug Jackson's word clock. The interaction with the RTC is based on I2C (Wire library)