Estoy usando Arduino IDE con arduino-tiny
( https://code.google.com/p/arduino-tiny/ ) en un ATTIny85 . Mi código está maximizando la RAM, o eso parece:
Agregar un solo String
a mi código, incluso solo con un carácter, genera un error de compilación:
(...)region `text' overflowed by 452 bytes
La línea que agrego para llegar a esto es un simple
String name2 = "A";
(...)
matrix.print(temp2 + name2);
Solo para comparar: el tamaño del código del .hex
archivo sin la cadena es de 7.430 bytes, con la cadena definida pero no utilizada es de 8092 bytes, con la definición y el uso se desborda. Esto parece ser demasiado, especialmente porque no parece importar si mi Cadena es A
o ABCDEFG
: siempre obtengo el desbordamiento de 452 bytes.
¿Alguna idea de como solucionar esto? Intenté poner String en PROGMEM
, pero matrix.print
no funciona con ningún método de recuperación que haya probado (además de copiar en RAM, pero luego, por supuesto, obtengo el desbordamiento nuevamente). También intenté eliminar la biblioteca Adafruit GFX, pero parece que solo las partes necesarias se incluyen en la compilación de todos modos (ya que no hubo cambios en el .hex
tamaño del archivo).
El código completo, solo para darle una idea de lo que estoy haciendo (acceder a un Adafruit 8x8 LED matrix
, leer un valor de temperatura de un DS18S20
termómetro digital de 1 cable, mostrar un emoticón que se desvanece de entrada y salida, la temperatura y el nombre de mi hijo para esa matriz LED ;), está aquí:
#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;
}
"texto" es en realidad el tamaño del flash del código, no SRAM.
Hay varios problemas aquí:
1) La función "imprimir" extrae una gran cantidad de código para formatear cadenas de formato. Esto es tonto. El '85 solo tiene 8 kB de flash total, en comparación con los 32 kB del Arduino Uno.
2) La clase String usa tanto una cierta cantidad de espacio de código como una gran cantidad de SRAM. El '85 solo tiene 512 bytes de SRAM, para todas sus variables, constantes de cadena que no son de programa y pila. La clase String puede incluso usar asignaciones de montón (malloc()/nw). La clase String es una abominación desde el punto de vista de la programación integrada. ¡No lo uses!
3) Para un uso adecuado de los recursos incrustados, desea que los literales de cadena vivan en PROGMEM. Desea un solo búfer en la RAM en el que copie las cadenas en las que realmente necesita operar, cuando necesite operar en ellas. Busque strcpy_P() y amigos, como un conjunto de funciones mucho más adecuado.
4) No desea usar malloc() o new, nunca, en sistemas integrados como estos, por dos razones. La primera razón es que el montón hará un uso ineficiente de la RAM para controlar la sobrecarga. La segunda es que no puede probar que su programa será realmente correcto tan fácilmente. Más RAM no proviene de ninguna parte, por lo que debería poder contabilizar toda la RAM que realmente necesita. La forma de hacerlo es con asignaciones estáticas o globales. Tenga en cuenta que esto es contrario a los consejos de estructura de código que usaría en un sistema grande que se ejecuta en una CPU grande: las reglas son diferentes, porque la CPU/sistema es diferente.
Finalmente, si lo necesita, puede usar la ubicación nueva para inicializar instancias de objetos; es la versión de asignación de new la que es mala.
De antemano, creo que su problema es que el método de impresión coloca las cadenas de texto constante en la RAM. Consulte mi respuesta al límite de memoria flash de arduino , donde la macro F () compila el código para usar la cadena const directamente desde Flash y no RAM.
Entonces intenta
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
y error: initializer fails to determine size of '__c'
... Err?Básicamente, la respuesta es escribir su programa en C y no usar malloc
ninguna otra asignación de memoria dinámica.
Si bien entiendo por qué la gente de arduino quiere facilitar la programación, pero como ha dicho @JohnWatte, la String
clase en un microcontrolador integrado nunca ha sido más que una idea terrible. Si realmente tiene que tener manipulación de cadenas, hágalo como lo haría en char
las matrices CEg y todas las antiguas rutinas de manipulación de cadenas C ( strstr
, strcat
, strcpy
, etc...).
Asignar estáticamente TODO . Esto no es un problema en este caso, pero es bueno recordarlo.
No sé qué matrix
está haciendo la biblioteca, pero me sorprendería si un simple reemplazo de
matrix.print(temp2 + name2);
con
matrix.print(temp2);
matrix.print("A");
No funcionaría, aunque todavía puede arrastrar toda la maquinaria de impresión gigante de la biblioteca de arduino. Es posible que deba crear su propio convertidor de int a cadena (realmente es bastante fácil de hacer).
Como un aparte:
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 */
}
}
La temperatura se convierte en float
, se divide por 16 y luego se vuelve a convertir en int
? ¿Por qué? Cualquier precisión adicional que obtenga de la operación en un flotador se descarta, y los flotadores son lentos , particularmente en una MCU de 8 bits.
readTemperatureFromSensor
de otro lugar. Definitivamente buscaré hacer esta función más fácil, especialmente porque tienes razón: no necesito nada detrás del punto decimal.
PedroJ
cristiano