В сигнале с пульта ДУ идут рандомные числа (обновлено)

Тема в разделе "Arduino & Shields", создана пользователем Kyouma, 12 сен 2018.

  1. Kyouma

    Kyouma Нерд

    Скетч должен по сигналу с ИК-пульта плавно зажигать два светодиода, включать воспроизведение аудиозаписи на мини mp3 плеере(при начале воспроизведения включается реле усилителя, по окончании - выключается), в определенный момент воспроизведения включать реле дым машины на короткий промежуток времени, по окончании воспризведения и выключении реле дым машины - плавно тушить светодиоды.

    На ИК пульте кроме кнопок №1 и №2 включения определенной аудиозаписи, используются кнопки регулировки громкости, кнопка эквалайзера, и кнопка для сброса плеера (reset).

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

    Код (C++):
    #include "Arduino.h"
    #include "SoftwareSerial.h"
    #include "DFRobotDFPlayerMini.h"
    #include <IRremote.h>
    #define Bitrate 4500
    #define Speed 1

    IRrecv irrecv(3); // вход ИК-приемника
    unsigned long ir_dt, ir_kod;
    decode_results results;
    SoftwareSerial mySoftwareSerial(4, 11); //RX, TX связь с mp3 плеером
    DFRobotDFPlayerMini myDFPlayer;
    const byte led1 = 9;
    const byte led2 = 10;
    const byte rele1 = 5; //реле дым машины
    const byte rele4 = 8; //включение-выключение усилителя
    const int interva1 = 3600; //задержка включения, интервал между включениями дыма
    const int interva2 = 500; //время удержания во включенном состоянии дым-машины
    unsigned long previousMillis = 0;
    unsigned long previousMillis1 = 0;
    bool releSrab = false;
    bool finishPlay = false;
    bool zaderjka = false;
    bool mp3_flag = true;
    uint8_t eq;


    void setup()
    {
    mySoftwareSerial.begin(9600);
    Serial.begin(115200);
    irrecv.enableIRIn(); // включить ИК-приемник
    Serial.println();
    Serial.println(F("DFRobot DFPlayer Mini Demo"));
    Serial.println(F("Initializing DFPlayer ... (May take 3~5 seconds)"));

    while (!myDFPlayer.begin(mySoftwareSerial)) { //Use softwareSerial to communicate with mp3.
    Serial.println(F("Unable to begin:"));
    Serial.println(F("1.Please recheck the connection!"));
    Serial.println(F("2.Please insert the SD card!"));
    myDFPlayer.reset();
    mySoftwareSerial.begin(9600);
    }
    Serial.println(F("DFPlayer Mini online."));

    myDFPlayer.volume(30); //Set volume value. From 0 to 30
    myDFPlayer.EQ(DFPLAYER_EQ_BASS);
    digitalWrite (rele1, HIGH);
    digitalWrite (rele4, HIGH);
    pinMode (3, INPUT); // ИК приемник
    pinMode (9, OUTPUT); //светодиод
    pinMode (10, OUTPUT); //светодиод
    pinMode (5, OUTPUT); //реле дым машины
    pinMode (8, OUTPUT); //реле усилителя
    pinMode (13, OUTPUT); //сигнализация приема сигнала с пульта ДУ
    attachInterrupt(1,get_ir_kod,FALLING); // назначим прерывание
    }

    void loop() {
    //Serial.println(ir_kod, HEX);
    if (ir_kod > 0) { //прием данных с пульта ДУ
    switch (ir_kod) {
    case 0xFF30CF: //кнопка "1" нажата
    if (mp3_flag == true) {
    led_ON();
    digitalWrite (rele4, LOW); //включение усилителя
    myDFPlayer.play(1);
    delay (100);
    mp3_flag = false;
    zaderjka = true;
    }
    break;

    case 0xFF18E7: //кнопка "2" нажата
    if (mp3_flag == true) {
    led_ON();
    digitalWrite (rele4, LOW); //включение усилителя
    myDFPlayer.play(2);
    delay (100);
    mp3_flag = false;
    zaderjka = true;
    }
    break;

    case 0xFFE01F: //кнопка звук- нажата
    myDFPlayer.volumeDown();
    delay (100);
    break;

    case 0xFFA857: //кнопка звук+ нажата
    myDFPlayer.volumeUp();
    delay (100);
    break;

    case 0xFF906F: //кнопка "EQ" нажата
    myDFPlayer.readEQ();
    delay (100);
    eq = myDFPlayer.read()+1; //переключение эквалайзера на следующий режим
    myDFPlayer.EQ(eq);
    delay (100);
    break;

    case 0xFFC23D: //кнопка play/pause нажата
    myDFPlayer.reset(); //перезагрузка плеера
    delay (100);
    myDFPlayer.volume(30);
    delay (100);
    break;

    default:
    break;
    }
    ir_kod = 0;
    irrecv.resume();
    }

    unsigned long currentMillis = millis();
    if (myDFPlayer.readState() == 0x201 && currentMillis - previousMillis >= interva1) { //плеер играет, задержка включения реле дыма (чтобы под конец песни)
    if (zaderjka == true) {
    previousMillis = currentMillis;
    zaderjka = false;
    }
    else {
    digitalWrite (rele1, LOW);
    releSrab = true;
    previousMillis = currentMillis;
    }
    }

    if (releSrab == true && currentMillis - previousMillis >= interva2) {
    digitalWrite (rele1, HIGH);
    previousMillis = currentMillis;
    releSrab = false;
    }

    if(myDFPlayer.readState() == 0x0200 && mp3_flag == false) { //плеер закончил воспроизведение трека.
    digitalWrite (rele4, HIGH);
    mp3_flag = true;
    finishPlay = true;
    myDFPlayer.stop();
    }

    if (finishPlay == true && releSrab == false) { //плеер закончил воспроизведение трека и реле дым машины выключено. сделал подобную конструкцию ибо плеер в последовательный порт как-то перестал передавать что он окончил воспроизведение трека, вместо этого пишет о том что он в режиме "стоп" как при начальной загрузке
    led_OFF();
    }
    }

    void led_ON() {
    for(uint16_t i = 0; i<Bitrate; i+=Speed) {
    uint16_t del = pow(i,2) / Bitrate;
    PORTB |= (1 << PB1)|(1 << PB2); //включение 9й и 10й ноги
    delayMicroseconds(del);
    PORTB &= (~((1 << PB1)|(1 << PB2))); //выключение 9й и 10й ноги
    delayMicroseconds(Bitrate - del);
    }
    PORTB |= (1 << PB1)|(1 << PB2);
    }

    void led_OFF() {
    for(uint16_t i = Bitrate; i>Speed; i-=Speed) {
    uint16_t del = pow(i,2) / Bitrate;
    PORTB |= (1 << PB1)|(1 << PB2); //включение 9й и 10й ноги
    delayMicroseconds(del);
    PORTB &= (~((1 << PB1)|(1 << PB2))); //выключение 9й и 10й ноги
    delayMicroseconds(Bitrate - del);
    }
    PORTB &= (~((1 << PB1)|(1 << PB2)));
    }

    void get_ir_kod() { // получить код, переданный с ИК-пульта
    cli();
    if (irrecv.decode(&results)) {
    irrecv.blink13(1);
    if (results.value > 0 && results.value != REPEAT) {
    ir_dt = results.value;
    ir_kod = ir_dt;
    }
    else if (results.value == REPEAT){
    ir_kod = ir_dt;
    }
    }
    sei();
    }
     
    Последнее редактирование: 13 сен 2018
  2. Un_ka

    Un_ka Гуру

    А что идёт в Com порт покажи
    FFF или 000?
     
  3. DetSimen

    DetSimen Guest

    Код твой, или в сети нашол?
     
  4. Kyouma

    Kyouma Нерд

    большей частью мой, но местами взятый из примеров. например функции led_ON и led_OFF взяты в сети с незначительной переделкой.
     
  5. Kyouma

    Kyouma Нерд

    при нажатии на кнопку с сигналом FFA857 в COM идут следующие сигналы в HEX
    Код (C++):
    BA2BABE
    2BE1AEC6
    F0863FD9
    34E34A00
    6935CC56
    AAF6B2E
     
    они могут чередоваться, повторяться и т.д., то есть какая-то зависимость есть, но откуда это все может возникать я не понимаю, учитывая что там кроме двойного (может и тройного) нажатия и кода повторения 0xFFFFFFFF больше и нет ничего.

    Например залив такой скетч
    Код (C++):
    #include <IRremote.h>


    int RECV_PIN = 3;     // вход ИК-приемника
    IRrecv irrecv(RECV_PIN);
    decode_results results;
    unsigned long ir_dt;
    long ir_kod;

    void setup()
    {
    pinMode (13, OUTPUT);
    Serial.begin(19200);   // последовательный порт
    irrecv.enableIRIn();   // включить приемник

    attachInterrupt(1, get_ir_kod, FALLING);    // FALLING – вызов прерывания при изменении уровня напряжения с высокого (HIGH) на низкое (LOW)
    }

    void loop() {
      if(ir_kod > 0){                                 // обработка кода нажатия
      Serial.println(ir_kod, HEX);
      ir_kod = 0;
      }
    }

    void get_ir_kod() {                         // получить код, переданный с ИК-пульта
    detachInterrupt(1);                         // отключить прерывание 0
    if (irrecv.decode(&results))  {
      irrecv.blink13(1);
      if (results.value > 0 && results.value != REPEAT)  {
        ir_dt = results.value;

             ir_kod = ir_dt;

        }
        else if (results.value == REPEAT){
          ir_kod = ir_dt;
        }
     
    irrecv.resume();
      }
    attachInterrupt(1, get_ir_kod, FALLING);    // активировать процедуру прерывания 0
    }


    Результаты нажатия кнопки FFA857:

    FF0000
    FFA857
    55DED162  //двойное нажатие
    FFA857
    55DED162  //двойное нажатие
    55DED162  //двойное нажатие
    FFA800
    FFA857
    FFA857
    FFA857
     
    то есть какие-то посторонние данные тоже есть, но они встречаются довольно редко по сравнении с полным вариантом скетча, и, что самое главное, функция loop продолжает выполняться. В полном варианте она перестает это делать спустя какое-то количество принятых с пульта сигналов почему-то
     
    Последнее редактирование: 13 сен 2018
  6. ZAZ-965

    ZAZ-965 Гуру

    По моему не верно вызывать функции IRremote из attachInterrupt.
     
    Kyouma и Mitrandir нравится это.
  7. Kyouma

    Kyouma Нерд

    Простите, не понял. Вы имеете в виду что нужно отказаться от использования прерываний и пытаться ловить сигнал с пульта в loop?
     
  8. Mitrandir

    Mitrandir Гуру

    Насколько я знаю, прием ик работает на прерываниях. Внутри прерывания обработка прерываний отключается.
     
    Kyouma нравится это.
  9. Kyouma

    Kyouma Нерд

    ок, попробую. отпишусь по результатам
     
  10. Kyouma

    Kyouma Нерд

    опробовал без отдельного прерывания, работает, loop больше не виснет, спасибо
    Код (C++):
    #include "Arduino.h"
    #include "SoftwareSerial.h"
    #include "DFRobotDFPlayerMini.h"
    #include <IRremote.h>
    #define Bitrate 4500
    #define Speed 1

    IRrecv irrecv(3); // вход ИК-приемника
    unsigned long ir_dt, ir_kod;
    decode_results results;
    SoftwareSerial mySoftwareSerial(4, 11); //RX, TX связь с mp3 плеером
    DFRobotDFPlayerMini myDFPlayer;
    const byte led1 = 9;
    const byte led2 = 10;
    const byte rele1 = 5; //реле дым машины
    const byte rele4 = 8; //включение-выключение усилителя
    const int interva1 = 3600; //задержка включения, интервал между включениями дыма
    const int interva2 = 500; //время удержания во включенном состоянии дым-машины
    unsigned long previousMillis = 0;
    unsigned long previousMillis1 = 0;
    bool releSrab = false;
    bool finishPlay = false;
    bool zaderjka = false;
    bool mp3_flag = true;
    uint8_t eq;


    void setup()
    {
    mySoftwareSerial.begin(9600);
    Serial.begin(115200);
    irrecv.enableIRIn(); // включить ИК-приемник
    Serial.println();
    Serial.println(F("DFRobot DFPlayer Mini Demo"));
    Serial.println(F("Initializing DFPlayer ... (May take 3~5 seconds)"));

    while (!myDFPlayer.begin(mySoftwareSerial)) { //Use softwareSerial to communicate with mp3.
    Serial.println(F("Unable to begin:"));
    Serial.println(F("1.Please recheck the connection!"));
    Serial.println(F("2.Please insert the SD card!"));
    myDFPlayer.reset();
    mySoftwareSerial.begin(9600);
    }
    Serial.println(F("DFPlayer Mini online."));

    myDFPlayer.volume(30); //Set volume value. From 0 to 30
    myDFPlayer.EQ(DFPLAYER_EQ_BASS);
    digitalWrite (rele1, HIGH);
    digitalWrite (rele4, HIGH);
    pinMode (3, INPUT); // ИК приемник
    pinMode (9, OUTPUT); //светодиод
    pinMode (10, OUTPUT); //светодиод
    pinMode (5, OUTPUT); //реле дым машины
    pinMode (8, OUTPUT); //реле усилителя
    pinMode (13, OUTPUT); //сигнализация приема сигнала с пульта ДУ
    }

    void loop() {
    //Serial.println(ir_kod, HEX);
    if (irrecv.decode(&results)){                           //прием данных с пульта ДУ
    irrecv.blink13(1);
      if (results.value > 0 && results.value != REPEAT)  {
          ir_dt = results.value;
          ir_kod = ir_dt;
          }
        else if (results.value == REPEAT){
          ir_kod = ir_dt;
        }
    Serial.println(ir_kod, HEX);

    switch (ir_kod) {
    case 0xFF30CF: //кнопка "1" нажата
    if (mp3_flag == true) {
    led_ON();
    digitalWrite (rele4, LOW); //включение усилителя
    myDFPlayer.play(1);
    delay (100);
    mp3_flag = false;
    zaderjka = true;
    }
    break;

    case 0xFF18E7: //кнопка "2" нажата
    if (mp3_flag == true) {
    led_ON();
    digitalWrite (rele4, LOW); //включение усилителя
    myDFPlayer.play(2);
    delay (100);
    mp3_flag = false;
    zaderjka = true;
    }
    break;

    case 0xFFE01F: //кнопка звук- нажата
    myDFPlayer.volumeDown();
    delay (100);
    break;

    case 0xFFA857: //кнопка звук+ нажата
    myDFPlayer.volumeUp();
    delay (100);
    break;

    case 0xFF906F: //кнопка "EQ" нажата
    myDFPlayer.readEQ();
    delay (100);
    eq = myDFPlayer.read()+1; //переключение эквалайзера на следующий режим
    myDFPlayer.EQ(eq);
    delay (100);
    break;

    case 0xFFC23D: //кнопка play/pause нажата
    myDFPlayer.reset(); //перезагрузка плеера
    delay (100);
    myDFPlayer.volume(30);
    delay (100);
    break;

    default:
    break;
    }
    ir_kod = 0;
    irrecv.resume();
    }

    unsigned long currentMillis = millis();
    if (myDFPlayer.readState() == 0x201 && currentMillis - previousMillis >= interva1) { //плеер играет, задержка включения реле дыма (чтобы под конец песни)
    if (zaderjka == true) {
    previousMillis = currentMillis;
    zaderjka = false;
    }
    else {
    digitalWrite (rele1, LOW);
    releSrab = true;
    previousMillis = currentMillis;
    }
    }

    if (releSrab == true && currentMillis - previousMillis >= interva2) {
    digitalWrite (rele1, HIGH);
    previousMillis = currentMillis;
    releSrab = false;
    }

    if(myDFPlayer.readState() == 0x0200 && mp3_flag == false) { //плеер закончил воспроизведение трека.
    digitalWrite (rele4, HIGH);
    mp3_flag = true;
    finishPlay = true;
    myDFPlayer.stop();
    }

    if (finishPlay == true && releSrab == false) { //плеер закончил воспроизведение трека и реле дым машины выключено. сделал подобную конструкцию ибо плеер в последовательный порт как-то перестал передавать что он окончил воспроизведение трека, вместо этого пишет о том что он в режиме "стоп" как при начальной загрузке
    led_OFF();
    }
    }

    void led_ON() {
    for(uint16_t i = 0; i<Bitrate; i+=Speed) {
    uint16_t del = pow(i,2) / Bitrate;
    PORTB |= (1 << PB1)|(1 << PB2); //включение 9й и 10й ноги
    delayMicroseconds(del);
    PORTB &= (~((1 << PB1)|(1 << PB2))); //выключение 9й и 10й ноги
    delayMicroseconds(Bitrate - del);
    }
    PORTB |= (1 << PB1)|(1 << PB2);
    }

    void led_OFF() {
    for(uint16_t i = Bitrate; i>Speed; i-=Speed) {
    uint16_t del = pow(i,2) / Bitrate;
    PORTB |= (1 << PB1)|(1 << PB2); //включение 9й и 10й ноги
    delayMicroseconds(del);
    PORTB &= (~((1 << PB1)|(1 << PB2))); //выключение 9й и 10й ноги
    delayMicroseconds(Bitrate - del);
    }
    PORTB &= (~((1 << PB1)|(1 << PB2)));
    }
    но осталась проблема с мусором, то есть на нажатие кнопки с кодом 0xFF30CF мне в COM прилетает следующее:
    Код (C++):
    339D7E7A
    B8014A0E
    43A723EE
    B8194820
    62A21B9B
    387F6605
    B736791B
    755349D
    5908ABD9
    B18E0736
    225719DA
    875D141B
    8264E0CF
    54FB1970
    D905B6AD
    8DDB4FA0
    AA2F66F0
    71A49921
    A87D35BA
    FC13E339
    2DCBC07D
    4EE0B0BF
    1A987CF2
    2D166452
    55E7CD5C
    C0D93D97
    8CD1F22A
    48A71A77
    D0E775B6
    6C777F96
    CBC0957D
    B1C3D6E1
    1B50C0A7
    501607AD
    D8050BB8
    1FDEB98A
    48E13806
    76FC4FA6
    AE0CD68E
    7181FB16
    7181FB16
    D7B0A230
    61BF2EB6
    9AFA0EA3
    10926CC7
    4A4446C6
    758651CE
    13240545
    83B5E23B
    75C3402F
    6DC4C8C3
    82589C4C
    742C5099
    BC44395E
    F477C5AD
    7923D13
    4409E4E4
    6A2F682D
    E6D7A791
    107F5AC5
    D13A1E54
    6302950D
    4ACA39DA
    7468D89F
    50FBD923
    3752ED45
    C541D83A
    D7B0A230
    707686FF
    DBC5071
    DBC5071
    5616B410
    A6C8C50
    196B134B
    294234C3
    F66A8BE6
    F550312D
    702B0FDE
    AA7E916
    54BFED3D
    BA85502B
    C9D435A4
    B85703BF
    A6DF47C2
    C70F2C05
    CB5087B1
    7676ED9B
    5BA1DA22
    5338372D
    754D2B59
    F916F385
    ABCFF37
    34E8E063
    FC501C27
    4F89A674
    38E73363
    A74012D9
    DE9D896B
    E63AE3D3
    A162AD58
    EDB6C1AF
    893A055D
    6AD0A625
    753A055B
    160E2726
    341C9894
    8A8A8730
    E9C6A3EA
    B4C97A15
    F052838
    B4F242A0
    F8313AA8
    12DD044
    955CEA32
    9F5BC763
    921FCEA
    D9136E16
    70B731C7
    DE398E0C
    8F6CE3
    D6F2F46C
    C224FD1E
    7DC8355E
    DC2EFEA9
    5D10F7E3
    FBCF81F6
    8EF125D
    F29E0205
    8AA051A3
    772555EF
    F57D5B72
    672B5745
    672B5745
    6563283B
    1BAA387F
    3797C533
    1BE77B9
    7CD874F3
    F7B4540C
    1ACE5C5D
    6367B6BD
    DFC304A6
    657A1EBF
    468569F1
    A5F80D50
    916FFB9A
    916FFB9A
    916FFB9A
    4D959C13
    4D959C13
    4D959C13
    5F0E6305
    9488796E
    326E45EB
     
    то есть ни одного верного кода вообще не прилетело, хотя, опять же, в сокращенном варианте программы (в котором только прием IR и вывод его в COM) - все идеально.
    кстати код REPEAT тоже не приходит. возможно какие-то таймеры друг друга пересекают, я даже не представляю в какую сторону копать. Может кто подскажет?
     
    Последнее редактирование: 13 сен 2018
    Un_ka нравится это.
  11. parovoZZ

    parovoZZ Гуру

    отказаться от абдурины и писать всё ручками.
     
  12. Airbus

    Airbus Радиохулиган Модератор

    А причем здесь ручки?Или if/else в Ардуино IDE работает как то по-другому?
     
  13. Airbus

    Airbus Радиохулиган Модератор

    Почему?У Аффтара стоит Falling ИМХО должно быть Rising по фронту первого принятого импульса.
     
    DetSimen нравится это.
  14. Kyouma

    Kyouma Нерд

    я уже убрал прерывание, очевидно оно уже прописано в библиотеке IRremote.h, ибо все работает. В мини скетче в котором только прием сигнала от пульта ДУ - никаких проблем, прием сигнала идеальный. как только я добавляю if/else и связь с плеером - вместо сигнала идет набор полурандомных чисел
     
  15. SergeiL

    SergeiL Оракул Модератор

    Закомментируйте работу с SoftSerial и плеером.
    Проверьте, что все работает, добавляете по одному - найдет , что влияет на работу IRremote.
     
  16. Kyouma

    Kyouma Нерд

    Как раз писал это сообщение, а тут ваш совет)
    исключил использование функций библиотеки DFRobotDFPlayerMini.h (и SoftwareSerial.h), код с пульта принимается корректно. я думаю что проблема связана с передачей данных плееру. в сети не смог найти информацию какой таймер использует библиотека SoftwareSerial.h, может кто знает? IRremote.h исходя из описания использует таймер №2 (хотя у UNO всего два таймера - №0 и №1, опять же, не пойму как тогда работает IR...)
     
  17. SergeiL

    SergeiL Оракул Модератор

    Так Вы попробовали выяснит, что именно мешает приему кода DFRobotDFPlayerMini.h или SoftwareSerial.h.
    В SoftwareSerial есть запрещение прерываний, это тоже может влиять на прием кода.
     
    Mitrandir нравится это.
  18. Kyouma

    Kyouma Нерд

    я не имею представления как это выяснить, ибо они используются совместно. Выкинул все команды использующие DFRobotDFPlayerMini.h, отключил эту библиотеку. Из SoftwareSerial оставил только инициализацию
    Код (C++):
    SoftwareSerial mySoftwareSerial(4, 12);

    void setup()
    {
      mySoftwareSerial.begin(9600);
    ...
    }
    Прием сигнала с пульта корректный, но можно ли утверждать что проблема в DFRobotDFPlayerMini.h, ведь в loop не используются ни та ни другая библиотека?
     
  19. Mitrandir

    Mitrandir Гуру

    Пускай совтваре сериал в лупе что нибудь пошлет. Есть переходник usb ttl? Черезнего на softwareserial пошли данные
     
    Kyouma нравится это.
  20. Kyouma

    Kyouma Нерд

    переходников нет. есть шнур к компу и плеер. на этом в общем-то ресурсы кончаются
    вставил в loop строчку
    Код (C++):
    mySoftwareSerial.println(ir_kod, HEX);
    данные отправляются в пустоту, но нам это и не сильно важно, как мне кажется.
    итог: вернулся мусор в основной Serial, данные с пульта некорректны. очевидно проблема в совместном использовании SoftwareSerial.h и IRremote.h. Может они оба используют таймер №2?
    есть какие-то мысли как это исправить?
     
    Последнее редактирование: 14 сен 2018