Needs help in programming logic on a simple idea.

I am trying to build a Morse code beep time announcer. Already have problems trying different tone generate library.
my questions are:

1, how can I generate a tone without using delay()?

2, how can I make tones corresponds to the Morse code? ie, dit, dot,dot,dot,dot for 1

3, how can I make it beeps every minutes? ie, when it’s 12:44, it should beep like this: .---- …— …- …-

any help will be highly appreciated!! thanks in advance

Here is what I got so far. Using softtimer library, I get compiling errors. I have no idea what went wrong.

#include <SoftTimer.h>
#include <TonePlayer.h>
#include <LiquidCrystal.h>
#define beep 7
LiquidCrystal lcd(8,9,10,11,12,13);

int sec=0;
int minu=0;
int hr=0;
unsigned long pstimer=0;

int pbutton3=1;
int pbutton5=1;
int count=0;

TonePlayer tonePlayer(beep, 500);

void setup(){

lcd.begin(16,2);  

pinMode (A3, INPUT_PULLUP); 
pinMode (A5, INPUT_PULLUP);   
}

void loop(){
  
  
int button3= digitalRead(A3);

if(button3!=pbutton3){
  if(button3==0){
    minu++;
  }
  pbutton3=button3;
}

int button5= digitalRead(A5);
if(button5!=pbutton5){
  if(button5==0){
    hr++;
  }
  pbutton5=button5;  
}  
  
unsigned long timer= millis();

 if(timer-pstimer > 1000){
   sec++;
   pstimer = timer;   
   count++;
 }    

if(count==3){
  tonePlayer.play("c1g1c1g1j2j2c1g1c1g1j2j2o1n1l1j1h2l2_2j1h1g1e1c2c2");
}

if(count==6){
count=0;
  tonePlayer.play("c1g1c1g1j2j2c1g1c1g1j2j2o1n1l1j1h2l2_2j1h1g1e1c2c2");
}

 
if(sec==60){
 sec=0; 
 minu++;
}

if(minu==60){
 minu=0;
 hr++;
}  
 


char szTime[16];
sprintf( szTime, "Time:%02d:%02d:%02d", hr, minu, sec );
lcd.setCursor(0,1);
lcd.print( szTime ); 

lcd.setCursor(0,0);
lcd.print( "Morse Code Clock" ); 

}

arduinomagbit:
Here is what I got so far. Using softtimer library, I get compiling errors.

Which are?

A dot is a tone for one unit of time a dash fr three units of time with a gap of one unit of time between them,

3, how can I make it beeps every minutes

Use the technique in the blink without delay example in the IDE.

Grumpy_Mike:
A dot is a tone for one unit of time a dash fr three units of time with a gap of one unit of time between them,

3, how can I make it beeps every minutes

Use the technique in the blink without delay example in the IDE.

that example will repeatedly blink a led, which is not the cause here. I need to beep a tone in a complicated morse code pattern.

that library is complicated, and with little documentation. I decided not to use it right now.

arduinomagbit:
1, how can I generate a tone without using delay()?

Have a "state machine". Remember how far through the current sequence you are, and when the desired time is up (one dot length or one dash length) start (or stop) the next tone.

thanks

Given that you are generating these sequences on a timed basis there are two approaches you can take.

The blocking approach is to wait until it is time to send a sequence and then carry out a blocking sequence of beep/wait actions until the sequence is complete, then go back to waiting until it is time to send the next sequence. This approach means your sketch can only control one thing at a time and is a very limited approach, but it could be made to work. This would be using the delay() function that you mentioned in point (1) and say you want to get away from - IMO you're right to want to get away from it.

The non-blocking approach needs two activities to be performed on a timed basis. The first activity decides whether it is time to send out a morse code sequence. The second activity sends the timed beeps that comprise the requested sequence. The two activities need to communicate with each other. The way I'd implement this is with a circular buffer containing a queue of morse characters which need to be sent and haven't been sent yet. Your clock processing would just write morse characters to this queue. The sending function would use the timing logic demonstrated in the blink without delay example sketch to manage the sending of the sequence of beeps and gaps that constitute a given character, then pull the next morse character off the queue. It's up to you whether you want the queue to hold ascii characters or dot/dash/gap tokens. Having it hold dot/dash/gap tokens would simplify the sending code but means the queue would take up more space.

I would give it a try like this, using some arrays and making your own tone.
Have to declare all the variables, add setup, etc.
Sorry about the lack of indenting

byte timeArray [] = {0,0,0,0,};
byte dotdash [] = {0b00000000, 0b00010000, 0b00011000, 0b00011100, 0b00011110, 0b00011111, 0b00001111, 0b00000111, 0b00000011, 0b00000001,};
//http://en.wikipedia.org/wiki/Morse_code

void loop(){
currentTime = micros(); // capture the 'time'
if ( (currentTime – nextTime) >= oneSecond){ // one second gone by?
nextTime = nextTime + oneSecond; // update for next time check
minutesOnes = minutesOnes + 1;
timeUpdate = 1; // set flag to make some noise on 1 minute updates
if (minutesOnes == 10){ // rollover
minutesOnes = 0;
minutesTens = minutesTens +1;
if (minutesTens == 6){ // rollover
minutesTens = 0;
hoursOnes = hoursOnes + 1;
if (hoursOnes == 10){  // rollover
hoursOnes = 0;
hoursTens = hoursTens +1;
if ( (hoursTens == 2) && (hoursOnes== 4){ // rollover at 24:00 - or set to 1 & 2 for 12 hour
hoursTens = 0;
hoursOnes = 0;
} // hoursTens check
} // hoursOnes check
} // minutesTens check
} // minutesOnes check
timeArray[0] = hoursTens;
timeArray[1] = hoursMinutes;
timeArray[2] = minutesTens;
timeArray[3] = minutesOnes;
} // end 1 second check
// or replace all that with reading the 4 variables from an RTC such as DS1307 using I2C commands

if (timeUpdate == 1){  // check the time update flag for 1 minute -> make noise!
timeUpdate = 0; // clear the flag
for (timeDigit = 0 ; timeDigit <4; timeDigit = timeDigit+1){ // cycle thru the digits
for (ditDa = 0b00010000; ditDa >0; ditDa >>1){  // masking bit
if ( (dotDash[timeArray[timeDigit]] & ditDa) > 0){ // play a dot if the bit is a  1 (one &? two &&?? I think just 1)
for (noise = 0; noise <100; noise = noise+1){ //  burst of tone for a dot- play with how long
digitalWrite (noisePin, HIGH);
delayMicroseconds (1132); // ~ Concert A
digitalWrite (noisePin, LOW);
delayMicroseconds (1132);
} // end dot
else { // play a burst of tone for a dash
for (noise = 0; noise <300; noise = noise+1){ //  burst of tone for a dot - 3x as long here, play with how long
digitalWrite (noisePin, HIGH);
delayMicroseconds (1132); // ~ Concert A
digitalWrite (noisePin, LOW);
delayMicroseconds (1132);
} // end dash
delay (innerDelay); // how fast the dots/dashes come out
} // end 5 bits of dot/dash
delay(digitDelay); // how fast the 4 digits come out
} // end 4 digits

// write code here for time setting, alarm setting, etc.

} // end loop

PeterH:
Given that you are generating these sequences on a timed basis there are two approaches you can take.

The blocking approach is to wait until it is time to send a sequence and then carry out a blocking sequence of beep/wait actions until the sequence is complete, then go back to waiting until it is time to send the next sequence. This approach means your sketch can only control one thing at a time and is a very limited approach, but it could be made to work. This would be using the delay() function that you mentioned in point (1) and say you want to get away from - IMO you're right to want to get away from it.

The non-blocking approach needs two activities to be performed on a timed basis. The first activity decides whether it is time to send out a morse code sequence. The second activity sends the timed beeps that comprise the requested sequence. The two activities need to communicate with each other. The way I'd implement this is with a circular buffer containing a queue of morse characters which need to be sent and haven't been sent yet. Your clock processing would just write morse characters to this queue. The sending function would use the timing logic demonstrated in the blink without delay example sketch to manage the sending of the sequence of beeps and gaps that constitute a given character, then pull the next morse character off the queue. It's up to you whether you want the queue to hold ascii characters or dot/dash/gap tokens. Having it hold dot/dash/gap tokens would simplify the sending code but means the queue would take up more space.

thanks a lot. this explanation is clear. I don't want the blocking approach, as later I would want to add a button to this and have it announce the time after pressed.

I can trigger the first activity using this, am I correct?

if(sec==60){
 sec=0; 
 minu++;
}

and the communication between these 2 activities are time based?

I want to queue the number, ie 12:13 to 1213 instead of dot/dash, but how can I do that? and since first one number takes time, how can I set the time for the second number? and how can the program see that 1213 number and does the sequence? thank you for your time.

thanks a lot, I will try to read and understand your codes.
=( I don’t think it works… I saw a lot of simple errors…

CrossRoads:
I would give it a try like this, using some arrays and making your own tone.
Have to declare all the variables, add setup, etc.
Sorry about the lack of indenting

byte timeArray [] = {0,0,0,0,};

byte dotdash = {0b00000000, 0b00010000, 0b00011000, 0b00011100, 0b00011110, 0b00011111, 0b00001111, 0b00000111, 0b00000011, 0b00000001,};
//http://en.wikipedia.org/wiki/Morse_code

void loop(){
currentTime = micros(); // capture the ‘time’
if ( (currentTime – nextTime) >= oneSecond){ // one second gone by?
nextTime = nextTime + oneSecond; // update for next time check
minutesOnes = minutesOnes + 1;
timeUpdate = 1; // set flag to make some noise on 1 minute updates
if (minutesOnes == 10){ // rollover
minutesOnes = 0;
minutesTens = minutesTens +1;
if (minutesTens == 6){ // rollover
minutesTens = 0;
hoursOnes = hoursOnes + 1;
if (hoursOnes == 10){  // rollover
hoursOnes = 0;
hoursTens = hoursTens +1;
if ( (hoursTens == 2) && (hoursOnes== 4){ // rollover at 24:00 - or set to 1 & 2 for 12 hour
hoursTens = 0;
hoursOnes = 0;
} // hoursTens check
} // hoursOnes check
} // minutesTens check
} // minutesOnes check
timeArray[0] = hoursTens;
timeArray[1] = hoursMinutes;
timeArray[2] = minutesTens;
timeArray[3] = minutesOnes;
} // end 1 second check
// or replace all that with reading the 4 variables from an RTC such as DS1307 using I2C commands

if (timeUpdate == 1){  // check the time update flag for 1 minute → make noise!
timeUpdate = 0; // clear the flag
for (timeDigit = 0 ; timeDigit <4; timeDigit = timeDigit+1){ // cycle thru the digits
for (ditDa = 0b00010000; ditDa >0; ditDa >>1){  // masking bit
if ( (dotDash[timeArray[timeDigit]] & ditDa) > 0){ // play a dot if the bit is a  1 (one &? two &&?? I think just 1)
for (noise = 0; noise <100; noise = noise+1){ //  burst of tone for a dot- play with how long
digitalWrite (noisePin, HIGH);
delayMicroseconds (1132); // ~ Concert A
digitalWrite (noisePin, LOW);
delayMicroseconds (1132);
} // end dot
else { // play a burst of tone for a dash
for (noise = 0; noise <300; noise = noise+1){ //  burst of tone for a dot - 3x as long here, play with how long
digitalWrite (noisePin, HIGH);
delayMicroseconds (1132); // ~ Concert A
digitalWrite (noisePin, LOW);
delayMicroseconds (1132);
} // end dash
delay (innerDelay); // how fast the dots/dashes come out
} // end 5 bits of dot/dash
delay(digitDelay); // how fast the 4 digits come out
} // end 4 digits

// write code here for time setting, alarm setting, etc.

} // end loop

Well, I am not somewhere where I can compile, and as noted the variable declarations and void setup() need to be written.

I’ve recently written a morse code generator.
It does use delay, but the delay is short enough that you could check a button in there somewhere too. Or convert it from using delay to something else.

And of course, instead of connecting an LED, connect a buzzer…

/*
 * The duration (in milliseconds) of one tick.
 * A tick can be a morse code "dot" or a pause.
 */
#define TICK_DURATION        200

/*
 * The basic morse elements "DOT" and "DASH".
 * These constants define how many ticks each are in length.
 */
#define DOT                  1
#define DASH                 3

/*
 * Parameters for the pulse() function.
 * Specify wheter to output a "mark" or a pause (gap).
 */
#define MARK                 0x08  /* Digital port 3 */
#define GAP                  0

/*
 * The default gap duration as measured in ticks.
 */
#define GAP_BETWEEN_MARKS    1
#define GAP_BETWEEN_LETTERS  2 // It's 3 - GAP_BETWEEN_MARKS
#define GAP_BETWEEN_WORDS    7

/*
 * Some pre-compiler magic to encode a morse
 * code character into a 2-byte unsigned integer.
 */
#define ENC1(n0)                     (n0)
#define ENC2(n0, n1)                 (n0 + (n1 << 2))
#define ENC3(n0, n1, n2)             (n0 + (n1 << 2) + (n2 << 4))
#define ENC4(n0, n1, n2, n3)         (n0 + (n1 << 2) + (n2 << 4) + (n3 << 6))
#define ENC5(n0, n1, n2, n3, n4)     (n0 + (n1 << 2) + (n2 << 4) + (n3 << 6) + (n4 << 8))

/*
 * The international morse code representatino of
 * the letters of the alphabet.
 */
PROGMEM const prog_uint16_t MORSE_ALPHA[] = {
    ENC2( DOT,  DASH ),                     /* A */
    ENC4( DASH, DOT,  DOT,  DOT ),          /* B */
    ENC4( DASH, DOT,  DASH, DOT ),          /* C */
    ENC3( DASH, DOT,  DOT ),                /* D */
    ENC1( DOT ),                            /* E */
    ENC4( DOT,  DOT,  DASH, DOT ),          /* F */
    ENC3( DASH, DASH, DOT ),                /* G */
    ENC4( DOT,  DOT,  DOT,  DOT ),          /* H */
    ENC2( DOT,  DOT ),                      /* I */
    ENC4( DOT,  DASH, DASH, DASH ),         /* J */
    ENC3( DASH, DOT,  DASH ),               /* K */
    ENC4( DOT,  DASH, DOT,  DOT ),          /* L */
    ENC2( DASH, DASH ),                     /* M */
    ENC2( DASH, DOT ),                      /* N */
    ENC3( DASH, DASH, DASH ),               /* O */
    ENC4( DOT,  DASH, DASH, DOT ),          /* P */
    ENC4( DASH, DASH, DOT,  DASH ),         /* Q */
    ENC3( DOT,  DASH, DOT ),                /* R */
    ENC3( DOT,  DOT,  DOT ),                /* S */
    ENC1( DASH ),                           /* T */
    ENC3( DOT,  DOT,  DASH ),               /* U */
    ENC4( DOT,  DOT,  DOT,  DASH ),         /* V */
    ENC3( DOT,  DASH, DASH ),               /* W */
    ENC4( DASH, DOT,  DOT,  DASH ),         /* X */
    ENC4( DASH, DOT,  DASH, DASH ),         /* Y */
    ENC4( DASH, DASH, DOT,  DOT )           /* Z */
};

/*
 * Same thing, but digits this time...
 */
PROGMEM const prog_uint16_t MORSE_NUM[] = {
    ENC5( DASH, DASH, DASH, DASH, DASH ),   /* 0 */
    ENC5( DOT,  DASH, DASH, DASH, DASH ),   /* 1 */
    ENC5( DOT,  DOT,  DASH, DASH, DASH ),   /* 2 */
    ENC5( DOT,  DOT,  DOT,  DASH, DASH ),   /* 3 */
    ENC5( DOT,  DOT,  DOT,  DOT,  DASH ),   /* 4 */
    ENC5( DOT,  DOT,  DOT,  DOT,  DOT ),    /* 5 */
    ENC5( DASH, DOT,  DOT,  DOT,  DOT ),    /* 6 */
    ENC5( DASH, DASH, DOT,  DOT,  DOT ),    /* 7 */
    ENC5( DASH, DASH, DASH, DOT,  DOT ),    /* 8 */
    ENC5( DASH, DASH, DASH, DASH, DOT )     /* 9 */
};

/*
 * Outputs either a MARK or GAP for the given number of ticks.
 */
static void pulse(char ticks, const char mark)
{
    PORTD = mark;
    while (ticks-- > 0)
        delay(TICK_DURATION);
    PORTD = 0;
}

/*
 * Outputs a morse code sequence, including any required
 * gaps between marks.
 */
static void pulseChar(prog_uint16_t seq)
{
    while ((seq & DASH) != 0)
    {
        pulse((seq & DASH), MARK);
        pulse(GAP_BETWEEN_MARKS, GAP);
        seq >>= 2;
    }
}

/*
 * Converts a message to morse code and sends the resulting pulses.
 */
static void morseMessage(const char* ch)
{
    /* Iterate over all characters in the message and convert letters to upper-case */
    while (*ch)
    {
        if (*ch >= 'A' && *ch <= 'Z')
            pulseChar(pgm_read_word(&MORSE_ALPHA[*ch - 'A']));

        else if (*ch >= '0' && *ch <= '9')
            pulseChar(pgm_read_word(&MORSE_ALPHA[*ch - '0']));

        if (*ch++ == ' ')
            pulse(GAP_BETWEEN_WORDS, GAP);
        else
            pulse(GAP_BETWEEN_LETTERS, GAP);
    }
}

void setup()
{
    /* Direct port access, setting the port associcated with "MARK" to OUTPUT */
    DDRD = MARK;
}

void loop()
{
    morseMessage("SOS 123\0"); /* !!! WARNING: LETTERS MUST BE CAPITALIZED !!! */
    delay(5000);
}

Ok, this is working.
Take out the serial prints, watch the LED on 13, replace with a speaker and adjust the tone frequency, burst, length, time between dots & dashes, and time between digits as needed.

byte timeArray [] = {
  0,0,0,0,};
byte dotDash [] = {
  0b00000000, 0b00010000, 0b00011000, 0b00011100, 0b00011110, 0b00011111, 0b00001111, 0b00000111, 0b00000011, 0b00000001,};
//http://en.wikipedia.org/wiki/Morse_code

unsigned long currentTime = 0;
unsigned long nextTime = 0;
unsigned long elapsed = 0;
unsigned long oneSecond = 1000000UL;  // sped up for testing
byte seconds;
byte minutesOnes;
byte minutesTens;
byte hoursOnes;
byte hoursTens;
byte timeUpdate;
byte timeDigit;
byte ditDa;
byte noise;
byte noisePin = 13;
int innerDelay = 50; 
int digitDelay = 100;
byte maskBit;

void setup(){
  Serial.begin (115200);
  pinMode (noisePin, OUTPUT);
}
void loop(){
  currentTime = micros(); // capture the time
  elapsed = currentTime - nextTime;
  if ( elapsed >= oneSecond ){ // one second gone by?
    nextTime = nextTime + oneSecond; // update for next time check
    seconds = seconds +1; // 
    if (seconds == 60){
      seconds = 0;
      minutesOnes = minutesOnes + 1;
      timeUpdate = 1; // set flag to make some noise on 1 minute updates
      if (minutesOnes == 10){ // rollover
        minutesOnes = 0;
        minutesTens = minutesTens +1;
        if (minutesTens == 6){ // rollover
          minutesTens = 0;
          hoursOnes = hoursOnes + 1;
          if (hoursOnes == 10){  // rollover
            hoursOnes = 0;
            hoursTens = hoursTens +1;
            if ( (hoursTens == 2) && (hoursOnes== 4)){ // rollover at 24:00 - or set to 1 & 2 for 12 hour
              hoursTens = 0;
              hoursOnes = 0;
            } // hoursTens check
          } // hoursOnes check
        } // minutesTens check
      } // minutesOnes check
      timeArray[0] = hoursTens;
      timeArray[1] = hoursOnes;
      timeArray[2] = minutesTens;
      timeArray[3] = minutesOnes;

    }
    Serial.print (".");
    if ((seconds == 0) || (seconds == 30) ){
      Serial.print ("Time ");
      Serial.print (timeArray[0]);
      Serial.print (" ");
      Serial.print (timeArray[1]);
      Serial.print (" : ");
      Serial.print (timeArray[2]);
      Serial.print (" ");
      Serial.print (timeArray[3]);
      Serial.print (" : ");
      Serial.println (seconds);
      //Serial.print (" time update flag ");
      //Serial.println (timeUpdate);
    }

  } // end 1 second check
  // or replace all that with reading the 4 variables from an RTC such as DS1307 using I2C commands

    if (timeUpdate == 1){  // check the time update flag for 1 minute -> make noise!
    timeUpdate = 0; // clear the flag
    for (timeDigit = 0 ; timeDigit <4; timeDigit = timeDigit+1){ // cycle thru the digits
      for (ditDa = 0b00010000; ditDa >0; ditDa = ditDa >> 1){  // masking bit
        //Serial.print ("ditDa ");
        //Serial.print (ditDa, BIN);
        //Serial.print (" maskBit ");
        maskBit = dotDash[timeArray[timeDigit]] & ditDa;
        //Serial.println (maskBit, BIN);

        if (maskBit == 0){ 
          // play a burst of tone for a dash
          Serial.print ("dash ");
          for (noise = 0; noise <30; noise = noise+1){ //  burst of tone for a dot - 3x as long here, play with how long
            digitalWrite (noisePin, HIGH);
            delayMicroseconds (1132); // ~ Concert A
            digitalWrite (noisePin, LOW);
            delayMicroseconds (1132);
          } // end inner dash
        }

        else { 
          // play a dot if the bit is a 1
          Serial.print ("dot ");
          for (noise = 0; noise <10; noise = noise+1){ //  burst of tone for a dot- play with how long
            digitalWrite (noisePin, HIGH);
            delayMicroseconds (1132); // ~ Concert A
            digitalWrite (noisePin, LOW);
            delayMicroseconds (1132);
          } // end inner dot
        }
        // end dot
        // Serial.println ("inner ");
        delay (innerDelay); // how fast the dots/dashes come out
      }
      //Serial.println ("digit ");
      Serial.println(" ");
      delay(digitDelay); // how fast the 4 digits come out
    } // end 5 bits of dot/dash

  } // end 4 digits
  // write code here for time setting, alarm setting, etc.

} // end loop

CrossRoads:
Ok, this is working.
Take out the serial prints, watch the LED on 13, replace with a speaker and adjust the tone frequency, burst, length, time between dots & dashes, and time between digits as needed.

byte timeArray [] = {

0,0,0,0,};
byte dotDash = {
  0b00000000, 0b00010000, 0b00011000, 0b00011100, 0b00011110, 0b00011111, 0b00001111, 0b00000111, 0b00000011, 0b00000001,};
//http://en.wikipedia.org/wiki/Morse_code

unsigned long currentTime = 0;
unsigned long nextTime = 0;
unsigned long elapsed = 0;
unsigned long oneSecond = 1000000UL;  // sped up for testing
byte seconds;
byte minutesOnes;
byte minutesTens;
byte hoursOnes;
byte hoursTens;
byte timeUpdate;
byte timeDigit;
byte ditDa;
byte noise;
byte noisePin = 13;
int innerDelay = 50;
int digitDelay = 100;
byte maskBit;

void setup(){
  Serial.begin (115200);
  pinMode (noisePin, OUTPUT);
}
void loop(){
  currentTime = micros(); // capture the time
  elapsed = currentTime - nextTime;
  if ( elapsed >= oneSecond ){ // one second gone by?
    nextTime = nextTime + oneSecond; // update for next time check
    seconds = seconds +1; //
    if (seconds == 60){
      seconds = 0;
      minutesOnes = minutesOnes + 1;
      timeUpdate = 1; // set flag to make some noise on 1 minute updates
      if (minutesOnes == 10){ // rollover
        minutesOnes = 0;
        minutesTens = minutesTens +1;
        if (minutesTens == 6){ // rollover
          minutesTens = 0;
          hoursOnes = hoursOnes + 1;
          if (hoursOnes == 10){  // rollover
            hoursOnes = 0;
            hoursTens = hoursTens +1;
            if ( (hoursTens == 2) && (hoursOnes== 4)){ // rollover at 24:00 - or set to 1 & 2 for 12 hour
              hoursTens = 0;
              hoursOnes = 0;
            } // hoursTens check
          } // hoursOnes check
        } // minutesTens check
      } // minutesOnes check
      timeArray[0] = hoursTens;
      timeArray[1] = hoursOnes;
      timeArray[2] = minutesTens;
      timeArray[3] = minutesOnes;

}
    Serial.print (".");
    if ((seconds == 0) || (seconds == 30) ){
      Serial.print ("Time “);
      Serial.print (timeArray[0]);
      Serial.print (” “);
      Serial.print (timeArray[1]);
      Serial.print (” : “);
      Serial.print (timeArray[2]);
      Serial.print (” “);
      Serial.print (timeArray[3]);
      Serial.print (” : “);
      Serial.println (seconds);
      //Serial.print (” time update flag ");
      //Serial.println (timeUpdate);
    }

} // end 1 second check
  // or replace all that with reading the 4 variables from an RTC such as DS1307 using I2C commands

if (timeUpdate == 1){  // check the time update flag for 1 minute → make noise!
    timeUpdate = 0; // clear the flag
    for (timeDigit = 0 ; timeDigit <4; timeDigit = timeDigit+1){ // cycle thru the digits
      for (ditDa = 0b00010000; ditDa >0; ditDa = ditDa >> 1){  // masking bit
        //Serial.print ("ditDa “);
        //Serial.print (ditDa, BIN);
        //Serial.print (” maskBit ");
        maskBit = dotDash[timeArray[timeDigit]] & ditDa;
        //Serial.println (maskBit, BIN);

if (maskBit == 0){
          // play a burst of tone for a dash
          Serial.print ("dash ");
          for (noise = 0; noise <30; noise = noise+1){ //  burst of tone for a dot - 3x as long here, play with how long
            digitalWrite (noisePin, HIGH);
            delayMicroseconds (1132); // ~ Concert A
            digitalWrite (noisePin, LOW);
            delayMicroseconds (1132);
          } // end inner dash
        }

else {
          // play a dot if the bit is a 1
          Serial.print ("dot ");
          for (noise = 0; noise <10; noise = noise+1){ //  burst of tone for a dot- play with how long
            digitalWrite (noisePin, HIGH);
            delayMicroseconds (1132); // ~ Concert A
            digitalWrite (noisePin, LOW);
            delayMicroseconds (1132);
          } // end inner dot
        }
        // end dot
        // Serial.println ("inner ");
        delay (innerDelay); // how fast the dots/dashes come out
      }
      //Serial.println ("digit “);
      Serial.println(” ");
      delay(digitDelay); // how fast the 4 digits come out
    } // end 5 bits of dot/dash

} // end 4 digits
  // write code here for time setting, alarm setting, etc.

} // end loop

It works. thank you a lot. I thought it won’t work because you use delay here. won’t this block the system?

int2str:
I’ve recently written a morse code generator.
It does use delay, but the delay is short enough that you could check a button in there somewhere too. Or convert it from using delay to something else.

And of course, instead of connecting an LED, connect a buzzer…

/*
  • The duration (in milliseconds) of one tick.
  • A tick can be a morse code “dot” or a pause.
    */
    #define TICK_DURATION        200

/*

  • The basic morse elements “DOT” and “DASH”.
  • These constants define how many ticks each are in length.
    */
    #define DOT                  1
    #define DASH                 3

/*

  • Parameters for the pulse() function.
  • Specify wheter to output a “mark” or a pause (gap).
    /
    #define MARK                 0x08  /
    Digital port 3 */
    #define GAP                  0

/*

  • The default gap duration as measured in ticks.
    */
    #define GAP_BETWEEN_MARKS    1
    #define GAP_BETWEEN_LETTERS  2 // It’s 3 - GAP_BETWEEN_MARKS
    #define GAP_BETWEEN_WORDS    7

/*

  • Some pre-compiler magic to encode a morse
  • code character into a 2-byte unsigned integer.
    */
    #define ENC1(n0)                     (n0)
    #define ENC2(n0, n1)                 (n0 + (n1 << 2))
    #define ENC3(n0, n1, n2)             (n0 + (n1 << 2) + (n2 << 4))
    #define ENC4(n0, n1, n2, n3)         (n0 + (n1 << 2) + (n2 << 4) + (n3 << 6))
    #define ENC5(n0, n1, n2, n3, n4)     (n0 + (n1 << 2) + (n2 << 4) + (n3 << 6) + (n4 << 8))

/*

  • The international morse code representatino of
  • the letters of the alphabet.
    /
    PROGMEM const prog_uint16_t MORSE_ALPHA[] = {
       ENC2( DOT,  DASH ),                     /
    A /
       ENC4( DASH, DOT,  DOT,  DOT ),          /
    B /
       ENC4( DASH, DOT,  DASH, DOT ),          /
    C /
       ENC3( DASH, DOT,  DOT ),                /
    D /
       ENC1( DOT ),                            /
    E /
       ENC4( DOT,  DOT,  DASH, DOT ),          /
    F /
       ENC3( DASH, DASH, DOT ),                /
    G /
       ENC4( DOT,  DOT,  DOT,  DOT ),          /
    H /
       ENC2( DOT,  DOT ),                      /
    I /
       ENC4( DOT,  DASH, DASH, DASH ),         /
    J /
       ENC3( DASH, DOT,  DASH ),               /
    K /
       ENC4( DOT,  DASH, DOT,  DOT ),          /
    L /
       ENC2( DASH, DASH ),                     /
    M /
       ENC2( DASH, DOT ),                      /
    N /
       ENC3( DASH, DASH, DASH ),               /
    O /
       ENC4( DOT,  DASH, DASH, DOT ),          /
    P /
       ENC4( DASH, DASH, DOT,  DASH ),         /
    Q /
       ENC3( DOT,  DASH, DOT ),                /
    R /
       ENC3( DOT,  DOT,  DOT ),                /
    S /
       ENC1( DASH ),                           /
    T /
       ENC3( DOT,  DOT,  DASH ),               /
    U /
       ENC4( DOT,  DOT,  DOT,  DASH ),         /
    V /
       ENC3( DOT,  DASH, DASH ),               /
    W /
       ENC4( DASH, DOT,  DOT,  DASH ),         /
    X /
       ENC4( DASH, DOT,  DASH, DASH ),         /
    Y /
       ENC4( DASH, DASH, DOT,  DOT )           /
    Z */
    };

/*

  • Same thing, but digits this time…
    /
    PROGMEM const prog_uint16_t MORSE_NUM[] = {
       ENC5( DASH, DASH, DASH, DASH, DASH ),   /
    0 /
       ENC5( DOT,  DASH, DASH, DASH, DASH ),   /
    1 /
       ENC5( DOT,  DOT,  DASH, DASH, DASH ),   /
    2 /
       ENC5( DOT,  DOT,  DOT,  DASH, DASH ),   /
    3 /
       ENC5( DOT,  DOT,  DOT,  DOT,  DASH ),   /
    4 /
       ENC5( DOT,  DOT,  DOT,  DOT,  DOT ),    /
    5 /
       ENC5( DASH, DOT,  DOT,  DOT,  DOT ),    /
    6 /
       ENC5( DASH, DASH, DOT,  DOT,  DOT ),    /
    7 /
       ENC5( DASH, DASH, DASH, DOT,  DOT ),    /
    8 /
       ENC5( DASH, DASH, DASH, DASH, DOT )     /
    9 */
    };

/*

  • Outputs either a MARK or GAP for the given number of ticks.
    */
    static void pulse(char ticks, const char mark)
    {
       PORTD = mark;
       while (ticks-- > 0)
           delay(TICK_DURATION);
       PORTD = 0;
    }

/*

  • Outputs a morse code sequence, including any required
  • gaps between marks.
    */
    static void pulseChar(prog_uint16_t seq)
    {
       while ((seq & DASH) != 0)
       {
           pulse((seq & DASH), MARK);
           pulse(GAP_BETWEEN_MARKS, GAP);
           seq >>= 2;
       }
    }

/*

  • Converts a message to morse code and sends the resulting pulses.
    /
    static void morseMessage(const char
    ch)
    {
       /* Iterate over all characters in the message and convert letters to upper-case */
       while (*ch)
       {
           if (*ch >= ‘A’ && *ch <= ‘Z’)
               pulseChar(pgm_read_word(&MORSE_ALPHA[*ch - ‘A’]));

else if (*ch >= ‘0’ && *ch <= ‘9’)
           pulseChar(pgm_read_word(&MORSE_ALPHA[*ch - ‘0’]));

if (*ch++ == ’ ')
           pulse(GAP_BETWEEN_WORDS, GAP);
       else
           pulse(GAP_BETWEEN_LETTERS, GAP);
   }
}

void setup()
{
   /* Direct port access, setting the port associcated with “MARK” to OUTPUT */
   DDRD = MARK;
}

void loop()
{
   morseMessage(“SOS 123\0”); /* !!! WARNING: LETTERS MUST BE CAPITALIZED !!! */
   delay(5000);
}

thanks for sharing, I can see you have some neat coding here.

Yes, delay will block. Its a clock tho outputs the time once a minute - what else did you want to have going on?
The dits and dahs take a second or two or three, outside of that nothing is blocked and time is accurately maintained (as accurate as your crystal or resonator allow).

CrossRoads:
Yes, delay will block. Its a clock tho outputs the time once a minute - what else did you want to have going on?
The dits and dahs take a second or two or three, outside of that nothing is blocked and time is accurately maintained (as accurate as your crystal or resonator allow).

Thanks for all the help so far. I am yet to fully understanding your code.

This time announcer clock is a Christmas gift for a blind friend of mine. I want it to run using an 8 pins attiny chip. It will have 1 button or 2 to set the time without using a computer, preferable a morse code input to do so. I am thinking using a triple button presses to trigger the input of current time by morse code, then after finishing entering the morse code, the beeper will confirm the time. I also want it to announce the time by the beeper with a single button press, as beeping every minute is not what I really want it to do.

since there are 5 usable pins in an attiny chip: 1 for the beeper, 2 for the buttons, maybe having a LED to repeatedly flash a morse code once enter through the button would be a neat feature, and for the last pin, I would want to have a mic-phone as an simple input similar to a button, but instead of pressing, a pattern of sound will trigger some actions, such as announcing the time.

photos of my testing board

Well, you’ve got quite the programming challenge set for yourself!
Analog-in will need some bit of external circuitry, from microphone +/- maybe 0.5V need to amplify a little and offset into 2.5V +/- 2.5V range (op-amp, couple of resistors, capacitor or two).
I could ‘see’ your friend chirping away getting it into programming mode, and then more chirping as entered each digit.

As written, my code, with no Serial.begin and all Serial.prints commented out, compiles to 1616 bytes.
The other compiles to 958 but has no time keeping code.
ATtiny85 has 8K of memory.
Add button code, add ADC code, hard to predict what the final size will be.

For instance, taking out the once/minute time check and adding this:

if (digitalRead (button1) == LOW){
timeUpdate = 1;
}

the size goes to 1856.

Using direct port manipulation instead:
if ((PINB & 0b00000100) == 0){ // BIT2 arbitrarily selected for the button, LOW = pressed
timeUpdate = 1;
}
1692 bytes.

ATTiny25-45-85 summary.pdf (692 KB)

CrossRoads:
Well, you've got quite the programming challenge set for yourself!
Analog-in will need some bit of external circuitry, from microphone +/- maybe 0.5V need to amplify a little and offset into 2.5V +/- 2.5V range (op-amp, couple of resistors, capacitor or two).
I could 'see' your friend chirping away getting it into programming mode, and then more chirping as entered each digit.

As written, my code, with no Serial.begin and all Serial.prints commented out, compiles to 1616 bytes.
The other compiles to 958 but has no time keeping code.
ATtiny85 has 8K of memory.
Add button code, add ADC code, hard to predict what the final size will be.

For instance, taking out the once/minute time check and adding this:

if (digitalRead (button1) == LOW){
timeUpdate = 1;
}

the size goes to 1856.

Using direct port manipulation instead:
if ((PINB & 0b00000100) == 0){ // BIT2 arbitrarily selected for the button, LOW = pressed
timeUpdate = 1;
}
1692 bytes.

again, thanks a lot. the external circuitry part is not a big problem for me, as I am a little experienced on that. Honestly, I still haven't fully understood how your code work logically, but it did work great. I have it running for hours, and it will beep every minute. I really need to learn more before I try to really start writing codes for this beeper clock. Now I know a simple program like this is very complex.

I have a simple question about attiny85. Won't it reset itself about 50 or so days? Is it wise to really build this project on it?