Вешается Нано при использовании if

ZXoR
Offline
Зарегистрирован: 14.04.2021

Добрый вечер! Рискую разжечь много стульев под старожилами форума, и прослыть недалёким человеком. Но всё же.

В электронике любитель со стажем, а вот программирование недавно начал постигать. Повторял пару готовых проектов на ардуино, все достаточно легко получилось, теперь захотелось сделать своё что-то, поскольку готового один в один проекта под мои нужды нет, решил постепенно собирать свой скетч используя примеры. Проект - это банальный селектор на 4 аудиовхода на реле, с перебиранием входов 1 кнопкой, выводом названия входа на 3 матрицы 8х8+МАХ7219, и в период бездействия выводом спектроанализатора. Код закомментирован мной, что как должно работать построчно  понимаю, алгоритм тоже понимаю. Но Закоментированный if в 80-82 строке вешает ардуино, если его расскоментировать. По моей логике проверяемый там btnflagPush должен отправлять в функцию вывода бегущей строки tape,  она его выводит и сбрасывает флаг, указывая что вывод был, дальше проверяется каждый цикл, флаг поднимается при нажатии кнопки- изменении состояния и tape,  все, дальше должно крутится loop, если условие не выполняется Сам спектроанализатор(код в loop) крутится, в конце проверяется изменение btnflagPush , опрашивается функция кнопки. Вообще подумал, что ардуино издохло, когда оно зависло.

Запаситесь льдом при просмотре моего скетча.!

/*
  Д.КР. Copyright (c) 2021
  Переключение последовательно кнопкой четырех реле, для коммутации входов
  D3-вход кнопки, на землю, подтяжка резистором 10К к плюсу.
  D4, D5, D6, D7 - выходы на реле.
*/
//Общие настройки, библиотеки
#include <SPI.h>                             // Подключаем библиотеку SPI
#include <Adafruit_GFX.h>                    // Подключаем библиотеку Adafruit_GFX
#include <Max72xxPanel.h>                    // Подключаем библиотеку Max72xxPanel
int pinCS = 10;                               // Указываем к какому выводу подключен контакт CS
int numberOfHorizontalDisplays = 1;          // Количество матриц по горизонтали
int numberOfVerticalDisplays = 3;            // Количество матриц по-вертикали

Max72xxPanel matrix = Max72xxPanel(pinCS, numberOfHorizontalDisplays, numberOfVerticalDisplays);







// Настройки для функции вывода бегущей строки  list()
String tape = "";                           // Слово для вывода на матрицу
int wait = 50;                              // интервал, чем меньше тем бытрее бежит строка
int spacer = 1;                             // Промежуток между символами (кол-во точек)
int width = 5 + spacer;                     // Ширина шрифта составляет 5 пикселей
// Конец настроек


// Настройки для функции переключения реле modeChange()
int modeState = 4;          // Переменная, которая указывает номер включенного реле, по умолчанию включается  реле с этим номером сразу при запуске
bool btnflagPush = true;    //  Флаг  что кнопка была нажата
bool btnflag = false;      //  Флаг, который будет помнить состояние кнопки
uint32_t btnTimer = 0;     //  таймер нажатия для антидребезга
// Конец настроек


void setup() {
  // отладка
  Serial.begin(9600);
  
  // Инициализация выводов для
  pinMode(3, INPUT);  // D3 как вход
  pinMode(4, OUTPUT);  // D4 как выход
  pinMode(5, OUTPUT);  // D5 как выход
  pinMode(6, OUTPUT);  // D6 как выход
  pinMode(7, OUTPUT);  // D7 как выход

  digitalWrite(modeState, HIGH); //  высокий сигнал на реле,  по умолчанию включается это реле

  // Начальная инициализация матрицы и вывод приветствия
   matrix.setIntensity(5);                    // Задаем яркость от 0 до 15
  matrix.setRotation(1);                     // Направление текста 1,2,3,4
  tape = utf8rus("Морион Э-103");             // Приветствие 1 раз, возвращается, utf8rus Функцией перекодировки русских букв из UTF-8 в Win-1251
   tape = list(tape);                         // Отправляем на вывод в функцию list
   
   btnflagPush = true;                        //  Флаг  поднимаем, что бы вевести  надпись про вход
 
                      
  


}

void loop() {

  





  
  Serial.println(modeState);  // Для отладки
Serial.println(btnflagPush);  // Для отладки

  modeChange ();                                              // Проверка состояния кнопки и переключение режимов входа
  
  //if (btnflagPush == true) {
    // tape = list(tape);                                       // Проверяем было ли нажатие на кнопку и выводим на матрицу
  //}
}


void modeChange() {

  bool btnState = !digitalRead(3);                            // читаем инвертированное значение для удобства
  if (btnState && !btnflag && millis() - btnTimer > 100) {
    btnflag = true;                                           // Кнопка нажата
    btnTimer = millis();
  }
  if (!btnState && btnflag && millis() - btnTimer > 100) {
    btnflag = false;                                          // Кнопка отпущена
    btnflagPush = true;                                       // Было действие на кнопке
    btnTimer = millis();
    Serial.println("release");// Для отладки
    modeState = modeState + 1;
  }
  {
    switch (modeState) {                                     // Переключаем последовательно выходы D4-D7
      case 4:
        digitalWrite(5, LOW);           //  выключается это реле
        digitalWrite(6, LOW);           //  выключается это реле
        digitalWrite(7, LOW);           //  выключается это реле
        digitalWrite(4, HIGH);          //  высокий сигнал на реле,   включается это реле
        tape = utf8rus("Вход 1");       //  Присваиваем название для вывода на матрицу

        break;
      case 5:
        digitalWrite(4, LOW);           //  выключается это реле
        digitalWrite(6, LOW);           //  выключается это реле
        digitalWrite(7, LOW);           //  выключается это реле
        digitalWrite(5, HIGH);          //  высокий сигнал на реле,   включается это реле
        tape = utf8rus("Вход 2");       //  Присваиваем название для вывода на матрицу

        break;
      case 6:
        digitalWrite(4, LOW);           //  выключается это реле
        digitalWrite(5, LOW);           //  выключается это реле
        digitalWrite(7, LOW);           //  выключается это реле
        digitalWrite(6, HIGH);          //  высокий сигнал на реле,   включается это реле
        tape = utf8rus("Вход 3");       //  Присваиваем название для вывода на матрицу

        break;
      case 7:
        digitalWrite(4, LOW);           //  выключается это реле
        digitalWrite(5, LOW);           //  выключается это реле
        digitalWrite(6, LOW);           //  выключается это реле
        digitalWrite(7, HIGH);          //  высокий сигнал на реле,   включается это реле
        tape = utf8rus("Вход 4");       //  Присваиваем название для вывода на матрицу

        break;
      default:
        modeState = 4;                     // выполнить, если значение не совпадает ни с одним из case
        break;
    }


  }

}
String list(String source) {

  for ( int i = 0 ; i < width * tape.length() + matrix.width() - spacer; i++ )
  {
    matrix.fillScreen(LOW);

    int letter = i / width;                   // номер символа выводимого на матрицу

    int x = (matrix.width() - 1) - i % width;
    int y = (matrix.height() - 8) / 2;         // отцентрировать текст по вертикали

    while ( x + width - spacer >= 0 && letter >= 0 ) {
      if ( letter < tape.length() ) {
        matrix.drawChar(x, y, tape[letter], HIGH, LOW, 1);
      }
      letter--;
      x -= width;
    }
    matrix.write();                       // выведим значения на матрицу
    delay(wait);
   
  }
  btnflagPush = false;    //  Сбрасываем флаг кнопки, поскольку вывели надпись 1 раз
}

/* Функция перекодировки русских букв из UTF-8 в Win-1251 */
String utf8rus(String source)
{
  int i, k;
  String target;
  unsigned char n;
  char m[2] = { '0', '\0' };
  k = source.length(); i = 0;
  while (i < k) {
    n = source[i]; i++;
    if (n >= 0xC0) {
      switch (n) {
        case 0xD0: {
            n = source[i]; i++;
            if (n == 0x81) {
              n = 0xA8;
              break;
            }
            if (n >= 0x90 && n <= 0xBF) n = n + 0x2F;
            break;
          }
        case 0xD1: {
            n = source[i]; i++;
            if (n == 0x91) {
              n = 0xB7;
              break;
            }
            if (n >= 0x80 && n <= 0x8F) n = n + 0x6F;
            break;
          }
      }
    }
    m[0] = n; target = target + String(m);
  }
  return target;
}

 

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

А-я-яй, молодой человек! Нехорошо дедушек обманывать!

В 81 строке Вы чего пишете? А в п/п list() где return?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

ZXoR пишет:
Вешается Нано при использовании if

Я бы от такого тоже повесился.

Функция list не возвращает ничего. Вы это ничего присваиваете переменной tape, а потом в наглую используете, как если бы это было не ничего, а прямо-таки строка "

Ну, и кто ты сможет не повеситься?

ZXoR
Offline
Зарегистрирован: 14.04.2021

 

mykaida пишет:

А-я-яй, молодой человек! Нехорошо дедушек обманывать!

В 81 строке Вы чего пишете? А в п/п list() где return?

ЕвгенийП пишет:

ZXoR пишет:
Вешается Нано при использовании if

Я бы от такого тоже повесился.

Функция list не возвращает ничего. Вы это ничего присваиваете переменной tape, а потом в наглую используете, как если бы это было не ничего, а прямо-таки строка "

Ну, и кто ты сможет не повеситься?

 

А как правильно передать тогда аргумент в функцию? list(tape);  ? Если в 81 и до кучи уж в 56 так написать, то всё равно виснет на  втором нажатии, вход1 при запуске пишет, клик кнопкой вход 2 и висяк. Может дело в синтаксисе, чего то простого не догоняю? или переполнение чего то? Но ведь без if , если просто тупо в луп выводить на матрицу значение тейп (постоянно  пишет какой вход) можно кнопкой щелкать по кругу режимы(ну если момент поймать когда лист возвращается.) 

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

ZXoR пишет:

А как правильно передать тогда аргумент в функцию?

Вы правильно передаёте аргумент (если не считать необоснованного расхода памяти, но если памяти хватает, то и хрен с ним).

Ваша проблема не в передаче аргумента, а в том, что Ваша функция НЕ возвращает никакого значения

ZXoR
Offline
Зарегистрирован: 14.04.2021

ЕвгенийП пишет:

Вы правильно передаёте аргумент (если не считать необоснованного расхода памяти, но если памяти хватает, то и хрен с ним).

Ваша проблема не в передаче аргумента, а в том, что Ваша функция НЕ возвращает никакого значения

Спасибо, но еще вас помучаю. 

Смотрите, я передаю в функцию list глобальную переменную tape, функция выводит её на матрицу, заканчивает вывод, возвращается в loop, в то место откуда она вызвалась по условию. Она не меняет tape. Что она должна возвратить, ничего? Пусть в моем первом посте коряво написано tape = list(tape); Ставим list(tape); так же виснет ардуинка. Флаг, который в конце вывода list сбрасывается в false, указывает, что вывод был, и поднимается только после нажатия кнопки. Всё правильно?

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

155 строка у меня вызывает сомнение. tape.length()

Выведите-ка это в ком-порт

v258
v258 аватар
Offline
Зарегистрирован: 25.05.2020

ZXoR пишет:

Она не меняет tape. Что она должна возвратить, ничего? 

Тогда зачем вы пишите tape = list(tape) ?

ZXoR пишет:

так же виснет ардуинка. Флаг, который в конце вывода list сбрасывается в false, указывает, что вывод был, и поднимается только после нажатия кнопки. Всё правильно?

В чем выражается зависание?

Alexey_Rem
Offline
Зарегистрирован: 09.09.2019

Я дико извиняюсь, но где-то читал что во избежание ошибок компиляции лучше организовать прогу так что бы была с начала описана функция а потом следовал ее вызов 

v258
v258 аватар
Offline
Зарегистрирован: 25.05.2020

Alexey_Rem пишет:

Я дико извиняюсь, но где-то читал что во избежание ошибок компиляции лучше организовать прогу так что бы была с начала описана функция а потом следовал ее вызов 

При чем здесь это? Если функция ничего не возвращает, зачем присваивать переменной значение этой функции?

ZXoR
Offline
Зарегистрирован: 14.04.2021

mykaida пишет:

155 строка у меня вызывает сомнение. tape.length()

Выведите-ка это в ком-порт

Это длина слова переменной тейп, к библиотеке Adafruit_GFX относится

v258
v258 аватар
Offline
Зарегистрирован: 25.05.2020

Ну и какова длина этой переменной после присвоения ей значения "ничто"?

ZXoR
Offline
Зарегистрирован: 14.04.2021

v258 пишет:

 

Тогда зачем вы пишите tape = list(tape) ?

 

В чем выражается зависание?

Чуть исправился на list(tape);

Перестает ардуинка реагировать на кнопку, не выводит ничего на монитор порта. ресет только.

 

v258
v258 аватар
Offline
Зарегистрирован: 25.05.2020

ZXoR пишет:

v258 пишет:

 

Тогда зачем вы пишите tape = list(tape) ?

 

В чем выражается зависание?

Чуть исправился на list(tape);

Перестает ардуинка реагировать на кнопку, не выводит ничего на монитор порта. ресет только.

 

А вы везде исправили? У вас же эта функция не в одном месте вызывается

Kakmyc
Offline
Зарегистрирован: 15.01.2018

Есть такая штука, как монитор порта.
Что мешает прописать вывод в этот самый монитор, на каждом шаге программы ?

ЗЫ: неясна работа в цикле while, я бы там покопал.

ZXoR
Offline
Зарегистрирован: 14.04.2021

да 56 и 81 строка 

Не могу понять, если убрать это в 81 строке, то опрос кнопки, присвоение тейп значения, корректно, если убрать if, оставить list(tape); тоже корректно входы переключаются, но на постоянку выводится  название тейп Может еще в условии нужно что учитывать, не только флаг  btnflagPush = true; // Было действие на кнопке 95 строка?

list(tape);  тоже норм
if (btnflagPush == true) {
    list(tape);                                       // Проверяем было ли нажатие на кнопку и выводим на матрицу
  }

 

ZXoR
Offline
Зарегистрирован: 14.04.2021

Kakmyc пишет:
Есть такая штука, как монитор порта. Что мешает прописать вывод в этот самый монитор, на каждом шаге программы ? ЗЫ: неясна работа в цикле while, я бы там покопал.
 

Если вы про функцию list(), то это взято отсюда, только выделил в функцию, поскольку она не часто нужна. 

 

v258
v258 аватар
Offline
Зарегистрирован: 25.05.2020

ZXoR пишет:

да 56 и 81 строка 

Не могу понять, если убрать это в 81 строке, то опрос кнопки, присвоение тейп значения, корректно

Если корректно, то в чем проблема?

ZXoR пишет:

если убрать if, оставить list(tape); тоже корректно входы переключаются, но на постоянку выводится  название тейп 

Это естественно, по другому и быть не может. Зачем убирать if ?

ZXoR
Offline
Зарегистрирован: 14.04.2021

v258 пишет:

Это естественно, по другому и быть не может. Зачем убирать if ?

С if работать перестаёт. Это условия, по моему мнению, должно работать для однократной отправки tape для вывода на матрицу,  проверяемый там btnflagPush должен отправлять в функцию вывода бегущей строки tape,  она его выводит и сбрасывает флаг, указывая что вывод был, дальше проверяется каждый цикл, флаг поднимается при нажатии кнопки- изменении состояния и tape,  все, дальше должно крутится loop, пока снова флаг не поднимется. А вот с if виснет и не меняется modeState (32 и 98 строка), т соотв tape 

Возможно, у меня тупой обработчик кнопки, и с этим связано зависание. Всё равно спасибо всем за участие !

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

ZXoR пишет:
Она не меняет tape.

А выражение tape = list(tape);- меняет. Присваивает tape то, что вернула функция. Всё, с этого момента tape угроблена.

ZXoR пишет:

Ставим list(tape); так же виснет ардуинка

Я не видел этого кода, потому ничего сказать не могу. Вы же этот вариант засекретили.

Кстати, если эта tape глобальна, НАФИГА Вы передаёте её копию? И вообще, Вы в utf8rus копии строк передайте. Вам память девать некуда?

ZXoR
Offline
Зарегистрирован: 14.04.2021

ЕвгенийП пишет:

А выражение tape = list(tape);- меняет. Присваивает tape то, что вернула функция. Всё, с этого момента tape угроблена.

Я не видел этого кода, потому ничего сказать не могу. Вы же этот вариант засекретили.

Кстати, если эта tape глобальна, НАФИГА Вы передаёте её копию? И вообще, Вы в utf8rus копии строк передайте. Вам память девать некуда?

Спасибо за критику! Памяти хватает для этого применения, я только в самой нулевой точке в ардуино. Более опытный человек, напишет лучше, я не сомневаюсь.

Ошибка моя была в неправильном типе данных, при названии функции String list(String source), при замене на void все заработало как надо. Ниже приведу нынешний скетч, работает как задумано, есть микрокосяк с переключателем с последнего режима на первый,  но реально это не мешает.

Еще раз всем спасибо за участие!

 

/*
  Д.КР. Copyright (c) 2021
  Переключение последовательно кнопкой четырех реле, для коммутации входов
  D3-вход кнопки, на землю, подтяжка резистором 10К к плюсу.
  D4, D5, D6, D7 - выходы на реле.
*/
//Общие настройки, библиотеки
#include <SPI.h>                             // Подключаем библиотеку SPI
#include <Adafruit_GFX.h>                    // Подключаем библиотеку Adafruit_GFX
#include <Max72xxPanel.h>                    // Подключаем библиотеку Max72xxPanel
int pinCS = 10;                               // Указываем к какому выводу подключен контакт CS
int numberOfHorizontalDisplays = 1;          // Количество матриц по горизонтали
int numberOfVerticalDisplays = 3;            // Количество матриц по-вертикали

Max72xxPanel matrix = Max72xxPanel(pinCS, numberOfHorizontalDisplays, numberOfVerticalDisplays);







// Настройки для функции вывода бегущей строки  list()
String tape = "";                           // Слово для вывода на матрицу
int wait = 40;                              // интервал, чем меньше тем бытрее бежит строка
int spacer = 1;                             // Промежуток между символами (кол-во точек)
int width = 5 + spacer;                     // Ширина шрифта составляет 5 пикселей
// Конец настроек


// Настройки для функции переключения реле modeChange()
int modeState = 4;          // Переменная, которая указывает номер включенного реле, по умолчанию включается  реле с этим номером сразу при запуске
bool btnflagPush = true;    //  Флаг  что кнопка была нажата
bool btnflag = false;      //  Флаг, который будет помнить состояние кнопки
uint32_t btnTimer = 0;     //  таймер нажатия для антидребезга
// Конец настроек


void setup() {
  // отладка
  Serial.begin(9600);

  // Инициализация выводов для
  pinMode(3, INPUT);  // D3 как вход
  pinMode(4, OUTPUT);  // D4 как выход
  pinMode(5, OUTPUT);  // D5 как выход
  pinMode(6, OUTPUT);  // D6 как выход
  pinMode(7, OUTPUT);  // D7 как выход

  digitalWrite(modeState, HIGH); //  высокий сигнал на реле,  по умолчанию включается это реле

  // Начальная инициализация матрицы и вывод приветствия
  matrix.setIntensity(5);                     // Задаем яркость от 0 до 15
  matrix.setRotation(1);                       // Направление текста 1,2,3,4
  tape = utf8rus("Морион Э-103");             // Приветствие 1 раз, возвращается, utf8rus Функцией перекодировки русских букв из UTF-8 в Win-1251
  list(tape);                                 // Отправляем на вывод в функцию list

}

void loop() {


  Serial.println(modeState);  // Для отладки
  Serial.println(btnflagPush);  // Для отладки

  modeChange ();                                              // Проверка состояния кнопки и переключение режимов входа

  if (btnflagPush == true) {
    list(tape);                                               // Проверяем было ли нажатие на кнопку и выводим на матрицу
    btnflagPush = false;                                      //  Сбрасываем флаг кнопки, поскольку вывели надпись 1 раз
  }
}


void modeChange() {

  bool btnState = !digitalRead(3);                            // читаем инвертированное значение для удобства
  if (btnState && !btnflag && millis() - btnTimer > 100) {
    btnflag = true;                                           // Кнопка нажата
    btnTimer = millis();
  }
  if (!btnState && btnflag && millis() - btnTimer > 100) {
    btnflag = false;                                          // Кнопка отпущена
    btnflagPush = true;                                       // Было действие на кнопке
    btnTimer = millis();
    Serial.println("release");// Для отладки
    modeState = modeState + 1;

  }
  {
    switch (modeState) {                                     // Переключаем последовательно выходы D4-D7
      case 4:
        digitalWrite(5, LOW);           //  выключается это реле
        digitalWrite(6, LOW);           //  выключается это реле
        digitalWrite(7, LOW);           //  выключается это реле
        digitalWrite(4, HIGH);          //  высокий сигнал на реле,   включается это реле
        tape = utf8rus("Вход 1");       //  Присваиваем название для вывода на матрицу
        break;
        
      case 5:
        digitalWrite(4, LOW);           //  выключается это реле
        digitalWrite(6, LOW);           //  выключается это реле
        digitalWrite(7, LOW);           //  выключается это реле
        digitalWrite(5, HIGH);          //  высокий сигнал на реле,   включается это реле
        tape = utf8rus("Вход 2");       //  Присваиваем название для вывода на матрицу
        break;
        
      case 6:
        digitalWrite(4, LOW);           //  выключается это реле
        digitalWrite(5, LOW);           //  выключается это реле
        digitalWrite(7, LOW);           //  выключается это реле
        digitalWrite(6, HIGH);          //  высокий сигнал на реле,   включается это реле
        tape = utf8rus("Вход 3");       //  Присваиваем название для вывода на матрицу
        break;
        
      case 7:
        digitalWrite(4, LOW);           //  выключается это реле
        digitalWrite(5, LOW);           //  выключается это реле
        digitalWrite(6, LOW);           //  выключается это реле
        digitalWrite(7, HIGH);          //  высокий сигнал на реле,   включается это реле
        tape = utf8rus("Вход 4");       //  Присваиваем название для вывода на матрицу
        break;
        
      default:
        modeState = 4;                   // выполнить, если значение не совпадает ни с одним из case
        tape = utf8rus("Вход 1");        // Присваиваем название для вывода на матрицу, иначе накладка с названием
        break;
    }
  }
}
void list(String source) {

  for ( int i = 0 ; i < width * tape.length() + matrix.width() - spacer; i++ )
  {
    matrix.fillScreen(LOW);

    int letter = i / width;                     // номер символа выводимого на матрицу

    int x = (matrix.width() - 1) - i % width;
    int y = (matrix.height() - 8) / 2;         // отцентрировать текст по вертикали

    while ( x + width - spacer >= 0 && letter >= 0 ) {
      if ( letter < tape.length() ) {
        matrix.drawChar(x, y, tape[letter], HIGH, LOW, 1);
      }
      letter--;
      x -= width;
    }
    matrix.write();                           // выведим значения на матрицу
    delay(wait);
  }
}

/* Функция перекодировки русских букв из UTF-8 в Win-1251 */
String utf8rus(String source)
{
  int i, k;
  String target;
  unsigned char n;
  char m[2] = { '0', '\0' };
  k = source.length(); i = 0;
  while (i < k) {
    n = source[i]; i++;
    if (n >= 0xC0) {
      switch (n) {
        case 0xD0: {
            n = source[i]; i++;
            if (n == 0x81) {
              n = 0xA8;
              break;
            }
            if (n >= 0x90 && n <= 0xBF) n = n + 0x2F;
            break;
          }
        case 0xD1: {
            n = source[i]; i++;
            if (n == 0x91) {
              n = 0xB7;
              break;
            }
            if (n >= 0x80 && n <= 0x8F) n = n + 0x6F;
            break;
          }
      }
    }
    m[0] = n; target = target + String(m);
  }
  return target;
}

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

ZXoR пишет:
при замене на void все заработало как надо
Вот и отлично! Именно про это Вам вчера говорил mykaida, а потом и я. Функция ничего не возвращает и как только Вы описали, что она ничего не возвращает (void означает именно это) и поправили сопутствующие вещи, всё и наладилось.