Вопрос про много режимов работы и, частично, про ШИМ.

ivanumass
ivanumass аватар
Offline
Зарегистрирован: 04.09.2011

Народ, помогите проблему решить. Решил сделать себе подсветку на велосипед. Придумал 3 группы светодиодов (на переднем колесе, на раме, на заднем колесе) и придумал к ним 5 режимов работы, на картинке проиллюстрировал схемку (пятый, когда горят все фулл-тайм). Так вот, написал кусок, как режимы можно переключать, с помощью тактовой кнопки (через switch, я так понял). Но, не могу понять вот что: 
  1) все пять режимов надо делать отдельно, уж больно разная у них структура, но пихать все в луп, это бред (как мне сейчас кажется), но, надо же как-то сделать так, чтобы при вызове режима он повторялся по кругу (не через goto делать же). Как сделать так, чтобы не будучи в void loop они по кругу шли, а в лупе только выбирклка режимов лежала, например, или как это в лупе все уместить?
2) как сделать бегущую строку, если при этом ножки нужные не идут друг за другом, да еще и в ШИМе, к тому же на схеме видно, что пульсация каждой группы сдвинута на пол-фазы относительно другой. Как сделать так, чтобы вторая/третья группа загоралась, когда первая/вторая группы находятся в апогее? 

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

Вот схема на имэйджшак img508.imageshack.us/img508/8174/unled1cc.jpg


 

 

Zaliv
Offline
Зарегистрирован: 05.03.2011

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

ivanumass
ivanumass аватар
Offline
Зарегистрирован: 04.09.2011

Схему, кажется, понял, сейчас попробуем. А про бегущий огонь такой хитрый нет идей? Мозг уже сломал, как его так сделать получше 

Zaliv
Offline
Зарегистрирован: 05.03.2011

 Объяви глобальную переменную (т.е. вне loop и функций) для хранения номера такта и три для хранения номеров выходов led

int led1 = 7; //номера выходов 
int led2 = 8;
int led3 = 9;

int tick = 0; //номер текущего такта

void runningLight ()
{
  switch (tick) {
   case 0:
    // тут для первого нулевого такта
    digitalWrite(led1, HIGH);
    digitalWrite(led2, LOW);
    digitalWrite(led3, HIGH);
    break;
   case 1:
    // для второго такта и т.д.
    break;
  }
  //Потом проверяешь не последний ли такт (у тебя их шесть из рисунка
  if (tick>=5)
  { tick = 0; } //если последний идешь в начало
  else {tick++;}//если нет, то просто прибавляешь 1 к номеру такта
}

Как то так, не забудь выставить pinMode(led1,OUTPUT) для каждого светодиода

ivanumass
ivanumass аватар
Offline
Зарегистрирован: 04.09.2011

А разделить на 6 тактов таким образом я чего-то не догадался, спасибо! 

 

UPD: спасибо, помогло, только чего-то я с последовательностью напутал :) но это мелочи, главное, алгоритм понятен

ivanumass
ivanumass аватар
Offline
Зарегистрирован: 04.09.2011

Вопрос касательно оператора switch. Как в него можно запихать конструкцию, содержащую ШИМ, в смысле управление яркостью светодиода?
конструкция типа этой:

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

int brightness = 0;

int fadeAmount = 5;

switch (wMode)
{
case 1:
analogWrite (9, brightness);
brightness = brightness + fadeAmount;

if (brightness == 0 || brightness == 255) 
{
fadeAmount = -fadeAmount ;
}
delay (30)
break;

case 2:
//******
break;
}

переключается. ШИМ без свитч работает нормально, но запихиваешь его в switch и, такое впечатление, что счетчик плюсует fadeAmaunt только один раз, и скидывает, походу из-за break. Как можно сделать так, чтобы ШИМ работал нормально? 

Soso
Offline
Зарегистрирован: 22.03.2011

 А может  проблема в отсутствии ;  после delay(30) в 15-ой строке?

ivanumass
ivanumass аватар
Offline
Зарегистрирован: 04.09.2011

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

Zaliv
Offline
Зарегистрирован: 05.03.2011

 Приведи весь код. 

ivanumass
ivanumass аватар
Offline
Зарегистрирован: 04.09.2011

Весь так весь :)

//выходы/входы******************************************
const int switchPin = 12;        //константа для входа кнопки
const int ledPin1 = 3;           //константа для выхода диода 1 
const int ledPin2 = 5;           //константа для выхода диода 2
const int ledPin3 = 6;           //константа для выхода диода 3
//общие переменные**************************************
int wMode = 1;                   //переменная переключенмя режима мигалки
// переменные для дребезга******************************
boolean lastButton = LOW;        //состояние кнопки в прошлый раз
boolean currentButton = LOW;     //хранит текущее положение кнопки
//переменные для режима 2*******************************
boolean ledState = LOW;          //последнее состояние кнопки
long prevMillis = 0;             //последнее состояние счетчика времени
long interval = 500;             //интервал мигания
//Переменные для режима 3*******************************i
int brightness = 0;
int fadeAmount = 5;

//******************************************************

void setup()
{
  pinMode(switchPin, INPUT);     //кнопко-ногу на вход  
  pinMode(ledPin1, OUTPUT);      //диодо-ногу 1 на выход
  pinMode(ledPin2, OUTPUT);      //диодо-ногу 2 на выход
  pinMode(ledPin3, OUTPUT);      //диодо-ногу 3 на выход  
}

//*********Стабилизация дребезга кнопки*****************

boolean debounce(boolean last)               //булевая Функция debounce
{
  boolean current = digitalRead(switchPin);  //узнаем текущее положение кнопки
  if (last != current)                       //сравниваем ласт и курент, то есть узнаем, нажата ли кнопка
  {
    delay(5);                                //ждем дребезг
    current = digitalRead(switchPin);        // считываем спокойное состояние кнопки еще раз
  }
  return current;                            // возвращаем в функцию значение куррент
}

void loop()
 {
    currentButton = debounce(lastButton);
    if (lastButton == LOW && currentButton == HIGH)       //Проверяем последнее и текущее состояние кнопки
    {
      wMode = wMode + 1;                                  //если кнопка нажата плюсуем к переменной кнопки один
    }  
    switch (wMode)                                        // по нажатию 1 раз, меняем режим из 3 + в случае превышения 4 строкой выше, скидываем  до 1
    {
        case 1: // Full time режим****************************************
          digitalWrite (ledPin1, HIGH);                   //мигаем всем пачкой
          digitalWrite (ledPin2, HIGH);
          digitalWrite (ledPin3, HIGH);
        break;
        
        case 2: // Blink режим********************************************
        {
          unsigned long curMillis = millis();
          if(curMillis - prevMillis > interval)
          {
             prevMillis = curMillis;                         // сохраняем время последнего переключения
             if (ledState == LOW)                            // если светодиод не горит, то зажигаем, и наоборот
               ledState = HIGH;
             else
              ledState = LOW;
          }    
             digitalWrite (ledPin1, ledState);               // устанавливаем состояния выхода, чтобы включить или выключить светодиоды
             digitalWrite (ledPin2, ledState);
             digitalWrite (ledPin3, ledState);
        break; 
        }
        case 3: // Blink режим********************************************

          analogWrite (ledPin1, brightness);  
          analogWrite (ledPin2, brightness);
          analogWrite (ledPin3, brightness);
          brightness = brightness + fadeAmount;
 
          if (brightness == 0 || brightness == 255) 
            {
              fadeAmount = -fadeAmount ;
            }
          delay (30);
     
        break; 

       }
    lastButton = currentButton;
 }

 

Zaliv
Offline
Зарегистрирован: 05.03.2011

 На беглый взгляд все ОК. Я бы порекомендовал вместо brightness == 0 || brightness == 255 всегда использовать brightness <= 0 || brightness >= 255 на случай если переменная пролетит точное значение. В данном случае вроде непринципально, но так обычно безопаснее проверять.

Вставь в setup  Serial.begin(9600);

а в case 3 для дебага

 Serial.println(brightness);
 Serial.println(fadeAmount);

и посмотри, что будет возвращать, может мысли придут, еще можно проверить, что у тебя wMode, можно тоже вставить вывод где-нибудь до switch

ivanumass
ivanumass аватар
Offline
Зарегистрирован: 04.09.2011

Хорошая идея на счет больше меньше. Буду смотреть в чем дело. Спасибо 

step962
Offline
Зарегистрирован: 23.05.2011

>void loop() {
>    currentButton = debounce(lastButton);
>    if (lastButton == LOW && currentButton == HIGH) //Проверяем последнее и текущее состояние кнопки
>    {
>      wMode = wMode + 1; //если кнопка нажата плюсуем к переменной кнопки один
>    }
 и так далее...

Или я что-то упустил, или wMode принимает у вас  значения 1, 2, 3, 4, 5, и так далее - увеличиваясь при каждом новом нажатии кнопки.

Хотите несколько раз вызывать ветви switch'а - сбрасывайте wMode на ноль после превышения максимального значения

ЗЫ:

комментарий с намеком на подобное действо вроде как нашелся:

 // по нажатию 1 раз, меняем режим из 3 + в случае превышения 4 строкой выше, скидываем до 1
а вот самого скидывания что-то не видно

ivanumass
ivanumass аватар
Offline
Зарегистрирован: 04.09.2011

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

ivanumass
ivanumass аватар
Offline
Зарегистрирован: 04.09.2011

Странное дело: сначала воткнул, потом убрал Serial.begin и всю фигню, и все заработало как надо, сейчас убрал - тоже все ок. Мистика. Ну да ладно. Осталось только две бегущие дорожки прикрутить (с пульсацией и без неё) и энкодер для управления скоростью мигания, а дальше - железячная часть.

Думаю, вопросы еще будут