Dynamic Memory Help on Atmega16

Hi all!

I am programming an alarm clock that I have made based on the Atmega16. I have added a Piezo buzzer, so I can make the alarm be a song instead of just a regular buzzer. I have barely added any notes for the song though, and things on the clock stop functioning. The dynamic memory is only at 70% though, so it isn't maxed out :thinking:.

Now, if I try to add a couple more notes, for example, the alarm set just flashes zeros, and you cant set it.

Any ideas on what's going on? And how I can finish the song?

Thanks in advance!

alarm.ino:

#include "Clock.hpp"
#include "music.h"
#include <avr/eeprom.h>

#define setbuttondelay 2000

int hour = 6;
int minute = 0;

int lastsecond = 0;
bool secondflash = false;

bool setalarm = false;
bool alarm = true;
String alarmtime = "";

unsigned long stmillis = 0;
unsigned long buttonmillis = 0;

bool flash = false;
unsigned long flashmillis = 0;
int flashon = 500;
int flashoff = 1200;

bool pm = false;

SevSeg sevseg;
dht DHT;
uRTCLib rtc(0x68);

Clock clock(&sevseg, &DHT, &rtc);

void setup(){
  //to set the time, uncomment the lines below
  //URTCLIB_WIRE.begin();
  //rtc.set(0, 27, 7, 5, 8, 3, 23);
  clock.begin();

  hour = eeprom_read_byte((const uint8_t*)0);
  minute = eeprom_read_byte((const uint8_t*)1);
  alarm = eeprom_read_byte((const uint8_t*)2);
  pm = eeprom_read_byte((const uint8_t*)3);
  if (alarm){
    clock.setalarm(1,hour,minute,0,rtc.day(),pm);
  }
  if (pm){
    hour = hour+12;
  }
}

void loop(){
  if (setalarm){
    ret:
    handlesetalarm();
    if (setalarm){goto ret;}
    eeprom_update_byte((uint8_t*)0,hour);
    eeprom_update_byte((uint8_t*)1,minute);
    eeprom_update_byte((uint8_t*)2,alarm);
    if (hour > 11){pm = true;}//afternoon is PM
    if (hour == 24){pm = false;}//midnight would be AM
    if (hour <= 11){pm = false;}//morning is AM
    if (hour > 12){hour=hour-12;}//12 hour time
    eeprom_update_byte((uint8_t*)3,pm);
    clock.setalarm(1,hour,minute,0,rtc.day(),pm);
    if (pm){
      hour = hour+12;
    }
    playtone();
  }
  if (lastsecond != rtc.second()){
    secondflash = !secondflash;
    lastsecond = rtc.second();
  }
  if (secondflash){
    clock.displayint(clock.gettime());
  }
  else {
    int timee = 0;
    if (rtc.hour() > 12){//convert to 12hr time
      timee = rtc.hour() - 12;
    }
    else {
      timee = rtc.hour();
    }

    String displaytime = "";
    if (rtc.minute() < 10){
      displaytime = String(timee) + "0" + String(rtc.minute());
    }
    else {
      displaytime = String(timee) + String(rtc.minute());
    }
    clock.displayint(displaytime.toInt(),0);
  }

  clock.rgb(0,clock.potentiometer(),0);

  if (digitalRead(Button1) == LOW){
    stmillis = millis();
    while (digitalRead(Button1) == LOW);
    if (millis() - stmillis > setbuttondelay){
      setalarm = true;
      flashmillis = millis();
    }
    else {
      setalarm = false;
    }
  }
  if (digitalRead(Button2) == LOW){
    unsigned long stmill = millis();
    while(digitalRead(Button2) == LOW);
    if (millis() - stmill > 3000){
      alarm = !alarm;
      if (alarm){
        clock.setalarm(1,hour,minute,0,rtc.day(),pm);
        playtone();
        unsigned long curmil = millis();
        while(millis() - curmil < 4000){
          clock.displaychar("ON");
          clock.refresh();
        }
      }
      else {
        clock.setalarm(1,hour,minute,0,rtc.day(),pm,false);
        unsigned long curmil = millis();
        while(millis() - curmil < 4000){
          clock.displaychar("OFF");
          clock.refresh();
        }
      }
    }
  }
  clock.checkalarm();
  if (buzzeralarm){
    playmelody();
    buzzeralarm = false;
  }
  clock.refresh();
}

void handlesetalarm(){
  if (minute < 10){
    alarmtime = String(hour) + "0" + String(minute);
  }
  else {
    alarmtime = String(hour) + String(minute);
  }
  if (flash){
    if (millis() - flashmillis > flashon){
      flashmillis = millis();
      flash = !flash;
    }
  }
  else {
    if (millis() - flashmillis > flashoff){
      flashmillis = millis();
      flash = !flash;
    }
  }

  if (flash){
    clock.displayclear();
  }
  else {
    clock.displayint(alarmtime.toInt());
  }

  if (digitalRead(Button1) == LOW){
    buttonmillis = millis();
    while (digitalRead(Button1) == LOW);
    if (millis() - buttonmillis > setbuttondelay){
      setalarm = false;
    }
    else {
      hour++;
      if (hour > 24){
        hour = 1;
      }
    }
    clock.beep(50);
  }
  if (digitalRead(Button2) == LOW){
    buttonmillis = millis();
    while (digitalRead(Button2) == LOW){
      if (millis() - buttonmillis > 200){
        minute++;
        goto ext;
      }
    }
    ext:
    minute++;
    if (minute >= 60){
      minute = 0;
    }
    clock.beep(50);
  }
  clock.refresh();
}

music.h:

#include "pitches.h"

int mel[] = {
  NOTE_E4, NOTE_G4, NOTE_D4, NOTE_E4, NOTE_C4
};
int notedur[] = {
  2, 4, 4, 4, 3
};
void playtone(float speed=0.8){
  for (int thisNote = 0; thisNote < 5; thisNote++) {

    // to calculate the note duration, take one second divided by the note type.
    //e.g. quarter note = 1000 / 4, eighth note = 1000/8, etc.
    int noteDuration = (1000 / notedur[thisNote]) * speed;
    tone(Buzzer, mel[thisNote], noteDuration);

    // to distinguish the notes, set a minimum time between them.
    // the note's duration + 30% seems to work well:
    int pauseBetweenNotes = noteDuration * 1.30;
    delay(pauseBetweenNotes);
    // stop the tone playing:
    noTone(Buzzer);
  }
}

// change this to make the song slower or faster
int tempo = 100;

// notes of the moledy followed by the duration.
// a 4 means a quarter note, 8 an eighteenth , 16 sixteenth, so on
// !!negative numbers are used to represent dotted notes,
// so -4 means a dotted quarter note, that is, a quarter plus an eighteenth!!
int melody[] = {

  // Cannon in D - Pachelbel
  // Score available at https://musescore.com/user/4710311/scores/1975521
  // C F
  /*NOTE_FS4,2, NOTE_E4,2,
  NOTE_D4,2, NOTE_CS4,2,
  NOTE_B3,2, NOTE_A3,2,
  NOTE_B3,2, NOTE_CS4,2,
  NOTE_FS4,2, NOTE_E4,2,
  NOTE_D4,2, NOTE_CS4,2,
  NOTE_B3,2, NOTE_A3,2,
  NOTE_B3,2, NOTE_CS4,2,
  NOTE_D4,2, NOTE_CS4,2,
  NOTE_B3,2, NOTE_A3,2,
  NOTE_G3,2, NOTE_FS3,2,
  NOTE_G3,2, NOTE_A3,2,*/

  NOTE_A4,4,  NOTE_FS4,8, NOTE_G4,8,  NOTE_A4,4,  NOTE_FS4,8, NOTE_G4,8, 
  NOTE_A4,8,  NOTE_A3,8,  NOTE_B3,8,  NOTE_CS4,8, NOTE_D4,8,  NOTE_E4,8, NOTE_FS4,8, NOTE_G4,8, 
  NOTE_FS4,4, NOTE_D4,8,  NOTE_E4,8,  NOTE_FS4,4, NOTE_FS4,8, NOTE_G4,8,
  NOTE_A4,8,  NOTE_B4,8,  NOTE_A4,8,  NOTE_G4,8,  NOTE_A4,8,  NOTE_FS4,8, NOTE_G4,8, NOTE_A4,8,
  /*NOTE_G4,4,  NOTE_B4,8,  NOTE_A4,8,  NOTE_G4,4,  NOTE_FS4,8, NOTE_E4,8, 
  NOTE_FS4,8, NOTE_E4,8,  NOTE_D4,8,  NOTE_E4,8,  NOTE_FS4,8, NOTE_G4,8,  NOTE_A4,8, NOTE_B4,8,*/

  /*NOTE_G4,4, NOTE_B4,8, NOTE_A4,8, NOTE_B4,4, NOTE_CS4,8, NOTE_D5,8,
  NOTE_A3,8, NOTE_B3,8, NOTE_CS4,8, NOTE_D4,8, NOTE_E4,8, NOTE_FS4,8, NOTE_G4,8, NOTE_A4,8,

  NOTE_A4,1, NOTE_A4,4, NOTE_B4,4, NOTE_A4,4, NOTE_G4,4,
  NOTE_FS4,1, NOTE_FS4,4, NOTE_G4,4, NOTE_FS4,4, NOTE_E4,4, NOTE_D4,4, NOTE_C3,4, NOTE_B3,4, NOTE_C3,4, NOTE_A3,1,

  NOTE_G3,2, NOTE_B3,2,  NOTE_C3,1, NOTE_D4,-16, NOTE_D4,1,*/


  /*NOTE_A4,4, NOTE_FS4,8, NOTE_G4,8, NOTE_A4,4,
  NOTE_FS4,8, NOTE_G4,8, NOTE_A4,8, NOTE_A3,8, NOTE_B3,8, NOTE_CS4,8,
  NOTE_D4,8, NOTE_E4,8, NOTE_FS4,8, NOTE_G4,8, NOTE_FS4,4, NOTE_D4,8, NOTE_E4,8,
  NOTE_FS4,8, NOTE_CS4,8, NOTE_A3,8, NOTE_A3,8,*/

  /*NOTE_CS4,4, NOTE_B3,4, NOTE_D4,8, NOTE_CS4,8, NOTE_B3,4,
  NOTE_A3,8, NOTE_G3,8, NOTE_A3,4, NOTE_D3,8, NOTE_E3,8, NOTE_FS3,8, NOTE_G3,8,
  NOTE_A3,8, NOTE_B3,4, NOTE_G3,4, NOTE_B3,8, NOTE_A3,8, NOTE_B3,4,
  NOTE_CS4,8, NOTE_D4,8, NOTE_A3,8, NOTE_B3,8, NOTE_CS4,8, NOTE_D4,8, NOTE_E4,8,
  NOTE_FS4,8, NOTE_G4,8, NOTE_A4,2,*/
   
  
};

// sizeof gives the number of bytes, each int value is composed of two bytes (16 bits)
// there are two values per note (pitch and duration), so for each note there are four bytes
int notes = sizeof(melody) / sizeof(melody[0]) / 2;

// this calculates the duration of a whole note in ms
int wholenote = (60000 * 4) / tempo;

int divider = 0, noteDuration = 0;

void playmelody(){
  // iterate over the notes of the melody.
  // Remember, the array is twice the number of notes (notes + durations)
  for (int thisNote = 0; thisNote < notes * 2; thisNote = thisNote + 2) {

    // calculates the duration of each note
    divider = melody[thisNote + 1];
    if (divider > 0) {
      // regular note, just proceed
      noteDuration = (wholenote) / divider;
    } else if (divider < 0) {
      // dotted notes are represented with negative durations!!
      noteDuration = (wholenote) / abs(divider);
      noteDuration *= 1.5; // increases the duration in half for dotted notes
    }

    // we only play the note for 90% of the duration, leaving 10% as a pause
    tone(Buzzer, melody[thisNote], noteDuration * 0.9);

    // Wait for the specief duration before playing the next note.
    delay(noteDuration);

    // stop the waveform generation before the next note.
    noTone(Buzzer);

    if (digitalRead(Button1) == LOW){
      goto ex;
    }
  }
  ex:
  delay(1);
}

pitches.h:

#define NOTE_C3  131
#define NOTE_CS3 139
#define NOTE_D3  147
#define NOTE_DS3 156
#define NOTE_E3  165
#define NOTE_F3  175
#define NOTE_FS3 185
#define NOTE_G3  196
#define NOTE_GS3 208
#define NOTE_A3  220
#define NOTE_AS3 233
#define NOTE_B3  247
#define NOTE_C4  262
#define NOTE_CS4 277
#define NOTE_D4  294
#define NOTE_DS4 311
#define NOTE_E4  330
#define NOTE_F4  349
#define NOTE_FS4 370
#define NOTE_G4  392
#define NOTE_GS4 415
#define NOTE_A4  440
#define NOTE_AS4 466
#define NOTE_B4  494
#define NOTE_C5  523
#define NOTE_CS5 554
#define NOTE_D5  587
#define NOTE_DS5 622
#define NOTE_E5  659
#define NOTE_F5  698
#define NOTE_FS5 740
#define NOTE_G5  784
#define NOTE_GS5 831
#define NOTE_A5  880
#define NOTE_AS5 932
#define NOTE_B5  988
#define REST 0

Clock.hpp library can be found here:

Edit:
Here is the verbose output on space when uploading:

Sketch uses 14506 bytes (91%) of program storage space. Maximum is 15872 bytes.
Global variables use 718 bytes (70%) of dynamic memory, leaving 306 bytes for local variables. Maximum is 1024 bytes.

Don't have time to look closely before work, but a couple of ideas:

Can you store the array of notes in PROGMEM?

Avoid the use of String - it looks like you are using that to do a convoluted version of combining the hours and minutes, would be much easier to just use 100 * hours + minutes.

1 Like

Good idea! I tried that, and for some reason, the piezo just plays a really high note for about 2 seconds, and then shuts off. Nothing else happens.

Sometimes I just like to do things the hard way :man_facepalming: . I fixed everything that was a string, and now it works with the whole song in dynamic memory!
Here's the program space:

Sketch uses 12086 bytes (76%) of program storage space. Maximum is 15872 bytes.
Global variables use 898 bytes (87%) of dynamic memory, leaving 126 bytes for local variables. Maximum is 1024 bytes.

Thanks @david_2018 !

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