Оптимизация кода, решение проблем пропадания текста (String)

adrusha
Offline
Зарегистрирован: 02.03.2015

Здравствуйте!

3 день пишу и оптимизирую свой код. И имеются некоторые проблемы в работа, на которые компилятор никак не ругается.

Что я использую в ардуино:

  • - Модуль часов (RTC)
  • - Датчик влажности и температуры (DHT11)
  • - IR (ИК-приемник) для управления с пульта
  • - Модуль 4-х реле
  • - Cron задания (эмулятор на основе часов)
  • - EEPROM память для хранения данных (в частности cron задания и другие переменные)
  • - Дисплей 128X64

Иногда, пропадает текст отправленный в Serial.print, к примеру текстовая строка String отправленная в консоль, не всегда отображается, т.е она отправляет но либо пустая, либо порой иероглифами, а иногда нормально. Путем долгих мучений я выявил такую особенность, что если память глобальных переменных занята более ем на 75% начинаются такие проблемы. Но сейчас у меня память занята на 74%.
Если отключить дисплей, то объем глобальных переменных сократится, а значит память будет высвобождена и программа работает корректно. Текст в консоли не пропадает.

Из-за этого, я начал оптимизировать свой код, вынося и сокращая String переменные за функции в один массив, затем я избавился от лишних выводов информации в Serial.print т.к. строки формата String занимают много байт. Но все эти движения не спасли ситуацию, и с использованием дисплея "все ломается". Я понимаю, что загрузил ардуино "по максимум". но память еще есть, как решить данный вопрос?

Прикладывая скетч, помогите решить вопрос, это последний штрих.

Как еще можно оптимизировать программу? Какие методы использовать, дайте хотябы подсказку и я попробую сделать сам.

adrusha
Offline
Зарегистрирован: 02.03.2015
#include <Wire.h>
#include <EEPROM.h>
#include <RTClib.h>
#include <IRremote.h>
#include <U8glib.h>
#include <dht11.h>
#include <Cron.h>

#define PIN_IR 2    // ИК-приемник
#define PIN_DHT 4   // Датчик DHT11

#define T_1 text 3

// включена/выключена панель меню
boolean panel = false;
byte menuSize = 0;
//byte i; // используется для for функций как глобальная переменная
int section = -1;
int selectItem = -1;
int selectField = -1;
String tempValue;
// здесь будут хранится кроны
Cron Crons[10];
// здесь система автоматизации полива
stAuto Automat;
// Структура меню
structMenu data[10];
// здесь хранятся данные температуры и влажности
stClime clime;
// для автоматизации насоса полива
byte autoCount = 0;
unsigned long autoMilis = 0;
// количество кронов определяется количеством элементов в нем
byte cronSize = 10;
//int cronSize = sizeof(Crons) / sizeof(*Crons);


stText text = {
  "Menu",
  "Datetime",
  "Cron",
  "Watering",
  "Clear flash",
  "Pin",
  ":",
  " ",
  "Empty",
  "Period min",
  "Duration",
  "Replays",
  "Yes",
  "No",
  "Sec",
  "Min",
  "Hour",
  "Command",
  "-",
  "/",
  "Set"
};

dht11 DHT;           // датчик dht11
U8GLIB_SH1106_128X64 u8g(8, 9, 12, 11, 10);  // CLK=8, MOSI=9, CS=12, DC=11, RES=10
IRrecv irrecv(PIN_IR);
decode_results rec;  // данные ИК-приемника в HEX формате
RTC_DS1307 RTC;      // модуль часов

// кнопки на пульте и их коды
enum{
  BUTTON_1 = 0xFF906F,
  BUTTON_2 = 0xFFB847,
  BUTTON_3 = 0xFFF807,
  BUTTON_4 = 0xFF9867,
  BUTTON_5 = 0xFFD827,
  BUTTON_6 = 0xFF8877,
  BUTTON_7 = 0xFFE817,
  BUTTON_8 = 0xFF48B7,
  BUTTON_9 = 0xFF6897,
  BUTTON_0 = 0xFF12ED,
  BUTTON_UP = 0xFFB04F,
  BUTTON_DOWN = 0xFFA857,
  BUTTON_CHUP = 0xFF32CD,
  BUTTON_CHDOWN = 0xFF00FF,
  BUTTON_HIDE = 0xFF30CF,
  BUTTON_LEFT = 0xFF708F,
  BUTTON_RIGHT = 0xFF58A7,
  //BUTTON_FREEZE = 0xFFB24D,
  BUTTON_REC = 0xFF2A5D,
  //BUTTON_SNAPSHOT = 0xFFA05F,
  BUTTON_RECALL = 0xFF02FD,
  //BUTTON_AV = 0xFF40BF,
  BUTTON_PWR = 0xFF08F7,
  BUTTON_MUTE = 0xFF609F,
  BUTTON_FULL = 0xFF38C7
};

// возможные функции вызова
char calls[3][10] = {"switchOn","switchOff",""};
byte callsSize = 3;

void(* reset) (void) = 0;

void setup() {
  Wire.begin();
  RTC.begin();
  Serial.begin(9600);
  // Clear EEPROM memory
  for( int i = 0 ; i < EEPROM.length() ; i++) EEPROM.write(i, 0);
  irrecv.enableIRIn();
  digitalWrite(13, HIGH);
  EEPROM.get(0, Crons);
  EEPROM.get(sizeof(Crons), Automat);
  digitalWrite(13, LOW);
  if (!RTC.isrunning()) {
    //Serial.println("RTC is NOT running!");
    RTC.adjust(DateTime(__DATE__, __TIME__));
  }
  // Переводим PIN выходы в режим выход
  for(byte i=0; i < cronSize; i++)
    if(Crons[i].pin)
      pinMode(Crons[i].pin, OUTPUT);
}

void call(byte pin, String name) {
  if(name.equals(String(calls[0]))) switchOn(pin); else //"switchOn"
  if(name.equals(String(calls[1]))) switchOff(pin);// else "switchOff"
  //name = "unknown";
  // print to serail log
  //Serial.print("Call " + name + " function to pin ");
  //Serial.println(pin);
}

void switchOn(byte pin){
  pinMode(pin, OUTPUT);
  digitalWrite(pin, HIGH);
}

void switchOff(byte pin){
  digitalWrite(pin, LOW);
}

void events(unsigned long ir) {
  if(ir == false) return;
  Serial.println(ir, HEX);
  unsigned long numpad[10] = {BUTTON_0,BUTTON_1,BUTTON_2,BUTTON_3,BUTTON_4,BUTTON_5,BUTTON_6,BUTTON_7,BUTTON_8,BUTTON_9};
  for(byte i = 0; i < 10; i++) {
    if(ir == numpad[i]) if(panel) select(i); else write(i);
  }
  if(ir == BUTTON_CHUP || ir == BUTTON_UP || ir == BUTTON_LEFT) up();
  if(ir == BUTTON_DOWN || ir == BUTTON_CHDOWN || ir == BUTTON_RIGHT) down();
  if(ir == BUTTON_HIDE) hide();
  //if(ir == BUTTON_FREEZE){ }
  if(ir == BUTTON_REC){ }
  //if(ir == BUTTON_SNAPSHOT){ }
  if(ir == BUTTON_RECALL){ }
  //if(ir == BUTTON_AV){  }
  if(ir == BUTTON_FULL) {
    if(!panel) {
      panel = true;
      data[0] = {text.menu, 255};
      data[1] = {text.datetime, 1};
      data[2] = {text.cron, 2};
      data[3] = {text.watering, 3};
      data[4] = {text.clear, 4};
      //data[5] = {"Exit", 0};
      menu(5);
    } else close();
  }
  if(ir == BUTTON_MUTE) {
    for(byte i=0; i < cronSize; i++)
      if(Crons[i].pin)
        digitalWrite(Crons[i].pin, HIGH);
  }
  if(ir == BUTTON_PWR) {
    for(byte i=0; i < cronSize; i++)
      if(Crons[i].pin)
        digitalWrite(Crons[i].pin, LOW);
  }
}


void draw() {
  byte li = 2; // межстрочный интервал
  byte fs = 9; // размер шрифта
  byte cur = 0;
  byte i, p;
  u8g.setFont(u8g_font_profont12);
  
  if(menuSize) {
    for(i=0; i < menuSize; i++) {
      u8g.setPrintPos(0, cur + fs);
      u8g.print(data[i].label);
      cur += fs + li;
    }
  } else {
    for(i=0; i < cronSize; i++) {
      if(!String(Crons[i].call).length()) continue;
      for(p=0; i < menuSize; i++) {
        u8g.setPrintPos(0, cur + fs);
        u8g.print(text.cron + text.space + String(i) + text.colon + text.space + (!digitalRead(Crons[i].pin) ? text.yes : text.no));
        cur += fs + li;
      }
    }
    /*
    // Температура
    u8g.setPrintPos(32, 9);
    u8g.print(DHT.temperature);
    // Влажность
    u8g.setPrintPos(32, 20);
    u8g.print(DHT.humidity);
    // Углекислый газ
    u8g.setPrintPos(32, 31);
    u8g.print(analogRead(A7));
    // Аэрация
    u8g.setPrintPos(98, 9);
    u8g.print(!digitalRead(5) ? "On" : "Off");
    // Синие-красный свет
    u8g.setPrintPos(98, 20);
    u8g.print(!digitalRead(6) ? "On" : "Off");
    // Солнечный свет
    u8g.setPrintPos(98, 31);
    u8g.print(!digitalRead(7) ? "On" : "Off");
    // IR value
    u8g.setPrintPos(0, 53);
    u8g.print(rec.value, HEX);
    // Время
    u8g.setPrintPos(0, 64);
    u8g.print(datetime);
    */
  }
}

void loop() {
  unsigned long time = millis();
  //now = RTC.now();
  // проверяем кроны по порядку и выполняем если настало его время
  for(byte i=0; i < cronSize; i++) {
    if(String(Crons[i].call).length())
      matchCron(Crons[i]);
  }
  //getDHT();
  
  // если переданы данные с пульта
  if(irrecv.decode(&rec)) {
    if(rec.bits > 0) events(rec.value);
    irrecv.resume();
  }
  
  u8g.firstPage();  
  do { draw(); } while( u8g.nextPage() );
  
  //Serial.println();
  //Serial.println("Duration: "+ String(Automat.duration));
  //Serial.println("Time: "+ String(time) + " / automilis: "+ String(autoMilis));
  pinMode(Automat.pin, OUTPUT);
  if(autoCount) {
    if(time >= autoMilis) {
      digitalWrite(Automat.pin, LOW);
      autoMilis = time + (Automat.duration*2*1000);
      autoCount--;
    } else if(time > autoMilis - (Automat.duration*1000)) {
      digitalWrite(Automat.pin, HIGH);
    }
    //Serial.println("Count: "+ String(autoCount));
  }
  if(Automat.period > 0) {
    if((time/1000) % (Automat.period*60) == 0 && autoCount == 0 && Automat.duration) {
      //Serial.println("Automat period: " +String(time/1000/60));
      digitalWrite(Automat.pin, HIGH);
      autoMilis = time + (Automat.duration*2*1000);
      autoCount = max(Automat.replay, 1);
    }
  } else {
    digitalWrite(Automat.pin, HIGH);
  }
  
  digitalWrite(13, LOW);
  delay(100);
}


void menu(byte l) {
  menuSize = l;
  for(byte i = 0; i < l; i++) {
    if(data[i].button == 255) {
      Serial.print(text.space + text.space + text.space);
    } else {
      Serial.print(data[i].button);
      Serial.print(text.space + text.minus + text.space);
    }
    Serial.println(data[i].label);
  }
}

void select(int n) {
  if(section < 0) {
    section = n;
    n = -1;
  }
  if(section == 1) {
    panel = false;
    Serial.println(text.datetime);
    Serial.println(getDateTime());
    setTime(23, 59, 59, 4, 1, 16);
  }
  if(section == 2) {
    if(n < 0) {
      selectItem = -1;
      for(byte i=0; i < cronSize; i++) {
        structMenu &m = data[i];
        Cron &c = Crons[i];
        m.button = i;
        if(String(c.call).length()) {
          m.label = text.pin + text.colon + text.space +String(min(c.pin, 255))+ text.space \
          +String(min(c.s, 59))+ text.colon +String(min(c.m, 59))+ text.colon +String(min(c.h, 59))+ \
          text.space + text.command + text.colon + text.space +String(c.call).substring(0, 10);
        } else {
          m.label = text.empty;
        }
      }
      menu(10);
    } else {
      selectItem = n;
      section = 10;
      n = -1;
    }
  }
  
  if(section == 3) {
    if(n < 0) {
      data[0] = {text.watering, 255};
      data[1] = {text.period + text.colon + text.space +String(Automat.period), 1};
      data[2] = {text.duration + text.colon + text.space +String(Automat.duration), 2};
      data[3] = {text.replays + text.colon + text.space +String(Automat.replay), 3};
      data[4] = {text.pin + text.colon + text.space +String(Automat.pin), 4};
      menu(5);
    } else {
      selectField = n;
      if(n == 1) data[0] = {text.period + text.colon, -1, true, 0, 3600};
      if(n == 2) data[0] = {text.duration + text.colon, -1, true, 0, 60};
      if(n == 3) data[0] = {text.replays + text.colon, -1, true, 0, 60};
      if(n == 4) data[0] = {text.pin + text.colon, -1, true, 0, 255};
      panel = false;
      menu(1);
    }
  }
  if(section == 4) {
    if(n < 0) {
      data[0] = {text.clear + text.colon, 255};
      data[1] = {text.yes, 1};
      data[2] = {text.no, 2};
      menu(3);
    } else {
      if(n == 1) { for(int i = 0; i < EEPROM.length(); i++) EEPROM.write(i, 0); reset(); }
      if(n == 2) hide();
    }
  }
  if(section == 10) {
    if(n < 0) {
      Cron &d = Crons[selectItem];
      data[0] = {text.cron + text.space + "num" + text.space +String(selectItem)+ text.space + "edit" + text.colon, 255};
      data[1] = {text.pin + text.colon + text.space +String(d.pin), 1};
      data[2] = {text.sec + text.colon + text.space +String(d.s), 2};
      data[3] = {text.min + text.colon + text.space +String(d.m), 3};
      data[4] = {text.hour + text.colon + text.space +String(d.h), 4};
      data[5] = {text.command + text.colon + text.space +String(d.call), 5};
      menu(6);
    } else {
      selectField = n;
      if(n == 1) data[0] = {text.set + text.space + "pin 0-255:" + text.colon, -1, true, 0, 255};
      if(n == 2) data[0] = {text.set + text.space + "second:" + text.colon, -1, true, 0, 60};
      if(n == 3) data[0] = {text.set + text.space + "minute" + text.colon, -1, true, 0, 60};
      if(n == 4) data[0] = {text.set + text.space + "hour" + text.colon, -1, true, 0, 60};
      if(n == 5) {
        section = 5;
        n = -1;
      } else {
        panel = false;
        menu(1);
      }
    }
  }
  if(section == 5) {
    if(n < 0) {
      data[0] = {"Select" + text.space + text.command + text.space + "item" + text.colon + String(selectItem), 255};
      for(byte i = 0; i < callsSize; i++) {
        data[i+1] = {calls[i], i};
      }
      menu(callsSize+1);
    } else {
      n = max(0, min(n, callsSize));
      writeParam(calls[n]);
      section = 10;
      select(-1);
    }
  }
  if(section == 0) close();
}



void write(int n) {
  tempValue += String(n);
  tempValue = String(max(data[0].min, min(data[0].max, tempValue.toInt())));
  data[1] = {tempValue, -1};
  menu(2);
  writeParam(tempValue);
}

void up() {
  tempValue = String(min(data[0].max, tempValue.toInt()+1));
  data[1] = {tempValue, -1};
  menu(2);
  writeParam(tempValue);
}

void down() {
  tempValue = String(max(data[0].min, tempValue.toInt()-1));
  data[1] = {tempValue, -1};
  menu(2);
  writeParam(tempValue);
}

void writeParam(String v) {
  if(section == 3) {
    if(selectField == 1) Automat.period = v.toInt();
    if(selectField == 2) Automat.duration = v.toInt();
    if(selectField == 3) Automat.replay = v.toInt();
    if(selectField == 4) Automat.pin = v.toInt();
    EEPROM.put(sizeof(Crons), Automat);
  }
  // запись параметров для крона
  if(section == 10 || section == 5) {
    Cron &d = Crons[selectItem];
    if(selectField == 1) d.pin = v.toInt();
    if(selectField == 2) d.s = v.toInt();
    if(selectField == 3) d.m = v.toInt();
    if(selectField == 4) d.h = v.toInt();
    if(selectField == 5) v.toCharArray(d.call, 10);
    EEPROM.put(0, Crons);
  }
}

void close() {
  panel = false;
  menuSize = 0;
  section = -1;
  selectItem = -1;
  selectField = -1;
}

void hide() {
  if(section == 1) section = 0;
  if(section == 2) section = 0;
  if(section == 3 && panel) section = 0;
  if(section == 10) section = 2;
  if(section == 5) section = 10;
  if(section == 6) section = 10;
  panel = true;
  tempValue = "";
  selectField = -1;
  select(-1);
}

// запрос температуры и влажности у датчика и подсчет общего среднего числа
void getDHT() {
  // Мониторинг ошибок
  switch(DHT.read(PIN_DHT)){
    case DHTLIB_OK:
      clime.data_temp[clime.t] = DHT.temperature;
      clime.data_hum[clime.h] = DHT.humidity;
      clime.temp = average(clime.data_temp);
      clime.hum = average(clime.data_hum);
      if(clime.t < 9) clime.t++; else clime.t = 0;
      if(clime.h < 9) clime.h++; else clime.h = 0;
      break;
    case DHTLIB_ERROR_CHECKSUM:
      //Serial.println("DHT - Checksum error");
      break;
    case DHTLIB_ERROR_TIMEOUT:
      //Serial.println("DHT - Time out error");
      break;
    default:
      //Serial.println("DHT - Unknown error");
      break;
  }
}

// если текущее время подходит под параметры крона, выполняем call функцию.
boolean matchCron(Cron d){
  boolean s, m, h;
  DateTime now; //текущее время
  s = (d.s == now.second() || d.s == 255);
  m = (d.m == now.minute() || d.m == 255);
  h = (d.h == now.hour() || d.h == 255);
  if(s && m && h) {
    call(d.pin, String(d.call));
    return true;
  }
  return false;
}

// подсчитываем среднее значение
float average(byte data[]) {
  float total = 0;
  byte l = sizeof(data); 
  for(byte i = 0; i < l; i++) total += data[i];
  return total / l;
}

// выводит таблицу записей HEX в памяти EEPROM
void maprom() {
  byte value;
  for(byte i = 0, l = EEPROM.length(); i < l; i++) {
    if(0 == i % 8) Serial.println();
    value = EEPROM.read(i);
    Serial.print(value, HEX);
    Serial.print(text.space);
  }
  Serial.println();
  for(byte i=0; i < 30; i++) Serial.print(text.minus);
  Serial.println();
}

void setTime(byte hh, byte mm, byte ss, byte d, byte m, byte y) {
  RTC.adjust(DateTime(y, m, d, hh, mm, ss));
}

String getDateTime() {
  DateTime now = RTC.now(); //текущее время
  return String(now.day()) + text.slash \
        +String(now.month()) + text.slash \
        +String(now.year()) + text.space \
        +String(now.hour()) + text.colon \
        +String(now.minute()) + text.colon \
        +String(now.second());
}

 

adrusha
Offline
Зарегистрирован: 02.03.2015
struct Cron {
  byte pin;  // канал Pin-port
  byte s; // секунды
  byte m; // минуты
  byte h; // часы
  char call[10]; // какую функцию вызвать
};

struct structMenu {
  String label;
  byte button;
  bool arrow;
  int min;
  int max;
};

struct stAuto {
  int period;
  byte duration;
  byte replay;
  byte pin;
};

struct stText {
	String menu;
	String datetime;
	String cron;
	String watering;
	String clear;
	String pin;
	String colon;
	String space;
	String empty;
	String period;
	String duration;
	String replays;
	String yes;
	String no;
	String sec;
	String min;
	String hour;
	String command;
	String minus;
	String slash;
	String set;
};

// здесь хранятся данные температуры и влажности
struct stClime {
  byte t;
  byte h;
  byte data_temp[10];
  byte data_hum[10];
  float temp;
  float hum;
};

 

std
Offline
Зарегистрирован: 05.01.2012

Можно попробовать уменьшить Serial buffer.

В файле \hardware\cores\arduino\HardwareSerial.cpp есть строка:

#define RX_BUFFER_SIZE 128

Поставьте 32 или 16. Если не будут напрягать паузы при работе сериала, можно поставить 8.

adrusha
Offline
Зарегистрирован: 02.03.2015

Это в какой версии Arduino ? В только что скачанной нет такой директории \hardware\cores\

adrusha
Offline
Зарегистрирован: 02.03.2015

Выглядит это так:

4- то есть строка, то нет. Это при том что 74% глобальных переменных используется.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

adrusha пишет:

Как еще можно оптимизировать программу? Какие методы использовать, дайте хотябы подсказку и я попробую сделать сам.

1. Отказаться от использования класса String вообще - он очень ресурсоёмкий.
2. Добрая половина из используемых Вами библиотек В Вашем скетче выполняют тривиальные операции, но при этом тянут за собой ого-го сколько. Отказаться от части библиотек, сделав их работу вручную

На второй пункт обратите внимание. Я тут недавно некий проект на Tiny45 делал, а там далласовский датчик температуры. Библиотека DallasTemeperature (а она ещё и OneWire за собой тянет) оказалось насмешкой на ресурсами тиньки. Я просто выбросил её (и OneWire  туда же) и написал нужную мне работу с датчиком вручную, благо протокл OneWire подробно в даташите описан - всё влезло.

std
Offline
Зарегистрирован: 05.01.2012

Жмите Win+F3 и пишите имя файла HardwareSerial.cpp, система найдёт.

adrusha
Offline
Зарегистрирован: 02.03.2015

В общем, решил я в пойти по другому пути. Отказался я от меню, а отправлять данные буду по WiFi модулю. По нему и буду отправлять с компьютера задания по крону и другие параметры.

Скетч получился в 30кб, а места всего 32, кроме того памяти категорически не хватает для выполнения данных простых задач.

Всем спасибо за внимание.

adrusha
Offline
Зарегистрирован: 02.03.2015

std пишет:

Жмите Win+F3 и пишите имя файла HardwareSerial.cpp, система найдёт.

Дело не в Serial, он тут вообще не причем. Текст иногда пропадает даже на дисплее, иногда он кракозябрами. Это из-за формата String, а char для моих задач не подходил.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

adrusha пишет:

а char для моих задач не подходил.

"Не любите кошек? Вы просто не умеете их готовить!" :)

adrusha
Offline
Зарегистрирован: 02.03.2015

ЕвгенийП пишет:

adrusha пишет:

а char для моих задач не подходил.

"Не любите кошек? Вы просто не умеете их готовить!" :)

Хорошо, как можно используя char записать такую строку:

myText = "Position num: "+ String(num) + " from "+ String(from);

?

пользоваться всякими приблудами вроде toCharArray не вижу смысла

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Вам уже правильно отписали: ресурсы "съедены" вовсе не вами, а теми Г-изделями, что называются "библиотека для Ардуино". Тому что вы делаете, памяти у УНО или Про Мини (как понимаю эти версии в работе) - более чем достаточно. Не пользуйте Wiring и будет вам "щастье". Обсуждено тут многажды. Вот даже ЕвгенийП уже осознал сей прискорбный факт. :)

adrusha
Offline
Зарегистрирован: 02.03.2015

я тут вспомнил про sprintf, вот она могла бы подойти для таких вырожений. Однако, есть некоторые тонкости

к примеру есть функция

void func(char name[]) {
  if(String(name) == "mytext") {
    Serial.print("Found: ");
  } else {
    Serial.print("NotFound: ");
  }
  Serial.println(name);
}

Ее вы можем вызвать так:

func("mytext");
// или так
char text[] = "mytext";
func(text);
// но не так
func("my" + "text");

В последнем варианте будет ошибка, т.к это уже будет не char, а String, компилятор выдаст ошибку.

Конечно, можно воспользоваться функцией strcat, но получает уже не то и не красиво, а чтоб записать строку придется объявлять ранее переменную типа char. То же относится и к sprintf где первым агрументом должен быть буфер типа char, которую так же необходимо предварительно объявить с определенным размером, мы можем вписаться в него, а можем и попросту расходовать занятую память. Нелогично.

String ресурсоемкий, но и char не исключение. Чем отпличается char[10] от String = "123456789"; ?...

adrusha
Offline
Зарегистрирован: 02.03.2015

А вообще, память благополучно была снижена до 69%! Путем уменьшения переменной Crons[10] на Crons[6] поскольку, для моих задач хватит и 6. Но это 4 занимали порядком памяти глобальных переменных. Вообще, можно было и поизвращаться, например прикрутив SD карту. Но что-то жирно будет для обычного контроля освещения по заданию cron и системы автоматического полива каждые n минут по n раз c n продолжительностью в секундах и выводом всего этого в меню, для дальнейшего редактирования.

Почему разработчики не сделаю память 4кб как старт или 16? в 21 веке живем, экономят на всем.

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

Вы передаете структуры и String в функции по значению, что приводит к передаче копии.

void foo(const Cron &d) более правильно, нежели void foo(Cron d).

На размер программы это может не отразиться, но размер используемого ОЗУ будет меньше, да и бессмысленного выделения памяти, а потом её освобождения компилятору уже не понадобится.

Вцелом, передача Объектов производится либо константной ссылкой, либо, если требуется модификация, передаётся указатель на объект.

 

adrusha
Offline
Зарегистрирован: 02.03.2015

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

Вот у меня вопрос на будущее, как лучше и где хранить большие текстовые строки, 32 кб, это довольно достаточно даже для строк типа String и по моим планам входило в рамки, и вошло. Вот только почему то String пропадает или передается некорректно, в то время как char работает хорошо. Я даже специально провел эксперимент, загрузил скетч максимально, программа то и делала что слала определенную строку в консоль. Если это была строка (String) то при занятой памяти более 75% были косяки в ее отображении, были крякозябры и прочее. Потой эта строка была бесконечной что приходилось перезагружать ардуино. А char же напротив, даже при 80% занятой памяти не давал сбоев. Но работать c char неудобно, или непривычно. Строка легко модифицируется, в то время как для char стоят небоскребы для изменения..

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

Ну что ж, удивляйтесь дальше. String использует, жрёт ОЗУ, функции при вызове делают копию объектов, снова жрут ОЗУ. Я Вам про то, как правильно передавать объекты в качестве параметров, а Вам это не нужно, ну как угодно.

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

adrusha пишет:

я тут вспомнил про sprintf

Ещё один отжиратель памяти.

adrusha пишет:

Хорошо, как можно используя char записать такую строку:

myText = "Position num: "+ String(num) + " from "+ String(from);

?

Элементарно, Ватсон!

adrusha пишет:

пользоваться всякими приблудами вроде toCharArray не вижу смысла

Я Вам даже больше скажу! Нет смысла использовать класс String вообще.

И ещё, чтение разных топиков и комментариев, позволило мне сделать вывод, что kisoft здесь один из лучших специалистов. Он выделил время на чтение Вашего кода и сделал предельно корректное, а главное, абсолютно верное замечание. Но вместо "спасибо" он получил попытку оспорить его замечание, причём попытку столь же безграмотную, сколь и наглую. Если Вы знаете как программировать лучше, чем он - какого чёрта Вы здесь вопросы задаёте? Тем более, если ответов слушать не хотите? У Вас зуд поспорить и умность свою показать? Давайте это без нас: сами задавайте вопросы, сами на них отвечайте и сами с собой спорьте. До свидания.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Arhat109-2 пишет:

даже ЕвгенийП уже осознал сей прискорбный факт. :)

Ни хрена не осознал, Вы меня в свою секту не записывайте! :)

Моё осознание не меняется с тех давних и уже почти легендарных времён, когда я на 96 байтах ОЗУ системы навигации делал. И осознание это я много раз Вам доводил: бороться за память, когда её хватает, т.е. "бороться ради борьбы" считаю онанизмом. Когда же её не хватает, уж будьте уверены - ужмусь и в игольное ушко пролезу не хуже других.

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Так "не верю", пока примеров не увижу .. вот, увидел и сделал свой "вывод", пусть и не очень верный. :)

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Arhat109-2 пишет:

Так "не верю"

Ну, это уж точно не моя проблема :)

adrusha
Offline
Зарегистрирован: 02.03.2015

ЕвгенийП пишет:
Элементарно, Ватсон!

Например?

И не делайте поспешных выводов за меня. Возможно в Си я не силен, зато уже 7 лет веду разработку на другиях языках и уверен знаю их лучше Вас. Но мы здесь собрались чтоб не письками мериться, а решить проблему. kisoft выдвинул замечание по коду, очень хорошо, спасибо. Но я уже сделал по другому.

Valera19701
Valera19701 аватар
Offline
Зарегистрирован: 18.10.2015

вот читаю тут и думаю, сделать конструктор смс как String или как буквы через char? - где и в чем выигрыш?, считая и то и то получается 50/50 и кто что скажет?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Мне казалось, я с Вами уже попрощался.

adrusha пишет:

Например?

Я Вам уже сказал в посте №6: "сами задавайте вопросы, сами на них отвечайте и сами с собой спорьте", а меня увольте. Тем более, что:

adrusha пишет:

 уже 7 лет веду разработку на другиях языках

Да, и ещё, я согласен с Вами

adrusha пишет:

Но мы здесь собрались чтоб не письками мериться

Действительно не надо. Вы смешно выглядите :)

adrusha пишет:

а решить проблему.

Да, нет. Вы пришли сюда, очевидно, нас потроллить. Тот плёвый пустяк, что выбран в качестве повода никак не может быть проблемой, для человека, который уже 7 лет программирует.

До свидания, ещё раз.

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Valera19701 пишет:

вот читаю тут и думаю, сделать конструктор смс как String или как буквы через char? - где и в чем выигрыш?, считая и то и то получается 50/50 и кто что скажет?

Валера, Вы ведёте сябе как Архат - не с того конца подходите. Не от задачи, а от инструмента.

Поймите не бывает инструментов плохих или хороших. Каждый хорош будучи применён с умом и в правильной ситуации.

Поэтому ответить на Ваш вопрос, что лучше "char" или "String" невозможно, не зная задачи и условий её выполнения.

Чтобы Вам было понятнее, ответьте сами, что лучше Мерседес-кабриолет или Камаз с фурой? Только при ответе учитывайте, что Вы не знаете что нужно спрашивающему - девочку покатать или партию холодильников перевезти. Вы сможете ответить?

Вот таков же и Ваш вопрос. Вы понимаете о чём я?

Valera19701
Valera19701 аватар
Offline
Зарегистрирован: 18.10.2015

в том та и вся соль, что для чего лучше или хуже, я просто задал вопрос и жду разные мнения

Valera19701
Valera19701 аватар
Offline
Зарегистрирован: 18.10.2015

Евгений, не обижайтесь, я держу паяльник с пяти лет, и я думаю что  архат тоже хочет что-то сделать что - то  (это его проблемы), вам этого не понять, и вы это не пытаетесь даже, так что ой!!

adrusha
Offline
Зарегистрирован: 02.03.2015

Вы видимо не видите разницы, а я Вам поясню, что каждый язык программирования по разному построен, по разному работает. В тех сфеах что работаю я, таких проблем с паматью нет да и там не приходится выбирать char или String. Все потому, что для них это одно и тоже. Но сталкнувшись с C++ я для себя открыл много вопросов. И все что я здесь говорю, это исключительно наработки моего опыта в других сферах. Вы говорите что я оспариваю ваше мнение? Ни в коем случае, я лишь привожу частичку своих знаний в этом. Я могу быть не прав, в данном вопросе, поскольку повторюсь с С++ я не сталкивался ранее. Учусь я быстро, мне нужно лишь понять и открыть новые возможности програмирования в нем, которые мне не известны. С каждой задачей я открываю все больше нового. Но когда я опираюсь в ограничения, это заставляет меня изрядно "попотеть", так отсюда и появился вопрос решения которого еще не последовало, за исключением предложенного kisoft.

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

Я учту все Ваши замечания и предложения по моей работе, поскольку я учусь и могу не знать того, чего знаете Вы. Я ожидал здесь более теплого приема, чем камни с помидорами.

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

Мужчины, попрошу больше не склонять мой ник в каких бы то ни было целях. Увы, форум не позволяет ни игнорировать, ни многого другого, что очень прискорбно. Лично меня не парит, если ко мне не прислушиваются, потому что Богом я себя не считаю. Всем удачи!

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Valera19701 пишет:

Евгений, не обижайтесь, я держу паяльник с пяти лет, и я думаю что  архат тоже хочет что-то сделать что - то  (это его проблемы), вам этого не понять, и вы это не пытаетесь даже, так что ой!!

Похожий ник наблюдал на skif.biz, где-то в 2005-м, откуда-то поблизости .. не Вы, случаем? У меня тогда так и не получилось из КЗ обмоток запилить "сверхтранс" .. магнитное поле разделенное КЗ обмоткой ведет себя как "коггерентное" и не складывается. :)

Valera19701
Valera19701 аватар
Offline
Зарегистрирован: 18.10.2015

Arhat109-2 пишет:

Похожий ник наблюдал на skif.biz, где-то в 2005-м, откуда-то поблизости .. не Вы, случаем? У меня тогда так и не получилось из КЗ обмоток запилить "сверхтранс" .. магнитное поле разделенное КЗ обмоткой ведет себя как "коггерентное" и не складывается. :)

Вы ошиблись

sirota
Offline
Зарегистрирован: 18.08.2015

Ну так к чему пришли? Я сейчас тоже столкнулся с тем что уже схавал 60% памяти. Пробежался по переменным, 12% высвободил. Использую вот такую конструкцию:

typedef struct
{
  char* label;
  char textsize;
  uint16_t fill;
  uint16_t textcolor;
  bool enable;
  int x;
  int y;
  int w;
  int h;
  bool reapete;
  char pressedCount;
  char doFirst;
  bool visible;
}
Baton;

Baton baton[] =
{
  //{"YES", 2, BLACK, WHITE, true, 45, 160, 70, 40, false, 0, 0, false},
  //{"NO", 2, BLACK, WHITE, true, 125, 160, 70, 40, false, 0, 0, false},
  {"СОСТОЯНИЕ", 1, CYAN, RED, false, 0, 0, 72, 80, false, 0, 0, false},
  {"УМЫВАНИЕ", 4, RED, GREEN, true, 0, 246, tft.width(), 74, false, 0, 0, true},
  {"КУПАНИЕ", 4, RED, GREEN, true, 0, 246, tft.width(), 74, false, 0, 0, false},
  {"-", 6, BLUE, GREEN, true, 0, 126, 54, 54, true, 0, 0, true},
  {"37", 6, GREEN, BLUE, false, 56 , 126, tft.width() - 112, 54, false, 0, 0, true},
  {"+", 6, RED, GREEN, true, tft.width() - 54, 126, 54, 54, true, 0, 0, true},
  {"-", 6, BLUE, GREEN, true, 0, 186, 54, 54, true, 0, 0, true},
  {"20", 6, YELLOW, BLUE, false, 56 , 186, tft.width() - 112, 54, false, 0, 0, true},
  {"+", 6, RED, GREEN, true, tft.width() -54, 186, 54, 54, true, 0, 0, true}
}
;

Или такую функцию:

String Adafruit_GFX::utf8rus(String source)
{
  int i,k;
  String target;
  unsigned char n;
  char m[2] = { '0', '\0' };

  k = source.length(); i = 0;

  while (i < k) {
    n = source[i]; i++;

    if (n >= 0xBF){
      switch (n) {
        case 0xD0: {
          n = source[i]; i++;
          if (n == 0x81) { n = 0xA8; break; }
          if (n >= 0x90 && n <= 0xBF) n = n + 0x2F;
          break;
        }
        case 0xD1: {
          n = source[i]; i++;
          if (n == 0x91) { n = 0xB7; break; }
          if (n >= 0x80 && n <= 0x8F) n = n + 0x6F;
          break;
        }
      }
    }
    m[0] = n; target = target + String(m);
  }
return target;
}

Собственно вопрос, что же все таки правильно использовать? и как дела с boolean? Я вообще только вот недавно стал гондобить проекты где памяти не хватает, а так я виндовый программер, мне эти различия int и long int там ни к чему, один хер винда сожрала кучу лишнего, мои 10метров памяти ни чего страшного не сделают ) А тут вот начинаю понимать, что там где до этого я бездумно кидал int, теперь смотрю что-то может можно и char и как я понимаю char - минимальная единица который выделяется 8бит. Получается тот же bool по факту char в размере? И смысл тогда от byte? ведь все равно 8бит выделяется памяти?

И как избавитсья от String для результат выполднения функции? Ведь размерность я не могу заранее предугадать.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

sirota пишет:

Я сейчас тоже столкнулся с тем что уже схавал 60% памяти. Пробежался по переменным, 

А с какой целью пробегались? Что-то большое впихнуть собираетесь? Или чисто из эстетических соображений? Так-то в принципе её хватает.

У меня молодые сторудники (студенты или вчерашние студенты) тоже любят поэкономить то, чего и так хватает. Эстеты. Если программа жрёт лишний байт или работет лишнюю микросекунду - они "кушать не могут". Еле отучил - пришлось прибегнуть к жёстким мерам. Вот с одним был такой диалог:

- (ОН) смотри, я тут пару дней поковырялся и сэкономил 4КБ.
- а что памяти не хватает?
- да, нет, там ещё много, но всегда ведь лучше сэкономить да и просто так красивее.
- знаешь, что! Мы пошли на установку большей памяти, хотя это и удорожило изделие, исключитально для того, чтобы сотрудники не тратили рабочее время на её экономию. Мы заплатили за память, чтобы не оплачивать лишние рабочие часы. Ты же предлагаешь нам оплачивать и то, и другое. Извини. Пару дней, говоришь, ковырялся? В этом месяце 20 рабочих дней, так что с тебя будет удержано 10% зарплаты, т.к. два дня ты занимался удовлетворением своих эстетических потребностей, а не работой на проект.

Как-то так.

Нет, в любительском проекте (который сам финансируешь) - не вопрос. Если доставляет удовольствие, то почему бы и нет? Сам иногда эстетствую. Но это непрофессионально.

P.S. Кстати, сообщение IDE моего сегодняшнего проекта на ATtiny45:

Sketch uses 4 088 bytes (99%) of program storage space. Maximum is 4 096 bytes.

И, знаете, не парит абсолютно!
 
То, что микросхема будет стоять в изделии загруженной на 9% или на 99% мне как-то абсолютно фиолетово.
sirota
Offline
Зарегистрирован: 18.08.2015

ЕвгенийП пишет:

А с какой целью пробегались? Что-то большое впихнуть собираетесь? Или чисто из эстетических соображений? Так-то в принципе её хватает.

P.S. Кстати, сообщение IDE моего сегодняшнего проекта на ATtiny45:

Sketch uses 4 088 bytes (99%) of program storage space. Maximum is 4 096 bytes.

И, знаете, не парит абсолютно!
 
То, что микросхема будет стоять в изделии загруженной на 9% или на 99% мне как-то абсолютно фиолетово.

Пока только вывод изображения о том что нет соединения с "сервером" (другая ардуинка), и с 10-ок кнопок. Ну AdafruitGFX + TouchScreen + шрифт для вывода русских символов. Из-зна них пришлось вот довесить целый класс String. Кнопки пока без обработчиков, точнее обработчик нажатия один, а вот то что должно случиться много. Потом из всего случившего надо собрать последовательности символов и залепить в serial, А еще надо постоянно читать serial и разбирать его для отображения данных. Так что - да. Еще много. И вопрос был не только в размере скетча. 

Global variables use 1,056 bytes (51.6%) of dynamic memory, leaving 992 bytes for local variables. Maximum is 2,048 bytes.

Вот я к чему веду. А с "дисковым" пространством все еще хуже:

Sketch uses 26,474 bytes (82.1%) of program storage space. Maximum is 32,256 bytes.

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

ЕвгенийП пишет:

У меня молодые сторудники (студенты или вчерашние студенты) тоже любят поэкономить то, чего и так хватает. Эстеты. Если программа жрёт лишний байт или работет лишнюю микросекунду - они "кушать не могут". Еле отучил - пришлось прибегнуть к жёстким мерам. Вот с одним был такой диалог:

- (ОН) смотри, я тут пару дней поковырялся и сэкономил 4КБ.
- а что памяти не хватает?
- да, нет, там ещё много, но всегда ведь лучше сэкономить да и просто так красивее.
- знаешь, что! Мы пошли на установку большей памяти, хотя это и удорожило изделие, исключитально для того, чтобы сотрудники не тратили рабочее время на её экономию. Мы заплатили за память, чтобы не оплачивать лишние рабочие часы. Ты же предлагаешь нам оплачивать и то, и другое. Извини. Пару дней, говоришь, ковырялся? В этом месяце 20 рабочих дней, так что с тебя будет удержано 10% зарплаты, т.к. два дня ты занимался удовлетворением своих эстетических потребностей, а не работой на проект.

Как-то так.

А вот тут отчасти я с Вами не согласен! Да что там от части. Много не согласен. Скажем высвободить 4K места при 32k всего возможных... это очень даже не плохо. Тем более пока код только написан и ты не разбираешь его заного. Вот 7 лет назад я писал обработку баз данных. Там dbf изначально без индексов, общий объем где-то 400MB. В общем из 2-х программ я одлжен был получить результаты в 3-ю. Тот код обрабатывал эти данные порядка 3-4 часов. При этом приходилось создавать порядка 100MB временных таблиц.

Полтора года назад код был переписан. Сейчас на все про все уходит 1 час, элементарно структурировав исходные таблицы перед началом работ, дабавив в них индексы, убрав не нужные данные для меня и переписав часть выборок. Временных таблиц 3 и и их размер сейчас где-то 10MB. По факту сейчас 2 узких места - сравнение идентификационных данных в 2-х программах (приходится сначала удостоверится что каждой записи из проаграммы 1 есть запись в программе 2 и у этих записей есть параметры которые отвечают опредленным критериям и потом наобород) и фактически сам расчет сумм (его ни как не удается завернуть в запрос, слишком много вещей которые sql хоть и потянет, но запрос будет настолько монструозным и многие моменты прийдется запрашивать по 10 раз, когда я просто значение записи присваиваю переменной). 

Так что оптимизация - вещь шикарная. Есть пределы, но и вот так вот на корню рубить... а потом мы удивляемся, почему калькулятор запускается 30 секунд. Просто я для себя решил - оптимизация, хотя бы 1 проход по коду - обязателен. Вот сегодня первый раз пересматривая одну функцию я заметил что под конец функции заводится 2 переменных int8_t, а у меня во входных параметрах инициализировано 8 int16_t при том 2 из них дальше по коду уже мною не используются. Зачем заводить еще лишних 16бит, когда есть уже инициализированные и еще не уничтоженные 2 по 16? 

А вот еще процесал функцию вывода текущих параметров. До:

Sketch uses 26,474 bytes (82.1%) of program storage space. Maximum is 32,256 bytes.
Global variables use 1,056 bytes (51.6%) of dynamic memory, leaving 992 bytes for local variables. Maximum is 2,048 bytes.
После:
Sketch uses 26,150 bytes (81.1%) of program storage space. Maximum is 32,256 bytes.
Global variables use 1,056 bytes (51.6%) of dynamic memory, leaving 992 bytes for local variables. Maximum is 2,048 bytes.
Потратил на это 10 минут. Повысил производительность этого кода в 2 раза.
Я правда промолчу что там были float, а мне все равно надо только целые в итоге. А я не знал что у авр туго с плавающей запятой дела обстоят. Пришлось то что раньше было /1,9 привести к виду *10/19
ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

sirota пишет:

Скажем высвободить 4K места при 32k всего возможных... это очень даже не плохо. 

Это не может быть ни плохо, ни хорошо, без дополнительной информации. 

Главный вопрос: а что потом произошло с этими 4К?

Они были использованы для новой функциональности, которая раньше не лезла? Тогда это не "неплохо", а просто отлично! А вот если они так и остались неиспользованными в конечном изделии, то это не просто плохо, а ужасно - на их "экономию" были впустую потрачены ресурсы проекта.

Вот эту простую мысль я пытаюсь довести до сотрудников. И с нею согласны все, кто реально руководил реальными коммерческими проектами (под "руководил" я понимаю - отвечал не только за техническую сторону дела, но и за бюджет тоже).

sirota
Offline
Зарегистрирован: 18.08.2015

Вот и я до Вас! Через пол года, или 5 лет Вас попросят добавить рюшку. Она будет как раз 4К, а их нет. И тогда Вы будете разбирать скорее всего уже чужой код и переведете на только понятие его столько же времени. Оптимизация должна быть обязательной. Код нужно вычитывать после отладки обязательно. И я с вам не спорю что нужно выжимать, но если эта трудозатрата стоит того, то почему бы и нет. Скажем возьмем 16U - стоит она 50 рублей. 32U стоит 75 рублей. При тираже в 1000000 штук оптмиизировать лишний 1К будет более чем, чем покупать 32-ю.

А по Вашему - вы после отладки сразу запусливаете в продакшен.

Logik
Offline
Зарегистрирован: 05.08.2014

sirota пишет:

 после отладки сразу запусливаете в продакшен.

К сожалению такая практика имеет место быть. От чего все (конечный потребитель, заказчик и разработчик) потом и страдают. Зато в срок сдано!

В остальном я +1. 

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

По теме ТС. Либки ардуновские - плохо за редким исключением. Зато на них можно быстро проверит исправность свежекупленой железяки, правильность монтажа и могут послужить донорами для написания своих, рассово верных либ. Строка как екземпляр класса (String и т.п.) - плохо. Потому что может содержать неявные действия, за простым "a"+"b" может и релокейт прятатся.  Допустимо в простых прогах ПК, не более. Можна конечно написать класс строк и без этого, но тогда это просто обертка на char[] без каких либо плюсов и минусов.  Кто не согласен - ИМХО, я не виноват ;)

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Sirota,

я говорю по опыту, а Вы теоретизируете :)

sirota пишет:

Через пол года, или 5 лет Вас попросят добавить рюшку.

А если не попросят? А попросят, так оплатят новую работу.

sirota пишет:

но если эта трудозатрата стоит того

Кто это определяет? В моих проектах - я. Вот я и оштрафовал сотрудника, т.к. один день его работы обходится фирме в 9 тыс. рублей, а ни на копейку улучшения продукта от его оптимизации я не заметил.

sirota пишет:

А по Вашему - вы после отладки сразу запусливаете в продакшен.

 
Иногда даже не после, а во время. Похоже, этого рынка Вы совсем не знаете. Я же говорю, что я пишу как оно есть, а Вы как теоретически могло бы быть.
Logik
Offline
Зарегистрирован: 05.08.2014

ЕвгенийП пишет:

 попросят, так оплатят новую работу.

Угу. Захотят добавить пару датчиков, а им трудозатраты в 30% от всех затрат на проект за всё время разработки. В таких случаях "выгребают" уже не прогеры, а прожектмены и архитекторы, потому как вовремя не думали о ресурсах. А если они еще и штрафовали за экономию то воще печалька.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Logik пишет:

Угу. Захотят добавить пару датчиков, а им трудозатраты в 30% от всех затрат на проект за всё время разработки.

Не знаю, в каком мире Вы живёте. В реальном мире, существует договор и стороны действуют в соответствие с договором. Если в нём предусмотрено "добавление пары датчиков" после сдачи изделия, то это будет учтено при разработке. А если нет, то они захотят не "добавить пару датчиков", а разработать новую версию изделия с расширенной функциональностью. Во что это им обойдется - зависит от миллиона вещей. Например, этим датчикам может элементарно питания не хватить. Что, заранее надо было питание с трёхкратным запасом делать? И сколько бы проект стоил?

Свеженький пример из жизни: договор - кластер на 20 узлов с возможстью расширения до 30. Сделали. Сдали. Заказчику вдруг протребовалось расширить не до 30, а до 36. Посчитали, сделали предложение. Тот типа как Вы "чего это мне вкатили такую цену, всего-то на 6 узлов больше, чем было оговоренно.!" Ему объяснили, что добавить-то узлы не проблема, только системы питания и охлаждения заточены под 32 узла - максимум, так что если нужно 36 - переделываем пиатние и охлаждение, а это половина цены всего проекта. Заказчик почесал репу и остановился на 32.

 

sirota
Offline
Зарегистрирован: 18.08.2015

ЕвгенийП пишет:

я говорю по опыту, а Вы теоретизируете :)

Культура программирования. У Вас же на выходе только деньги. При чем толко себе. По факту барыга. Возможно таким и стоит быть, но тогда и 32MB памяти на 16MHz процессоре скоро будет мало если с таким подходом учить молодеж.

Logik
Offline
Зарегистрирован: 05.08.2014

ЕвгенийП пишет:

Logik пишет:

Угу. Захотят добавить пару датчиков, а им трудозатраты в 30% от всех затрат на проект за всё время разработки.

Не знаю, в каком мире Вы живёте. В реальном мире, существует договор и стороны действуют в соответствие с договором. Если в нём предусмотрено "добавление пары датчиков" после сдачи изделия, то это будет учтено при разработке. А если нет, то они захотят не "добавить пару датчиков", а разработать новую версию изделия с расширенной функциональностью. Во что это им обойдется - зависит от миллиона вещей. Например, этим датчикам может элементарно питания не хватить. Что, заранее надо было питание с трёхкратным запасом делать? И сколько бы проект стоил?

Свеженький пример из жизни: договор - кластер на 20 узлов с возможстью расширения до 30. Сделали. Сдали. Заказчику вдруг протребовалось расширить не до 30, а до 36. Посчитали, сделали предложение. Тот типа как Вы "чего это мне вкатили такую цену, всего-то на 6 узлов больше, чем было оговоренно.!" Ему объяснили, что добавить-то узлы не проблема, только системы питания и охлаждения заточены под 32 узла - максимум, так что если нужно 36 - переделываем пиатние и охлаждение, а это половина цены всего проекта. Заказчик почесал репу и остановился на 32.

 

Не надо уводить тему разговора от разработки ПО. А то я тут давеча такси ловил, таксис хотел 100 а я давал 80. Этот таксист был послан ни с чем, а другой за 80 повез. И все в рамках договора.

Есть железо и есть ПО, у всего своя специфика. Про железо в другой ветке.

И если по завершению договора клиент желает заключить новый договор на те же +2 датчика, то выкатывать ему прайс как за пол разработки - прямой путь ити следом первого таксиста. Да конечно многое может осложнить решение, питание, архитектура ПО и т.д. Но если блокирующее - это криворукость прогера, разбазаривающего ресурсы при попустительстве менеджера - можна закрывать лавочку, клиент попал, может искать новых разработчиков.  В моей практике есть проекты активно развивавшиесе более 10 лет, и хотелки клиентов решались за адекватные трудозатраты. Разумеется по соответствующим договорам. А все в том числе и потому, что перед доработкой проводилось нормальное проектирование, на этой стадии и определялось в т.ч. де и сколько памяти и производительности должно потребоватся из весьма ограниченых ресурсов. 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

sirota пишет:

Культура программирования. 

Культура программирования состоит не в том, чтобы тратить два дня на никому ненужную экономию четырёх килобайт, а в том. чтобы сразу писать пристойный код, который легко тестируется и не особо разбрасывается ресурсами.

sirota пишет:

У Вас же на выходе только деньги.

Ну, не только, но деньги - очень важная вещь. Мне, знаете ли, надо кормить коллектив в котором десятки людей, у каждого из которых семьи. И каждый из которых должен пятого числа получить зарплату.

Кстати, это одно из отличий профессионала от любителя. Любителю в разумных пределах всё равно сколько стоит создаваемый им продукт, профессионалу - нет.

sirota пишет:

По факту барыга. 

По факту - хам.

sirota пишет:

тогда и 32MB памяти на 16MHz процессоре скоро будет мало если с таким подходом учить молодеж.

Какой-то у Вас двоичный мир - либо ноль, либо единица. Я разве говорил, что оптимизировать не надо? Я говорил, что этого не надо делать там, где задача этого не требует. А там, где требует - конечно, нужно соки выжимать. Какой идиот будет с этим спорить?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Logik пишет:

Не надо уводить тему разговора от разработки ПО.

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

sirota
Offline
Зарегистрирован: 18.08.2015

ЕвгенийП пишет:

По факту - хам.

По факту от Вас тут толку ноль. Я поставил вопрос, мне нужно его решить. Вопрос зачем мне его решить Вас не касается. Вы развели полемику - мол оптимизация - херня. Я объяснил, но все равно помощи от Вас нет и в помине. Прошли бы мимо и все если не хотите и/или считаете лишним. А так совета то от Вас дельного не поступило, одна Бла-бла-бла. Так и пректы у Вас:

Sketch uses 4 088 bytes (99%) of program storage space. Maximum is 4 096 bytes.

Потому что бла-бла-бла.

А мне помог человек, рассказал что и как. Вычитав в названии функции utf8 сразу запалил что я работаю не только с ASCII и что в одном случае один символ - это char, а в другом он уже не помещается в него, и по этому в функции оптимизировать не чего.

А по поводу:

ЕвгенийП пишет:

сразу писать пристойный код, который легко тестируется и не особо разбрасывается ресурсами.

Ну если Вы такой гений, то конечно пожалуйста. Ни кто не против. Но скажем я только перешел с x86 и там я не задумывался о char. У меня целое всегда начиналось с int. Ведь там-то в наше время есть куда развернуться. Хотя и там я проводил оптимизацию, но только на скорость, объемы памяти в моих проектах меня не волновали.

arduinec
Offline
Зарегистрирован: 01.09.2015

sirota пишет:

А мне помог человек, рассказал что и как. Вычитав в названии функции utf8 сразу запалил что я работаю не только с ASCII и что в одном случае один символ - это char, а в другом он уже не помещается в него, и по этому в функции оптимизировать не чего.

В первом топике темы http://arduino.ru/forum/programmirovanie/rusifikatsiya-biblioteki-adafru... подробно описано как работает функция utf8rus.

adrusha
Offline
Зарегистрирован: 02.03.2015

sirota не удивляйтесь, ответы на мои вопросы аналогичны.

"Я умею, я могу, я знаю"... А как? Думайте сами!

Ваши сообщения в этой теме, уважаемые, трата времени, если не собираетесь помогать друг другу или драться, смысл разводить руками?

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

ЕвгенийП пишет:
... Мы заплатили за память, чтобы не оплачивать лишние рабочие часы.

Ключевая фраза в вашем опусе. Как понимаю, сотрудника ПРЕДУПРЕДИТЬ ЗАРАНЕЕ об этом внезапно забыли. Наверное как раз для такой цели - удержать 10%, когда он "сэкономит". :)

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

sirota пишет:
А вот тут отчасти я с Вами не согласен! Да что там от части. Много не согласен ... а потом мы удивляемся, почему калькулятор запускается 30 секунд.

И правильно что не согласны. Просто говнокодерство возведено в ранг "профессионализма" и все больше занимает агрессивную позицию на рынке ПО. Нечему удивляться в 30сек. запуске калькулятора .. или то, что "Фобос - в грунт". Говнокодерский подход ничего иного создать не может. Зато "быстро": "тяп-ляп и готово".

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Arhat109-2 пишет:

Как понимаю, сотрудника ПРЕДУПРЕДИТЬ ЗАРАНЕЕ об этом внезапно забыли. 

Хреново понимаете. У сотрудника было конкретное задание на которое он забил, и два дня потратил на никому нахрен ненужную оптимизацию. Теперь стал дисциплинированнее.

А то раньше с ним удержу не было. Другой пример с ним же: был кусок кода, который формирует содежимое экрана, выводит его и ждёт ввода от оператора. Формирование содержимого и вывод занимали около 20мс. Кусок работал уже в нескольких версиях продукта и "есть не просил". Этот орёл "соптимизировал" до 9мс. На впоросы "заметит ли это оператор?" "увеличит ли это общую скорость работы?" и, наконец, "кому это нахрен нужно?" мялся и говорил, "так быстрее же"! Тогда объяснили словами - не понял. А вот после штрафа, вдруг дошло, что профессиональная работа и "ускорения ради ускорения" (вернее ради того, чтобы самому себе доказать, что "длинее") - это вовсе не одно и тоже.