Помогите найти ошибку

Maka
Offline
Зарегистрирован: 24.10.2015

Давно написал функцию, и вроде проблем не помню с ней. Сейчас вернулся к проекту, и не работает как надо. Это таймер (да да, опять аквариум). Почему то во втором таймере выход pwm срывается на ноль, а потом нормализуется согласно программе. Здесь три канала по четыре "таймера". Таймер это временной интервал с постоянным уровнем pwm. Можно задать уровни в каждом "таймере", изменить время старта и окончания работы каждого. Уровень pwm между "таймерами" должен плавно изменяться с уровня предыдущего "таймера" до уровня следующего. Начало и конец дня pwm - 0. Так оно и работает, кроме второго таймера. Код можно загрузить в ардуину и все увидеть. Пока тестирую без RTC, просто переменная Utime приращивается в лупе. 

Может свежим взглядом виднее, я не вижу уже ничего...


struct Timer {
  long start;
  long end;
  int level;
  bool on;
};
Timer timer[4];

struct Channel {
  long startDay;
  long endDay;
  Timer timer[4];
};

Channel channel[3];
long Utime;

long Channel_pwm(Channel &c) {
  int _pwm = 0;
  //таймер -0
  if (Utime >= c.startDay && Utime < c.timer[0].start) {
    _pwm = (((Utime - c.startDay) * c.timer[0].level) / (c.timer[0].start - c.startDay));
  }// таймер 0
  else if (Utime >= c.timer[0].start && Utime < c.timer[0].end) {
    _pwm = c.timer[0].level;
  }// таймер 0 - 1
  else if (Utime >= c.timer[0].end && Utime < c.timer[1].start) {
    _pwm = ((Utime - c.timer[0].end) * (c.timer[1].level - c.timer[0].level) / (c.timer[1].start - c.timer[0].end)) + c.timer[0].level;
  }// таймер 1
  else if (Utime >= c.timer[1].start && Utime < c.timer[1].end) {
    _pwm = timer[1].level;
  }// таймер 1 - 2
  else if (Utime >= c.timer[1].end && Utime < c.timer[2].start) {
    _pwm = ((Utime - c.timer[1].end) * (c.timer[2].level - c.timer[1].level) / (c.timer[2].start - c.timer[1].end)) + c.timer[1].level;
  }// таймер 2
  else if (Utime >= c.timer[2].start && Utime < c.timer[2].end) {
    _pwm = c.timer[2].level;
  }// таймер 2 - 3
  else if (Utime >= c.timer[2].end && Utime < c.timer[3].start) {
    _pwm = ((Utime - c.timer[2].end) * (c.timer[3].level - c.timer[2].level) / (c.timer[3].start - c.timer[2].end)) + c.timer[2].level;
  }// таймер 3
  else if (Utime >= c.timer[3].start && Utime < c.timer[3].end) {
    _pwm = c.timer[3].level;
  }// таймер 3 +
  else if (Utime >= c.timer[3].end && Utime < c.endDay) {
    _pwm = (((c.endDay - Utime) * c.timer[3].level) / (c.endDay - c.timer[3].end));
  }
  else _pwm = 0;
  return _pwm;
}
void setup() {
  Serial.begin(9600);
  channel[0].startDay = 10000;
  channel[0].endDay = 82000;
  channel[0].timer[0].start = 24400;
  channel[0].timer[0].end = 31600;
  channel[0].timer[1].start = 38800;
  channel[0].timer[1].end = 46000;
  channel[0].timer[2].start = 53200;
  channel[0].timer[2].end = 60400;
  channel[0].timer[3].start = 67600;
  channel[0].timer[3].end = 74800;
  channel[0].timer[0].level = 70;
  channel[0].timer[1].level = 140;
  channel[0].timer[2].level = 200;
  channel[0].timer[3].level = 250;
  channel[0].timer[0].on = true;
  channel[0].timer[1].on = true;
  channel[0].timer[2].on = true;
  channel[0].timer[3].on = true;

  channel[1].startDay = 1000;
  channel[1].endDay = 82000;
  channel[1].timer[0].start = 24400;
  channel[1].timer[0].end = 31600;
  channel[1].timer[1].start = 38800;
  channel[1].timer[1].end = 46000;
  channel[1].timer[2].start = 53200;
  channel[1].timer[2].end = 60400;
  channel[1].timer[3].start = 67600;
  channel[1].timer[3].end = 74800;
  channel[1].timer[0].level = 140;
  channel[1].timer[1].level = 280;
  channel[1].timer[2].level = 560;
  channel[1].timer[3].level = 1120;
  channel[1].timer[0].on = true;
  channel[1].timer[1].on = true;
  channel[1].timer[2].on = true;
  channel[1].timer[3].on = true;

  channel[2].startDay = 1000;
  channel[2].endDay = 82000;
  channel[2].timer[0].start = 24400;
  channel[2].timer[0].end = 31600;
  channel[2].timer[1].start = 38800;
  channel[2].timer[1].end = 46000;
  channel[2].timer[2].start = 53200;
  channel[2].timer[2].end = 60400;
  channel[2].timer[3].start = 67600;
  channel[2].timer[3].end = 74800;
  channel[2].timer[0].level = 210;
  channel[2].timer[1].level = 420;
  channel[2].timer[2].level = 840;
  channel[2].timer[3].level = 1680;
  channel[2].timer[0].on = true;
  channel[2].timer[1].on = true;
  channel[2].timer[2].on = true;
  channel[2].timer[3].on = true;
}


void loop() {
Utime+=5;
  Serial.print(Utime);
  Serial.print(" pwm    ");
  Serial.print(Channel_pwm(channel[0]));
  Serial.print(" ");
  Serial.print(Channel_pwm(channel[1]));
  Serial.print(" ");
  Serial.println(Channel_pwm(channel[2]));
  }

  

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Мне кажется, что автор скетча и есть ошибка.

Maka
Offline
Зарегистрирован: 24.10.2015

Очень загадочный ответ. А главное полезный. Спасибо.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Maka пишет:

Очень загадочный ответ. А главное полезный. Спасибо.

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

ПС: И да long лучше заменить на unsigned long https://www.arduino.cc/reference/en/language/variables/data-types/unsignedlong/

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

qwone пишет:

Maka пишет:

Очень загадочный ответ. А главное полезный. Спасибо.

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

ПС: И да long лучше заменить на unsigned long https://www.arduino.cc/reference/en/language/variables/data-types/unsignedlong/

Не могу не согласится с уважаемым qwone - очень сложно читать программу без комментариев. Для Вас все прозрачно, но нам трудно оценить полет Вашей мысли... Комментарии для Вас - это несколько минут, но они могут и для Вас открыть истину!

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

Надо ж было такую простую вещь так сложно написать! Есть же, блин, специалисты!

Maka
Offline
Зарегистрирован: 24.10.2015

Не хочется классов, структурами можно обойтись, мне кажется. Откомментировал как смог:


struct Timer { //описываю параметры таймера
  long start; // время в секундах от начала суток
  long end;   // время в секундах от начала суток
  int level;  // уровень шим в таймере
  bool on;    //признак активности таймера, здесь пока не используется
};
Timer timer[4]; //создаю четыре объекта структуры Timer

struct Channel { // описываю параметры канала
  long startDay;  //время начала работы канала в сек от начала суток
  long endDay;    // время окончания работы канала в сек от начала суток
  Timer timer[4]; // добавляю массив объектов типа Timer
};
long Utime;
long Channel_pwm(Channel &c) {
  int _pwm = 0;
  //таймер -0
  if (Utime >= c.startDay && Utime < c.timer[0].start) { //интервал от начала дня до первого таймера
    _pwm = (((Utime - c.startDay) * c.timer[0].level) / (c.timer[0].start - c.startDay)); //расчет шим 
  }// таймер 0
  else if (Utime >= c.timer[0].start && Utime < c.timer[0].end) { // интервал собственно таймера 0
    _pwm = c.timer[0].level; // приравниваю, здесь шим не меняется
  }// таймер 0 - 1
  else if (Utime >= c.timer[0].end && Utime < c.timer[1].start) { // интервал между 0 и 1 таймером
    _pwm = ((Utime - c.timer[0].end) * (c.timer[1].level - c.timer[0].level) / (c.timer[1].start - c.timer[0].end)) + c.timer[0].level;//расчет шим 
  }// таймер 1
  else if (Utime >= c.timer[1].start && Utime < c.timer[1].end) { // интервал собственно таймера 1
    _pwm = timer[1].level;  // приравниваю, здесь шим не меняется
  }// таймер 1 - 2
  else if (Utime >= c.timer[1].end && Utime < c.timer[2].start) {
    _pwm = ((Utime - c.timer[1].end) * (c.timer[2].level - c.timer[1].level) / (c.timer[2].start - c.timer[1].end)) + c.timer[1].level;//расчет шим 
  }// таймер 2
  else if (Utime >= c.timer[2].start && Utime < c.timer[2].end) { // интервал собственно таймера 2
    _pwm = c.timer[2].level; // приравниваю, здесь шим не меняется
  }// таймер 2 - 3
  else if (Utime >= c.timer[2].end && Utime < c.timer[3].start) {
    _pwm = ((Utime - c.timer[2].end) * (c.timer[3].level - c.timer[2].level) / (c.timer[3].start - c.timer[2].end)) + c.timer[2].level;//расчет шим 
  }// таймер 3
  else if (Utime >= c.timer[3].start && Utime < c.timer[3].end) { // интервал собственно таймера 3
    _pwm = c.timer[3].level;  // приравниваю, здесь шим не меняется
  }// таймер 3 +
  else if (Utime >= c.timer[3].end && Utime < c.endDay) { //интервал от конца последнего таймера до конца светового дня 
    _pwm = (((c.endDay - Utime) * c.timer[3].level) / (c.endDay - c.timer[3].end)); // снижение уровня шим со значения последнего таймера до нуля
  }
  else _pwm = 0; // время до startDay и после endDayendDay
  return _pwm;
}

void setup() {
  Serial.begin(9600);
  // присваиваю значения
  channel[0].startDay = 10000;
  channel[0].endDay = 82000;
  channel[0].timer[0].start = 24400;
  channel[0].timer[0].end = 31600;
  channel[0].timer[1].start = 38800;
  channel[0].timer[1].end = 46000;
  channel[0].timer[2].start = 53200;
  channel[0].timer[2].end = 60400;
  channel[0].timer[3].start = 67600;
  channel[0].timer[3].end = 74800;
  channel[0].timer[0].level = 70;
  channel[0].timer[1].level = 140;
  channel[0].timer[2].level = 200;
  channel[0].timer[3].level = 250;
  channel[0].timer[0].on = true;
  channel[0].timer[1].on = true;
  channel[0].timer[2].on = true;
  channel[0].timer[3].on = true;

  channel[1].startDay = 1000;
  channel[1].endDay = 82000;
  channel[1].timer[0].start = 24400;
  channel[1].timer[0].end = 31600;
  channel[1].timer[1].start = 38800;
  channel[1].timer[1].end = 46000;
  channel[1].timer[2].start = 53200;
  channel[1].timer[2].end = 60400;
  channel[1].timer[3].start = 67600;
  channel[1].timer[3].end = 74800;
  channel[1].timer[0].level = 140;
  channel[1].timer[1].level = 280;
  channel[1].timer[2].level = 560;
  channel[1].timer[3].level = 1120;
  channel[1].timer[0].on = true;
  channel[1].timer[1].on = true;
  channel[1].timer[2].on = true;
  channel[1].timer[3].on = true;

  channel[2].startDay = 1000;
  channel[2].endDay = 82000;
  channel[2].timer[0].start = 24400;
  channel[2].timer[0].end = 31600;
  channel[2].timer[1].start = 38800;
  channel[2].timer[1].end = 46000;
  channel[2].timer[2].start = 53200;
  channel[2].timer[2].end = 60400;
  channel[2].timer[3].start = 67600;
  channel[2].timer[3].end = 74800;
  channel[2].timer[0].level = 210;
  channel[2].timer[1].level = 420;
  channel[2].timer[2].level = 840;
  channel[2].timer[3].level = 1680;
  channel[2].timer[0].on = true;
  channel[2].timer[1].on = true;
  channel[2].timer[2].on = true;
  channel[2].timer[3].on = true;
}


void loop() {
  
Utime+=5; 
  Serial.print(Utime);
  Serial.print(" pwm    ");
  Serial.print(Channel_pwm(channel[0]));
  Serial.print(" ");
  Serial.print(Channel_pwm(channel[1]));
  Serial.print(" ");
  Serial.println(Channel_pwm(channel[2]));
  }

  

 

Maka
Offline
Зарегистрирован: 24.10.2015

Ворота пишет:

Надо ж было такую простую вещь так сложно написать! Есть же, блин, специалисты!

 

Вы про структуры или про функцию? Мне показалось так проще всего. Хоть на словах, объясните как описать просто такую "простую вещь"

unsigned long не помог...

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Maka пишет:
Не хочется классов, структурами можно обойтись, мне кажется.
А по факту у вас получились протоклассы. Все это *** потом сделали официальными классами.

Maka
Offline
Зарегистрирован: 24.10.2015

Да, это очень похоже на классы, я и хотел, в общем, библиотеку сделать, но пока не потянул. Только не в структурах же ошибка, а в расчете уровня шим, подозреваю. Не могу найти где. Шим то во всех таймерах одинако рассчитывается, почему глюк во втором только? Или я неправильно декларирую структуры? Или неправильно помещаю массив структур timer в структуру channel?

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Скорее неправильная методика программирования. Неправильно что-то продумали и эта неясность полезла в код, породив глюки в коде.

Maka
Offline
Зарегистрирован: 24.10.2015

Неправильный расчет уровня шим в интервалах между таймерами. Переписывать.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Неправильный подход. Не зачем делать расчет Шима. У объекта ШИМ должно быть три состояния. Стабильное, плавно(логарифмически) возврастать до нужного и плавно (логарифмически)убывать.

ПС: И зачем Вы все усложняете. Посмотрите мультфильм "Шкатулка с секретом" Там прообраз вашей программы. https://www.youtube.com/watch?v=2wDESvyj1qo

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Вот это "пружина"

/**/
unsigned long time = 0;
//----------main()---------
void setup() {
}

void loop() {
  time = time + 1;
  if (time >= 24ul * 60 * 60) time = 0;
}
/**/

А дальше "барабан"

/**/
unsigned long time = 0;
typedef struct note_t {
  byte hour;
  byte minute;
  byte second;
  byte channel;
  byte PWM;
};
const note_t NOTES[] {
  /*час-мин-сек-канал-шим*/
  {0, 0, 0, 0, 10},  // канал 0
  {6, 0, 0, 0, 50},
  {12, 0, 0, 0, 40},
  {18, 0, 0, 0, 100},
  {23, 0, 0, 0, 10},
  {0, 0, 0, 1, 10},  // канал 1
  {6, 0, 0, 1, 50},
  {12, 0, 0, 1, 40},
  {18, 0, 0, 1, 80},
  {23, 0, 0, 1, 10},
  {0, 0, 0, 2, 10},  // канал 2
  {6, 0, 0, 2, 50},
  {12, 0, 0, 2, 40},
  {18, 0, 0, 2, 30},
  {23, 0, 0, 2, 10}
};
//----------main()---------
void setup() {
}

void loop() {
  time = time + 1;
  if (time >= 24ul * 60 * 60) time = 0;
}
/**/

И в эскизном виде "шкатулка" будет такой

/**/
unsigned long time = 0;
typedef struct{
  byte hour;
  byte minute;
  byte second;
  byte channel;
  byte PWM;
} note_t ;
const int numNotes = 15;
const note_t NOTES[numNotes] {
  /*час-мин-сек-канал-шим*/
  {0, 0, 0, 0, 10},  // канал 0
  {6, 0, 0, 0, 50},
  {12, 0, 0, 0, 40},
  {18, 0, 0, 0, 100},
  {23, 0, 0, 0, 10},
  {0, 0, 0, 1, 10},  // канал 1
  {6, 0, 0, 1, 50},
  {12, 0, 0, 1, 40},
  {18, 0, 0, 1, 80},
  {23, 0, 0, 1, 10},
  {0, 0, 0, 2, 10},  // канал 3
  {6, 0, 0, 2, 50},
  {12, 0, 0, 2, 40},
  {18, 0, 0, 2, 30},
  {23, 0, 0, 2, 10}
};
bool state[numNotes];
void clearState() {
  time = 0;
  for (int i = 0; i < numNotes; i++) {
    state[i] = true;
  }
}
//----------main()---------
void setup() {
  clearState();
}
void loop() {
  time = time + 1;
  if (time >= 24ul * 60 * 60) clearState();
  for (int i = 0; i < numNotes; i++) {
    if (state[i] == true && (time >= 0ul+NOTES[i].hour * 60 * 60 + NOTES[i].minute * 60 + NOTES[i].second)) {
      state[i] = false;
      // сдедать ШИМ NOTES[i].PWM каналу NOTES[i].channel
    }
  }
}
/**/

 

Maka
Offline
Зарегистрирован: 24.10.2015

qwone пишет:

Вот это "пружина"

/**/
unsigned long time = 0;
//----------main()---------
void setup() {
}

void loop() {
  time = time + 1;
  if (time >= 24ul * 60 * 60) time = 0;
}
/**/

А дальше "барабан"

/**/
unsigned long time = 0;
typedef struct note_t {
  byte hour;
  byte minute;
  byte second;
  byte channel;
  byte PWM;
};
const note_t NOTES[] {
  /*час-мин-сек-канал-шим*/
  {0, 0, 0, 0, 10},  // канал 0
  {6, 0, 0, 0, 50},
  {12, 0, 0, 0, 40},
  {18, 0, 0, 0, 100},
  {23, 0, 0, 0, 10},
  {0, 0, 0, 1, 10},  // канал 1
  {6, 0, 0, 1, 50},
  {12, 0, 0, 1, 40},
  {18, 0, 0, 1, 80},
  {23, 0, 0, 1, 10},
  {0, 0, 0, 2, 10},  // канал 2
  {6, 0, 0, 2, 50},
  {12, 0, 0, 2, 40},
  {18, 0, 0, 2, 30},
  {23, 0, 0, 2, 10}
};
//----------main()---------
void setup() {
}

void loop() {
  time = time + 1;
  if (time >= 24ul * 60 * 60) time = 0;
}
/**/

И в эскизном виде "шкатулка" будет такой

/**/
unsigned long time = 0;
typedef struct{
  byte hour;
  byte minute;
  byte second;
  byte channel;
  byte PWM;
} note_t ;
const int numNotes = 15;
const note_t NOTES[numNotes] {
  /*час-мин-сек-канал-шим*/
  {0, 0, 0, 0, 10},  // канал 0
  {6, 0, 0, 0, 50},
  {12, 0, 0, 0, 40},
  {18, 0, 0, 0, 100},
  {23, 0, 0, 0, 10},
  {0, 0, 0, 1, 10},  // канал 1
  {6, 0, 0, 1, 50},
  {12, 0, 0, 1, 40},
  {18, 0, 0, 1, 80},
  {23, 0, 0, 1, 10},
  {0, 0, 0, 2, 10},  // канал 3
  {6, 0, 0, 2, 50},
  {12, 0, 0, 2, 40},
  {18, 0, 0, 2, 30},
  {23, 0, 0, 2, 10}
};
bool state[numNotes];
void clearState() {
  time = 0;
  for (int i = 0; i < numNotes; i++) {
    state[i] = true;
  }
}
//----------main()---------
void setup() {
  clearState();
}
void loop() {
  time = time + 1;
  if (time >= 24ul * 60 * 60) clearState();
  for (int i = 0; i < numNotes; i++) {
    if (state[i] == true && (time >= 0ul+NOTES[i].hour * 60 * 60 + NOTES[i].minute * 60 + NOTES[i].second)) {
      state[i] = false;
      // сдедать ШИМ NOTES[i].PWM каналу NOTES[i].channel
    }
  }
}
/**/

 

Крутой мультфильм, я вспомнил как он удивил меня в детстве.

"Барабан" - интересная идея, с часов я могу получать часы, минуты и секунды. Дык самое главное - логарифмическое возрастание - убывание как сделать? Собственно мой код и городился на расчете шим каждую секунду нон-стоп.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

X=X+delta;//линейное прирастание
X=X*delta;//логармфмическое прирастание
где delta некая константа.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

qwone пишет:

X=X+delta;//линейное прирастание
X=X*delta;//логармфмическое прирастание
где delta некая константа.

Только не логарифмическое, а экспоненциальное. (хотя можно сказать "в логарифмическом масштабе")

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

X = X * delta;
log(X) = log(X*delta) = log(X) + log(delta); Именно логарифмическое прирастание

 

Maka
Offline
Зарегистрирован: 24.10.2015

Я баран. Я никак не пойму как из X = X * delta; сделать pwm. pwm[i] = time * delta? Дельта это крутизна, если я правильно понял. Как расчитывать ее в каждом переходном интервале, и как то  pwm должен стартовать с нужного значения, и доходить до нужного значения? В барабане заданы значения  pwm, но не задано сколько времени быть в статическом режиме, следовательно нужны еще ячейки в struct note_t? Или я не правильно все понял? Ведь сейчас получается, что в первом канале pwm каким то образом (пока мне непонятным) переходит с 10 -> 50 -> 40 -> 100-> 10.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Вот вернемся к ..мультику . Там есть ... колокольчик . И он звучит . Динь. Что заставляет звучать его? Конструкция. А висит он в шкатулке или на церви уже от звука не зависит. 
  Теперь про ШИМ. Пусть максимум 255. 0 нет ШИМ. Уберем плавный ШИМ переход. Не понимаю зачем он вам. Вода в аквариуме инерциона. Была к примеру ШИМ=25. Пришла команда savePID(100). И стало 100. 
  При плавном 25,25*1.2,25*1.2*1.2,25*1.2*12,25*1.2*1.2*1.2  и так до 100 . Разумеется на каждый цикл ON-OFF новое обновление ШИМ.

ПС: Здесь константа delta=1.2 К примеру.

ПС2: Но все же лучше регулировать не ШИМ, а температуру по времени дня. Так лучше. А шим пусть ее отрабатывает.

Maka
Offline
Зарегистрирован: 24.10.2015

Этож свет а не грелка! Рыбкам будет страшно когда pwm с 0 на 255 бабахать будет. :)

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Ну тогда делайте снижение/ рост на delta через каждые 100 циклов. Хотя в сети переменка в 50 Гц вроде. Как вы ШИМ организовываете??

Maka
Offline
Зарегистрирован: 24.10.2015

12 канальная 16 битная i2c платка, контроль времени ds3231. Значения задаются в меню. Я потому и считал шим каждую секунду, это полный контроль, можно из меню выключить канал, внести изменения в настройки. Ваш вариант хранения отдельно часов, минут и секунд лучше моего в виде секунд, а вот расчет шим мне пока не ясен совсем.

Я должен, наверно, на словах объяснить как будет работать. В каждом канале есть 

startDay

это начало светового дня. Есть четыре таймера с атрибутами

long start;
  long end;
  int level;
  bool on;

и, соответственно 

endDay

канала.

Шим в startDay равен 0 и нарастает до момента start первого таймера, если он включен. С момента start до момента stop pwm стабилен и равен level, заданному в таймере. В интервале между timer[0].stop и timer[1].start pwm нарастает или уменьшается в зависимости от того меньше timer[0].level чем timer[1].level или нет. И так до Channel[].endDay. По этому то мне и нужна точная формула расчета шим, чтобы переход по всему дню был без скачков.Я уже понял где я ошибся в своей функции - формулы расчета возрастающего и убывающего шим разные, а у меня только возрастающая. Наверно есть проще путь, как то с линейными ф-иями, или по вашей, с дельтой, только как прикрутить!

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

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

qwone пишет:


X = X * delta;
log(X) = log(X*delta) = log(X) + log(delta); Именно логарифмическое прирастание

 

Все верно, в логарифмическом масштабе приращение выглядит постоянным. 

А x(n) = x(0)*delta^n - это экспонента.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Ну для начала надо написать тестовый скетч . Например такой. И конопками подавать комады

/**/
const byte btn1Pin = 2;
bool btn1;
const byte btn2Pin = 3;
bool btn2;
//--------------------------
class Cl_PWM {
  protected:
    byte pwm;
  public:
    void init() {}
    void run() {}
    void save(byte p) {
      pwm = p;
      Serial.print("PWM:");
      Serial.print(pwm);
      Serial.println();
    }
};
Cl_PWM PWM;
//------------------------------------
void setup() {
  Serial.begin(9600);
  pinMode(btn1Pin, INPUT_PULLUP);
  btn1 = false;
  pinMode(btn2Pin, INPUT_PULLUP);
  btn2 = false;
  PWM.init();
}
void loop() {
  bool tmp = digitalRead(btn1Pin);
  switch (btn1) {
    case false:
      if (!tmp) {
        delay(50);
        btn1 = true;
        PWM.save(0);
      }
      break;
    case true:
      if (tmp) {
        delay(50);
        btn1 = false;
      }
      break;
  }
  tmp = digitalRead(btn2Pin);
  switch (btn2) {
    case false:
      if (!tmp) {
        delay(100);
        btn2 = true;
        PWM.save(100);
      }
      break;
    case true:
      if (tmp) {
        delay(100);
        btn2 = false;
      }
      break;
  }
  PWM.run();
}
/**/

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Кривовато. Но где-то так 

/**/
const byte btn1Pin = 2;
bool btn1;
const byte btn2Pin = 3;
bool btn2;
//--------------------------
class Cl_PWM {
  protected:
    byte pwm = 50, needPwm;
    const float delta = 1.2;
    enum state_t {sStable, sUp, sDown} state;
    const unsigned long time1s = 1000;
    unsigned long past;
    void stand(state_t s) {
      state = s;
      past = millis();
      switch (state) {
        case sStable:
          break;
        case sUp:
          pwm = pwm * delta;
          break;
        case sDown:
          pwm = pwm / delta;
          break;
      }
      Serial.print("PWM:");
      Serial.print(pwm);
      Serial.println();
    }
  public:
    void init() {
      stand(sStable);
    }
    void run() {
      switch (state) {
        case sStable:
          break;
        case sUp:
          if (millis() - past >= time1s) {
            past = millis();
            if (pwm * delta < needPwm) stand(sUp);
            else {
              pwm = needPwm;
              stand(sStable);
            }
          }
          break;
        case sDown:
          if (millis() - past >= time1s) {
            past = millis();
            if (pwm / delta > needPwm) stand(sDown);
            else {
              pwm = needPwm;
              stand(sStable);
            }
            break;
          }
      }
    }
    void save(byte p) {
      if (p == pwm) return;
      if (p > pwm) {
        needPwm = p;
        stand(sUp);
      }
      else {
        needPwm = p;
        stand(sDown);
      }
    }
};
Cl_PWM PWM;
//------------------------------------
void setup() {
  Serial.begin(9600);
  pinMode(btn1Pin, INPUT_PULLUP);
  btn1 = false;
  pinMode(btn2Pin, INPUT_PULLUP);
  btn2 = false;
  PWM.init();
}
void loop() {
  bool tmp = digitalRead(btn1Pin);
  switch (btn1) {
    case false:
      if (!tmp) {
        delay(50);
        btn1 = true;
        PWM.save(10);
      }
      break;
    case true:
      if (tmp) {
        delay(50);
        btn1 = false;
      }
      break;
  }
  tmp = digitalRead(btn2Pin);
  switch (btn2) {
    case false:
      if (!tmp) {
        delay(100);
        btn2 = true;
        PWM.save(100);
      }
      break;
    case true:
      if (tmp) {
        delay(100);
        btn2 = false;
      }
      break;
  }
  PWM.run();
}
/**/

 

Maka
Offline
Зарегистрирован: 24.10.2015

дома проверю, на работе