Две ардуины или оптимизация

Тема в разделе "Arduino & Shields", создана пользователем issida, 26 июн 2016.

  1. issida

    issida Нерд

    Не хватает памяти на про мини. Должно быть подключено 4 сервы, DS1307, экран 1602 по I2C, но хватило только на 3 сервы. Работа с таймером,выбор режимов работы. Каким способом лучше соединить ардуины, чтобы разделить работу сервоприводов? Или лучше использовать ардуину с бОльшим объемом памяти?
     
  2. Tomasina

    Tomasina Сушитель лампочек Модератор

    Из той периферии, что написана - памяти должно хватать с запасом.
    Значит, дело в скетче - оптимизировать скетч - освободится память ;)
    Где код?
     
  3. issida

    issida Нерд

    Слишком много частей выходило, весь не хотел вставляться. скетч еще не доделан
     

    Вложения:

    • menu.ino.ino
      Размер файла:
      111,9 КБ
      Просмотров:
      284
  4. Tomasina

    Tomasina Сушитель лампочек Модератор

    да, тут пора уже на Мегу переходить.
     
  5. DIYMan

    DIYMan Guest

    Бегло просмотрел код, не знаю, что там за "OneButton.h". Предварительный вердикт - код поддаётся сильной оптимизации, можно сократить объём занимаемой оперативки достаточно сильно. Например, вместо bool для каждого флага юзать битовые поля, вместо bool для каждого дня недели - также битовые поля, прошерстить размерность всех переменных и оставить только такую размерность, которая на самом деле нужна (возможно, где-то можно обойтись двухбайтовыми переменными, вместо четырёхбайтовых). Выкинуть жирные библиотеки типа DS1307 и самому написать код работы с часами. Ну и т.д.

    В общем, работать есть над чем. Но в том виде, в котором код сейчас - он трудноподдерживаем и малосопровождаем, к сожалению.
     
  6. ZAZ-965

    ZAZ-965 Гуру

    @issida, если я правильно понял не хватает SRAM , вы четыре переменных servoХ_hmsv объявляете как long, а используете их как byte
    Код (C++):
    //время срабатывания первого сервопривода
    long servo1_hmsv[30];
    ....................................
    for (byte s = 0;s < 30; s++){ //считывание с 0 по 29 eeprom для расписания сервы1
    servo1_hmsv[s]=EEPROM.read(s);
    ....................................
    unsigned long servo1timeon = ((servo1_hmsv[3*a]*3600)+(servo1_hmsv[(3*a)+1]*60)); //пересчет времени в секунды сервы 1
    }
     
  7. DIYMan

    DIYMan Guest

    Собственно, вот я о чём:
    Код (C++):
    int servo2_week [7];//первое значение - понедельник, последнее - воскресенье
    Имеем 14 занятых байт для проверки, в какой день недели срабатывать. Четырнадцать, Карл! Вместо одного:

    Код (C++):
    byte servo2_week;

    if(servo2_week & 1) // работаем в понедельник
    if(servo2_week & 2) // работаем во вторник
    if(servo2_week & 4) // работаем в среду
    if(servo2_week & 8) // работаем в четверг
    if(servo2_week & 16) // работаем в пятницу
    if(servo2_week & 32) // работаем в субботу
    if(servo2_week & 64) // работаем в воскресенье
    Или, если библиотека возвращает dayOfTheWeekначиная с 0 (т.е. 0 - это понедельник):

    Код (C++):
    if( servo2_week & (1 << myTime.dayOfTheWeek()) )
     
  8. issida

    issida Нерд

    Когда ставил byte или int считало бессмыслицу, появляются отрицательные значения или вовсе не то, что нужно. И это сбивало с толку.
    Код (C++):

    byte servo1_hmsv[30];
    ----------------------
    for (byte a = 0; a < 10; a++){
    long h = servo1_hmsv[3*a];
    int m = servo1_hmsv[(3*a)+1];
    long servo1timeon = (h*3600)+(m*60); //пересчет времени в секунды сервы 1
    так немного сэкономило памяти.
    "OneButton.h" - обработка нажатий на кнопку, одиночное, двойное, длинное
    С днями недели и битовыми полями таким способом не понял . С кнопок устанавливаются дни, когда должно срабатывать, и в процессе должна быть возможность изменения. Исправил на byte servo2_week
     
  9. DIYMan

    DIYMan Guest

    И что мешает битовым полям изменяться, не подскажете? С кнопок сколько угодно можно устанавливать дни, просто записывать флаг для в нужный бит, и всё. Например, если нажата кнопка "3" (в среду работать), то запись
    Код (C++):
    dayMask |= 1 << 3;
    установит третий бит в байте. Проверить, установлен ли этот бит (т.е., работаем ли мы в среду), можно тоже крайне просто:
    Код (C++):
    if(dayMask & (1 << 3))
    {
    // Урра, мы работаем в среду!
    }
    Просто у вас аж 14 байт используется для маски дней недели, когда достаточно всего лишь одного. Итого, на одну серву экономия - 13 байт оперативы, немало, знаете ли.
     
    issida и ostrov нравится это.
  10. ZAZ-965

    ZAZ-965 Гуру

    @issida, еще замечания
    Код (C++):
    unsigned long utime = myTime.unixtime(); //сохраняем в переменную - время в формате UNIX
    utime %= 86400; //Сохраняем в этой же переменной остаток деления на кол-во секнд в сутках,
    //Это дает количество секунд с начала текущих суток
    myTime.unixtime() - даст количество секунд прошедших с 1970 года
    Код (C++):
    unsigned long z = EEPROM.read(160);//считывание последних часов с памяти
    unsigned long x = EEPROM.read(161);//считывание последних минут с памяти
    unsigned long time_last_1 = (z*3600)+(x*60); //перевод в секунды
    запишите проще, компилятор сам разберется где хранить временную переменную
    Код (C++):
    //считывание последних часов и минут с памяти и перевод в секунды
    unsigned long time_last_1 = (EEPROM.read(160)*3600)+(EEPROM.read(161)*60);
    Я у вас не увидел начальных установок EEPROM, EEPROM.read(s) вернет 255, если в ячейку ранее не занесли значение.
    Я бы занес значения по умолчанию в PROGMEM
    Код (C++):
    static const uint8_t servo1_hmsv_default[30] PROGMEM = {
      08,00,08,30,09,00,09,30,............16,00,16,30
    };
    и если EEPROM.read(s) вернет невалидные значения, использовал значения по умолчанию (или предупреждал пользователя, или как-то что-то делал)
     
  11. issida

    issida Нерд

    Спасибо за подсказку. Сделал, заработало
    Код (C++):
    servo11_week ^= 1 << trash;
    с возможностью инвертирования. ОЗУ убавилось, но выросла флеш-память, с которой у меня напряг. для одной сервы на 40-50 байт кажется.
    Не работает подомным методом
    Код (C++):
    byte a = 15;
    byte b = 35;
    void setup() {
    Serial.begin(9600);
    long c = (a*3600)+(b*60);
    Serial.println(c);
    int d=a;
    int e=b;
    long f = (d*3600)+(e*60);
    Serial.println(f);
    long g = a;
    long h = b;
    long i = (g*3600)+(h*60);
    Serial.println(i);
    }

    void loop() {}
    Простой пример для наглядности. Ввполняет одинаковые операции, а ответы разные.
    С первой записью в EEPROM не критично, когда код будет готов запишу нужные значения в нужные ячейки
     
  12. ZAZ-965

    ZAZ-965 Гуру

    @issida, 3600L записывать как long
    Код (C++):
    //считывание последних часов и минут с памяти и перевод в секунды
    unsigned long time_last_1 = (EEPROM.read(160)*3600L)+(EEPROM.read(161)*60);
     
    Последнее редактирование: 27 июн 2016
  13. issida

    issida Нерд

    Такой кусок ода можно запихнуть в класс? Слишком много одинаковых частей для четырех серв
    Код (C++):

    //--------------АВТОМАТИЧЕСКИЙ РЕЖИМ СЕРВЫ1----------------
    if(servo1_week[dayOfWeek-1]==1 && servo1_always_on){ //если совпадает день недели и серва должна работать
    for (byte a = 0; a < 10; a++){
    unsigned long servo1timeon = (servo1_hmsv[3*a]*3600L)+(servo1_hmsv[(3*a)+1]*60); //пересчет времени в секунды сервы 1
    if (utime==servo1timeon ){
      servo1_setvol= servo1_hmsv[(3*a)+2]; //запоминаем объем
      as1=100;// запуск режима
    }
    }
    }
    switch (as1) {
    case 100:
    if(servo1_late && servo1_on){//если не работает никакой из режимов
      servo1_on=false;//ручной режим не запустится
    if(!servo1_on){
      as1=1;
      break;
    }
    }
     
    case 1:
    if(utime-prev_mixer_time>120)as1=2;//если с момента остановки миксера прошло 120сек, входим в режим включения миксера
    if(utime-prev_mixer_time<120)as1=4; //если меньше 120сек, то минуем этот режим
    break;
         
    case 2:
    analogWrite(11, mixer_speed);// запуск миксера

    s1t=utime;//запоминаем время включения миксера
    as1=3;//переход в следующий
    break;

    case 3:
    if(utime-s1t>=mixer_time){ //если мисер отработал заданное время
      analogWrite(11, 0);//выключаем
      prev_mixer_time = utime;//запоминаем время выключения миксера
    }
    if(utime-s1t>=mixer_time+5){//ждем 5 сек
      as1=6;//переходим в следующий
    }
    break;

    break;
    case 4:
    s1t=utime;
    as1=5;
        break;

    case 5:
    if(utime-s1t>1)as1=6;
    break;

        case 6:
    servo1_current_vol = servo1_current_vol + servo1_setvol; // вычисление текущего угла сервы 1
    as1=7;
        break;

       
        case 7:

    if(servo1_current_vol<180 && servo1_current_vol>=0){//если текущий угол находится от 0 до 179
      as1=11;//переходим в 11
       break;
      }  
    if(servo1_current_vol>=180){//если текущий угол от 180 и больше
    s1t=utime;//запоминаем это время
      as1=8; //переходим в 8
        break;
      }
       

        case 8:
    if(utime-s1t>=1){//ждем одну секунду и выполняем
      servo1_current_vol=servo1_current_vol-180;// вычисляем нужный угол
      myservo1.attach(3);
      myservo1.write(180);//поворачиваем в 180
      as1=9;
       }
        break;

        case 9:
    if(utime-s1t>=3){//ждем
    myservo1.write(0);//поворачиваем в 0
    as1=10;
    }
        break;

        case 10:
    if(utime-s1t>=5){//ждем
    as1=7;// переходим в 5
    }
        break;

        case 11:
    myservo1.attach(3);//включаем серву
    myservo1.write(servo1_current_vol);//записывем текущий угол
    s1t=utime;//запоминаем время
    as1=12;
        break;
        case 12:
    if(utime-s1t>=2){//ждем 2 сек
    myservo1.detach();//отключаем серву
    servo1_on=true;
    EEPROM.update(160, hour );
    EEPROM.update(161, minute );

    as1=0; //выход
       break;
    }
    }
     
  14. DIYMan

    DIYMan Guest

    Любой кусок кода можно запихнуть в класс ;) Первый признак для введения слоя абстракции, как вы правильно заметили - наличие дублирующегося кода. Самого корёжит в своих исходниках такое, если честно :) Иногда забиваю до лучших времён, когда жать в подмышках не начинает. Но чаще, конечно - лучше сразу разобраться ;)