Остановка цикла

env
Offline
Зарегистрирован: 25.02.2018

Добрый день!

Ищу решение по переключению режимов адресной ленты кнопкой.

Дано: адреска, ардуино, сенсорная кнопка, желание сделать переключение между двумя тремя режимами свечения

Проблема: приходится удерживать кнопку нажатой, видимо, пока не закончится один из циклов

Укажите, пожалуйста, на ошибку в коде, из-за которой кнопка не работает мгновенно.

Спасибо, заранее!

#define PIN 13       
#define NUM_LEDS 60   
#include "Adafruit_NeoPixel.h"
Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_LEDS, PIN, NEO_GRB + NEO_KHZ800);

const int buttonPin = 5;
int count = 0; 

void setup() 

{
pinMode(buttonPin, INPUT); 


  strip.begin();
  strip.setBrightness(50);   
  strip.clear();                         
  strip.show();                           
}
void loop() 
{
if(digitalRead(buttonPin)) { 
count = count + 1; 
if(count > 2){ 
count = 0;

}

}

if(count == 0) 
{
   
  for (int i = 0; i < 30; i++ ) {   
    strip.setPixelColor(i, 0x000000);    
    strip.show();                         
    delay(50);
    

  }

    for (int i = 30; i < 60; i++ ) {   
    strip.setPixelColor(i, 0x000000);     
    strip.show();                         
    delay(50);
   
  }

  
 
 
} else if(count == 1) 


{
   
  for (int i = 0; i < 30; i++ ) {   
    strip.setPixelColor(i, 0x51f0ae);    
    strip.show();                         
    delay(50);

  }

    for (int i = 30; i < 60; i++ ) {   
    strip.setPixelColor(i, 0xff7a00);     
    strip.show();                         
    delay(50);
    
  }

  
 
 
} else 

{
   
  for (int i = 0; i < 30; i++ ) {   
    strip.setPixelColor(i, 0xff007a);     
    strip.show();                         
    delay(50);

  }

    for (int i = 30; i < 60; i++ ) {   
    strip.setPixelColor(i, 0x51aef0);     
    strip.show();                         
    delay(50);
   
  }

}

}

 

BOOM
BOOM аватар
Offline
Зарегистрирован: 14.11.2018

Использовать прерывание по нажатию кнопки?

v258
v258 аватар
Offline
Зарегистрирован: 25.05.2020

Это не ошибка, это неправильный выбор ))

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

bool checkButton()
{
  bool result = false;
  if (digitalRead(buttonPin)) {
    result = true;
    count = count + 1;
    if (count > 2) {
      count = 0;
    }
  }
  return (result);
}

И вызывайте ее в цикле

if checkButton()
  break;

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

void setStrip(byte idx, uint32_t color)
{
  for (int i = idx; i < idx + 30; i++ ) {
    if checkButton()
      break;
    strip.setPixelColor(i, color);
    strip.show();
    delay(50);
  }
}

И тогда в лупе останется только несколько строк

void loop() {
  switch (count)
  {
    case 0:
      setStrip(0, 0x000000);
      setStrip(30, 0x000000);
      break;
    case 1:
      setStrip(0, 0x51f0ae);
      setStrip(30, 0xff7a00);
      break;
    case 2:
      setStrip(0, 0xff007a);
      setStrip(30, 0x51aef0);
      break;
  }
}

И еще - возьмите себе в привычку форматировать код. Так он воспринимается гораздо легче, вам же проще будет с ним работать. В Arduino IDE за это отвечает комбинация Ctrl+T

env
Offline
Зарегистрирован: 25.02.2018

v258, cпасибо, очень помогли все советы

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

Предположил, что это может быть связано с отсутствием задержки в кнопке, добавил делей (в то место, где мне показалось, это нужно (5 строчка), но это не точно :) ), в общем, по крайней мере, теперь порядок. Правда минимальная задержка 500, если ставлю 50, к примеру, снова беда с работой. Видимо все-таки решать надо иначе.

bool checkButton()
{
  bool result = false;
  if (digitalRead(buttonPin)) {
    delay(500);
    result = true;
    count = count + 1;
    if (count > 2) {
      count = 0;
    }
  }
  return (result);
}

Еще раз спасибо!

b707
Offline
Зарегистрирован: 26.05.2017

env пишет:

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

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

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

v258
v258 аватар
Offline
Зарегистрирован: 25.05.2020

env пишет:

v258, cпасибо, очень помогли все советы

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

Предположил, что это может быть связано с отсутствием задержки в кнопке, добавил делей (в то место, где мне показалось, это нужно (5 строчка), но это не точно :) ), в общем, по крайней мере, теперь порядок полный.

bool checkButton()
{
  bool result = false;
  if (digitalRead(buttonPin)) {
    delay(500);
    result = true;
    count = count + 1;
    if (count > 2) {
      count = 0;
    }
  }
  return (result);
}

Еще раз спасибо!

Это дребезг контактов. 500 миллисекунд многовато, достаточно 50-100. Вообще есть библиотеки для работы с кнопками, они обычно хорошо отрабатывают дребезг

b707
Offline
Зарегистрирован: 26.05.2017

v258 пишет:

Это дребезг контактов. 500 миллисекунд многовато, достаточно 50-100. Вообще есть библиотеки для работы с кнопками, они обычно хорошо отрабатывают дребезг

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

env
Offline
Зарегистрирован: 25.02.2018

b707 пишет:

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

Забавно, но решает, если нажимать по завершении эффекта, все работает корректно после добавления этой строчки.

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

env
Offline
Зарегистрирован: 25.02.2018

b707, сейчас код выглядит так:

#define PIN 13        // пин DI
#define NUM_LEDS 60   // число диодов
#include "Adafruit_NeoPixel.h"
Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_LEDS, PIN, NEO_GRB + NEO_KHZ800);

const int buttonPin = 5; // Выставляем значения порта, подсоединённого с сигнал-портом кнопки
int count = 0; // Переменная, предназначенная для выбора режима работы

void setup()

{
  pinMode(buttonPin, INPUT); // Открываем порт для считывания


  strip.begin();
  strip.setBrightness(50);    // яркость, от 0 до 255
  strip.clear();                          // очистить
  strip.show();
}

bool checkButton()
{
  bool result = false;
  if (digitalRead(buttonPin)) {
    delay(500);
    result = true;
    count = count + 1;
    if (count > 2) {
      count = 0;
    }
  }
  return (result);
}

void setStrip(byte idx, uint32_t color)
{
  for (int i = idx; i < idx + 30; i++ ) {
    if (checkButton())
      break;
    strip.setPixelColor(i, color);
    strip.show();
    delay(50);
  }
}


void loop() {
  switch (count)
  {
    case 0:
      setStrip(0, 0x000000);
      setStrip(30, 0x000000);
      break;
    case 1:
      setStrip(0, 0x51f0ae);
      setStrip(30, 0xff7a00);
      break;
    case 2:
      setStrip(0, 0x51aef0);
      setStrip(30, 0xff007a);
      break;
  }
}

 

b707
Offline
Зарегистрирован: 26.05.2017

env пишет:

b707, сейчас код выглядит так:

 

ок, был неправ. Слушайте коллегу V258. он дело говорит

v258
v258 аватар
Offline
Зарегистрирован: 25.05.2020

b707 пишет:

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

При том, что без его нейтрализации кнопка срабатывает несколько раз и несколько же раз перезапускает режимы. Отсюда, видимо, и артефакты, выражающиеся в нескольких последовательно прерванных режимах ленты. Задержка позволяет не реагировать на импульсы, следующие после первого. Хотя, конечно, так с дребезгом не борются ))

А завершать или нет текущий режим - это уже дело вкуса, имхо ))

v258
v258 аватар
Offline
Зарегистрирован: 25.05.2020

Если нужно корректно завершать режим, то переменную count нужно менять в лупе, а кнопкой просто поднимать флаг смены режима. Типа такого

#define PIN 13        // пин DI
#define NUM_LEDS 60   // число диодов
#include "Adafruit_NeoPixel.h"
Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_LEDS, PIN, NEO_GRB + NEO_KHZ800);

const int buttonPin = 5; // Выставляем значения порта, подсоединённого с сигнал-портом кнопки
int count = 0; // Переменная, предназначенная для выбора режима работы
bool f = false;

void setup()

{
  pinMode(buttonPin, INPUT); // Открываем порт для считывания


  strip.begin();
  strip.setBrightness(50);    // яркость, от 0 до 255
  strip.clear();                          // очистить
  strip.show();
}

void checkButton()
{
  if (digitalRead(buttonPin)) {
    delay(500);
    f = true;
  }
}

void setStrip(byte idx, uint32_t color)
{
  for (int i = idx; i < idx + 30; i++ ) {
    checkButton();
    strip.setPixelColor(i, color);
    strip.show();
    delay(50);
  }
}


void loop() {
  if (f)
  {
    f = false;
    count = count + 1;
    if (count > 2) {
      count = 0;
    }
  }
  switch (count)
  {
    case 0:
      setStrip(0, 0x000000);
      setStrip(30, 0x000000);
      break;
    case 1:
      setStrip(0, 0x51f0ae);
      setStrip(30, 0xff7a00);
      break;
    case 2:
      setStrip(0, 0x51aef0);
      setStrip(30, 0xff007a);
      break;
  }
}

Но тогда реакция на нажатие кнопки будет сильно замедлена. Правда, держать кнопку нажатой тогда будет не нужно и даже вредно ))

Гриша
Offline
Зарегистрирован: 27.04.2014

пост 11,

там задержку стр 25 можно уменьшать т.к. 34-36 вроде входят в период опроса кнопки, являясь тоже задержкой опроса кнопки.  И пока эффект не закончится, он все равно не поменяется. 

Единственное, эта задержка задает "подвисание эффекта" и даже можно будет "увидеть" что кнопка нажата... но не на всех эффектах.  

v258
v258 аватар
Offline
Зарегистрирован: 25.05.2020

Гриша пишет:

пост 11,

там задержку стр 25 можно уменьшать т.к. 34-36 вроде входят в период опроса кнопки, являясь тоже задержкой опроса кнопки.  И пока эффект не закончится, он все равно не поменяется. 

Единственное, эта задержка задает "подвисание эффекта" и даже можно будет "увидеть" что кнопка нажата... но не на всех эффектах.  

Да я знаю, я об этом еще в пятом посте говорил. Здесь же просто переделал имеющийся скетч, а задержку пускай ТС сам регулирует

Гриша
Offline
Зарегистрирован: 27.04.2014

v258 пишет:

Да я знаю, я об этом еще в пятом посте говорил. Здесь же просто переделал имеющийся скетч, а задержку пускай ТС сам регулирует

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