I am trying to get this code working:
#include <Button.h>
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <RTClib.h>
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 32 // OLED display height, in pixels
// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
#define OLED_RESET 4 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
RTC_DS1307 RTC;
// when I remove this part it works...
int mode = 1;
const String periodicSystem[60] = {
"H", "He", "Li", "Be", "B", "C", "N", "O",
"F", "Ne", "Na", "Mg", "Al", "Si", "P", "S",
"Cl", "Ar", "K", "Ca", "Sc", "Ti", "V", "Cr",
"Mn", "Fe", "Co", "Ni", "Cu", "Zn", "Ga", "Ge",
"As", "Se", "Br", "Kr", "Rb", "Sr", "Y", "Zr", "Nb",
"Mo", "Tc", "Ru", "Rh", "Pd", "Ag", "Cd", "In", "Sn",
"Sb", "Te", "I", "Xe", "Cs", "Ba", "La", "Ce", "Pr", "Nd"
};
/////////////////////////////////////////////////////////////////////
Button button1(7);
void setup() {
Serial.begin(9600);
// SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3C for 128x32
Serial.println(F("SSD1306 allocation failed"));
for(;;); // Don't proceed, loop forever
}
RTC.begin();
if (! RTC.isrunning()) {
Serial.println("RTC is NOT running!");
// This will reflect the time that your sketch was compiled
RTC.adjust(DateTime(__DATE__, __TIME__));
}
display.display();
}
void loop() {
DateTime now = RTC.now();
if(button1.pressed()) {
display.clearDisplay();
display.setTextSize(1); // Draw 2X-scale text
display.setTextColor(WHITE);
display.setCursor(10, 0);
display.print(now.second());
display.display();
}
}
Whenever I try to add the constant periodicSystem
, I get the error SSD1306 allocation failed
over Serial. The error also goes away when I remove the part with button1.pressed()
. Basically I am not able to add the constant periodicSystem
and read out a digital pin at the same time. To me it seems to be some sort of memory issue (I am only adding the constant, I am not doing anything else with it), but my IDE tells me I am only using 52% of the available storage. What am I doing wrong?
Here is my wiring (in reality I am using a 128x32 display, I didn't have the correct part for Fritzing; my display is labeled SDA, SCK, VCC, GND instead of SDA, SCK, VDD, GND; the RTC Module I am using is a DS1307 AT24C32 RTC Module):
-
Hint: Consider a more memory efficient storage for the string table. Using Arduino String for this is a very very very bad idea. Use character strings and put the whole table in program memory. Ref. arduino.cc/reference/en/language/variables/utilities/progmemMikael Patel– Mikael Patel2019年01月06日 13:38:11 +00:00Commented Jan 6, 2019 at 13:38
1 Answer 1
Your display needs 624 bytes of RAM for its internal buffer (128 * ((32 + 7) / 8)
). The periodicSystem
array needs a massive 360 bytes of RAM just for the objects. That doesn't include the memory used to store the actual string data, which by my reckoning is 168 bytes.
So far we're up to 624+たす360+たす168 =わ 1152 bytes of a maximum of 2048. Over half way and we haven't touched on the serial buffers or other objects that you're using.
An array (const
or otherwise) of String
objects is by far the least efficient way possible of storing constant string data on an Arduino. You're using 528 bytes of RAM to store what could be stored in 121 bytes of flash.
Personally I would store the data thus:
const char periodicSystem[] PROGMEM = "H HeLiBeB C N O F NeNaMgAlSiP S ClArK CaScTiV CrMnFeCoNiCuZnGaGeAsSeBrKrRbSrY ZrNbMoTcRuRhPdAgCdInSnSbTeI XeCsBaLaCePrNd";
Each symbol consists of exactly two bytes, and the PROGMEM
forces it to stay in flash and never be copied to RAM.
You can get the two bytes of each symbol with:
char b1 = pgm_read_byte(periodicSystem + (i * 2));
char b2 = pgm_read_byte(periodicSystem + (i * 2) + 1);
Then either print them separately, or combine them into a C string:
char symbol[3] = { b1, b2, 0 };
That will include the space character, of course. So you could remove that if you like:
if (symbol[1] == ' ') symbol[1] = 0;
Theoretically you could also change the spaces in the original data to be character 0 if you like - depending on what you do with it, it shouldn't cause any issues:
const char periodicSystem[] PROGMEM = "H0円HeLiBeB0円C0円N0円O0円F0円NeNaMgAlSiP0円S0円ClArK0円CaScTiV0円CrMnFeCoNiCuZnGaGeAsSeBrKrRbSrY0円ZrNbMoTcRuRhPdAgCdInSnSbTeI0円XeCsBaLaCePrNd";