Can it be possible to mute hourly chime between 11 pm to 7am?

the code is here:


// packed date  yymmdd w
uint32_t pd = 0x16010105; // obvious bogus (but valid) date

// packed time  hhmmssff
uint32_t pt = 0x00000000; // intentionally bogus (for testing)

uint32_t last_tick_usec = 0UL;
char buf[50]; // this is intentionally bigger than I need

uint8_t set_state = 0;
// set_state indicates what is currently being set, as follows:
// 7 for hour tens,   6 for hour ones,
// 5 for minute tens, 4 for minute ones,
// 3 for second tens, 2 for second ones,
// 1 for normal timekeeping mode (i.e. finished setting the time)
// and it is 0 if the time has not yet been set

const uint32_t TIME_SET_MAX = 0x29595999;
// each digit is at max possible value for time

const uint32_t DATE_SET_MAX = 0x99123907;
// each digit (except units digit of month) is at max possible value for date

const uint8_t BUTTON_PIN_A = 12; // this button moves the cursor
const uint8_t BUTTON_PIN_B = 11; // this button makes the numbers change

uint8_t button_a_now;
uint8_t button_a_last;
uint8_t button_b_now;
uint8_t button_b_last;

enum rtc_status_type {
  RTC_UNKNOWN,
  RTC_PRESENT,
  RTC_ABSENT,
  RTC_TROUBLE
};

enum rtc_status_type rtc_status = RTC_UNKNOWN;

#include <LiquidCrystal.h>
#include <Wire.h>
#include <toneAC.h>

//                RS  EN DB4 DB5 DB6 DB7
LiquidCrystal lcd( 7,  6,  5,  4,  3,  2);

void setup() {
  pinMode(BUTTON_PIN_A, INPUT_PULLUP);
  pinMode(BUTTON_PIN_B, INPUT_PULLUP);
  // pressing either button makes its pin's voltage go low
  button_a_now = (digitalRead(BUTTON_PIN_A)==LOW);
  button_a_last = button_a_now;
  button_b_now = (digitalRead(BUTTON_PIN_B)==LOW);
  button_b_last = button_b_now;
  // set up the LCD
  lcd.begin(16, 2); // LCD dimensions
  // define special characters for single cell numerals 10 through 12
  uint8_t singleCellTen[]    = { 18, 21, 21, 21, 21, 21, 18,  0 };
  uint8_t singleCellEleven[] = {  9, 27,  9,  9,  9,  9,  9,  0 };
  uint8_t singleCellTwelve[] = { 22, 21, 17, 18, 20, 20, 23,  0 };
  lcd.createChar(5, singleCellTen); // "illogical" indices, I know
  lcd.createChar(6, singleCellEleven);
  lcd.createChar(7, singleCellTwelve);
  // initialize connection so we can read the time from the external RTC
  Wire.begin();
  // attempt to read the time from the external RTC
  getNewTime();
  // show (possibly bogus) time on display
  displayTime();
}

void loop() {
  button_a_last = button_a_now;
  button_b_last = button_b_now;
  // remember, pressing either button makes its pin's voltage go low
  button_a_now = (digitalRead(BUTTON_PIN_A)==LOW);
  button_b_now = (digitalRead(BUTTON_PIN_B)==LOW);
  // has either button just been pushed down?
  uint8_t pushed_a = (button_a_now && !button_a_last);
  uint8_t pushed_b = (button_b_now && !button_b_last);
  // what happens next depends on what mode we're in
  if (set_state <= 1) {
    // if we're in here, then the clock is running
    if (pushed_a) {
      // enter time setting mode
      pt &= 0xFFFFFF00;
      set_state = 15;
      displayTime();
    }
    else {
      // just show the time (regular timekeeping mode)
      uint32_t old_pt = pt;
      getNewTime();
      if (pt != old_pt) {
        if (set_state == 1) {
          if (((pt + 0x00000030) & 0xFFFFFF80) != ((old_pt + 0x00000030) & 0xFFFFFF80)) {
            uint16_t pt_hi = ((uint16_t)((pt >> 16) & 0x0000FFFF));  
            if ((pt_hi & 0x00FF) == 0x0000) {
              // the "zeroth" minute of the hour ... but which hour?
              // how many times to strike?
              uint8_t strike_num = (((pt_hi >> 12) & 0xF) * 10) + ((pt_hi >> 8) & 0xF);
              if (strike_num > 12) strike_num -= 12;
              if (strike_num == 0) strike_num = 12;
              // how many half-seconds into the minute are we?
              uint16_t pt_lo = ((uint16_t)(pt & 0x0000FFFF));
              uint8_t half_sec = (((pt_lo >> 12) & 0xF) * 20) + (((pt_lo >> 8) & 0xF) * 2);
              if ((pt_lo & 0xFF) >= 0x50) half_sec++;
              if (half_sec < 26) {
                switch (half_sec) {
                  // Westminster Chimes
                  case 0:  toneAC(330, 10, 420, true); break;
                  case 1:  toneAC(415, 10, 420, true); break;
                  case 2:  toneAC(370, 10, 420, true); break;
                  case 3:  toneAC(247, 10, 735, true); break;
                  case 6:  toneAC(330, 10, 420, true); break;
                  case 7:  toneAC(370, 10, 420, true); break;
                  case 8:  toneAC(415, 10, 420, true); break;
                  case 9:  toneAC(330, 10, 735, true); break;
                  case 12: toneAC(415, 10, 420, true); break;
                  case 13: toneAC(330, 10, 420, true); break;
                  case 14: toneAC(370, 10, 420, true); break;
                  case 15: toneAC(247, 10, 735, true); break;
                  case 18: toneAC(247, 10, 420, true); break;
                  case 19: toneAC(370, 10, 420, true); break;
                  case 20: toneAC(415, 10, 420, true); break;
                  case 21: toneAC(330, 10, 735, true); break;
                  default: break;
                }
              }
              else if ((half_sec < (26 + (3 * strike_num))) && ((half_sec % 3) == 2)){
                // bong the hours
                toneAC(415, 10, 750, true); 
              }
            }
          }
        }
        displayTime();    
      }
    }
  }
  else if ((set_state >= 2) && (set_state <= 15)) {
    // if we're in here, then we're in the midst of setting the date/time
    if (pushed_a) {
      // move the cursor
      set_state--;
      if (set_state == 13) set_state--; // this is not triskaidekaphobia
      while ((set_state == 9) || (set_state == 8)) set_state--;
      if (set_state == 7) {
        pd &= 0xFFFFFF00;
        pd += packedDateWeekday(pd);  
      }
      if (set_state <= 1) {
        // if we're finished setting the time, we start the clock running
        if (rtc_status == RTC_PRESENT) {  
          // BEGIN code to write the time to the Chronodot
          Wire.beginTransmission(0x68); // address DS3231
          Wire.write(0x00); // select register
    
          Wire.write((uint8_t)((pt >> 8)  & 0xFF)); // seconds
          Wire.write((uint8_t)((pt >> 16) & 0xFF)); // minutes
          Wire.write((uint8_t)((pt >> 24) & 0xFF)); // hours
          Wire.write((uint8_t)(pd & 0xFF));         // day of week
          Wire.write((uint8_t)((pd >> 8)  & 0xFF)); // day of month
          Wire.write((uint8_t)((pd >> 16) & 0xFF)); // month
          Wire.write((uint8_t)((pd >> 24) & 0xFF)); // year
    
          Wire.endTransmission();
          // END code to write the time to the Chronodot
        }
        last_tick_usec = micros();
      }
      displayTime();       
    }
    else if (pushed_b) {
      // change the number that the cursor is pointing to
      // (that is, the number itself gets changed; the cursor does not move)
      uint32_t digit_mask = (((uint32_t)0x0000000F)<<(4*(set_state&7)));      
      if (set_state >= 8) {
        if (set_state == 12) digit_mask = 0x00FF0000; // special mask for month
        // change one digit (or maybe two digits) of the date
        if ((pd & digit_mask) >= (DATE_SET_MAX & digit_mask)) pd &= ~digit_mask;
        else pd += (digit_mask & 0x11011111);
        if (set_state == 12) {
          // the month requires special treatment
          if ((pd & 0x00FF0000) == ((uint32_t)0x00000000)) {
            // there is no month 0
            pd += 0x00010000;
          }
          if ((pd & 0x000F0000) > 0x00090000) {
            // after month 9 comes month 10
            pd = (pd & 0xFFF0FFFF) + 0x00100000;
          }
        }
      }
      else {
        // change one digit of the time
        if ((pt & digit_mask) >= (TIME_SET_MAX & digit_mask)) pt &= ~digit_mask;
        else pt += (digit_mask & 0x11111111);
      }
      // show the new time
      displayTime();         
    }
  }
  delay(10); // poor man's switch debounce
}

void displayTime() {
  // set cursor to beginning of top row
  lcd.setCursor(0, 0);
  //                                     01234567890123456 
  if      (set_state == 0)  lcd.print(F("RTC not found!  "));
  else if (set_state == 1) {
    switch (rtc_status) {
      //                                 01234567890123456
      case RTC_PRESENT:     lcd.print(F("Date    Time RTC")); break;
      case RTC_ABSENT:      lcd.print(F("Date    Time    ")); break;
      case RTC_TROUBLE:     lcd.print(F("!DEAD RECKONING!")); break;
      default:              lcd.print(F("rtc_status error")); break;
    }
  }
  else if (set_state <= 7) {
    switch ((uint8_t)(pd & 0xFF)) {
      //                                 01234567890123456
      case 1:               lcd.print(F("Monday, right?  ")); break;
      case 2:               lcd.print(F("Tuesday, right? ")); break;
      case 3:               lcd.print(F("Wednesday,right?")); break;
      case 4:               lcd.print(F("Thursday, right?")); break;
      case 5:               lcd.print(F("Friday, right?  ")); break;
      case 6:               lcd.print(F("Saturday, right?")); break;
      case 7:               lcd.print(F("Sunday, right?  ")); break;
      default:              lcd.print(F("Calendar error! ")); break;
    }    
  }
  else if (set_state <= 15) lcd.print(F("Set date & time:"));
  else                      lcd.print(F("Oops, Error!    "));
  // set cursor to beginning of bottom row
  lcd.setCursor(0, 1);
  // determine the correct character for the month (we'll need this for the next step)
  uint8_t month_byte = (uint8_t)((pd >> 16) & 0xFF);
  char month_char = '*';
  if       (month_byte <= 0x09) month_char = (char)('0' + month_byte);
  else if  (month_byte == 0x10) month_char = (char)5;
  else if  (month_byte == 0x11) month_char = (char)6;
  else if  (month_byte == 0x12) month_char = (char)7;
  else if ((month_byte >= 0x0A) && (month_byte <= 0x0F)) {
    // this should never happen -- I'm including it strictly for debugging purposes 
    month_char = (char)('a' + (month_byte - 0xA));
  }
  //
  //                                              01234567890123456
  // show the date and time on the display, thus: YY.M.DD HH:MM:SS
  sprintf(buf, "%02x.%c.%02x %02x:%02x:%02x",
    (uint8_t)((pd>>24)&0xFF), month_char, (uint8_t)((pd>>8)&0xFF),
    (uint8_t)((pt>>24)&0xFF), (uint8_t)((pt>>16)&0xFF), (uint8_t)((pt>>8)&0xFF));  
  // change the zeros to capital "O"s
  for (int i=0; i<16; i++) {
    if (buf[i]=='0') buf[i]='O'; 
  }
  lcd.print(buf);
  switch (set_state) {
    case 15: lcd.setCursor(0,  1); lcd.cursor(); break; // cursor under year tens
    case 14: lcd.setCursor(1,  1); lcd.cursor(); break; // cursor under year ones
    case 12: lcd.setCursor(3,  1); lcd.cursor(); break; // cursor under month
    case 11: lcd.setCursor(5,  1); lcd.cursor(); break; // cursor under date tens
    case 10: lcd.setCursor(6,  1); lcd.cursor(); break; // cursor under date ones
    case 7:  lcd.setCursor(8,  1); lcd.cursor(); break; // cursor under hour tens
    case 6:  lcd.setCursor(9,  1); lcd.cursor(); break; // cursor under hour ones
    case 5:  lcd.setCursor(11, 1); lcd.cursor(); break; // cursor under minute tens
    case 4:  lcd.setCursor(12, 1); lcd.cursor(); break; // cursor under minute ones
    case 3:  lcd.setCursor(14, 1); lcd.cursor(); break; // cursor under second tens
    case 2:  lcd.setCursor(15, 1); lcd.cursor(); break; // cursor under second ones
    default: lcd.noCursor();                           // if not setting the time, then no cursor
  }
}


void getNewTime() {
  // 
  // In case no external RTC is available, this function can serve as a substitute.
  // However, if there is an external RTC, then this function will make use of it.
  //
  const uint32_t ONE_TICK_USEC = 50000UL; // update the time every 0.05 second
  const uint32_t ONE_TICK_PACKED = 0x00000005; // see previous line
  uint32_t old_pt = pt;
  while ((micros()-last_tick_usec)>=ONE_TICK_USEC) {
    // figure out how much time has passed
    last_tick_usec += ONE_TICK_USEC;
    pt = timeAdd(pt, ONE_TICK_PACKED);
  }
  if (pt>=0x24000000) {
    pt = timeSub(pt, 0x24000000);
    // advance the date (yes, it really is this complicated!)
    // BEGIN date advance code
    if ((pd & 0x000000FF) >= 0x00000007) pd &= 0xFFFFFF00;
    pd += 0x00000101;
    if ((pd & 0x00000F00) >= 0x00000A00) pd = (pd & 0xFFFFF0FF) + 0x00001000;
    if ((pd & 0x0000FF00) >= 0x00003200) pd = (pd & 0xFFFF00FF) + 0x00010100;
    if ((pd & 0x00FFFF00) >= 0x00123200) pd = (pd & 0xFF0000FF) + 0x01010100;
    if ((pd & 0x0FFFFF00) >= 0x09123200) pd = (pd & 0xF00000FF) + 0x10010100;
    if ((pd & 0x00FFFF00) == 0x00113100) pd = (pd & 0xFF0000FF) + 0x00120100;
    if ((pd & 0x00FFFF00) == 0x00093100) pd = (pd & 0xFF0000FF) + 0x00100100;
    if ((pd & 0x00FFFF00) == 0x00063100) pd = (pd & 0xFF0000FF) + 0x00070100;
    if ((pd & 0x00FFFF00) == 0x00043100) pd = (pd & 0xFF0000FF) + 0x00050100;
    if ((pd & 0x00FFFE00) == 0x00023000) pd = (pd & 0xFF0000FF) + 0x00030100;
    if (!((((pd & 0x10000000) >> 3) ^ (pd & 0x03FFFF00)) == 0x00022900)) {
        if ((pd & 0x00FFFF00) == 0x00022900) {
          pd = (pd & 0xFF0000FF) + 0x00030100;
        }
    }
    // END date advance code
  }
  if ((rtc_status == RTC_UNKNOWN) || (old_pt != pt)) {
    if ((rtc_status == RTC_UNKNOWN) || (rtc_status == RTC_PRESENT)) {
      // We will attempt to read the RTC.
      // If we succeed, we assume that whatever date and time it gave us is correct.
      // If we fail, we assume that we don't have a good RTC, and we don't try to read it again. 
      uint32_t expected_pt = pt;
      // BEGIN attempt to read the time
      // send request to receive data starting at register 0
      Wire.beginTransmission(0x68); // 0x68 is DS3231 device address
      Wire.write((uint8_t)0); // start at register 0
      Wire.endTransmission();
      Wire.requestFrom(0x68, 7); // request seven bytes (ss, mi, hh, wd, dd, mo, yy)
      // check for a reply from the RTC, and use it if we can
      if (Wire.available() >= 7) { 
        // if we're here, we got a reply and it is long enough
        // so now we read the time
        pt =  (((Wire.read()) & (((uint32_t)(0x000000FF)))) << 8);  // seconds
        pt += (((Wire.read()) & (((uint32_t)(0x000000FF)))) << 16); // minutes
        pt += (((Wire.read()) & (((uint32_t)(0x000000FF)))) << 24); // hours
        pd =  (((Wire.read()) &  ((uint32_t)(0x000000FF))));        // day of week
        pd += (((Wire.read()) & (((uint32_t)(0x000000FF)))) << 8);  // day of month
        pd += (((Wire.read()) & (((uint32_t)(0x000000FF)))) << 16); // month
        pd += (((Wire.read()) & (((uint32_t)(0x000000FF)))) << 24); // year
        rtc_status = RTC_PRESENT;
        set_state = 1; // because we have successfully read the time
      }
      else {
        // if we're here, then we did not get a reply we could use
        if (rtc_status == RTC_UNKNOWN)  rtc_status = RTC_ABSENT;
        else rtc_status = RTC_TROUBLE;
      }
      // END attempt to read the time
      //
      // Most RTC units do not handle fractional seconds.
      // What follows is an attempt at estimating the missing fractional seconds.
      if ((pt & 0xFFFFFF00) == (expected_pt & 0xFFFFFF00)) {
        // hour, minute, and second are the same as expected
        // so we assume that the fractional seconds are also the same as expected
        pt = expected_pt;
      }
      else if (timeAdd(pt, 0x00000100) == (expected_pt & 0xFFFFFF00)) {
        // time is one second earlier than expected
        pt = timeAdd(pt, 0x00000099);
      }
      else if ((pt == 0x23595900) && (expected_pt < 0x00000100)) {
        // special case the second just before midnight 
        pt = 0x23595999;
      }
    }
  }  
}


// some old time manipulation functions I dug up for this

uint32_t timeAdd (uint32_t x, uint32_t y) {
  // no sanity checking of input
  // format is hhmmssff with ff being decimal fractions of a second
  // "out of range" results are e.g. A0000000 for 100 hours
  uint32_t binsum = x + y;
  uint32_t carry = ((binsum + 0x06A6A666) ^ x ^ y) & 0x11111110;
  return (binsum + ((carry - (carry>>4)) & 0x06A6A666));  
}

uint32_t timeSub (uint32_t x, uint32_t y) {
  // no sanity checking of input
  // format is hhmmssff with ff being decimal fractions of a second
  // "negative" results are e.g. F9595999 for -0.01 second
  uint32_t bindiff = x - y;
  uint32_t borrow = (bindiff ^ x ^ y) & 0x11111110;
  return (bindiff - ((borrow - (borrow>>4)) & 0x06A6A666) );
}

/*
   Usage example:

   2 h 58 min 30.98 s --> 0x02583098
   0 h  1 min 44.06 s --> 0x00014406
   
   Addition:
   timeAdd(0x02583098, 0x00014406) gives 0x03001504
                             which means 3 h 0 min 15.04 s
                             
   Subtraction:
   timeSub(0x02583098, 0x00014406) gives 0x02564692
                             which means 2 h 56 min 46.92 s
*/


// ... and a date manipulation function I made just for this

uint8_t packedDateWeekday(uint32_t p) {
  // Input is a packed date. Last two digits are ignored.
  // Format is   YYMMDDXX where XX is don't care.
  // Example:  0x16062688 means June 26, 2016
  // Output is the day of the week corresponding to the input date.
  // (1 for Monday, 2 for Tuesday, ..., 7 for Sunday)
  // There is hardly any sanity checking of input.
  uint8_t x = p >> 24;
  x -= (6 * ((x >> 4) & 0x0F));
  x += 4;
  if ((p & 0x00FF0000) <= 0x00020000) x--;
  x += (x >> 2);
  switch ((uint8_t)((p >> 16) & 0xFF)) { // the 0xFF part is paranoia
    case 0x03: x += 4; break;
    case 0x04: break;
    case 0x05: x += 2; break;
    case 0x06: x += 5; break;
    case 0x07: break;
    case 0x08: x += 3; break;
    case 0x09: x += 6; break;
    case 0x10: x += 1; break;
    case 0x11: x += 4; break;
    case 0x12: x += 6; break;
    case 0x01: x += 2; break;
    case 0x02: x += 5; break;
    default: return 0;
  }
  x += ((p >> 8) & 0xFF);
  x += ((p >> 12) & 0x0F);
  while (x > 7) x -= 7;
  return x;
}



that’s where this poorly written / documented spaghetti code is testing if it’s time to strike

Before subtracting 12 to the number of strikes, the strike_num variable seems to hold the number of hours since midnight.
You could use that and compare with your boundaries and not call tone() when you don’t want to

please give me the modified code.

Give it a try

its not working , it still striking on midnight time between 12 am to 6am

Your post was MOVED to its current location as it is more suitable.

Post your code

the code is here:


// packed date  yymmdd w
uint32_t pd = 0x16010105; // obvious bogus (but valid) date

// packed time  hhmmssff
uint32_t pt = 0x00000000; // intentionally bogus (for testing)

uint32_t last_tick_usec = 0UL;
char buf[50]; // this is intentionally bigger than I need

uint8_t set_state = 0;
// set_state indicates what is currently being set, as follows:
// 7 for hour tens,   6 for hour ones,
// 5 for minute tens, 4 for minute ones,
// 3 for second tens, 2 for second ones,
// 1 for normal timekeeping mode (i.e. finished setting the time)
// and it is 0 if the time has not yet been set

const uint32_t TIME_SET_MAX = 0x29595999;
// each digit is at max possible value for time

const uint32_t DATE_SET_MAX = 0x99123907;
// each digit (except units digit of month) is at max possible value for date

const uint8_t BUTTON_PIN_A = 12; // this button moves the cursor
const uint8_t BUTTON_PIN_B = 11; // this button makes the numbers change

uint8_t button_a_now;
uint8_t button_a_last;
uint8_t button_b_now;
uint8_t button_b_last;

enum rtc_status_type {
  RTC_UNKNOWN,
  RTC_PRESENT,
  RTC_ABSENT,
  RTC_TROUBLE
};

enum rtc_status_type rtc_status = RTC_UNKNOWN;

#include <Wire.h>
#include <toneAC.h>

//                RS  EN DB4 DB5 DB6 DB7


void setup() {
  pinMode(BUTTON_PIN_A, INPUT_PULLUP);
  pinMode(BUTTON_PIN_B, INPUT_PULLUP);
  // pressing either button makes its pin's voltage go low
  button_a_now = (digitalRead(BUTTON_PIN_A)==LOW);
  button_a_last = button_a_now;
  button_b_now = (digitalRead(BUTTON_PIN_B)==LOW);
  button_b_last = button_b_now;
  // set up the LCD

  // define special characters for single cell numerals 10 through 12
  uint8_t singleCellTen[]    = { 18, 21, 21, 21, 21, 21, 18,  0 };
  uint8_t singleCellEleven[] = {  9, 27,  9,  9,  9,  9,  9,  0 };
  uint8_t singleCellTwelve[] = { 22, 21, 17, 18, 20, 20, 23,  0 };



  // initialize connection so we can read the time from the external RTC
  Wire.begin();
  // attempt to read the time from the external RTC
  getNewTime();
  // show (possibly bogus) time on display
  displayTime();
}

void loop() {
  button_a_last = button_a_now;
  button_b_last = button_b_now;
  // remember, pressing either button makes its pin's voltage go low
  button_a_now = (digitalRead(BUTTON_PIN_A)==LOW);
  button_b_now = (digitalRead(BUTTON_PIN_B)==LOW);
  // has either button just been pushed down?
  uint8_t pushed_a = (button_a_now && !button_a_last);
  uint8_t pushed_b = (button_b_now && !button_b_last);
  // what happens next depends on what mode we're in
  if (set_state <= 1) {
    // if we're in here, then the clock is running
    if (pushed_a) {
      // enter time setting mode
      pt &= 0xFFFFFF00;
      set_state = 15;
      displayTime();
    }
    else {
      // just show the time (regular timekeeping mode)
      uint32_t old_pt = pt;
      getNewTime();
      if (pt != old_pt) {
        if (set_state == 1) {
          if (((pt + 0x00000030) & 0xFFFFFF80) != ((old_pt + 0x00000030) & 0xFFFFFF80)) {
            uint16_t pt_hi = ((uint16_t)((pt >> 16) & 0x0000FFFF));  
            if ((pt_hi & 0x00FF) == 0x0000) {
              // the "zeroth" minute of the hour ... but which hour?
              // how many times to strike?
              uint8_t strike_num = (((pt_hi >> 12) & 0xF) * 10) + ((pt_hi >> 8) & 0xF);
              if (strike_num > 12) strike_num -= 12;
              if (strike_num == 0) strike_num = 12;
              // how many half-seconds into the minute are we?
              uint16_t pt_lo = ((uint16_t)(pt & 0x0000FFFF));
              uint8_t half_sec = (((pt_lo >> 12) & 0xF) * 20) + (((pt_lo >> 8) & 0xF) * 2);
              if ((pt_lo & 0xFF) >= 0x50) half_sec++;
              if (half_sec < 26) {
                switch (half_sec) {
                  // Westminster Chimes
                  case 0:  toneAC(330, 10, 420, true); break;
                  case 1:  toneAC(415, 10, 420, true); break;
                  case 2:  toneAC(370, 10, 420, true); break;
                  case 3:  toneAC(247, 10, 735, true); break;
                  case 6:  toneAC(330, 10, 420, true); break;
                  case 7:  toneAC(370, 10, 420, true); break;
                  case 8:  toneAC(415, 10, 420, true); break;
                  case 9:  toneAC(330, 10, 735, true); break;
                  case 12: toneAC(415, 10, 420, true); break;
                  case 13: toneAC(330, 10, 420, true); break;
                  case 14: toneAC(370, 10, 420, true); break;
                  case 15: toneAC(247, 10, 735, true); break;
                  case 18: toneAC(247, 10, 420, true); break;
                  case 19: toneAC(370, 10, 420, true); break;
                  case 20: toneAC(415, 10, 420, true); break;
                  case 21: toneAC(330, 10, 735, true); break;
                  default: break;
                }
              }
              else if ((half_sec < (26 + (3 * strike_num))) && ((half_sec % 3) == 2)){
                // bong the hours
                toneAC(415, 10, 750, true); 
              }
            }
          }
        }
        displayTime();    
      }
    }
  }
  else if ((set_state >= 2) && (set_state <= 15)) {
    // if we're in here, then we're in the midst of setting the date/time
    if (pushed_a) {
      // move the cursor
      set_state--;
      if (set_state == 13) set_state--; // this is not triskaidekaphobia
      while ((set_state == 9) || (set_state == 8)) set_state--;
      if (set_state == 7) {
        pd &= 0xFFFFFF00;
        pd += packedDateWeekday(pd);  
      }
      if (set_state <= 1) {
        // if we're finished setting the time, we start the clock running
        if (rtc_status == RTC_PRESENT) {  
          // BEGIN code to write the time to the Chronodot
          Wire.beginTransmission(0x68); // address DS3231
          Wire.write(0x00); // select register
    
          Wire.write((uint8_t)((pt >> 8)  & 0xFF)); // seconds
          Wire.write((uint8_t)((pt >> 16) & 0xFF)); // minutes
          Wire.write((uint8_t)((pt >> 24) & 0xFF)); // hours
          Wire.write((uint8_t)(pd & 0xFF));         // day of week
          Wire.write((uint8_t)((pd >> 8)  & 0xFF)); // day of month
          Wire.write((uint8_t)((pd >> 16) & 0xFF)); // month
          Wire.write((uint8_t)((pd >> 24) & 0xFF)); // year
    
          Wire.endTransmission();
          // END code to write the time to the Chronodot
        }
        last_tick_usec = micros();
      }
      displayTime();       
    }
    else if (pushed_b) {
      // change the number that the cursor is pointing to
      // (that is, the number itself gets changed; the cursor does not move)
      uint32_t digit_mask = (((uint32_t)0x0000000F)<<(4*(set_state&7)));      
      if (set_state >= 8) {
        if (set_state == 12) digit_mask = 0x00FF0000; // special mask for month
        // change one digit (or maybe two digits) of the date
        if ((pd & digit_mask) >= (DATE_SET_MAX & digit_mask)) pd &= ~digit_mask;
        else pd += (digit_mask & 0x11011111);
        if (set_state == 12) {
          // the month requires special treatment
          if ((pd & 0x00FF0000) == ((uint32_t)0x00000000)) {
            // there is no month 0
            pd += 0x00010000;
          }
          if ((pd & 0x000F0000) > 0x00090000) {
            // after month 9 comes month 10
            pd = (pd & 0xFFF0FFFF) + 0x00100000;
          }
        }
      }
      else {
        // change one digit of the time
        if ((pt & digit_mask) >= (TIME_SET_MAX & digit_mask)) pt &= ~digit_mask;
        else pt += (digit_mask & 0x11111111);
      }
      // show the new time
      displayTime();         
    }
  }
  delay(10); // poor man's switch debounce
}

void displayTime() {
  // set cursor to beginning of top row

  //                                     01234567890123456 


    switch (rtc_status) {
      //                                 01234567890123456




    }
  }


      //                                 01234567890123456











  // set cursor to beginning of bottom row

  // determine the correct character for the month (we'll need this for the next step)
  uint8_t month_byte = (uint8_t)((pd >> 16) & 0xFF);
  char month_char = '*';





    // this should never happen -- I'm including it strictly for debugging purposes 


  //
  //                                              01234567890123456
  // show the date and time on the display, thus: YY.M.DD HH:MM:SS



  // change the zeros to capital "O"s










void getNewTime() {
  // 
  // In case no external RTC is available, this function can serve as a substitute.
  // However, if there is an external RTC, then this function will make use of it.
  //
  const uint32_t ONE_TICK_USEC = 50000UL; // update the time every 0.05 second
  const uint32_t ONE_TICK_PACKED = 0x00000005; // see previous line
  uint32_t old_pt = pt;
  while ((micros()-last_tick_usec)>=ONE_TICK_USEC) {
    // figure out how much time has passed
    last_tick_usec += ONE_TICK_USEC;
    pt = timeAdd(pt, ONE_TICK_PACKED);
  }
  if (pt>=0x24000000) {
    pt = timeSub(pt, 0x24000000);
    // advance the date (yes, it really is this complicated!)
    // BEGIN date advance code
    if ((pd & 0x000000FF) >= 0x00000007) pd &= 0xFFFFFF00;
    pd += 0x00000101;
    if ((pd & 0x00000F00) >= 0x00000A00) pd = (pd & 0xFFFFF0FF) + 0x00001000;
    if ((pd & 0x0000FF00) >= 0x00003200) pd = (pd & 0xFFFF00FF) + 0x00010100;
    if ((pd & 0x00FFFF00) >= 0x00123200) pd = (pd & 0xFF0000FF) + 0x01010100;
    if ((pd & 0x0FFFFF00) >= 0x09123200) pd = (pd & 0xF00000FF) + 0x10010100;
    if ((pd & 0x00FFFF00) == 0x00113100) pd = (pd & 0xFF0000FF) + 0x00120100;
    if ((pd & 0x00FFFF00) == 0x00093100) pd = (pd & 0xFF0000FF) + 0x00100100;
    if ((pd & 0x00FFFF00) == 0x00063100) pd = (pd & 0xFF0000FF) + 0x00070100;
    if ((pd & 0x00FFFF00) == 0x00043100) pd = (pd & 0xFF0000FF) + 0x00050100;
    if ((pd & 0x00FFFE00) == 0x00023000) pd = (pd & 0xFF0000FF) + 0x00030100;
    if (!((((pd & 0x10000000) >> 3) ^ (pd & 0x03FFFF00)) == 0x00022900)) {
        if ((pd & 0x00FFFF00) == 0x00022900) {
          pd = (pd & 0xFF0000FF) + 0x00030100;
        }
    }
    // END date advance code
  }
  if ((rtc_status == RTC_UNKNOWN) || (old_pt != pt)) {
    if ((rtc_status == RTC_UNKNOWN) || (rtc_status == RTC_PRESENT)) {
      // We will attempt to read the RTC.
      // If we succeed, we assume that whatever date and time it gave us is correct.
      // If we fail, we assume that we don't have a good RTC, and we don't try to read it again. 
      uint32_t expected_pt = pt;
      // BEGIN attempt to read the time
      // send request to receive data starting at register 0
      Wire.beginTransmission(0x68); // 0x68 is DS3231 device address
      Wire.write((uint8_t)0); // start at register 0
      Wire.endTransmission();
      Wire.requestFrom(0x68, 7); // request seven bytes (ss, mi, hh, wd, dd, mo, yy)
      // check for a reply from the RTC, and use it if we can
      if (Wire.available() >= 7) { 
        // if we're here, we got a reply and it is long enough
        // so now we read the time
        pt =  (((Wire.read()) & (((uint32_t)(0x000000FF)))) << 8);  // seconds
        pt += (((Wire.read()) & (((uint32_t)(0x000000FF)))) << 16); // minutes
        pt += (((Wire.read()) & (((uint32_t)(0x000000FF)))) << 24); // hours
        pd =  (((Wire.read()) &  ((uint32_t)(0x000000FF))));        // day of week
        pd += (((Wire.read()) & (((uint32_t)(0x000000FF)))) << 8);  // day of month
        pd += (((Wire.read()) & (((uint32_t)(0x000000FF)))) << 16); // month
        pd += (((Wire.read()) & (((uint32_t)(0x000000FF)))) << 24); // year
        rtc_status = RTC_PRESENT;
        set_state = 1; // because we have successfully read the time
      }
      else {
        // if we're here, then we did not get a reply we could use
        if (rtc_status == RTC_UNKNOWN)  rtc_status = RTC_ABSENT;
        else rtc_status = RTC_TROUBLE;
      }
      // END attempt to read the time
      //
      // Most RTC units do not handle fractional seconds.
      // What follows is an attempt at estimating the missing fractional seconds.
      if ((pt & 0xFFFFFF00) == (expected_pt & 0xFFFFFF00)) {
        // hour, minute, and second are the same as expected
        // so we assume that the fractional seconds are also the same as expected
        pt = expected_pt;
      }
      else if (timeAdd(pt, 0x00000100) == (expected_pt & 0xFFFFFF00)) {
        // time is one second earlier than expected
        pt = timeAdd(pt, 0x00000099);
      }
      else if ((pt == 0x23595900) && (expected_pt < 0x00000100)) {
        // special case the second just before midnight 
        pt = 0x23595999;
      }
    }
  }  
}


// some old time manipulation functions I dug up for this

uint32_t timeAdd (uint32_t x, uint32_t y) {
  // no sanity checking of input
  // format is hhmmssff with ff being decimal fractions of a second
  // "out of range" results are e.g. A0000000 for 100 hours
  uint32_t binsum = x + y;
  uint32_t carry = ((binsum + 0x06A6A666) ^ x ^ y) & 0x11111110;
  return (binsum + ((carry - (carry>>4)) & 0x06A6A666));  
}

uint32_t timeSub (uint32_t x, uint32_t y) {
  // no sanity checking of input
  // format is hhmmssff with ff being decimal fractions of a second
  // "negative" results are e.g. F9595999 for -0.01 second
  uint32_t bindiff = x - y;
  uint32_t borrow = (bindiff ^ x ^ y) & 0x11111110;
  return (bindiff - ((borrow - (borrow>>4)) & 0x06A6A666) );
}

/*
   Usage example:

   2 h 58 min 30.98 s --> 0x02583098
   0 h  1 min 44.06 s --> 0x00014406
   
   Addition:
   timeAdd(0x02583098, 0x00014406) gives 0x03001504
                             which means 3 h 0 min 15.04 s
                             
   Subtraction:
   timeSub(0x02583098, 0x00014406) gives 0x02564692
                             which means 2 h 56 min 46.92 s
*/


// ... and a date manipulation function I made just for this

uint8_t packedDateWeekday(uint32_t p) {
  // Input is a packed date. Last two digits are ignored.
  // Format is   YYMMDDXX where XX is don't care.
  // Example:  0x16062688 means June 26, 2016
  // Output is the day of the week corresponding to the input date.
  // (1 for Monday, 2 for Tuesday, ..., 7 for Sunday)
  // There is hardly any sanity checking of input.
  uint8_t x = p >> 24;
  x -= (6 * ((x >> 4) & 0x0F));
  x += 4;
  if ((p & 0x00FF0000) <= 0x00020000) x--;
  x += (x >> 2);
  switch ((uint8_t)((p >> 16) & 0xFF)) { // the 0xFF part is paranoia
    case 0x03: x += 4; break;
    case 0x04: break;
    case 0x05: x += 2; break;
    case 0x06: x += 5; break;
    case 0x07: break;
    case 0x08: x += 3; break;
    case 0x09: x += 6; break;
    case 0x10: x += 1; break;
    case 0x11: x += 4; break;
    case 0x12: x += 6; break;
    case 0x01: x += 2; break;
    case 0x02: x += 5; break;
    default: return 0;
  }
  x += ((p >> 8) & 0xFF);
  x += ((p >> 12) & 0x0F);
  while (x > 7) x -= 7;
  return x;
}




can anybody help me to turn of hourly chime in night time ( 11pm to 7am)?

Where is your attempt to do anything?

What time does case 2 play at? Let's say case 2 goes off at 2AM.

If the code for case 2 was changed to

//case 2:  toneAC(370, 10, 420, true); break;

Then what time would case 2 play at?

What time does case 2 play at? Let's say case 2 goes off at 2AM.

Nope, case 2 plays each hour, at exactly 1 second past the hour (at XX:00:01).
Case 3 plays at 1.5 seconds past the hour (at XX:00:01.5). And so forth.
I know this because I am the one who wrote the code.

I have a strong feeling of “deja vu” with this thread.
See Clock with hourly chime

Cool

if hour >=23 and <=7 then don't play.

The variable pt holds a hexadecimal number representing the current time. For example, if the time is 12:34:56, then pt will equal 0x12345600.

uint16_t pt_hi = ((uint16_t)((pt >> 16) & 0x0000FFFF));  

What the line above does is extract the top half of pt_hi. This gets you the four digits for hours and minutes. To continue with our example, if pt is 0x12345600, then pt_hi will be 0x1234 (meaning that the time is 12:34 and an unspecified number of seconds).

if ((pt_hi & 0x00FF) == 0x0000) {

What this line does is examine the minutes to make sure that they are zero. This is to ensure that the chimes sound only during the "zeroth" minute of the hour. Otherwise, the chimes would sound once every minute, rather than once every hour.
If you wish to restrict the chimes further, then take this line

if ((pt_hi & 0x00FF) == 0x0000) {

and change it to something like this:

if (((pt_hi & 0x00FF) == 0x0000) && (pt_hi >= 0x0800) && (pt_hi <= 0x2200)) {
// chimes only from 8 a.m. to 10 p.m.

I think the code checks if it’s a full hour and then every 0.5 second following strikes a tone. That’s what the case does.

As said in #2, strike_num. As initially calculated is ready for use to decide if you strike or not… (or @odometer approoach)

@subhrodeep

if you don't want to invest a minimum of

own effort

just go buying a ready to use clock with chimes off the shelf.
best regards Stefan

Indeed it is. This way, I could use the clock time itself to figure out where I am in the striking sequence. If I didn't do it this way, then I would need separate time and/or state variables to manage striking: in effect, I would need to code a separate "clock" just to manage the strikes, and why should I have two clocks where one will do?

Not saying it was wrong :slight_smile:
I was Just commenting on @subhrodeep’s comment who took the case for the actual hours apparently

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.