проблема задержки() для 74HC595 и 7-сегмента

Я пытаюсь запустить 3-значный 7-сегмент с использованием одного 74HC595 на основе Arduino. Но у меня есть серьезная проблема с функцией delay (). Когда я хочу считать от 000 до 999 с задержкой(1000), эта функция задержки приводит к тому, что все цифры отключаются! Мой код, как показано ниже, и я загрузил видео Нажмите здесь, чтобы понять свою цель. Эта проблема может повлиять на некоторые приложения, такие как чтение температуры DS12b20, которое требует задержки.

//                 2        1         0       
//               ----      ----      ----    
//              |    |    |    |    |    |
//               ----      ----      ----
//              |    |    |    |    |    |
//               ----      ----      ----

int latch = 8; //74HC595  pin STCP
int clock = 9; //74HC595  pin SHCP
int data = 10; //74HC595  pin DS

// Каждый контакт (для тех, кто не знает, думайте о нем как о переключателе, когда он назначен ВЫСОКИМ)
int dig1 = 2; // digit0
int dig2 = 3; // digit1
int dig3 = 4; // digit2
int digit[4]={dig1, dig2, dig3};

int timer=3;
// это биты, чтобы сделать 8-битный байт, принятый сегментным дисплеем, 9-й-демическая точка
// 0-9 затем invald numbers
byte table[] = {
  B00111111, B00000110, B01011011, B01001111, B01100110,
  B01101101, B01111101, B00000111, B01111111, B01101111, B01111111
};

void setup(){
  pinMode(latch, OUTPUT);
  pinMode(clock, OUTPUT);
  pinMode(data, OUTPUT);
  pinMode(dig1, OUTPUT);
  pinMode(dig2, OUTPUT);
  pinMode(dig3, OUTPUT);
}

//this sends the data to the digit
void RunNum(int num, int SelectDigit){
  digitalWrite(latch, LOW);
  shiftOut(data, clock, MSBFIRST, table[num]);
  digitalWrite(latch, HIGH);
  digitalWrite(digit[SelectDigit], LOW);
  delay(timer);
  digitalWrite(digit[SelectDigit], HIGH);
  
}


//main program
void loop() {
  for (int i=0; i<10; i++){
    for (int j=0; j<10; j++){
      for (int k=0; k<10; k++){
        RunNum(k, 0);
        RunNum(j, 1);
        RunNum(i, 2);
        delay(1000);  //  <====    This line affects the project
      }
    }
  }
}

Я обновил свой код (только void loop ()), как показано ниже, используя millis(). Вы можете посмотреть результаты (Нажмите здесь). Но проблема задержки до сих пор не решена!

const long interval = 1000;   //  1000 ms = 1 s
long previousMillis = 0; 
unsigned long currentMillis=0;

//main program
void loop() {
  for (int i=0; i<10; i++){
    for (int j=0; j<10; j++){
      for (int k=0; k<10; k++){
        while (currentMillis - previousMillis < interval){
          currentMillis=millis();
          RunNum(k, 0);
          RunNum(j, 1);
          RunNum(i, 2);
        }
        previousMillis = currentMillis;
      }
    }
  }
}

, 👍0

Обсуждение

Так что не используйте ' delay ()'. Чтобы делать синхронизированные вещи, вам нужно изучить неблокирующий стиль кодирования, как в примере "BlinkWithoutDelay` с помощью" millis ()". Посмотрите пример и на учебники о millis(). Когда вы полностью поймете их, вы сможете заменить задержку неблокирующим кодом, @chrisl

Спасибо @christl. Я уже использовал функцию "millis()". Но это полезно для цифрового счета только как для создания цифровых часов. Это слишком плохо для других приложений, таких как температура DS18b20., @soheil

@soheil О чем ты говоришь? Я не понимаю, почему millis()должно быть слишком плохо, чтобы использовать здесь. delay() также просто использует millis()в фоновом режиме. И я также не вижу, как это должно повлиять на измерение температуры. Это абсолютно правильный путь для обработки задержки 1s там., @chrisl

@chrisl, это хороший вопрос. Предположим, что у вас есть датчик температуры DS18B20. Время отклика датчика составляет около 0,5 с (может достигать 0,75 с). Если вы хотите отобразить его с помощью 74HC595, то в течение этого времени (точно так же, как задержка) 7-сегменты выключаются! и после этого они включаются для отображения температуры. Это выглядит как прошивка (внимательно посмотрите загруженное видео). Некоторые чипы, такие как MAX7219, не прерывают вывод, когда у них нет ввода (они запускают предыдущие команды), в то время как кажется, что 74HC595 постоянно нуждается в командах, чтобы поддерживать его выход активным., @soheil

@soheil Итак, ваша проблема с датчиком температуры. Тогда вам нужно показать код, который действительно использует ваш датчик температуры. В настоящее время вы спрашиваете о задержке 1s, на которую Юрай дал подходящий ответ. Мы можем только понять, как это может сговориться с датчиком температуры, когда мы видим код датчика температуры., @chrisl

74HC595 не нуждается в постоянных командах. Если вы перестанете передавать ему данные, он сохранит текущее состояние выходных данных. Хотя, поскольку вы повторно используете одни и те же пины для всех трех цифр, вам нужно постоянно предоставлять подходящие данные для каждой цифры. Это свойство не сдвигового регистра, а вашей схемы, которая образует матрицу, @chrisl

Если используемая вами библиотека датчиков 74HC595 имеет функции задержки() более чем на несколько миллисекунд, вам придется изменить свою библиотечную функцию, считывающую датчик температуры, чтобы она не блокировалась. (следуя модели blinkWithoutDelay.), @Duncan C

Либо это, либо вам нужно будет повторно подключить дисплей, чтобы зафиксировать все 3 цифры сразу и сохранить весь дисплей освещенным сразу, или использовать драйвер дисплея, который может автоматически передавать все 3 цифры по мультиплексу для вас. Например, можно использовать MAX7221. Вы бы подавали цифры, необходимые для отображения с помощью последовательного интерфейса, а затем считывали новое значение с датчика температуры и подавали новое значение драйверу дисплея. Драйвер дисплея будет продолжать отображать старое значение до тех пор, пока не будет отправлено новое значение., @Duncan C

@christl Большое спасибо. Но датчик температуры-это только один пример, который требует задержки. Задержка в моем коде имитирует возникшую проблему такого использования. Я могу просто сказать, что **как избежать мигания при отображении чисел в таких приложениях?**, @soheil

@chrisl. Я думаю, что одна из причин заключается в том, что в моем коде: сначала он должен активировать первую цифру и отображать ее номер, а затем неактивировать ее и активировать вторую цифру и отображать ее номер, а затем неактивировать ее и так далее. Этот процесс должен непрерывно выполняться, чтобы показать все номера без мигания. Но любая задержка (может быть более 20 мс) останавливает этот процесс (конечно, для наших глаз) и вызывает мигание на дисплее. Как вы думаете?, @soheil

Спасибо @Duncan-C. Задержка для отправки и получения данных может составлять до 750 мс. MAX7219 и MAX7221 отлично подходят. Ваша идея-перемотка. Как?, @soheil

Удалите 74HC595 из вашего проекта и замените его на Max7221. 7221 способен управлять до 8 7-сегментными символами (плюс десятичные знаки, в общей сложности 8 сегментов на символ). Он управляется последовательным интерфейсом, поэтому вы посылаете ему команды для отображения значений. Быстрый поиск в Google показывает библиотеки Arduino для его использования., @Duncan C


2 ответа


3

С дисплеями, которые используют регистр сдвига для освещения нескольких семисегментных цифровых блоков, регистр загорается только одна цифра за раз. Иллюзия зажжения нескольких цифр создается быстрым переключением цифр в раунде. Небольшие задержки при этом приводят к тому, что число выглядит тусклым, большие задержки создают мерцание, а длинные задержки показывают, что горит только одна цифра. Таким образом, скетч, обрабатывающий этот тип отображения, должен работать без задержек.

В этом типе скетча все должно быть обработано без задержек, поэтому, если какой-то датчик требует задержки, начните чтение и таймер millis и по прошествии времени прочитайте результат.

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


принятие базового примера BlinkWithoutDelay для вашего алгоритма:

unsigned long previousMillis = 0;
const long interval = 1000;
int i, j, k;

void setup() {
  Serial.begin(115200);
}

void loop() {
  unsigned long currentMillis = millis();

  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;
    k++;
    if ( k == 10) {
      k = 0;
      j++;
      if (j == 10) {
        j = 0;
        i++;
        if (i == 10) {
          i = 0;
        }
      }
    }
    Serial.print(i);
    Serial.print(j);
    Serial.println(k);
  }
}
,

Огромное спасибо. Но **это не правильный ответ!** Я уже пробовал. Пожалуйста, внимательно прочитайте вопрос., @soheil

Просто обратите внимание, что в представленном коде нет ни одного температурного датчика или библиотеки, включенной для него. На поставленный вопрос это правильный ответ. Если есть какая-то проблема, когда ваш датчик температуры считывает слишком много времени, то это отдельная проблема. Это не то же самое, что иметь задержку в вашем коде. Вместо того чтобы пытаться кодировать примерно в это время, исправьте библиотеку для датчика, чтобы это не заняло так много времени., @Delta_G

"delay()` просто имитирует требуемую задержку таких датчиков. В реальных приложениях эта задержка вызывает мигание на дисплее., @soheil

@soheil, я улучшил ответ, @Juraj

Спасибо. Я думаю, что замена чипа-лучшая идея. Я даже использовал два 74HC595 в сочетании с ULN2803. Но его результат оказался наихудшим. На самом деле, некоторые сегменты неактивной цифры были немного яркими!!!!!! 74HC595 не может справиться с " задержкой ()"., @soheil

Использование millis() подходит для цифровых часов, таймера,..., @soheil

@soheil, с миллисом мы проводим хронометражные мероприятия. см. этот скетч https://github.com/jandrassy/lab/blob/master/KitchenTimer/KitchenTimer.ino, @Juraj

Я обновил ваш код на основе millis()., @soheil

@soheil, этот код был неправильным. вы не можете встроить таймер внутри 3 for циклов. основной цикл должен выполняться, @Juraj

Я побежал, и это сработало хорошо. Без проблем., @soheil

@soheil, если это все, что должен сделать ваш скетч, то все в порядке, @Juraj


1

В цикле (), как вы показали в своем коде,вы можете переместить RunNum(i, 2); вниз за пределы циклов "j" и "k". Аналогично,вы можете переместить RunNum(j, 1); вниз за пределы цикла "k". Это не решит вашу проблему, но ускорит каждое обновление дисплея.

Затем знайте, что вы можете указать одному (или всем) вашим датчикам DS18B20 начать преобразование температуры, не дожидаясь завершения преобразования. Затем вы используете millis (), чтобы сообщить вам, когда преобразование будет выполнено, и вы можете получить результат очень быстро. Некоторые библиотеки предоставляют количество времени, необходимое для ожидания преобразования; некоторые предоставляют своего рода логическую функцию "уже сделано?". Любой из них позволит вам удалить задержку "ждать, пока не будет сделано".

Обновление:

Эта стратегия не работает должным образом!...

Извините, если я что - то пропустил-похоже, там были возможности для оптимизации.

Что касается датчика температуры, я должен сказать, что считывание температуры само по себе занимает около 750 мс. Другими словами, это действует как задержка и вызывает выключение дисплея на 750 мс.

Это измерение температуры и преобразование в 12-битный результат, которое полностью выполняется внутри самого датчика DS18B20, занимает 750 мс. Arduino не участвует в этом процессе и в течение этого времени может выполнять другие задачи, такие как обслуживание вашего дисплея.

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

Обновление: Библиотека Arduino-Контроля температуры Майлза Бертона предоставляет флаг "ожидание преобразования", который вы можете установить false, чтобы функция ::requestsTemperatures() немедленно возвращалась, и вызов ::isConversionComplete (), чтобы проверить, готовы ли данные. (Конечно, зная, что для 12-битного преобразования устройству требуется 750 мс, вы с таким же успехом можете использовать функцию millis (), чтобы решить это.)

,

Спасибо. Эта стратегия не работает должным образом! потому что, если вы это сделаете, цифры 1 и 2 будут отключены до тех пор, пока цифра 0 не начнет отсчитываться от 0 до 9. Затем цифра 1 быстро отображает цифру 1 и выключается, и снова цифра 0 отсчитывается от 0 до 9 и так далее., @soheil

Что касается датчика температуры, я должен сказать, что считывание температуры само по себе занимает около 750 мс. Другими словами, это действует как задержка и вызывает выключение дисплея на 750 мс. В качестве другого примера предположим, что вам нужно вызвать php-скрипт с использованием ESP8266 D1 Mini (его аналогично можно запрограммировать с помощью Arduino IDE), а затем отобразить некоторые возвращенные числа с помощью 74HC595. Вызов php-скрипта может занять более 15 секунд, и в течение этого времени все цифры будут отключены., @soheil