Можете ли вы помочь мне сократить мой код?

Прежде всего, я хочу прояснить: я не очень разбираюсь в методах программирования, все, что я узнал о CI, было для различных проектов Arduino.

Тем не менее, я только что закончил проект, который считывает некоторые данные с ELM327 через модуль Bluetooth HC-05 и выводит их на экран 3,5 дюйма. Все работает как задумано, но, по-видимому, я ограничил память своего Arduino UNO, поскольку скетч использует 99% ее. На данный момент это не очень хлопотно, но если когда-нибудь в будущем я захочу добавить больше данных для считывания, я не смогу этого сделать.

Поэтому я искал совет, как переписать код, чтобы он занимал меньше памяти. Я пробовал кое-что, но эффекта было мало. Как я уже сказал, я не знаком с передовыми методами программирования.

LE: Итак, я воспользовался всеми вашими советами, избавился от всех шрифтов, изменил библиотеку MCUFRIEND для работы только с моим дисплеем и избавился от части повторяющегося кода, и теперь эскиз стал на 35% меньше. Спасибо всем.

Sketch использует 21216 байт (65%) пространства для хранения программ. Максимум — 32256 байт. Глобальные переменные используют 642 байта (31%) динамической памяти, оставляя 1406 байт для локальных переменных. Максимум — 2048 байт.

Вот (старый) код:

#include <SoftwareSerial.h> 
#include <Adafruit_GFX.h> 
#include <MCUFRIEND_kbv.h>
#include <Fonts/FreeMonoBold9pt7b.h>
#include <Fonts/FreeMonoBold12pt7b.h>
#include <Fonts/FreeMonoBold18pt7b.h>
#include <Fonts/FreeMonoBold24pt7b.h>

SoftwareSerial BTSerial(10, 11);
MCUFRIEND_kbv tft;

#define BLACK   0x0000
#define WHITE   0xFFFF
#define GREY    0x8410

byte inData;
char inChar;
String constructor="";
String deconstructor="";
int A;
int B;
bool busy = false;

void setup()
{
    Retry:
    Serial.begin(9600);
    BTSerial.begin(38400);
    delay(1000);

    BTSerial.println("0100");
    while(BTSerial.available()>0)
    {
      inData=0;
      inChar=0;
      inData = BTSerial.read();
      inChar=char(inData);
      constructor = constructor + inChar;
      delay(20);
   }
    if (constructor.length()>0)
    {
      Serial.println("Conectat");
    }
    else { 
      goto Retry;
      Serial.println("retry");
    }
    delay(5000);
    ReadData();
    basicConditions();

    tft.reset();
    uint16_t identifier = tft.readID();
    if (identifier == 0xEFEF) identifier = 0x9486;
    tft.begin(identifier);

    tft.fillScreen(BLACK);
    tft.setRotation(1);
    tft.setTextColor(WHITE);

    tft.fillRect(10, 40, 70, 40, GREY);
    tft.fillRect(10, 140, 70, 40, GREY);
    tft.fillRect(10, 240, 70, 40, GREY);
    tft.fillRect(140, 70, 200, 100, GREY);
    tft.fillRect(150, 220, 180, 60, GREY);
    tft.fillRect(370, 40, 70, 40, GREY);
    tft.fillRect(370, 140, 70, 40, GREY);
    tft.fillRect(370, 240, 70, 40, GREY);

    tft.setCursor(170,10);
    tft.setFont(&FreeMonoBold12pt7b);
    tft.print("Dacia 4X4");

    tft.setCursor(30,35);
    tft.setFont(&FreeMonoBold9pt7b);
    tft.print("Cuplu");
    tft.setCursor(80,70);
    tft.setFont(&FreeMonoBold18pt7b);
    tft.print("%");

    tft.setCursor(15,120);
    tft.setFont(&FreeMonoBold9pt7b);
    tft.print("Presiune"); 
    tft.setCursor(15,135);   
    tft.print("motorina");
    tft.setCursor(82,170);
    tft.setFont(&FreeMonoBold12pt7b);
    tft.print("bar");

    tft.setCursor(15,220);
    tft.setFont(&FreeMonoBold9pt7b);
    tft.print("Presiune"); 
    tft.setCursor(20,235);   
    tft.print("admisie");  
    tft.setCursor(82,270);
    tft.setFont(&FreeMonoBold12pt7b);
    tft.print("bar");  

    tft.setCursor(395,20);
    tft.setFont(&FreeMonoBold9pt7b);
    tft.print("Temp."); 
    tft.setCursor(382,35);   
    tft.print("Antigel");
    tft.setCursor(450,70);
    tft.setFont(&FreeMonoBold12pt7b);
    tft.print("C"); 

    tft.setCursor(395,120);
    tft.setFont(&FreeMonoBold9pt7b);
    tft.print("Temp."); 
    tft.setCursor(382,135);   
    tft.print("Admisie");
    tft.setCursor(450,170);
    tft.setFont(&FreeMonoBold12pt7b);
    tft.print("C"); 

    tft.setFont(&FreeMonoBold9pt7b);
    tft.setCursor(370,235);   
    tft.print("Debit Aer");
    tft.setCursor(445,270);
    tft.setFont(&FreeMonoBold9pt7b);
    tft.print("g/s");     

    tft.setFont(&FreeMonoBold12pt7b);
    tft.setCursor(150, 62);   
    tft.print("Turatie (RPM)");

    tft.setFont(&FreeMonoBold12pt7b);
    tft.setCursor(152, 212);   
    tft.print("Viteza (KM/H)");



}

void loop()
{
  cuplu();
  PresMot();
  PresAdm();
  TempAntig();
  TempAdm();
  MAF();
  RPM();
  viteza();
}
void basicConditions(){
    if(constructor.indexOf(">")>0)  {
    busy=false;
    constructor="";
  }
}
void ReadData()
{   
  if (BTSerial.available()>0)
    busy = true;
  while(busy = true && constructor.indexOf(">")<0)
  {
    if (BTSerial.available()>0){
    inData=0;
    inChar=0;
    inData = BTSerial.read();
    inChar=char(inData);
    constructor = constructor + inChar;
    //Serial.println(constructor);
    //Serial.println(busy);
  }
  }
  //Serial.println("done");

  if (constructor.indexOf(">")>0){
    deconstructor=constructor.substring(11,13);
    A = strtol(deconstructor.c_str(),NULL,16);
    if (constructor.length()>15) {
        deconstructor = constructor.substring(14,16);
            B = strtol(deconstructor.c_str(),NULL,16);
    }
    else B = 0;
  }
}
void cuplu() {
  if (busy == false){
    BTSerial.println("01041");
      ReadData();
    tft.setTextSize(1);
    tft.setFont(&FreeMonoBold18pt7b);
    tft.setCursor(10, 70);
    tft.fillRect(10, 40, 70, 40, GREY); 
    tft.print(A/2.55, 0);   
  }
  basicConditions();
}
void PresMot() {
  if (busy == false){
      BTSerial.println("010A1");
      ReadData();
      tft.setTextSize(1);
      tft.setFont(&FreeMonoBold18pt7b);
      tft.setCursor(10, 170);
    tft.fillRect(10, 140, 70, 40, GREY); 
    tft.print((3*A)/100.0, 1);
  }
  basicConditions();
}
void PresAdm() {
  if (busy == false){
      BTSerial.println("010B1");
      ReadData();
      tft.setTextSize(1);
      tft.setFont(&FreeMonoBold18pt7b);
      tft.setCursor(10, 270);
    tft.fillRect(10, 240, 70, 40, GREY); 
    tft.print((A/100.0), 1);
  }
  basicConditions();
}
void TempAntig() {
    if (busy == false){
      BTSerial.println("01051");
      ReadData();
      tft.setTextSize(1);
      tft.setFont(&FreeMonoBold18pt7b);
      tft.fillRect(370, 40, 70, 40, GREY);
    tft.setCursor(370, 70);
    tft.print(A-40);
    }
  basicConditions();
}
void TempAdm() {
    if (busy == false){
      BTSerial.println("010F1");
      ReadData();
      tft.setTextSize(1);
      tft.setFont(&FreeMonoBold18pt7b);
      tft.fillRect(370, 140, 70, 40, GREY);
    tft.setCursor(370, 170);
    tft.print(A-40);
    }
  basicConditions();
}
void MAF() {
  if (busy == false){
      BTSerial.println("01101");
      ReadData();
      tft.setTextSize(1);
      tft.setFont(&FreeMonoBold18pt7b);
      tft.fillRect(370, 240, 70, 40, GREY);
    tft.setCursor(370, 270);
    tft.print(((256*A)+B)/4.0, 0);  
  }
  basicConditions();
}
void RPM() {
  if (busy == false){
      BTSerial.println("010C1");
      ReadData();
      tft.setFont(&FreeMonoBold18pt7b);
    tft.setTextSize(2);
    tft.fillRect(140, 70, 200, 100, GREY);
    tft.setCursor(150, 140); 
    tft.print(A/4.0, 0);
  }
  basicConditions();
}
void viteza() {
  if (busy == false){
      BTSerial.println("010D1");
      ReadData();
      tft.setFont(&FreeMonoBold18pt7b);
    tft.setTextSize(2); 
      tft.fillRect(150, 220, 180, 60, GREY);
    tft.setCursor(180, 270); 
    tft.print(A);
  }
  basicConditions();
}

, 👍3

Обсуждение

99% кода не проблема, 80% динамической памяти могут быть проблемой. Каков процент используемой динамической памяти? Библиотека gfx и шрифты используют много памяти. Вы можете обновиться до arduino mega для большего объема оперативной памяти и дополнительных аппаратных последовательных портов или обновиться до arduino zero или одной из плат mkr для более быстрого процессора, большего объема оперативной памяти и дополнительного аппаратного последовательного порта., @Jot

Вы пытаетесь сократить использование Flash (пространство кода) или RAM (пространство данных)? Какой из них составляет 99%? Методы сокращения того и другого различны., @JRobert

Там написано, что размер скетча составляет 99%, а динамической памяти — 30%. Так что я предполагаю, что проблема в размере кода., @sundaysfantasy

код для рисования серых прямоугольников в вашем эскизе дважды, @jsotola


4 ответа


Лучший ответ:

3

Я полагаю, вы имеете в виду, что не хватает флэш-памяти, а не RAM. Я основываю это предположение на том факте, что вы говорите, что это 99% полный, и что это «не очень хлопотно». Заполнение 99% оперативной памяти со статически выделенными данными, конечно, было бы проблематично. Но обратите внимание, что как всегда лучше изложить свой вопрос ясно и явными, а не ожидать, что респонденты будут строить догадки.

Теперь посмотрите на ваши файлы шрифтов. Каждый из них заканчивается комментарием похоже на это:

// Приблизительно 1672 байта

Просто сложив эти числа, мы получаем:

FreeMonoBold9pt7b   1672 bytes
FreeMonoBold12pt7b  2402 bytes
FreeMonoBold18pt7b  4485 bytes
FreeMonoBold24pt7b  7469 bytes
------------------------------
TOTAL              16028 bytes

Это примерно 49% флэш-памяти вашего Arduino. Так что это первое место, куда вы стоит посмотреть, если вы хотите сохранить флэш. Вам действительно нужно эти четыре разных размера шрифта? И, более конкретно, вы действительно нужны (очень жадные до вспышки) самые большие размеры? Избавляемся от некоторых из них это самый простой способ сохранить флэш.

Если вы действительно хотите сохранить их все, ваш следующий вариант — обрезать шрифты, чтобы иметь только те символы, которые вы фактически используете. Это может быть много работы, но это должен быть очень эффективный способ значительно сокращая площадь их флэш-памяти.

Если вы решили пойти по этому пути, первым шагом будет обратить внимание на то, что символы, которые вам нужны для каждого размера шрифта. При беглом взгляде на ваш источник, мне кажется, что шрифт 18 pt используется только для печать «%», «.», десять цифр и, возможно, «-». Это намного меньше чем полный репертуар ASCII, поддерживаемый шрифтом. И я не вижу, где вы используете шрифт 24 pt. Посмотрите в таблицу ASCII и возьмите обратите внимание на наименьший непрерывный диапазон, содержащий все символы вы используете один размер шрифта. Затем обрежьте массив Glyphs шрифта до оставить только этот диапазон и исправить поля first и last GFXfont структурируйте соответствующим образом.

Следующий шаг — это то, что займет большую часть работы. Для каждого персонажа вы на самом деле нужно, обратите внимание на поле bitmapOffset его глифа и следующий. Таким образом, вы узнаете диапазон смещений, которые используются этот символ. Затем удалите из массива Bitmaps шрифта все байты, которые находятся на смещениях, которые вам не нужны. При этом вы будете изменение смещения байтов, которые вы сохраняете, поэтому вам следует обновить Поля bitmapOffset в массиве Glyphs соответственно.

Да, это немалая работа, но в итоге вы получите собственные шрифты. которые намного легче оригинальных, но при этом способны отображая все, что вы показываете сейчас. Может быть, вы могли бы написать программа для автоматизации всего этого. Может кто-то уже это сделал и вы можете найдите его через поиск в Интернете...

,

Спасибо за совет и извините, что не совсем ясно выразил проблему. Первое, что я сделаю, это избавлюсь от шрифтов навсегда и пойду оттуда., @sundaysfantasy


4

В документации к проекту MCUFRIEND_kbv есть файл с описанием использования.

В этом документе содержится следующее заявление:

Most of these controllers are #define SUPPORT_xxxx by default.
You can save Flash memory on a Uno by commenting out the macro(s) in MCUFRIEND_kbv.cpp

Итак, вы открываете MCUFRIEND_kbv.cpp и закомментируете поддержку контроллеров, которые вы не используете.

Вы также можете сократить количество используемых шрифтов, чтобы сэкономить место во Flash-памяти.

,

1

Строки выделяются, перераспределяются и освобождаются по мере их использования, что может привести к фрагментации кучи — нижней части оперативной памяти — и фрагментам, по сути, стать непригодными для использования. Отчет о памяти от компилятора не может этого показать; это происходит во время выполнения.

Если вместо этого вы заранее выделяете массивы символов достаточного размера для максимального текста, который вы хотите в них поместить, они останутся на одном месте, не увеличиваясь и не уменьшаясь, но и не будут создавать эти неиспользуемые, но бесполезные «дыры» в оперативной памяти.

Обновление:

Вместо:

String xyz;
xyz = "Hello";
xyz = xyz + ',';
xyz = xyz + "World!\n";

, вы бы написали:

#define XYZ_MAX  25    // или любой другой размер, который вам нужен

char xyz[XYZ_MAX+1];
strcpy(xyz, "Hello";      // перезаписывает все, что там есть
strcat(xyz, ", World!\n"; // добавляет все, что есть

Вы можете дополнительно оптимизировать ОЗУ, указав компилятору сохранять строковый литерал ("Hello" и т. д.) во Flash. Это уже другая тема, но вот ссылкана статью об этом в Arduino Playground, чтобы вы могли начать.

,

Это то, о чем я не знал. Может быть, вы могли бы дать мне краткий пример того, как именно это сделать., @sundaysfantasy


0

Вы повторяете один и тот же код в 8 функциях в конце вашего скетча (примечание: код имеет плохой отступ, а последовательность команд между функциями непоследовательна)

похожая вещь происходит в середине вашего эскиза

вот данные, которые повторяются

Вы можете использовать одну функцию и таблицу поиска (массив)

это повторяющиеся данные

+---------------+-------+-------------------------------+---------------+-----------------------+
|  println     setTextSize        fillRect                 setCursor          print             |
+---------------+-------+-------------------------------+---------------+-----------------------+
|   "01041"     |   1   |    10,  40,  70,  40, GREY    |    10,  70    |   A/2.55         , 0  |
|   "010A1"     |   1   |    10, 140,  70,  40, GREY    |    10, 170    |   (3*A)/100.0    , 1  |
|   "010B1"     |   1   |    10, 240,  70,  40, GREY    |    10, 270    |   (A/100.0)      , 1  |
|   "01051"     |   1   |   370,  40,  70,  40, GREY    |   370,  70    |   A-40                |
|   "010F1"     |   1   |   370, 140,  70,  40, GREY    |   370, 170    |   A-40                |
|   "01101"     |   1   |   370, 240,  70,  40, GREY    |   370, 270    |   ((256*A)+B)/4.0, 0  |
|   "010C1"     |   2   |   140,  70, 200, 100, GREY    |   150, 140    |   A/4.0          , 0  |
|   "010D1"     |   2   |   150, 220, 180,  60, GREY    |   180, 270    |   A                   |
+---------------+-------+-------------------------------+---------------+-----------------------+

Вы также можете рассчитать некоторые значения в первых 6 функциях

,