mp3-плеер с управлением от тактовых кнопок, нужна помощь

gabber24
Offline
Зарегистрирован: 19.01.2016

Здравствуйте!

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

 

С ардуинкой только начал ознакомление, с базовыми функцииями разобрался, теперь ищу помощи в написании скетча для следующей задачи (вариация мп3 плеера):

Управление осуществляется 3 кнопками, кнопки 2 и 3 одновременно нажаты быть не могут. Кнопка 1 переключает треки (точнее дорожки, сделанные из кучи треков, записанные в один файл непрерывным потоком). Кнопки 2 и 3 включает громкость соответственной дорожки, одновременно работать не могут. Каждой дорожке присвоена своя кнопка громкости, т.е. кнопка 2 включает громкость при нажатой кнопке 1, а кнопка 3 - при отжатой. 

Матрица режимов кнопок (при которых есть определенное заданное действие), остальные возможные комбинации кнопок не делают ничего:

1) нажата только кнопка 1

2) нажаты кнопки 1 и 2

3) нажата кнопка 3

4) все кнопки отпущены

 

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

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

Компилятор не ругается, но сдается мне, что нифига не правильно я написал :)

На железяке еще не пробовал - мп3плеер еще не приехал, но уже на подходе). 

Спасибо!

01 #include <DFPlayer_Mini_Mp3.h>
02 #include <SoftwareSerial.h>
03 SoftwareSerial mySerial(10, 11); // RX, TX
04 const int songPin = 5; // кнопка "song"
05 const int song1volPin = 6; // кнопка "громкость song1"
06 const int song2volPin = 7; // кнопка "громкость song2"
07 int regim = 0;
08 int flag = 0;
09  
10  
11 //переменные
12 int song = 0; //переменная для хранения данных с кнопки "трек"
13 int song1vol = 0;//переменная для хранения данных с контакта контроля состояния тригеров дверей
14 int song2vol = 0;//переменная для хранения данных с контакта реле бензонасоса
15 void setup() {
16   Serial.begin(9600);  //для отладки
17   mySerial.begin(9600); //для общения с мп3плеером
18   pinMode (songPin, INPUT);
19   pinMode (song1volPin, INPUT);
20   pinMode (song2volPin, INPUT);
21   mp3_set_serial (Serial);
22 }
23  
24 void loop()
25 {
26   song = digitalRead(songPin); //сохраняем состояние с кнопки song
27   song1vol = digitalRead(song1volPin);//с кнопки song1vol
28   song2vol = digitalRead(song2volPin);//с кнопки song2vol
29     
30   if (song == HIGH && flag == 0) //кнопка song нажата
31   {
32     regim ++;
33     flag = 1;
34     if(regim>2)
35    {
36     regim = 1;
37    }
38   }
39   if(song == LOW  && flag == 1) //кнопка song не нажата
40   {
41     regim ++;
42     flag = 0;
43   }
44   if(regim == 1)
45   {
46     if(song==HIGH&&song1vol==HIGH)//нажата также кнопка song1vol
47     {
48       mp3_play (1);
49       delay(5);
50       mp3_set_volume (15);    //0~30
51       mp3_single_loop;
52     }
53     else if(song==HIGH)//любые иные комбинации с нажатой кнопкой song
54     {
55       mp3_play (1);
56       delay(5);
57       mp3_set_volume (0);    //0~30
58       mp3_single_loop;
59       }
60     }
61   
62   if(regim == 2)
63   {
64     if(song == LOW && song2vol == HIGH )//нажата кнопка song2vol
65     {
66       mp3_play (2);
67       delay(5);
68       mp3_set_volume (15);    //0~30
69       mp3_single_loop;
70     }
71     
72      else if(song==LOW)//иные комбинации при отжатой кнопке song
73     {
74       mp3_play (2);
75       delay(5);
76       mp3_set_volume (0);    //0~30
77       mp3_single_loop;
78       }
79   
80 }

 

vosara
vosara аватар
Offline
Зарегистрирован: 08.02.2014

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

const int songPin = 5; // кнопка "song"
const int song1volPin = 6; // кнопка "громкость song1"
const int song2volPin = 7; // кнопка "громкость song2"
//int regim = 0;
bool flag = 0;
//переменные
bool song = 0; //переменная для хранения данных с кнопки "трек"
bool song1vol = 0;//переменная для хранения данных с контакта контроля состояния тригеров дверей
bool song2vol = 0;//переменная для хранения данных с контакта реле бензонасоса
void setup() {
  Serial.begin(9600);  //для отладки
  //mySerial.begin(9600); //для общения с мп3плеером
  pinMode (songPin, INPUT);
  pinMode (song1volPin, INPUT);
  pinMode (song2volPin, INPUT);
  
}
void loop()
{
delay (300);
  song = digitalRead(songPin); //сохраняем состояние с кнопки song
  song1vol = digitalRead(song1volPin);//с кнопки song1vol
  song2vol = digitalRead(song2volPin);//с кнопки song2vol

  if (song == HIGH && flag == 0) //кнопка song нажата
  {
    //regim ++;
    flag = 1;
    //if(regim>2){
    //regim = 1;
   //}
  }
  if(song == LOW  && flag == 1) //кнопка song не нажата
  {
    //regim ++;
    flag = 0;
  }
  if(flag == 1)
  {
    if(song==HIGH&&song1vol==HIGH)//нажата также кнопка song1vol
    {
      Serial.println("1=1  2=1");
    }
    else if(song==HIGH)//любые иные комбинации с нажатой кнопкой song
    {
      Serial.println("1=1");
    }
 }
  
  //if(flag == 0)
  //{
    if(song == LOW && song2vol == HIGH )//нажата кнопка song2vol
    {
      Serial.println("1=0-3=1");
    }
    
     else if(song==LOW)//иные комбинации при отжатой кнопке song
    {
      Serial.println("1=0"); //0~30
 
    }
  //} 
}

 

gabber24
Offline
Зарегистрирован: 19.01.2016

Проверил, действительно, все работает, хотя и не совсем так, как я планировал (допускаю, что я некорректно сформулировал задачу).

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

Т.е. грубо говоря, в мониторе порта я буду видеть только одно сообщение "1=0" или "3=1".

У меня собственно с этим и есть основной затык, т.к. пока не понимаю, как делать такие проверки.

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

 

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

vosara
vosara аватар
Offline
Зарегистрирован: 08.02.2014

Вы задали 4 условия 

1) нажата только кнопка 1
2) нажаты кнопки 1 и 2
3) нажата кнопка 3
4) все кнопки отпущены
В коде я прокоментировал где выполняются эти условия, посмотрите. Или они изменились? И к стати антидребезга в коде нет.
 
const int songPin = 5; // кнопка "song"
const int song1volPin = 6; // кнопка "громкость song1"
const int song2volPin = 7; // кнопка "громкость song2"
//int regim = 0;
bool flag = 0;
//переменные
bool song = 0; //переменная для хранения данных с кнопки "трек"
bool song1vol = 0;//переменная для хранения данных с контакта контроля состояния тригеров дверей
bool song2vol = 0;//переменная для хранения данных с контакта реле бензонасоса
void setup() {
  Serial.begin(9600);  //для отладки
  //mySerial.begin(9600); //для общения с мп3плеером
  pinMode (songPin, INPUT);
  pinMode (song1volPin, INPUT);
  pinMode (song2volPin, INPUT);
  
}
void loop()
{

  song = digitalRead(songPin); //сохраняем состояние с кнопки song
  song1vol = digitalRead(song1volPin);//с кнопки song1vol
  song2vol = digitalRead(song2volPin);//с кнопки song2vol

  if (song == HIGH && flag == 0)
  {
     flag = 1;
  }
  if(song == LOW  && flag == 1)
  {
    flag = 0;
  }
  if(flag == 1)
   {
    if(song==HIGH&&song1vol==HIGH)
     {
      Serial.println("1=1  2=1");//Здесь условие №2 нажата кнопка 1 и 2
     }
    else if(song==HIGH)
     {
      Serial.println("1=1");//Здесь условие №1 нажата только кнопка 1
     }
   }
  if(song == LOW && song2vol == HIGH )
   {
     Serial.println("3=1");//Здесь условие №3 нажата кнопка 3
   }
  else if(song==LOW)
   {
     Serial.println("1=0"); ////Здесь условие №4 все кнопки отпущены
   }
  }

 

 

gabber24
Offline
Зарегистрирован: 19.01.2016

Условия выполняются, все верно, но каждый раз при проверке состояния кнопок и срабатывании одного из условий (например, нажаты кнопка 1 и 2), функция выполняется заново. Или это происходит именно изза наличия дребезга? А как в данном случае лучше сделать антидребезг? По логике мне нужно считать несколько значений, и если они одинаковые, то вызывать необходимую функцию... но я не знаю, как это сделать правильно :(

Либо делать проверку режимов при помощи функций boolean, но с ней я пока не разобрался.

vosara
vosara аватар
Offline
Зарегистрирован: 08.02.2014

Может я чегото не понимаю но - Если Вы нажали и держите кнопки 1 и 2 то условие 2 выполняется если отпустили то условие 4. И контролер каждый раз пробегая по loop проверяет, а не изменилось ли положение сигналов. Или Вам надо после кратковременного нажатия и отпускания кнопок 1 и 2 выполнения 2го условия - тогда вопрос как долго оно должно выполняться. По поводу Ваших слов (функция выполняется заново) то на этом и построена работа контролера, и чем с большей частотой он это делает тем лучше. В первом посте Вы очень четко сформулировали задачу по пунктам 1.2.3.4, сделайте это еще раз по пунктам как должно быть.

gabber24
Offline
Зарегистрирован: 19.01.2016

Возможно дело в выполняемой функции, но алгоритм, который есть сейчас, работает не корректно. В данном случае кнопка song переключает дорожки, т.е. если нажата и удерживается кнопка, то должна запуститься Дорожка 1, после чего программа должна ждать, пока не будет отпущена кнопка, чтобы переключить дорожку. Сейчас же при нажатии и удержании кнопки или при отпущенной кнопке дорожка запускается по новой при каждом цикле проверки. А мне нужно придумать проверку таким образом, чтобы можно было давать команду плееру таким образом, чтобы трек запускался и играл непрерывно дорожку до тех пор, пока не произойдёт смена состояния кнопки (с нажатой и удерживаемой на отпускание или с отпущенной на нажатую и удерживаемую). Ну и соответственно какой-то подходящий антидребезг - я пока не могу придумать, как его сделать((

Скнопками громкости схожая ситуация: нажатие и удержание должно включать громкость, и при удержании кнопки она не должна меняться до отпускания кнопки. Сейчас же каждый цикл проверки включает и выключает громкость.

 

Надеюсь, что теперь стало понятнее то, что я пытаюсь сделать..

vosara
vosara аватар
Offline
Зарегистрирован: 08.02.2014

Понял. Попробуйте так

const int songPin = 5; // кнопка "song"
const int song1volPin = 6; // кнопка "громкость song1"
const int song2volPin = 7; // кнопка "громкость song2"
//int regim = 0;
bool flag = 0;
bool flag_vol1=0;
bool flag_vol2=0;
//переменные
bool song = 0; //переменная для хранения данных с кнопки "трек"
bool song1vol = 0;//переменная для хранения данных с контакта контроля состояния тригеров дверей
bool song2vol = 0;//переменная для хранения данных с контакта реле бензонасоса
void setup() {
  Serial.begin(9600);  //для отладки
  //mySerial.begin(9600); //для общения с мп3плеером
  pinMode (songPin, INPUT);
  pinMode (song1volPin, INPUT);
  pinMode (song2volPin, INPUT);
  
}
void loop()
{

  song = digitalRead(songPin); //сохраняем состояние с кнопки song
  song1vol = digitalRead(song1volPin);//с кнопки song1vol
  song2vol = digitalRead(song2volPin);//с кнопки song2vol

  if (song == HIGH && flag == 0)
  {
     flag = 1;
     Serial.println("1=1");//Здесь условие №1 Была нажата кнопка 1
  }
  if(song == LOW  && flag == 1)
  {
    flag = 0;
    Serial.println("1=0"); ////Здесь условие №4 все кнопки отпущены
  }
  
  
    if(song==HIGH && song1vol==HIGH)
     {
	if (flag_vol1==0)
	{
	  flag_vol1 = 1;
	  Serial.println("1=1  2=1");//Здесь условие №2 нажата кнопка 1 и 2
	}
      
     }
    if (song1vol == LOW)
    {
      flag_vol1 = 0;
    }
    
  
  if(song == LOW && song2vol == HIGH )
    {
     if (flag_vol2==0)
      {
       Serial.println("3=1");//Здесь условие №3 нажата кнопка 3
       flag_vol2=1;
      }
    }
  if (song2vol == LOW)
    {
     flag_vol2=0;
    } 
  
  }

 

gabber24
Offline
Зарегистрирован: 19.01.2016

Спасибо большое, что помогли решить вопрос, допили программу, теперь работает как надо!)

Если вдруг кому-то понадобится скетч для DF Player, можно взять мой вариант. Особоенность - всего два трека, переключаются кнопкой "song", проигрывает до конца трека и останавливается. Кнопка "song_vol1" включает громкость, когда играет трек1, кнопка "song_vol2" включает громкость, когда играет трек2.

Еще раз спасибо огромное за помощь!!

#include <DFPlayer_Mini_Mp3.h>
#include <SoftwareSerial.h>
SoftwareSerial mySerial(11, 10); // RX, TX

const int songPin = 5; // кнопка "song"
const int song1volPin = 6; // кнопка "громкость song1"
const int song2volPin = 7; // кнопка "громкость song2"
bool flag = 1;
bool flag_vol1=0;
bool flag_vol2=0;
//переменные
bool song = 0; //переменная для хранения данных с кнопки "song"
bool song1vol = 0;//переменная для хранения данных с кнопки "song_vol1"
bool song2vol = 0;//переменная для хранения данных с кнопки "song_vol2"

void setup() {
  Serial.begin(9600);  //для отладки
  mySerial.begin(9600); //для общения с мп3плеером
  mp3_set_serial(mySerial);
  pinMode (songPin, INPUT);
  pinMode (song1volPin, INPUT);
  pinMode (song2volPin, INPUT);
  
}
void loop()
{

  song = digitalRead(songPin); //сохраняем состояние с кнопки song
  song1vol = digitalRead(song1volPin);//с кнопки song1vol
  song2vol = digitalRead(song2volPin);//с кнопки song2vol

  if (song == HIGH && flag == 0)
  {
     flag = 1;
     Serial.println("1=1");//Здесь условие №1 Была нажата кнопка 1     
     mp3_play (1);
     delay(50);
     mp3_set_volume (0);    //0~30
 
  }   

  if(song == LOW  && flag == 1)
  {
    flag = 0;
    Serial.println("1=0"); ////Здесь условие №4 все кнопки отпущены
    mp3_play (2);
    delay(50);
    mp3_set_volume (0);    //0~30
  }
  
  if(song==HIGH && song1vol==HIGH)
     {
        if (flag_vol1==0)
          {
           flag_vol1 = 1;
           Serial.println("1=1  2=1");//Здесь условие №2 нажата кнопка 1 и 2\
           delay(50);
           mp3_set_volume (30);    //0~30
          }
       }
   if (song==HIGH && song1vol == LOW)
         {
           if (flag_vol1==1)
           {
           flag_vol1 = 0;
           Serial.println("1=1 2=0");//Здесь условие №2 нажата кнопка 1 и 2\
           delay(50);
           mp3_set_volume (0);    //0~30
          }
         }
  
  if(song == LOW && song2vol == HIGH )
    {
     if (flag_vol2==0)
      {
       Serial.println("1=0 3=1");//Здесь условие №3 нажата кнопка 3
       flag_vol2=1;
       delay(50);
       mp3_set_volume (30);    //0~30
       }
    }
  if (song == LOW && song2vol == LOW)
    {
     if (flag_vol2==1)
      {
       flag_vol2=0;
       Serial.println("1=0 3=0");//Здесь условие №3 нажата кнопка 3
       delay(50);
       mp3_set_volume (0);    //0~30
       }
     } 
  
  }