ARDUINO Ошибки при приеме ИК

alertique

✩✩✩✩✩✩✩
16 Май 2020
5
0
При работе с ИК-приемником появились проблемы. Выяснил, что косяк программный, поскольку тестовые скетчи работают нормально. В моей же программе работать отказывается, весь прием идет неверно. Принятые слова все разные, хотя должно повторяться только одно слово. Возможно, проблема связана с прерываниями. Кто-нибудь сталкивался с подобным?



Таймер:
#include <AnalogButtons.h>
#include <SevenSeg.h>
#include <IRremote.h>

decode_results  results;
const int recvPin = 17;
IRrecv irrecv(recvPin); // пин для ИК-приемника

#define ANALOG_PIN A7 // пин аналоговой кнопки
#define zummer 13 // пин пищалки
#define pyro A0 // пин пиропатрона
#define RED A1 // красный цвет
#define BLUE A2 // синий цвет
#define T_PERIOD 1000  // отсчет 1 секунды в таймере
#define T_zummer 150 // время писка

byte mode = 1; // стартуем с режима FUSE
byte team = 0; //1-красные, 2-синие
bool out = false; // флаг для выхода из режима захвата
bool LB = false; // флаг левой кнопки
bool RB = false; // флаг правой кнопки
bool SB = false; // флаг малой кнопки
bool SBHold = false; // флаг удержания малой кнопки
bool BB = false; // флаг большой кнопки
bool BBHold = false; // флаг удержания большой кнопки
uint16_t Total = 0; // общее время в секундах
char str[5]; // промежуточная переменная для колхозной строки
uint16_t RedTime = 0; // время красных
uint16_t BlueTime = 0; // время синих

SevenSeg disp(12,11,10,9,8,7,6); // пины индикатора ABCDEFG
const int numOfDigits=4; // число разрядов
int digitPins[numOfDigits]={5,4,3,2}; // порядок следования разрядов слева направо

AnalogButtons analogButtons(ANALOG_PIN, INPUT); // создаем переменные кнопок с уровнями срабатывания
Button b1 = Button(713, &b1Click);
Button b2 = Button(235, &b2Click);
Button b3 = Button(464, &b3Click, &b3Hold);
Button b4 = Button(1023, &b4Click, &b4Hold);

void setup() {
  irrecv.enableIRIn();

  disp.setDigitPins(numOfDigits, digitPins);
  disp.setActivePinState(HIGH,HIGH);
  disp.setTimer(1) ;
  disp.startTimer();

  analogButtons.add(b1);
  analogButtons.add(b2);
  analogButtons.add(b3);
  analogButtons.add(b4);

  pinMode(zummer, OUTPUT);
  pinMode(RED, OUTPUT);
  pinMode(BLUE, OUTPUT);


  Serial.begin(115200); // для отладки
}

ISR(TIMER1_COMPA_vect){
  disp.interruptAction();
  analogButtons.check();
}

void b1Click() {  //LB
  LB = true;
}
void b2Click() {  //RB
  RB = true;
}
void b3Click() {  //SB
  SB = true;
}
void b3Hold() {  //SB Hold
  SBHold = true;
}
void b4Click() {  //BB
  BB = true;
}
void b4Hold() {  //BB Hold
  BBHold = true;
}

void loop(){
  if(mode == 1)disp.write("FUSE");
  if(mode == 2)disp.write("FLAG");

  if(BB) //По нажатию большой кнопки выбираем режим
  {
    mode++;
    if (mode > 2) mode = 1;
    BB = false;
  }
  if(SB) //По нажатию малой кнопки заходим в режим
  {
    SB = false;
    switch (mode) //выбор режима
    {
      case 1: MODE_1(); break; //Выбор режима 1
      case 2: MODE_2(); break; //Выбор режима 2
      case 3: MODE_3(); break; //Выбор режима 2
      default: break;
    }
  }
}

void MODE_1(){ // режим бомбермана
  byte mm = 0; // минуты
  byte ss = 0; // секунды
  byte def = 5; // время разминирования
  bool defuse = false; // флаг разминирования
  uint32_t timer = 0;   // переменная таймера
  byte counter = 0; // считаем время удержания разминирования

  while(!SB){ //устанавливаем секунды
    if(ss < 10){
      snprintf(str, 5, "---%d", ss);
      disp.write(str);
    }
    if(ss >= 10){
      snprintf(str, 5, "--%d", ss);
      disp.write(str);    
    }
    if(BB){
      ss++;
      BB = false;
    }
    if(BBHold){
      ss = ss+5;
      BBHold = false;
    }  
    if(ss > 59) ss = 0;
  }
  SB = false;
   
  while(!SB){ //устанавливаем минуты
    if(mm < 10){
      snprintf(str, 5, "-%d--", mm);
      disp.write(str);
    }
    if(mm >= 10){
      snprintf(str, 5, "%d--", mm);
      disp.write(str);    
    }
    if(BB){
      mm++;
      BB = false;
    }
    if(BBHold){
      mm = mm+5;
      BBHold = false;
    }      
    if(mm > 99) mm = 0;
  }
  SB = false;

  while(!SB){ //устанавливаем время разминирования
    if(def < 10){
      snprintf(str, 5, "de0%d", def);
      disp.write(str);
    }
    if(def >= 10){
      snprintf(str, 5, "de%d", def);
      disp.write(str);    
    }
    if(BB){
      def++;
      BB = false;
    }
    if(def > 25) mm = 0;
  }
  SB = false;

  Total = 60*mm + ss; // посчитали общее время

  while(!BBHold){
    showTime(Total);
  }
  BBHold = false;

  while(Total > 0 && defuse == false){
    if(millis() - timer >= T_PERIOD){ // таймер на millis()
      timer = millis(); // сброс
      digitalWrite(zummer, HIGH);
      Total--;
      if(BBHold){
        counter++;
        if(counter == def) defuse = true;
        BBHold = false;
      }
      else counter = 0;    
      if(Total & 1){
        digitalWrite(RED, HIGH);
        digitalWrite(BLUE, LOW);    
      } else{
        digitalWrite(RED, LOW);
        digitalWrite(BLUE, HIGH);    
        }
    }  
    if(millis() - timer >= T_zummer){
      digitalWrite(zummer, LOW); // отключение зуммера
    }

    if(Total == 0){
      digitalWrite(pyro, HIGH); // подрыв
      while(!SB){
        disp.write("");
      }
      SB = false;  
    }

    if(defuse){
      while(!SB){
        showTime(Total);
        if (millis() - timer >= T_zummer) { // таймер на millis()
          timer = millis(); // сброс
          digitalWrite(zummer, !digitalRead(zummer));
        }
      }
      SB = false;
      BB = false;
      SBHold = false;
      BBHold = false;
    }
    showTime(Total);
    }
  defuse = false;
  digitalWrite(pyro, LOW);
  digitalWrite(zummer, LOW);
  digitalWrite(RED, LOW);
  digitalWrite(BLUE, LOW);
  mm = 0; // обнуляем минуты
  ss = 0; // обнуляем секунды
  defuse = false; // снимаем флаг разминирования
  counter = 0; // обнуляем время удержания разминирования
}

void MODE_2(){ // режим захвата флага
  byte mm = 0; // минуты раунда
  byte ss = 0; // секунды раунда
  byte counter = 0; // считаем время удержания для выхода из режима
  uint32_t timer = 0;   // переменная таймера
   
  while(!SB){ //устанавливаем секунды
    analogButtons.check();
    if(ss < 10){
      snprintf(str, 5, "---%d", ss);
      disp.write(str);
    }
    if(ss >= 10){
      snprintf(str, 5, "--%d", ss);
      disp.write(str);    
    }
    if(BB){
      ss++;
      BB = false;
    }
    if(BBHold){
      ss = ss+5;
      BBHold = false;
    }  
    if(ss > 59) ss = 0;
  }
  SB = false;
     
  while(!SB){ //устанавливаем минуты
    if(mm < 10){
      snprintf(str, 5, "-%d--", mm);
      disp.write(str);
    }
    if(mm >= 10){
      snprintf(str, 5, "%d--", mm);
      disp.write(str);    
    }
    if(BB){
      mm++;
      BB = false;
    }
    if(BBHold){
      mm = mm+5;
      BBHold = false;
    }      
    if(mm > 99) mm = 0;
  }
  SB = false;

  Total = 60*mm + ss; // посчитали общее время

  disp.write("----");

  while(Total > 0){ // крутимся до тех пор, пока время не кончилось или не остановили игру
    if(SBHold){ // выходим из цикла
      Total = 0;
      SBHold = false;
    }
   
    if(LB){ // снимаем флаг левой кнопки
      team = 1;
      LB = false;
    }

    if(RB){ // снимаем флаг правой кнопки
      RB = false;
      team = 2;
    }

    if(irrecv.decode(&results)){
      Serial.println(results.value, HEX);
      if(results.value == 0x801) team = 1;
      if(results.value == 0x811) team = 2;
      irrecv.resume();
    }  

    if(team != 0){
      if(millis() - timer >= T_PERIOD){ // таймер на millis()
        timer = millis(); // сброс
        digitalWrite(zummer, HIGH); // начинаем пищать
        Total--;        

        if(team == 1){
          RedTime++;
          showRedTime();      
          digitalWrite(RED, HIGH);
          digitalWrite(BLUE, LOW);
        }
   
        if(team == 2){
          BlueTime++;
          showBlueTime();    
          digitalWrite(RED, LOW);
          digitalWrite(BLUE, HIGH);    
        }
      }
    }


    if(millis() - timer >= T_zummer){
     digitalWrite(zummer, LOW); // отключение зуммера
    }        
  }
  digitalWrite(zummer, LOW); // отключение зуммера шоб не пищал после выхода из цикла

  while(!SB){
    analogButtons.check();
   
    if(LB){ // снимаем флаг левой кнопки
      team = 1;
      LB = false;
    }

    if(RB){ // снимаем флаг правой кнопки
      RB = false;
      team = 2;
    }
   
    if(team == 1){
      showTime(RedTime);          
      digitalWrite(RED, HIGH);
      digitalWrite(BLUE, LOW);
    }

    if(team == 2){
      showTime(BlueTime);    
      digitalWrite(RED, LOW);
      digitalWrite(BLUE, HIGH);    
    }
  }
  SB = false;
  digitalWrite(RED, LOW);
  digitalWrite(BLUE, LOW);
  mm = 0; // обнуляем минуты
  ss = 0; // обнуляем секунды
}


void MODE_3(){
  disp.clearDisp();
}

void showTime(int val){ // показывалка времени с колхозными строчками
  if(val > 599) disp.writeClock(val); // выводим без колхоза
  if(val/60 < 10 && val%60 > 9){ // колхозим вывод 0, когда время меньше 10 минут и больше 59 секунд
    snprintf(str, 5, "0%d%d", val/60, val%60);
    disp.write(str);    
  }
  if(val/60 <= 9 && val%60 <= 9){
    snprintf(str, 5, "0%d0%d", val/60, val%60);
    disp.write(str);      
  }  
  if(val <= 59 && val%60 > 9){
    snprintf(str, 5, "00%d", val%60);
    disp.write(str);      
  }
  if(val <= 59 && val%60 <= 9){
    snprintf(str, 5, "000%d", val%60);
    disp.write(str);      
  }
  if(val <= 9){ // закончили колхоз строки с нулями
    snprintf(str, 5, "000%d", val%60);
    disp.write(str);        
  }
}

void showRedTime(){ // показывалка времени красных с колхозными строчками
  if(RedTime <= 9){
    snprintf(str, 5, "0%d--", RedTime);
    disp.write(str);      
  }  
  if(RedTime > 9 && RedTime <= 59){
    snprintf(str, 5, "%d--", RedTime);
    disp.write(str);      
  }
  if(RedTime > 59 && RedTime/60 < 10){
    snprintf(str, 5, "0%d--", RedTime/60);
    disp.write(str);      
  }
  if(RedTime > 59 && RedTime/60 > 9){
    snprintf(str, 5, "%d--", RedTime/60);
    disp.write(str);      
  }
}

void showBlueTime(){ // показывалка времени синих с колхозными строчками
  if(BlueTime <= 9){
    snprintf(str, 5, "--0%d", BlueTime);
    disp.write(str);      
  }  
  if(BlueTime > 9 && BlueTime <= 59){
    snprintf(str, 5, "--%d", BlueTime);
    disp.write(str);      
  }
  if(BlueTime > 59 && BlueTime/60 < 10){
    snprintf(str, 5, "--0%d", BlueTime/60);
    disp.write(str);      
  }
  if(BlueTime > 59 && BlueTime/60 > 9){
    snprintf(str, 5, "--%d", BlueTime/60);
    disp.write(str);      
  }
}
 

kalobyte

★★★✩✩✩✩
1 Янв 2020
724
148
ISR(TIMER1_COMPA_vect){
disp.interruptAction();
analogButtons.check();
}
скорей всего нарушает работу библиотеки ик приемника
эти операции в скобках вполне можно делать в главном цикле
 
  • Лойс +1
Реакции: alertique

alertique

✩✩✩✩✩✩✩
16 Май 2020
5
0
ISR(TIMER1_COMPA_vect){
disp.interruptAction();
analogButtons.check();
}
скорей всего нарушает работу библиотеки ик приемника
эти операции в скобках вполне можно делать в главном цикле
Пробовал ставить эти операции в главном цикле, индикатор начинает моргать, не очень хорошо получается - зато приемник работать начинает адекватно. Попробую избавиться от этого таймера как-нибудь еще.
 

kalobyte

★★★✩✩✩✩
1 Янв 2020
724
148
сделай софтовый таймер, если тебе надо обновлять индикатор через равные промежутки
 
  • Лойс +1
Реакции: alertique

alertique

✩✩✩✩✩✩✩
16 Май 2020
5
0
сделай софтовый таймер, если тебе надо обновлять индикатор через равные промежутки
Не понял, как это будет работать? Мне достаточно обновлять содержимое при изменении, допустим, времени. Во всех циклах работает нормально, кроме цикла в режиме 2, когда начинает работать режим типа шахматных часов. Информация выводится только в момент писка зуммера (как такое возможно?).
 

alertique

✩✩✩✩✩✩✩
16 Май 2020
5
0
Отказ от использования аппаратного таймера решил проблему с неправильным приемом.
 

kalobyte

★★★✩✩✩✩
1 Янв 2020
724
148
Не понял, как это будет работать?
обычно берется какой-то аппаратный таймер и на нем запускается софтовый счетчик миллисекунд, собственно как сделано в ардуине
кстати он по дефолту работает, даже если ты не пользуешся функцией millis, что сжирает память и скорость

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

ставиш этот макрос в конец или в начало суперцикла и тут главное выбрать скорость обновления, которая будет не так часто вызываться, а чтобы успели отработать все предыдущие функции и куски кода, иначе индикатор опять будет мерцать
500мс я думаю достаточное время и за это твой код должен успевать отработать
 
  • Лойс +1
Реакции: alertique

alertique

✩✩✩✩✩✩✩
16 Май 2020
5
0
@kalobyte, как оказалось, нет необходимости обновлять содержимое индикатора, все и так хорошо работает. Спасибо за помощь.