Как программно ограничить число нажатий кнопки?

Старик Похабыч

★★★★★★★
14 Авг 2019
4,188
1,280
Москва
Учу трассировать в голове:
1) Считаем что сетап верный, его не трогаем.
2) Начальное значение bright = 0; value = 0 ;
Начинаем цикл loop, при этом считаем что потенцимет сдвину на середину. Предположим, что нажата кнопка вверх,
3) Читаем значения с пина, получаем 512
3) bright стало быть по map становиться 3.
4) т.к. нажата кнопка вверх, то значение стало 1;
5) по 1-ому свичу получаем "bright"
6) по второму получаем "dim" и он же остается активным.
Идем в начала цикла. И как бы Вы не жали кнопки Вы будете выставлять всегда значение с потенциометра. Как ни крути. Если поменяете свичи местами. то по скольку у Вас значения яркости хранятся в разных переменных то будут выставленны значения кнопки.Но при этом смена яркости будет происходить ПОСТОЯННО, Т.Е. Вы сделали эдакий ШИМ сигнал. Занавес!
 

VictorArx

★★✩✩✩✩✩
22 Мар 2021
471
78
По какому алгоритму это работает, это выше моего понимания. Просто расскажу по факту. Потенц крайне левое положение. Светик не горит. Кнопки во всём диапазоне регулируют яркость в обе стороны. Меняем немного положение потенца и светик немного светится. Кнопкой увеличиваем яркость до мах, а второй кнопкой можем уменьшать только до значения выставленного потенцем ит.д.
 

Старик Похабыч

★★★★★★★
14 Авг 2019
4,188
1,280
Москва
Вот надо понимание поднимать на уровень.
Подключайте 2-ой светодиод к любому PWM пину и в любой из switch (но только в один) в кжадый раздел рядом с (например)
analogWrite(led, 200);
дописывайте
analogWrite(led2, 200);
Но дописать регулировку яркости нужно ко всем случаям одного switch. И цвет должен быть точно такой же. Ну и резистор конечно такой же.
И вы увидите, что яркость их на казалось бы одном и том же уровне будет РАЗНАЯ.

То, что вы не понимаете как все работает, это не значит что работает ВЕРНО. Сейчас у Вас работает КАК-ТО
И именно поэтому что бы зажечь светодиоды на правильной яркости и потенциометр и значение кнопок должны совпадать.
 

VictorArx

★★✩✩✩✩✩
22 Мар 2021
471
78
Вот надо понимание поднимать на уровень.
Болван, согласен. Вот и учусь поднимать свой уровень методом проб и ошибок. Не могу осилить , как выделить метод из LOOP. Вроде по русски написано, а не доходит. В своё время, когда начинал изучать компы с нуля, была книга Левина. Всё по русски, а не хрена не понятно. Купил другую Гукина для чайников и всё понятно стало.
 

Старик Похабыч

★★★★★★★
14 Авг 2019
4,188
1,280
Москва
Вот теперь я опять повторю свой вопрос:
при нажатии на кнопку становиться ясно, что кнопка была нажата и возможно (возможно!) надо менять яркость.
КАК вы будете понимать , что надо менять яркость от потенциометра ?
Подсказка в самом вопросе!
 

VictorArx

★★✩✩✩✩✩
22 Мар 2021
471
78
Согласен на ничью. Наверно уже все устали от этой темы.
 

VictorArx

★★✩✩✩✩✩
22 Мар 2021
471
78
Если пообещаете в дальнейшем помогать в продвижении моих познаний Arduino, тода сдаюсь.
 

Старик Похабыч

★★★★★★★
14 Авг 2019
4,188
1,280
Москва
А мне зачем что то обещать ? Что за шантаж ? Я с террористами переговоров не веду. :D
Я все достаточно подробно объяснил, вникайте, понимайте что получается.
 

poty

★★★★★★✩
19 Фев 2020
2,990
895
Единственное вменяемое описание требуемого результата я увидел здесь:
... серва на 360 градусов без ограничителя ...
... крутится неуправляемая через две кнопки...
... через потенциометр ... можно остановить её и регулировать...
... через потенц её остановить ... кнопками управлять.
Моё решение (возможны мелкие ошибки, на практике не проверял):
C++:
/* Реализация машины с конечными состояниями и двумя контурами управления
*  Постановка задачи:
*  1. Объект управления: сервопривод, количество состояний nPositions = 5
*  1.1. Положение "стоп" stopPosition = 128, требует подстройки с помощью потенциометра
*  1.2. Максимальная скорость по часовой стрелке maxSpeedPlus = 250
*  1.3. Половинная скорость по часовой стрелке halfSpeedPlus = stopPosition + (maxSpeedPlus - stopPosition) / 2
*  1.4. Максимальная скорость против часовой стрелки maxSpeedMinus = 5
*  1.5. Половинная скорость против часовой стрелки halfSpeedMinus = (stopPosition - maxSpeedMinus) / 2
*  2. Подстройка позиции "стоп" - потенциометром, границы подстройки: tuneMarginMin = 118, tuneMarginMax = 138
*     Регулируется только в средней позиции
*  3. Переключение состояний - кнопка kPlus - по часовой стрелке, кнопка kMinus - против часовой
*/

/* Определение органов управления */
#include <GyverButton.h>
#define KPLUS     2
#define KMINUS    3
GButton kPlus(KPLUS);
GButton kMinus(KMINUS);

#define PINPOT    A0
#define APOTU     1000              // период опроса потенциометра в рабочем режиме (мс)
#define APOTT     100               // период опроса потенциометра в режиме настройки (мс)
#define ACHM      2000              // период возврата из режима настройки в рабочий режим (мс)
#define MARGINL   118
#define MARGINH   138

/* Определение параметров объекта управления */
#define NPOS      5
#define MINPOS    5
#define MAXPOS    250
#define MIDPOS    128
#define MIDINDEX  2

#define SERVOPIN  11

class myServo {
  private:
    byte speedArray[NPOS] = { MINPOS, (MIDPOS-MINPOS)/2, MIDPOS, MIDPOS+(MAXPOS-MIDPOS)/2, MAXPOS };
    byte currentSpeedIndex;
    byte tuneState;                 // false = работа, true = настройка
    unsigned long askStart;         // начало периода опроса
    unsigned long tuneMode;         // начало периода регулировки

  public:
    myServo() : currentSpeedIndex {MIDINDEX}, tuneState {false} {
      countSpeeds();
      askStart = millis();
      analogWrite(SERVOPIN, speedArray[MIDINDEX]);
    }

    boolean countSpeeds() {
      byte tempTune = map(analogRead(PINPOT), 0, 1023, MARGINL, MARGINH);
      if (tempTune = speedArray[MIDINDEX]) return false;
      speedArray[2] = tempTune;
      speedArray[1] = (tempTune-speedArray[0])/2;
      speedArray[3] = tempTune+(speedArray[4]-tempTune)/2;
      return true;
    }

    void tuneProc() {
      if (currentSpeedIndex == MIDINDEX) {
        if (millis() - askStart >= tuneState ? APOTU : APOTT) {
          if (!countSpeeds()) {
            if (tuneState && (millis() - tuneMode >= ACHM)) tuneState = false;
          } else {
            askStart = tuneMode = millis();
            tuneState = true;
            analogWrite(SERVOPIN, speedArray[MIDINDEX]);
          }
        }
      }
    }

    /* перегрузка префиксного инкремента */
    byte operator++() {
      if (currentSpeedIndex != NPOS-1) {
        analogWrite(SERVOPIN, speedArray[++currentSpeedIndex]);
        if (currentSpeedIndex == MIDINDEX) { askStart = millis(); tuneState = false; }
      }
    };
    /* перегрузка префиксного декремента */
    byte operator--() {
      if (currentSpeedIndex != 0) {
        analogWrite(SERVOPIN, speedArray[--currentSpeedIndex]);
        if (currentSpeedIndex == MIDINDEX) { askStart = millis(); tuneState = false; }
      }
    }
} ms;


void setup() {
  pinMode(SERVOPIN, OUTPUT);
}

void loop() {
  ms.tuneProc();
  kPlus.tick();
  kMinus.tick();
  if (kPlus.isClick()) ++ms;
  if (kMinus.isClick()) --ms;
}
 
Изменено:

VictorArx

★★✩✩✩✩✩
22 Мар 2021
471
78
Единственное вменяемое описание требуемого результата я увидел здесь:

Моё решение (возможны мелкие ошибки, на практике не проверял):
C++:
/* Реализация машины с конечными состояниями и двумя контурами управления
*  Постановка задачи:
*  1. Объект управления: сервопривод, количество состояний nPositions = 5
*  1.1. Положение "стоп" stopPosition = 128, требует подстройки с помощью потенциометра
*  1.2. Максимальная скорость по часовой стрелке maxSpeedPlus = 250
*  1.3. Половинная скорость по часовой стрелке halfSpeedPlus = stopPosition + (maxSpeedPlus - stopPosition) / 2
*  1.4. Максимальная скорость против часовой стрелки maxSpeedMinus = 5
*  1.5. Половинная скорость против часовой стрелки halfSpeedMinus = (stopPosition - maxSpeedMinus) / 2
*  2. Подстройка позиции "стоп" - потенциометром, границы подстройки: tuneMarginMin = 118, tuneMarginMax = 138
*     Регулируется только в средней позиции
*  3. Переключение состояний - кнопка kPlus - по часовой стрелке, кнопка kMinus - против часовой
*/

/* Определение органов управления */
#include <GyverButton.h>
#define KPLUS     2
#define KMINUS    3
GButton kPlus(KPLUS);
GButton kMinus(KMINUS);

#define PINPOT    A0
#define APOTU     1000              // период опроса потенциометра в рабочем режиме (мс)
#define APOTT     100               // период опроса потенциометра в режиме настройки (мс)
#define ACHM      2000              // период возврата из режима настройки в рабочий режим (мс)
#define MARGINL   118
#define MARGINH   138

/* Определение параметров объекта управления */
#define NPOS      5
#define MINPOS    5
#define MAXPOS    250
#define MIDPOS    128
#define MIDINDEX  2

#define SERVOPIN  11

class myServo {
  private:
    byte speedArray[NPOS] = { MINPOS, (MIDPOS-MINPOS)/2, MIDPOS, MIDPOS+(MAXPOS-MIDPOS)/2, MAXPOS };
    byte currentSpeedIndex;
    byte tuneState;                 // false = работа, true = настройка
    unsigned long askStart;         // начало периода опроса
    unsigned long tuneMode;         // начало периода регулировки

  public:
    myServo() : currentSpeedIndex {MIDINDEX}, tuneState {false} {
      countSpeeds();
      askStart = millis();
      analogWrite(SERVOPIN, speedArray[MIDINDEX]);
    }

    boolean countSpeeds() {
      byte tempTune = map(analogRead(PINPOT), 0, 1023, MARGINL, MARGINH);
      if (tempTune = speedArray[MIDINDEX]) return false;
      speedArray[2] = tempTune;
      speedArray[1] = (tempTune-speedArray[0])/2;
      speedArray[3] = tempTune+(speedArray[4]-tempTune)/2;
      return true;
    }

    void tuneProc() {
      if (currentSpeedIndex == MIDINDEX) {
        if (millis() - askStart >= tuneState ? APOTU : APOTT) {
          if (!countSpeeds()) {
            if (tuneState && (millis() - tuneMode >= ACHM)) tuneState = false;
          } else {
            askStart = tuneMode = millis();
            tuneState = true;
            analogWrite(SERVOPIN, speedArray[MIDINDEX]);
          }
        }
      }
    }

    /* перегрузка префиксного инкремента */
    byte operator++() {
      if (currentSpeedIndex != NPOS-1) {
        analogWrite(SERVOPIN, speedArray[++currentSpeedIndex]);
        if (currentSpeedIndex == MIDINDEX) { askStart = millis(); tuneState = false; }
      }
    };
    /* перегрузка префиксного декремента */
    byte operator--() {
      if (currentSpeedIndex != 0) {
        analogWrite(SERVOPIN, speedArray[--currentSpeedIndex]);
        if (currentSpeedIndex == MIDINDEX) { askStart = millis(); tuneState = false; }
      }
    }
} ms;


void setup() {
  pinMode(SERVOPIN, OUTPUT);
}

void loop() {
  ms.tuneProc();
  kPlus.tick();
  kMinus.tick();
  if (kPlus.isClick()) ++ms;
  if (kMinus.isClick()) --ms;
}
Вау! Чтоб мне такое сообразить двадцать лет учится надо. Попробую скопировать и потом отпишусь. Благодарствуйте.
ЗЫ.. Теперь понял, чё такое ООП.Думал то ли Организация Объединённой Палестины, то ли Гуляй Россия и плачь Европа, а у меня самая, самая лучшая ООПА.
 
Изменено:

poty

★★★★★★✩
19 Фев 2020
2,990
895
Код в принципе бесполезный, потому и заморачиваться не стал. По хорошему нужно потенциометр ставить в обратную связь. Или заменять его энкодером (лучше абсолютным). Или набор датчиков положения (герконы?). Или вообще взять другой двигатель (шаговый?). Тогда можно сделать настраиваемый при инициализации объект и применить его для одного или нескольких исполнительных механизмов.
 

VictorArx

★★✩✩✩✩✩
22 Мар 2021
471
78
По хорошему нужно потенциометр ставить в обратную связь
Это я ещё не проходил, куда его втыкать. Поищу в инете. Всё это устройство у меня должно быть в приёмнике радиоуправляемой модели.
ЗЫ ... Вроде всё по русски написано, а о чём говорится пока для меня дрова.
 

poty

★★★★★★✩
19 Фев 2020
2,990
895
@VictorArx, :giggle: почитайте ту ветку, где Вы впервые описали свой двигатель на 360 градусов. В связи с тем, что этот двигатель управляется не как обычный шаговик, точное местоположение его предсказать невозможно.
Одна из возможностей - связать вал потенциометра и вал двигателя и на основе сопротивления оценивать положение. Проблема в том, что при неблагоприятных обстоятельствах двигатель свернёт потенциометр за пределы его угла поворота. Ну, и потенциометр должен быть достаточно надёжным.
Можно расставить в определённых точках концевики (например, герконы, а на ось надеть магнитик). Как минимум нужно иметь датчик среднего положения и экспериментальным путём найти длительность импульса поворота двигателя на нужный угол. Более правильное решение - среднее положение и крайние точки. Ещё более правильное - несколько концевиков в нужных положениях.
Как вариант - вместо потенциометра использовать энкодер. Если он сохраняет абсолютное положение, то решение аналогично множественным концевикам, расставленным через определённые углы. Если он относительный, то потребуется один датчик среднего положения, от которого отсчитывается необходимое количество импульсов.