Área de recuperación de cadenas cortas en ATtiny85, Arduino IDE

2

Estoy usando el IDE de Arduino con arduino-tiny ( enlace ) en un ATTIny85 . Mi código está maximizando la memoria RAM, o eso parece:

Al agregar un solo String a mi código, incluso si solo lleva un carácter, se produce un error de compilación:

(...)region 'text' overflowed by 452 bytes

La línea que agrego para llegar a esto es simple

String name2 = "A";
(...)
matrix.print(temp2 + name2);

Solo para comparación: el tamaño del código del archivo .hex sin la Cadena es 7.430 Bytes, con la Cadena definida pero no utilizada es 8092 bytes, y se define y se usa para desbordarse. Esto parece ser demasiado, especialmente porque no parece importar si mi String es A o ABCDEFG : siempre obtengo el desbordamiento en 452 bytes.

¿Alguna idea de cómo solucionar esto? Intenté colocar el String en PROGMEM , pero el matrix.print no funciona con ningún método de recuperación que haya intentado (además de copiar en la RAM, pero luego, de nuevo, obtengo el desbordamiento). También he intentado eliminar la biblioteca GFX de Adafruit, pero parece que de todos modos solo se incorporan las partes necesarias a la compilación (ya que no hubo cambios en el tamaño de archivo .hex ).

El código completo, solo para darle una idea de lo que estoy haciendo (accediendo a Adafruit 8x8 LED matrix , leyendo un valor de temperatura de a DS18S20 termómetro digital de 1 cable, que emite un emoticono de entrada y salida, la temperatura y el nombre de mi hijo a esa matriz de 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;
}
    
pregunta Christian

3 respuestas

8

"texto" es en realidad código flash, 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 cantidad de espacio de código Y una gran cantidad de SRAM. El '85 solo tiene 512 bytes de SRAM, para todas sus variables, constantes de cadena no progresivas y pila. La clase String puede incluso usar asignaciones de pila (malloc () / nw). La clase String es una abominación desde el punto de vista de la programación integrada. ¡No lo uses!

3) Para el uso adecuado de los recursos incrustados, desea que los literales de cadena vivan en PROGMEM. Desea un único búfer en la RAM en el que copia las cadenas que realmente necesita para operar, cuando necesita operar sobre ellas. Busque a strcpy_P () y amigos, como un conjunto de funciones mucho más adecuado.

4) No desea utilizar malloc () o nuevo, 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 la sobrecarga de control. La segunda es que no puedes probar que tu programa realmente será correcto tan fácilmente. Más RAM no proviene de ninguna parte, por lo que debería poder tener en cuenta toda la RAM que realmente necesita. La forma de hacerlo es con asignaciones estáticas o globales. Tenga en cuenta que esto es contrario al consejo de estructura de código que usaría en un sistema grande que se ejecuta en una gran CPU: 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; la versión de asignación de la nueva es mala.

    
respondido por el Jon Watte
2

De la mano, creo que su problema es que el método de impresión coloca las cadenas de texto constantes en la RAM. Consulte mi respuesta a límite de memoria flash arduino , donde la macro F () compila el código para usar la cadena constante directamente desde Flash y no desde la RAM.

Entonces intente

matrix.print(temp2);
matrix.print(F("Hello World"));
PROGMEM const char name2[] = "A"; // replaces: String name2 = "A";
matrix.print(name2);
    
respondido por el mpflaga
2

Básicamente, la respuesta es escribir su programa en C, y no usar malloc o cualquier otra asignación de memoria dinámica.

Aunque entiendo por qué la gente arduina quiere hacer la programación más fácil, pero como dijo @JohnWatte, la clase String en un microcontrolador integrado nunca ha sido nada más que una idea terrible. Si realmente tiene que tener manipulación de cuerdas, hágalo como lo haría en C. E.g. arrays char y todas las rutinas de manipulación de cadenas C antiguas ( strstr , strcat , strcpy , etc ...).

Asigna estáticamente TODOS LOS PRODUCTOS > . Esto no es un problema en este caso, pero es bueno recordarlo.

No sé qué está haciendo la biblioteca matrix , pero me sorprendería si un simple reemplazo de

matrix.print(temp2 + name2);

con

matrix.print(temp2);
matrix.print("A"); 

No funcionaría, por lo que todavía puede arrastrar toda la maquinaria de impresión gigante de la biblioteca arduino. Es posible que deba rodar su propio int al convertidor de cadenas (es realmente muy fácil de hacer).

Como 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 */
    }


}

¿Se está convirtiendo la temperatura en un float , dividido por 16, y luego volviendo a un int ? ¿Por qué? Cualquier precisión adicional que obtenga de la operación en un flotador se está desechando, y los flotadores son lentos , especialmente en una MCU de 8 bits.

    
respondido por el Connor Wolf

Lea otras preguntas en las etiquetas