Weird behavior after adding new variables

Hi,
i was trying to programm my arduino uno with i2c display attached. Everything was ok but after i added 4 more variables display now draws only set of random pixels and i cant get why.

This code broke my program:

//BT
String inData = "";
String btMsg;

//GPS
float gpsLat = 0;
float gpsLon = 0;

This says i have only half space used: Binary sketch size: 13 098 bytes (of a 32 256 byte maximum)

Every help would be appraciated.

PS: Sorry for my english, its not my primary language.

This is whole code but in this case it seems to me irrelevant:

#include <Adafruit_ssd1306syp.h>
#include <Button.h>
#include <AsMenuItem.h>
#include "Timer.h"
#define SDA_PIN 8
#define SCL_PIN 9
Adafruit_ssd1306syp display(SDA_PIN,SCL_PIN);

Timer t;

static const unsigned char PROGMEM arrow_sign[] =
{ B00000000, 
  B00000000,
  B10000000, 
  B11000000,
  B11100000, 
  B11000000,
  B10000000, 
  B00000000 };
  
boolean displayUpdateRequired = false;
//Temperature
int tempUnits = 0;
float temp_in_celsius = 0, temp_in_kelvin=0, temp_in_fahrenheit=0;

static const unsigned char PROGMEM tmp_sign[] =
{ B11100000, 
  B10100000,
  B11100000, 
  B00000000 };
  
//BT
String inData = "";
String btMsg;

//GPS
float gpsLat = 0;
float gpsLon = 0;
  
//TIME
int hours = 0;
int minutes = 0;
int seconds = 0;

int days = 1;
int months = 1;
int years = 2000;
  
//MENU
const int menItmCnt = 10;
AsMenuItem menuItems[menItmCnt];
int menuItmNow = 0;
int menuShowedMin = 0;
int scrIndex = 0;

const int btn1 = 6;
Button button1 = Button(btn1, BUTTON_PULLUP_INTERNAL);

void setup()
{
  menuItems[0] = AsMenuItem("Itm1", 6);
  menuItems[1] = AsMenuItem("Itm2", 7);
  menuItems[2] = AsMenuItem("Itm3", 8);
  menuItems[3] = AsMenuItem("Itm4", 3);
  menuItems[4] = AsMenuItem("Itm5", 10);
  menuItems[5] = AsMenuItem("Itm6", 5);
  menuItems[6] = AsMenuItem("Itm7", 1);
  menuItems[7] = AsMenuItem("Itm8", 2);
  menuItems[8] = AsMenuItem("Itm9", 9);
  menuItems[9] = AsMenuItem("Itm10", 4);
  
  //Serial.begin(9600); //BT

  delay(1000);
  display.initialize();
  /*
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(14,40);
  display.print("Start");
  display.update();
  delay(3000);
  display.clear();*/
  t.every(1000, timeTimer);
  displayUpdateRequired = true;
}

void loop()
{
  t.update();
  btnHandler();
  //btHandler();
  tempHandler();
  display_update();
}

void btnHandler()
{
   switch(scrIndex)
    {
      case 0:
      if (button1.uniquePress())
      {
        menuItmNow++;
        if(menuItmNow > menItmCnt - 1)
        {menuItmNow = 0; menuShowedMin = 0;}
        if(menuShowedMin + 3 < menuItmNow)
        {menuShowedMin++;}
        displayUpdateRequired = true;
      }
      break;
    }
}  

void display_update()
{
  if(displayUpdateRequired)
  {
    display.fillRect(0,8,128,56, BLACK);
    display.setTextSize(1);
    display.setTextColor(WHITE);
    display.setCursor(8,12);
    display.print(menuItems[menuShowedMin].getName());
    display.setCursor(8,22);
    display.print(menuItems[menuShowedMin + 1].getName());
    display.setCursor(8,32);
    display.print(menuItems[menuShowedMin + 2].getName());
    display.setCursor(8,42);
    display.print(menuItems[menuShowedMin + 3].getName());
    
    //display.setCursor(8,52);
    //display.print(menuShowedMin + 3);
    
    display.drawBitmap(0, ((menuItmNow + 1 - menuShowedMin) * 10) + 2, arrow_sign, 8, 8, WHITE);
    display.update();
    displayUpdateRequired = false;
  }
}

void timeTimer()
{
  seconds++;
  if(seconds > 59)
  {
    minutes++;
    seconds = 0;
  }
  if(minutes > 59)
  {
    hours++;
    minutes = 0;
  }
  if(hours > 23)
  {
    hours = 0;
  }
  
  //display.clear();
  display.fillRect(0,0,128,8, BLACK);
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(0,0);;
  display.print(temp_in_celsius);
  display.print(" C");
  display.drawBitmap(30, 1, tmp_sign, 4, 4, WHITE);
  display.setCursor(80,0);
  if(hours < 10){display.print("0");}
  display.print(hours);
  display.print(":");
  if(minutes < 10){display.print("0");}
  display.print(minutes);
  display.print(":");
  if(seconds < 10){display.print("0");}
  display.print(seconds);
  display.update();
}
/*
void btHandler()
{
  while (Serial.available() > 0)
  {
    char recieved = Serial.read();
    inData += recieved; 

    // Process message when new line character is recieved
    if (recieved == '\n')
    {
      Serial.print("Arduino Received: ");
      Serial.print(inData);
      btMsg = inData;
      
      //menuChangeNeed = true;
      
      if(inData.indexOf("TIME") >=0)
      {
        char charBuff[100];
        inData.toCharArray(charBuff, 100);
        char *p = charBuff;
        char *str;
        int cntSubstr = 0;
        while ((str = strtok_r(p, ":", &p)) != NULL) // delimiter is the semicolon
        {
          String strx = str;
          
            switch(cntSubstr)
            {
              case 1: hours = strx.toInt(); break; case 2: minutes = strx.toInt(); break; case 3: seconds = strx.toInt(); break;
            }
          cntSubstr++;
        }
        
        inData = ""; // Clear recieved buffer
      }
      else
      {
        if(inData.indexOf("DATE") >=0)
        {
          char charBuff[100];
          inData.toCharArray(charBuff, 100);
          char *p = charBuff;
          char *str;
          int cntSubstr = 0;
          while ((str = strtok_r(p, ":", &p)) != NULL) // delimiter is the semicolon
          {
            String strx = str;
            
              switch(cntSubstr)
              {
                case 1: days = strx.toInt(); break; case 2: months = strx.toInt(); break; case 3: years = strx.toInt(); break;
              }
            cntSubstr++;
          }
          
          inData = ""; // Clear recieved buffer
        }
        else
        {
          if(inData.indexOf("GLOC") >=0)
          {
            char charBuff[100];
            inData.toCharArray(charBuff, 100);
            char *p = charBuff;
            char *str;
            int cntSubstr = 0;
            while ((str = strtok_r(p, ":", &p)) != NULL) // delimiter is the semicolon
            {
              String strx = str;
              
                char floatbuf[32]; // make this at least big enough for the whole string
                strx.toCharArray(floatbuf, sizeof(floatbuf));
                float f = atof(floatbuf);
                
                switch(cntSubstr)
                {
                  case 1: gpsLat = f; break; case 2: gpsLon = f; break;
                }
              cntSubstr++;
            }
            
            inData = ""; // Clear recieved buffer
          }
        }
      }
    }
  }
}*/

void tempHandler()
{
   //Reads the input and converts it to Kelvin degrees
  temp_in_kelvin = analogRead(0) * 0.004882812 * 100;
  
  //Converts Kelvin to Celsius minus 2.5 degrees error
  temp_in_celsius = temp_in_kelvin - 2.5 - 273.15; 
  
  temp_in_fahrenheit = ((temp_in_kelvin - 2.5) * 9 / 5) - 459.67;
}

This code broke my program:

As the program uses these new variables you must have done more than just adding 4 new variables.

UKHeliBob:
As the program uses these new variables you must have done more than just adding 4 new variables.

I dont know if I understand you. Whole block (void btHandler()) is commented using /* */ it was my attempt to find where exactly is problem so this code block is harmless :).

I was thinking about not enought SRAM for variables instead but im just porting my working program piece by piece from one display type to another, im using same variables so i realy dont know why it happening. Is there some warning message about not enought SRAM or something like that?

Whole block (void btHandler()) is commented using /* */

Sorry, I missed that

Lil Update: Its more and more looking like SRAM isue, i found somewhere this kind of display using some kind of SRAM intensive buffer maybe?

Is there some way how i can expand memory for variables? Or idealy move display buffer to another memory? :)

I know nothing about the asMenuItem library, but a quick look and it seems to manage menus and fonts, which can chew up a lot of SRAM. I'd check my free memory as it runs using the free memory function:

http://playground.arduino.cc/Code/AvailableMemory

and see what's going on.

There is no way to expand the SRAM. The best you can do is to cut down on memory usage. Look at all your int variables and see if you can use byte for some of them.

econjack:
I know nothing about the asMenuItem library, but a quick look and it seems to manage menus and fonts, which can chew up a lot of SRAM. I’d check my free memory as it runs using the free memory function:

http://playground.arduino.cc/Code/AvailableMemory

and see what’s going on.

It was my library technicly its only data type with two values. I updated code a little in hope to fix it. I added this function (thanks):

// this function will return the number of bytes currently free in RAM
// written by David A. Mellis
// based on code by Rob Faludi http://www.faludi.com
int availableMemory() {
  int size = 1024; // Use 2048 with ATmega328
  byte *buf;

  while ((buf = (byte *) malloc(--size)) == NULL)
    ;

  free(buf);

  return size;
}

and its writing i have 293 bytes free i suppose? with this updated code (ints->bytes, modified some ways how are variables used, …) ( + striped from unused comented parts):

#include <Adafruit_ssd1306syp.h>
#include <Button.h>
#include "Timer.h"
#define SDA_PIN 8
#define SCL_PIN 9
Adafruit_ssd1306syp display(SDA_PIN,SCL_PIN);

Timer t;

static const unsigned char PROGMEM arrow_sign[] =
{ B00000000, 
  B00000000,
  B10000000, 
  B11000000,
  B11100000, 
  B11000000,
  B10000000, 
  B00000000 };
  
boolean displayUpdateRequired = false;
//Temperature
byte tempUnits = 0;
float temp_in_celsius = 0;

static const unsigned char PROGMEM tmp_sign[] =
{ B11100000, 
  B10100000,
  B11100000, 
  B00000000 };
  
//BT
String inData = "";
String btMsg;

//GPS
float gpsLat = 0;
float gpsLon = 0;
  
//TIME
byte hours = 0;
byte minutes = 0;
byte seconds = 0;

byte days = 1;
byte months = 1;
int years = 2000;
  
//MENU
const byte menItmCnt = 10;
#include <avr/pgmspace.h>
prog_char string_0[] PROGMEM = "Item A";   // "String 0" etc are strings to store - change to suit.
prog_char string_1[] PROGMEM = "Item B";
prog_char string_2[] PROGMEM = "Item C";
prog_char string_3[] PROGMEM = "Item D";
prog_char string_4[] PROGMEM = "Item E";
prog_char string_5[] PROGMEM = "Item F";
prog_char string_6[] PROGMEM = "Item G";
prog_char string_7[] PROGMEM = "Item H";
prog_char string_8[] PROGMEM = "Item I";
prog_char string_9[] PROGMEM = "Item J";

// Then set up a table to refer to your strings.

PROGMEM const char *menuItems[] =       // change "string_table" name to suit
{   
  string_0,
  string_1,
  string_2,
  string_3,
  string_4,
  string_5 };
char buffer[30]; 
  
byte menuItmNow = 0;
byte menuShowedMin = 0;
byte scrIndex = 0;

Button button1 = Button(6, BUTTON_PULLUP_INTERNAL);

void setup()
{
  
  Serial.begin(9600); //BT

  delay(1000);
  display.initialize();
  t.every(1000, timeTimer);
  displayUpdateRequired = true;
}

void loop()
{
  t.update();
  initOs();
  btHandler();
  tempHandler();
  display_update();
}

void initOs()
{
   switch(scrIndex)
    {
      case 0:
      if (button1.uniquePress())
      {
        menuItmNow++;
        if(menuItmNow > menItmCnt - 1)
        {menuItmNow = 0; menuShowedMin = 0;}
        if(menuShowedMin + 3 < menuItmNow)
        {menuShowedMin++;}
        displayUpdateRequired = true;
      }
      break;
    }
}  

void display_update()
{
  if(displayUpdateRequired)
  {
    display.fillRect(0,8,128,56, BLACK);
    display.setTextSize(1);
    display.setTextColor(WHITE);
    display.setCursor(8,12);
    strcpy_P(buffer, (char*)pgm_read_word(&(menuItems[menuShowedMin]))); // Necessary casts and dereferencing, just copy.
    display.print(buffer);
    display.setCursor(8,22);
    strcpy_P(buffer, (char*)pgm_read_word(&(menuItems[menuShowedMin + 1]))); // Necessary casts and dereferencing, just copy.
    display.print(buffer);
    display.setCursor(8,32);
    strcpy_P(buffer, (char*)pgm_read_word(&(menuItems[menuShowedMin + 2]))); // Necessary casts and dereferencing, just copy.
    display.print(buffer);
    display.setCursor(8,42);
    strcpy_P(buffer, (char*)pgm_read_word(&(menuItems[menuShowedMin + 3]))); // Necessary casts and dereferencing, just copy.
    display.print(buffer);
    
    display.setCursor(0, 56);
    display.print(availableMemory());
    
    display.drawBitmap(0, ((menuItmNow + 1 - menuShowedMin) * 10) + 2, arrow_sign, 8, 8, WHITE);
    display.update();
    displayUpdateRequired = false;
  }
  
  
}

int availableMemory() {
  int size = 2048; // Use 2048 with ATmega328
  byte *buf;

  while ((buf = (byte *) malloc(--size)) == NULL)
    ;

  free(buf);

  return size;
}

void timeTimer()
{
  seconds++;
  if(seconds > 59)
  {
    minutes++;
    seconds = 0;
  }
  if(minutes > 59)
  {
    hours++;
    minutes = 0;
  }
  if(hours > 23)
  {
    hours = 0;
  }
  
  //display.clear();
  display.fillRect(0,0,128,8, BLACK);
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(0,0);;
  display.print(temp_in_celsius);
  display.print(F(" C"));
  display.drawBitmap(30, 1, tmp_sign, 4, 4, WHITE);
  display.setCursor(80,0);
  if(hours < 10){display.print(F("0"));}
  display.print(hours);
  display.print(F(":"));
  if(minutes < 10){display.print(F("0"));}
  display.print(minutes);
  display.print(F(":"));
  if(seconds < 10){display.print(F("0"));}
  display.print(seconds);
  display.update();
}

void btHandler()
{
  while (Serial.available() > 0)
  {
    char recieved = Serial.read();
    inData += recieved; 

    // Process message when new line character is recieved
    if (recieved == '\n')
    {
      btMsg = inData;
      
      if(inData.indexOf("TIME") >=0)
      {
        char charBuff[100];
        inData.toCharArray(charBuff, 100);
        char *p = charBuff;
        char *str;
        int cntSubstr = 0;
        while ((str = strtok_r(p, ":", &p)) != NULL) // delimiter is the semicolon
        {
          String strx = str;
          
            switch(cntSubstr)
            {
              case 1: hours = strx.toInt(); break; case 2: minutes = strx.toInt(); break; case 3: seconds = strx.toInt(); break;
            }
          cntSubstr++;
        }
        
        inData = ""; // Clear recieved buffer
      }
    }
  }
}

void tempHandler()
{
  temp_in_celsius = (analogRead(0) * 0.004882812 * 100) - 2.5 - 273.15;
}

I realy dont understand that … so i have enought memory but it still going crazy (when i was not using strcpy_P(buffer, (char*)pgm_read_w… it goes crazy (random pixels on screen instead of my texts and images) imediatly but when im using this it goes wrong after i scroll down the menu.

If anybody can tell me why it would be nice, i realy dont know what else i could try now.

You need memory for the return stacks as well as variables.

Grumpy_Mike: You need memory for the return stacks as well as variables.

Im sorry but i cant get context of that information ... i must admit theese hw releated thinks like "return stacks" was not my strong side at school and now im not sure what you mean by it. Im practical kind of programmer, not theoretical one. I hope it makes sense in english :) . I know reading my english must be horrror for somebody who is primary english speaking.

String inData = "";
String btMsg;

Here's a good place to start looking for memory issues. Go read the source code for this class to see how poorly it manages memory, and then QUIT USING IT!

PaulS: String inData = ""; String btMsg;

Here's a good place to start looking for memory issues. Go read the source code for this class to see how poorly it manages memory, and then QUIT USING IT!

Ok, i know, i will do something about it .. its only - string is more easy to use than char arrays. Anyway why it writes i have 200+ bytes of free memory if there is realy memory isue like it seems to be?

its only - string is more easy to use than char arrays.

No, it isn't. There is NOTHING you can do with the String class that you can't do just as easily with string functions, except the dynamic memory allocation bit which is NOT suitable for use on a limited memory system like the Arduino.

Anyway why it writes i have 200+ bytes of free memory if there is realy memory isue like it seems to be?

200+ bytes is not a lot of free memory. The stack can eat that up quickly.

        while ((str = strtok_r(p, ":", &p)) != NULL) // delimiter is the semicolon

Why are you using the thread-safe, reentrant version of this function on a single-threaded system? The strtok() function has fewer arguments, and is harder to misuse.

          String strx = str;
          
            switch(cntSubstr)
            {
              case 1: hours = strx.toInt(); break; case 2: minutes = strx.toInt(); break; case 3: seconds = strx.toInt(); break;

What the f**k is this? Is your enter key broken? Get it fixed!

Pissing away more resources converting a string to a String, so you can call the toInt() function that calls atoi() is STUPID!

astromedia: i must admit theese hw releated thinks like "return stacks" was not my strong side at school and now im not sure what you mean by it. Im practical kind of programmer, not theoretical one.

You need memory for more than just variables, so just because you have some memory left that is not being used in global variables does not mean that you have enough memory to run the rest of the system. so comments like:-

I realy dont understand that ... so i have enought memory but it still going crazy

Do not make sense because you do not know what "enough" memory is.

First, Paul is trying to tell you that using the String class (note the uppercase "S") is inefficient. For example, the following program:

void setup() {

  String str;     // Using the String class
  
  str = "This is a test";
}

void loop() {


}

uses 2004 bytes of memory. This version:

void setup() {
  char str[20];
  
  strcpy(str, "This is a test");
}

void loop() {

}

uses 550 bytes of memory, a savings of about 70%.

The next problem is that the "free memory" you see after a compile is the amount of flash memory and the amount of SRAM after allocations. However, each time you call a function, the function arguments chew up bytes equal to the size of each argument that appears in the function argument list, plus anything that is returned from the function. If a function calls another function, which calls another function, these calls all chew up memory space that isn't available again until the stack is "unwound" by a series of return statements. So, you can have 30K free of flash memory but blow your SRAM space out of the water because of function calls taking place while the program runs. You need to pay attention to such things.

Ok, thanks, im starting to understand it now. Theese changes will take some time. Anyway i tryed how many SRAM (with that function) will left when i leave only display releated code in my program and that number was 768 bytes ... i dont know if its too high or not but it seems display tooks from me more than half of my memory right? It seems too much to me but maybe im wrong.

it seems too much to me

Why?

The memory has to match the display. Not sure what size it is but assuming it is just black / white then you get 8 pixels in a byte, so a 128 x 128 display will take:- 128 * 128 / 8 = 2048 bytes.

Grumpy_Mike:
Why?

The memory has to match the display. Not sure what size it is but assuming it is just black / white then you get 8 pixels in a byte, so a 128 x 128 display will take:-
128 * 128 / 8 = 2048 bytes.

Ok, thanks for clarification.

I edited more things and more striped and now im with this relativly small code:

#include <Adafruit_ssd1306syp.h>
#include <Button.h>
#include "Timer.h"
#define SDA_PIN 8
#define SCL_PIN 9
Adafruit_ssd1306syp display(SDA_PIN,SCL_PIN);

Timer t;

static const unsigned char PROGMEM arrow_sign[] =
{ B00000000, 
  B00000000,
  B10000000, 
  B11000000,
  B11100000, 
  B11000000,
  B10000000, 
  B00000000 };
  
boolean displayUpdateRequired = false;
//Temperature
byte tempUnits = 0;
float temp_in_celsius = 0;

static const unsigned char PROGMEM tmp_sign[] =
{ B11100000, 
  B10100000,
  B11100000, 
  B00000000 };
  
//BT
char inData[50];

//GPS
float gpsLat = 0;
float gpsLon = 0;
  
//TIME
byte hours = 0;
byte minutes = 0;
byte seconds = 0;

byte days = 1;
byte months = 1;
int years = 2000;
  
//MENU
const byte menItmCnt = 10;
#include <avr/pgmspace.h>
prog_char string_0[] PROGMEM = "Item A";   // "String 0" etc are strings to store - change to suit.
prog_char string_1[] PROGMEM = "Item B";
prog_char string_2[] PROGMEM = "Item C";
prog_char string_3[] PROGMEM = "Item D";
prog_char string_4[] PROGMEM = "Item E";
prog_char string_5[] PROGMEM = "Item F";
prog_char string_6[] PROGMEM = "Item G";
prog_char string_7[] PROGMEM = "Item H";
prog_char string_8[] PROGMEM = "Item I";
prog_char string_9[] PROGMEM = "Item J";

// Then set up a table to refer to your strings.

PROGMEM const char *menuItems[] =       // change "string_table" name to suit
{   
  string_0,
  string_1,
  string_2,
  string_3,
  string_4,
  string_5 };
char buffer[30]; 
  
byte menuItmNow = 0;
byte menuShowedMin = 0;
byte scrIndex = 0;

Button button1 = Button(6, BUTTON_PULLUP_INTERNAL);

void setup()
{

  Serial.begin(9600); //BT

  delay(1000);
  display.initialize();

  t.every(1000, timeTimer);
  displayUpdateRequired = true;
}

void loop()
{
  t.update();
  initOs();
  btHandler();
  tempHandler();
  display_update();
}

void initOs()
{
   switch(scrIndex)
    {
      case 0:
      if (button1.uniquePress())
      {
        menuItmNow++;
        if(menuItmNow > menItmCnt - 1)
        {menuItmNow = 0; menuShowedMin = 0;}
        if(menuShowedMin + 3 < menuItmNow)
        {menuShowedMin++;}
        displayUpdateRequired = true;
      }
      break;
    }
}  

void display_update()
{
  if(displayUpdateRequired)
  {
    display.fillRect(0,8,128,56, BLACK);
    display.setTextSize(1);
    display.setTextColor(WHITE);
    display.setCursor(8,12);
    //display.print(menuItems[menuShowedMin].getName());
    strcpy_P(buffer, (char*)pgm_read_word(&(menuItems[menuShowedMin]))); // Necessary casts and dereferencing, just copy.
    display.print(buffer);
    display.setCursor(8,22);
    //display.print(menuItems[menuShowedMin + 1].getName());
    strcpy_P(buffer, (char*)pgm_read_word(&(menuItems[menuShowedMin + 1]))); // Necessary casts and dereferencing, just copy.
    display.print(buffer);
    display.setCursor(8,32);
    //display.print(menuItems[menuShowedMin + 2].getName());
    strcpy_P(buffer, (char*)pgm_read_word(&(menuItems[menuShowedMin + 2]))); // Necessary casts and dereferencing, just copy.
    display.print(buffer);
    display.setCursor(8,42);
    //display.print(menuItems[menuShowedMin + 3].getName());
    strcpy_P(buffer, (char*)pgm_read_word(&(menuItems[menuShowedMin + 3]))); // Necessary casts and dereferencing, just copy.
    display.print(buffer);
    
    //display.setCursor(8,52);
    //display.print(menuShowedMin + 3);
    
    display.drawBitmap(0, ((menuItmNow + 1 - menuShowedMin) * 10) + 2, arrow_sign, 8, 8, WHITE);
    display.update();
    displayUpdateRequired = false;
  }
  
  
}

void timeTimer()
{
  seconds++;
  if(seconds > 59)
  {
    minutes++;
    seconds = 0;
  }
  if(minutes > 59)
  {
    hours++;
    minutes = 0;
  }
  if(hours > 23)
  {
    hours = 0;
  }
  
  //display.clear();
  display.fillRect(0,0,128,8, BLACK);
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(0,0);;
  display.print(temp_in_celsius);
  display.print(F(" C"));
  display.drawBitmap(30, 1, tmp_sign, 4, 4, WHITE);
  display.setCursor(80,0);
  if(hours < 10){display.print(F("0"));}
  display.print(hours);
  display.print(F(":"));
  if(minutes < 10){display.print(F("0"));}
  display.print(minutes);
  display.print(F(":"));
  if(seconds < 10){display.print(F("0"));}
  display.print(seconds);
  display.update();
}

void btHandler()
{
  
}

void tempHandler()
{
  temp_in_celsius = (analogRead(0) * 0.004882812 * 100) - 2.5 - 273.15;
}

Lot of things are now in program memory but its not enough to get it working properly. Am I missing something important or is arduino so small? I saw working more advanced thinks than my on arduino.

Im trying to make some werable device - lets say BT watches with some components like LM335 temperature sensor. Now it seems impossible for me to fit required code to arduino board. Am I wrong? Or is there some more suitable arduino based device? (My plan was to end up with arduino nano for this project)