Ich verwende die Arduino IDE mit arduino-tiny
( https://code.google.com/p/arduino-tiny/ ) auf einem ATTIny85 . Mein Code maximiert den RAM, oder so scheint es:
String
Wenn ich meinem Code eine Single hinzufüge , selbst wenn ich nur ein Zeichen trage, wird ein Compiler-Fehler ausgegeben:
(...)region `text' overflowed by 452 bytes
Die Zeile, die ich hinzufüge, um dorthin zu gelangen, ist einfach
String name2 = "A";
(...)
matrix.print(temp2 + name2);
Nur zum Vergleich: Die Codegröße der .hex
Datei ohne den String beträgt 7.430 Bytes, mit dem definierten, aber nicht verwendeten String sind es 8092 Bytes, mit definiertem und verwendetem String ist es überlaufend. Das scheint ein bisschen viel zu sein, zumal es anscheinend keine Rolle spielt, ob mein String ist A
oder ABCDEFG
- ich bekomme immer den Überlauf von 452 Bytes.
Irgendeine Idee, wie man das umgehen kann? Ich habe versucht, den String in einzufügen PROGMEM
, aber das matrix.print
funktioniert nicht mit allen Methoden zum Abrufen, die ich ausprobiert habe (außer dem Kopieren in den RAM, aber dann bekomme ich natürlich wieder den Überlauf). .hex
Ich habe auch versucht, die Adafruit GFX-Bibliothek zu entfernen, aber es scheint, als ob ohnehin nur die benötigten Teile in die Kompilierung gezogen würden (da es keine Änderung der -Dateigröße gab ).
Der vollständige Code, nur um Ihnen eine Vorstellung davon zu geben, was ich tue (Zugriff auf eine Adafruit 8x8 LED matrix
, Lesen eines Temperaturwerts von einem DS18S20
1-Wire-Digitalthermometer, Ausgeben eines ein- und ausblendenden Smileys, der Temperatur und des Namens meines Kindes an diese LED-Matrix ;), ist hier:
#include <TinyWireM.h>
#include <Tiny_LEDBackpack.h>
#include "Adafruit_GFX.h"
#include <avr/pgmspace.h>
#include <OneWire.h>
#define ONE_WIRE_BUS 4
OneWire ds(4); // on ATTiny85 pin 1
int buttonState = 0;
byte addr[8];
float temp;
static uint8_t PROGMEM
smile_bmp[] =
{ B00111100,
B01000010,
B10100101,
B10000001,
B10100101,
B10011001,
B01000010,
B00111100 };
Tiny_8x8matrix matrix = Tiny_8x8matrix();
void setup() {
matrix.begin(0x70); // pass in the address
matrix.setBrightness(1);
}
void loop() {
byte addr[] = { 0x28, 0xad, 0x3f, 0x51, 0x4, 0x0, 0x0, 0x2a };
temp = readTemperatureFromSensor(addr);
matrix.begin(0x70); // pass in the address
matrix.setBrightness(1);
for (int8_t c=1; c<=2; c++) {
for (int8_t x=1; x<=15; x++) {
matrix.setBrightness(x);
matrix.clear();
matrix.drawBitmap(0, 0, smile_bmp, 8, 8, LED_ON);
matrix.writeDisplay();
delay(50);
}
for (int8_t x=15; x>=1; x--) {
matrix.setBrightness(x);
matrix.clear();
matrix.drawBitmap(0, 0, smile_bmp, 8, 8, LED_ON);
matrix.writeDisplay();
delay(50);
}
}
matrix.clear();
matrix.writeDisplay();
delay(50);
String name2 = "A";
int temp2 = int(temp);
matrix.setBrightness(10);
matrix.setTextSize(1);
matrix.setTextWrap(false);
matrix.setTextColor(1);
for (int8_t x=0; x>=-24; x--) {
matrix.clear();
matrix.setCursor(x,0);
matrix.print(temp2 + name2);
matrix.writeDisplay();
delay(200);
}
}
float readTemperatureFromSensor(byte addr[])
{
byte i;
byte present = 0;
byte type_s;
byte data[12];
float celsius;
ds.reset();
ds.select(addr);
ds.write(0x44,1); // start conversion, with parasite power on at the end
delay(1000); // maybe 750ms is enough, maybe not
present = ds.reset();
ds.select(addr);
ds.write(0xBE); // Read Scratchpad
// reading the data from the sensor
for ( i = 0; i < 9; i++) { // we need 9 bytes
data[i] = ds.read();
}
// convert the data to actual temperature
unsigned int raw = (data[1] << 8) | data[0];
if (type_s) {
raw = raw << 3; // 9 bit resolution default
if (data[7] == 0x10) {
// count remain gives full 12 bit resolution
raw = (raw & 0xFFF0) + 12 - data[6];
}
} else {
byte cfg = (data[4] & 0x60);
if (cfg == 0x00) raw = raw << 3; // 9 bit resolution, 93.75 ms
else if (cfg == 0x20) raw = raw << 2; // 10 bit res, 187.5 ms
else if (cfg == 0x40) raw = raw << 1; // 11 bit res, 375 ms
// default is 12 bit resolution, 750 ms conversion time
}
celsius = (float)raw / 16.0;
return celsius;
}
"Text" ist eigentlich die Code-Flash-Größe, nicht SRAM.
Hier gibt es mehrere Probleme:
1) Die "print"-Funktion zieht eine große Menge an Code zum Formatieren von Formatzeichenfolgen ein. Das ist dumm. Der 85er hat insgesamt nur 8 kB Flash, verglichen mit den 32 kB des Arduino Uno.
2) Die String-Klasse verwendet sowohl etwas Coderaum als auch viel SRAM. Der 85er hat nur 512 Byte SRAM für alle Ihre Variablen, Nicht-Programm-String-Konstanten und Stack. Die String-Klasse kann sogar Heap-Zuweisungen verwenden (malloc()/nw). Die String-Klasse ist aus Sicht der eingebetteten Programmierung ein Greuel. Verwenden Sie es nicht!
3) Für eine ordnungsgemäße Nutzung eingebetteter Ressourcen möchten Sie, dass Zeichenfolgenliterale in PROGMEM vorhanden sind. Sie möchten einen einzelnen Puffer im RAM, in den Sie die Zeichenfolgen kopieren, die Sie tatsächlich bearbeiten müssen, wenn Sie sie bearbeiten müssen. Suchen Sie nach strcpy_P() und Co. als viel besser geeigneten Satz von Funktionen.
4) Sie wollen malloc() oder new niemals in eingebetteten Systemen wie diesen verwenden, und zwar aus zwei Gründen. Der erste Grund ist, dass der Heap RAM für den Steuerungsaufwand ineffizient nutzt. Zweitens können Sie nicht so einfach beweisen, dass Ihr Programm tatsächlich korrekt sein wird. Mehr RAM kommt nirgendwo her, also sollten Sie in der Lage sein, den gesamten RAM zu berücksichtigen, den Sie tatsächlich benötigen. Der Weg dazu ist mit statischen oder globalen Allokationen. Beachten Sie, dass dies den Ratschlägen zur Codestruktur widerspricht, die Sie auf einem großen System verwenden würden, das auf einer großen CPU läuft - die Regeln sind anders, weil die CPU/das System anders ist.
Schließlich können Sie bei Bedarf die Platzierung new verwenden, um Objektinstanzen zu initialisieren; es ist die zuordnende Version von new, die schlecht ist.
Ich glaube, Ihr Problem ist, dass die Druckmethode die konstanten Textzeichenfolgen in den Arbeitsspeicher legt. Bitte sehen Sie sich meine Antwort auf arduino flash memory limit an , wo das F()-Makro den Code kompiliert, um die const-Zeichenfolge direkt aus dem Flash und nicht aus dem RAM zu verwenden.
Dann versuche es
matrix.print(temp2);
matrix.print(F("Hello World"));
PROGMEM const char name2[] = "A"; // replaces: String name2 = "A";
matrix.print(name2);
only initialized variables can be placed into program memory area
und error: initializer fails to determine size of '__c'
... Ähm?Grundsätzlich lautet die Antwort, Ihr Programm in C zu schreiben und keine malloc
andere dynamische Speicherzuweisung zu verwenden.
Ich verstehe zwar, warum die Arduino-Leute das Programmieren vereinfachen wollen, aber wie @JohnWatte sagte, String
war die Klasse auf einem eingebetteten Mikrocontroller nie etwas anderes als eine schreckliche Idee. Wenn Sie wirklich eine String-Manipulation haben müssen, tun Sie es wie in CEg- char
Arrays und all den alten C-Routinen zur String-Manipulation ( strstr
, strcat
, strcpy
, etc ...).
ALLES statisch zuweisen . Dies ist in diesem Fall kein Problem, aber es ist gut, sich daran zu erinnern.
Ich weiß nicht, was die matrix
Bibliothek tut, aber ich wäre überrascht, wenn ein einfaches Ersetzen von
matrix.print(temp2 + name2);
mit
matrix.print(temp2);
matrix.print("A");
Würde nicht funktionieren, obwohl es möglicherweise immer noch alle riesigen Druckmaschinen aus der Arduino-Bibliothek einzieht. Möglicherweise müssen Sie Ihren eigenen int-to-string-Konverter rollen (es ist wirklich ganz einfach).
Nebenbei:
float readTemperatureFromSensor(byte addr[])
{
/* Snip */
celsius = (float)raw / 16.0;
return celsius;
}
....
void loop() {
byte addr[] = { 0x28, 0xad, 0x3f, 0x51, 0x4, 0x0, 0x0, 0x2a };
temp = readTemperatureFromSensor(addr);
/* Snip */
int temp2 = int(temp);
/* Snip */
}
}
Die Temperatur wird auf a geworfen float
, durch 16 geteilt und dann auf ein int
? Warum? Jede zusätzliche Genauigkeit, die Sie durch die Operation auf einem Float erhalten, wird weggeworfen, und Floats sind langsam , insbesondere auf einer 8-Bit-MCU.
readTemperatureFromSensor
von woanders kopiert. Ich werde auf jeden Fall versuchen, diese Funktion zu vereinfachen, zumal Sie Recht haben: Ich brauche nichts hinter dem Komma.
PeterJ
Christian