Как прервать бегущую строку led tm1637 по прерыванию?

Тема в разделе "Arduino & Shields", создана пользователем Дятел, 7 май 2021.

  1. Дятел

    Дятел Нерд

    Вопрос к знатокам прерываний
    На 4-х разрядный модуль дисплея TM1637
    вывожу бегущую строку:

    byte buf[] = { _P,_E,_n,_A ,0, _P,_r,_E,_S,_S,0, _S,_t,_A,_r,_t};

    disp.runningString(buf, sizeof(buf), 500); // время в мс

    Делаю прерывание по срабатыванию на нажатие кнопки
    attachInterrupt(0, buttonTick, FALLING);

    Все отрабатывает, но есть нюанс, который меня не устраивает:
    вызов функции запуска программы после нажатия кнопки происходит только по финалу прокрутки строки, а мне надо НЕМЕДЛЕННО.
    Как закончить выполнение текущей функции, кода, операции при возникновения прерывания.
    То же кстати касается и если прерывание возникло при выполнение какого-то кода. Прерывание будет зафиксировано, но использовано будет только в порядке очередности выполнения программы.
    Как запускать процессы немедленно? процессы длительные. например 1-2 минуты
     
  2. akl

    akl Гуру

    функция или код должны постоянно проверять например некую переменную и если оная (в прерывании) была изменена - заканчивать свое выполнение.

    или если по-умному - делать код полностью асинхронным
     
  3. Рокки1945

    Рокки1945 Гуру

    да только не забудьТЕ этой переменной значение вернуть - перед тем как брикнуться из функции
     
  4. Дятел

    Дятел Нерд

    как это сделать в функции runningString?
    простите, про асинхронным не понял
    честно сказать вас не понял.
    по прерыванию меняю значение некой переменной
    volatile byte f = 0;
    по прерыванию ставлю
    f = 1;
    вы про это, или подобное?
     
  5. Рокки1945

    Рокки1945 Гуру

    Псевдо - в обработчике меняете состояние флаг на 1
    В функции постоянно в if проверяете состояние этого флага - если он 1 то ставите ему 0 и break;
    флагу надо 0 при выходе чтобы зайдя в бегущую функцию сразу не выйти.
    Там ещё есть способы...
     
  6. Дятел

    Дятел Нерд

    спасибо, но тут то все понятно.
    а вот как прервать выполнение

    byte buf[] = { _P,_E,_n,_A ,0, _P,_r,_E,_S,_S,0, _S,_t,_A,_r,_t};
    disp.runningString(buf, sizeof(buf), 500); // время в мс
     
  7. Рокки1945

    Рокки1945 Гуру

    millis - наверное
    Upd - а разве нельзя в скобки засунуть if - ?
     
  8. Дятел

    Дятел Нерд

    запутали окончательно :)
    А куда millis то пришить в данном случае?

    можно поконкретнее, куда именно?
     
    Последнее редактирование: 7 май 2021
  9. akl

    akl Гуру

    выложи код целиком и чтобы в том числе было видно что за библиотека используется
     
  10. Дятел

    Дятел Нерд

    код у меня - куча проб, вряд ли наглядно будет.
    набросал короткий вариант, для наглядности
    плата, ардуино нано

    Код (C++):
    #define CLK 5
    #define DIO 4
    #include "TM1637.h"
    TM1637 disp(CLK, DIO);

    volatile byte f = 0;
    int led = 13;//светодиод на плате


    void setup()
    {
      // подключили кнопку на D2 и GND
      pinMode(2, INPUT_PULLUP); \
      // D2 это прерывание 0
      // обработчик - функция buttonTick
      // FALLING - при нажатии на кнопку будет сигнал 0, его и ловим
      attachInterrupt(0, buttonTick, FALLING);

      pinMode(led, OUTPUT);//светодиод на плате
      digitalWrite(led, LOW); // turn the LED off by making the voltage LOW

      disp.clear();
      disp.brightness(7);  // яркость минимум =0, стандарт=2,  максимум=7)

    }

    void buttonTick() {
    f = 1;  // + нажатие
    digitalWrite(led, HIGH); //зажигаю светодиод на плате
    }

    void loop()
    {



          if ( f==1){ //кнопка старт была нажата

    //запускает функцию таймера. ее не привожу для простоты
          }else{
    // в режиме ожидания гоняет текст на дисплее
    byte buf[] = { _P,_E,_n,_A ,0, _P,_r,_E,_S,_S,0,_S,_t,_A,_r,_t };
    disp.runningString(buf, sizeof(buf), 500);


          }//END IF кнопка старт была нажата




    }//end loop
     
     
  11. akl

    akl Гуру

    чет не нашел в библиотеке TM1637.h функции runningstring. в гайверовской аналогичной есть. предположим что это то же самое

    попробуй вот это

    Код (C++):
    #define CLK 5
    #define DIO 4
    #include "TM1637.h"
    TM1637 disp(CLK, DIO);

    volatile byte f = 0;
    int led = 13;//сетодиод на плате


    void setup()
    {
      // подключили кнопку на D2 и GND
      pinMode(2, INPUT_PULLUP); \
      // D2 это прерывание 0
      // обработчик - функция buttonTick
      // FALLING - при нажатии на кнопку будет сигнал 0, его и ловим
      attachInterrupt(0, buttonTick, FALLING);

      pinMode(led, OUTPUT);//светодиод на плате
      digitalWrite(led, LOW); // turn the LED off by making the voltage LOW

      disp.clear();
      disp.brightness(7);  // яркость минимум =0, стандарт=2,  максимум=7)

    }

    void buttonTick() {
    f = 1;  // + нажатие
    digitalWrite(led, HIGH); //зажигаю светодиод на плате
    }

    void loop()
    {



          if ( f==1){ //кнопка старт была нажата

    //запускает функцию таймера. ее не привожу для простоты
          }else{
    // в режиме ожидания гоняет текст на дисплее
    byte buf[] = { _P,_E,_n,_A ,0, _P,_r,_E,_S,_S,0,_S,_t,_A,_r,_t };
    runningString(buf, sizeof(buf), 500, &f);


          }//END IF кнопка старт была нажата




    }//end loop


    void runningString(uint8_t DispData[], byte amount, int delayMs, uint8_t* interrupt_flag) {
        uint8_t segm_data[amount + 8]; // оставляем место для 4х пустых слотов в начале и в конце
        for (byte i = 0; i < 4; i++) { // делаем первые 4 символа пустыми
           segm_data[i] = 0x00;
        }
        for (byte i = 0; i < amount; i++) { // далее забиваем тем что на входе (сам текст строки)
           segm_data[i + 4] = DispData[i];
        }
        for (byte i = amount + 4; i < amount + 8; i++) { // и последние 4 тоже забиваем пустыми символами
          segm_data[i] = 0x00;
        }
        for (byte i = 0; i <= amount + 4; i++) { // выводим
           disp.displayByte(segm_data[i], segm_data[i + 1], segm_data[i + 2], segm_data[i + 3]);
           int i=delayMs;
           while(i>0){
               delay(1);
               i--;
               if(*interrupt_flag){break;}
           }
           if(*interrupt_flag){break;}
        }
    }

    поправил - делать *interrupt_flag=0; не надо, т.к. это переменная f - она должна остаться 1 чтобы запустить таймер или че там.

    и конечно, в этой функции должно быть disp.displayByte
     
    Последнее редактирование: 7 май 2021
    Дятел нравится это.
  12. Дятел

    Дятел Нерд

    да, как оказалось, вроде гайверовская или на его основе:
    #######################################
    # Syntax Coloring Map For GyverTM1637
    #######################################
    формально, вы просто вместо библиотеки выводите строку бегущую "своей" функцией, и при наличии прерывания останавливаете ее.
    Правильно?
    Спасибо,
    правда такой вариант я уже обдумывал, и, даже хотел в библиотеке подправить под себя.
    То есть, я ошибался в главном, и оказывается, что прерывания не могут ничего прерывать сами по себе, они могут только поймать сигнал (от кнопки например) и сформировать флаг, который можно использовать в своем коде.
    Прерывания отличаются от обычного чтения порта только тем, что делают проверку намного чаще и при любых условиях.
    Так?

    Спасибо большое за код и за труды :)
     
  13. akl

    akl Гуру

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

    если код асинхронный (то есть "без delay()), и нет необходимости отслеживать события с особо высокой скоростью и гарантированностью - то можно обойтись и без прерываний

    прерывания не остлеживают порт чаще или реже - они просто позволяют гарантированно фиксировать событие на этом проту (или в других местах, есть разные прерывания). но тут же отреагировать на событие можно только в пределах функции-обработчика, повлиять на другие функции можно опосредованно
     
    Последнее редактирование: 7 май 2021
    Дятел нравится это.
  14. Дятел

    Дятел Нерд

    спасибо. помогли разобраться :)
     
  15. Дятел

    Дятел Нерд

    спасибо за уточнение :)
     
  16. Дятел

    Дятел Нерд

    спасибо. решил воспользоваться вашим кодом.
    в нем надо поправить небольшую ошибку. Вы повторно объявляете переменную i
    в этой строке: int ix=delayMs;

    Код (C++):
    #define CLK 5
    #define DIO 4
    #include "TM1637.h"
    TM1637 disp(CLK, DIO);

    volatile byte f = 0;
    int led = 13;//сетодиод на плате


    void setup()
    {
      // подключили кнопку на D2 и GND
      pinMode(2, INPUT_PULLUP); \
      // D2 это прерывание 0
      // обработчик - функция buttonTick
      // FALLING - при нажатии на кнопку будет сигнал 0, его и ловим
      attachInterrupt(0, buttonTick, FALLING);

      pinMode(led, OUTPUT);//светодиод на плате
      digitalWrite(led, LOW); // turn the LED off by making the voltage LOW

      disp.clear();
      disp.brightness(7);  // яркость минимум =0, стандарт=2,  максимум=7)

    }

    void buttonTick() {
    f = 1;  // + нажатие
    digitalWrite(led, HIGH); //зажигаю светодиод на плате
    }

    void loop()
    {



          if ( f==1){ //кнопка старт была нажата
    disp.clear();
    //запускает функцию таймера. ее не привожу для простоты
          }else{
    // в режиме ожидания гоняет текст на дисплее
    byte buf[] = { _P,_E,_n,_A ,0, _P,_r,_E,_S,_S,0,_S,_t,_A,_r,_t };
    runningString(buf, sizeof(buf), 500, &f);


          }//END IF кнопка старт была нажата




    }//end loop


    void runningString(uint8_t DispData[], byte amount, int delayMs, uint8_t* interrupt_flag) {
        uint8_t segm_data[amount + 8]; // оставляем место для 4х пустых слотов в начале и в конце
        for (byte i = 0; i < 4; i++) { // делаем первые 4 символа пустыми
           segm_data[i] = 0x00;
        }
        for (byte i = 0; i < amount; i++) { // далее забиваем тем что на входе (сам текст строки)
           segm_data[i + 4] = DispData[i];
        }
        for (byte i = amount + 4; i < amount + 8; i++) { // и последние 4 тоже забиваем пустыми символами
          segm_data[i] = 0x00;
        }
        for (byte i = 0; i <= amount + 4; i++) { // выводим
           disp.displayByte(segm_data[i], segm_data[i + 1], segm_data[i + 2], segm_data[i + 3]);
           int ix=delayMs;
           while(ix>0){
               delay(1);
               ix--;
               if(*interrupt_flag){break;}
           }
           if(*interrupt_flag){break;}
        }
    }
    Выше рабочий вариант, если несложно подправьте свой пост, а то кто-то скопирует, если неопытный, начнутся вопросы :)
    Ну и еще добавил очистку экрана, а то последнее что было на экране застывает.
    disp.clear();

    честно говоря, не понял вашу мысль.
    как пользоваться disp.displayByte понятно, но к чему вы это, не понял, поясните, вдруг чего-то интересное упускаю :)
    disp.displayByte(0, _P);
     
  17. akl

    akl Гуру

    там можно ваще вот так
    while(delayMs>0)
    {
    delayMs--;
    а нет так нельзя в этой функции, если б один раз надо было отсчитать тогда можно было бы

    про disp.displayByte к тому, что у меня там было просто displayByte как в библиотечной фенкции, потом исправил

    чтобы нормально сделать советую почитать про конечные автоматы http://wiki.amperka.ru/программирование:конечный-автомат
     
    Последнее редактирование: 8 май 2021