CUSTOMELECTRONICS.RU
Информационно-учебный блог о разработке электроники
Эл. почта: info@customelectronics.ru

Arduino. Динамическая индикация

Динамическая индикация — это метод отображения целостной картины путем последовательного отображения отдельных элементов этой картины.
Эта статья научит вас выводить на дисплее сегментного индикатора одновременно несколько цифр. Достигается это за счет «инерционности» человеческого зрения.

Подготовка к работе

В предыдущей статье мы разобрали пример работы с одним разрядом. В ней использовалась статическая индикация. Увеличить количество разрядов можно, если использовать еще один дисплей и еще семь выводов микроконтроллера, но гораздо выгоднее отображать разряды индикатора по очереди с высокой скоростью. Так, чтобы это стало не заметно для глаза.
Для этого на индикаторе должны быть объединены аноды разрядов и катоды сегментов.

Индикатор с динамической индикацией

Индикатор с динамической индикацией

Все примеры выполнены с использованием EduBoard и TutorShield. На нашем шилде именно такой индикатор. Для его использования установите перемычки, выделенные на рисунке:

Перемычки для включения индикатора

Перемычки для включения индикатора

Принципиальная схема подключения индикатора:

Принципиальная схема подключения индикатора

Принципиальная схема подключения индикатора

Первый пример

Для начала выведите два разных числа на индикаторе, используя следующий код:

#define DIG1 4
#define DIG2 5
#define A 6
#define B 7
#define C 8
#define D 9
#define E 10
#define FF 11
#define G 12
#define TAKT 1000

void setup() {                
  pinMode(A, OUTPUT); pinMode(B, OUTPUT);
  pinMode(C, OUTPUT); pinMode(D, OUTPUT);
  pinMode(E, OUTPUT); pinMode(FF, OUTPUT);
  pinMode(G, OUTPUT); pinMode(DIG1, OUTPUT);
  pinMode(DIG2, OUTPUT);
  digitalWrite(A,HIGH); digitalWrite(B,HIGH);
  digitalWrite(C,HIGH); digitalWrite(D,HIGH);
  digitalWrite(E,HIGH); digitalWrite(FF,HIGH);
  digitalWrite(G,HIGH); digitalWrite(DIG1,HIGH);
  digitalWrite(DIG2,HIGH);
}

void loop() {
  digitalWrite(DIG1,LOW);
  Show(3);
  delay(TAKT);
  Clean();
  digitalWrite(DIG1,HIGH);
  digitalWrite(DIG2,LOW);
  Show(4);
  delay(TAKT);
  Clean();
  digitalWrite(DIG2,HIGH);
}

void Show(int digit) {
  switch(digit) {
    case 0: {
      digitalWrite(A,LOW); digitalWrite(B,LOW);
      digitalWrite(C,LOW); digitalWrite(D,LOW);
      digitalWrite(E,LOW); digitalWrite(FF,LOW);
    }
    break;
    case 1: {
      digitalWrite(B,LOW); digitalWrite(C,LOW);
    }
    break;
    case 2: {
      digitalWrite(A,LOW); digitalWrite(B,LOW);
      digitalWrite(D,LOW); digitalWrite(E,LOW);
      digitalWrite(G,LOW);
    }
    break;
    case 3: {
      digitalWrite(A,LOW); digitalWrite(B,LOW);
      digitalWrite(C,LOW); digitalWrite(D,LOW);
      digitalWrite(G,LOW);
    }
    break;
    case 4: {
      digitalWrite(B,LOW); digitalWrite(C,LOW);
      digitalWrite(FF,LOW); digitalWrite(G,LOW);
    }
    break;
    case 5: {
      digitalWrite(A,LOW); digitalWrite(C,LOW);
      digitalWrite(D,LOW); digitalWrite(FF,LOW);
      digitalWrite(G,LOW);
    }
    break;
    case 6: {
      digitalWrite(A,LOW); digitalWrite(C,LOW);
      digitalWrite(D,LOW); digitalWrite(E,LOW);
      digitalWrite(FF,LOW); digitalWrite(G,LOW);
    }
    break;
    case 7: {
      digitalWrite(A,LOW); digitalWrite(B,LOW);
      digitalWrite(C,LOW);
    }
    break;
    case 8: {
      digitalWrite(A,LOW); digitalWrite(B,LOW);
      digitalWrite(C,LOW); digitalWrite(D,LOW);
      digitalWrite(E,LOW); digitalWrite(FF,LOW);
      digitalWrite(G,LOW);
    }
    break;
    case 9: {
      digitalWrite(A,LOW); digitalWrite(B,LOW);
      digitalWrite(C,LOW); digitalWrite(D,LOW);
      digitalWrite(FF,LOW); digitalWrite(G,LOW);
    }
    break;
  }
}

void Clean() {
    digitalWrite(A,HIGH); digitalWrite(B,HIGH);
    digitalWrite(C,HIGH); digitalWrite(D,HIGH);
    digitalWrite(E,HIGH); digitalWrite(FF,HIGH);
    digitalWrite(G,HIGH);
}

Основной цикл этого примера линеен и прост. Сначала в первом разряде на одну секунду выводится цифра 3, затем во втором 4.
Если уменьшить интервал TAKT, то можно добиться того, чтобы за счет инерционности зрения казалось, что цифра 34 горит непрерывно. Какую длительность поставить? С одной стороны она должна быть как можно больше, чтобы осталось время на выполнение других задач, с другой стороны как можно меньше, чтобы глаз не видел мерцания.
Эмпирическим путем установлено, что обновления изображения с частотой 50 раз в секунду вполне достаточно для приемлемого восприятия. Это значит, что идентификатор TAKT должен иметь значение меньше 10мс. Попробуйте запустить программу с этим числом, а затем попробуйте увеличить его до 20мс и понаблюдайте за разницей.
Не забудьте после оставить значение TAKT 10.

Управление яркостью

При динамической индикации разряды горят не на протяжении всего времени и светятся лишь на половину (при двух разрядах). Это нужно учитывать при подборе токоограничивающих резисторов индикатора.
Также можно управлять яркостью. В предыдущем примере добавьте еще один идентификатор BRIGHT и замените основной цикл:

#define BRIGHT 2

void loop() {
  digitalWrite(DIG1,LOW);
  Show(3);
  delay(BRIGHT);
  Clean();
  digitalWrite(DIG1,HIGH);
  delay(TAKT-BRIGHT);
  digitalWrite(DIG2,LOW);
  Show(4);
  delay(BRIGHT);
  Clean();
  digitalWrite(DIG2,HIGH);
  delay(TAKT-BRIGHT);
}

Переопределение идентификатора BRIGHT от 0 до 10 будет приводить к изменению яркости. На время BRIGHT индикатор будет включен, а на время TAKT-BRIGHT выключен. Надо понимать, что эта константа будет справедлива только для ситуаций, когда TAKT равен 10мс.

Упрощение использования

На данный момент программа в основном цикле занимается только тем, что выводит числа. Для дальнейшего ее упрощения нужно понимать для чего будет использоваться сегментный индикатор.
С применением индикатора можно сделать, например, вольтметр. В нем блок АЦП микроконтроллера периодически делает замер и сохраняет результат в память. Это результат можно из памяти вытащить и показать на индикаторе. То есть желательно иметь функцию, которая будет разделять двухразрядные числа две цифры. Назовем эту функцию DisplayMath():

void DisplayMath(int data) {
  dig1 = dig2 = 0;
  if (data < 100) {
    while (data >= 10) {
      data -= 10;
      dig1++;
    }
    dig2 = data;
  }
}

В эту функцию будет передаваться число, которое нужно разобрать по разрядам. Результат обработки функция записывает в глобальные переменные dig1 и dig2.
Для начала происходит проверка входных данных. Если переданное значение больше 100, то функция не будет делать ничего и переменные dig1 и dig2 обнулятся. Если меньше 100, то запускается пересчет.
Далее локальная переменная data декрементируется с шагом 10 и подсчитывается количество итераций. Например, если функции передано значение 48 цикл while будет выполнен 4 раза и концу его выполнения переменные будут иметь состояние dig1=4, data=8. Далее остается только записать остаток data в переменную dig2.
В итоге после запуска этой функции в переменных dig1 и dig2 окажутся значения разрядов.
Сам вывод цифр на дисплей тоже лучше вынести в отдельную функцию. Назовем ее DisplayShow():

void DisplayShow() {
  digitalWrite(DIG1,LOW);
  Show(dig1);
  delay(BRIGHT);
  Clean();
  digitalWrite(DIG1,HIGH);
  delay(TAKT-BRIGHT);
  digitalWrite(DIG2,LOW);
  Show(dig2);
  delay(BRIGHT);
  Clean();
  digitalWrite(DIG2,HIGH);
  delay(TAKT-BRIGHT);
}

Окончательный код с использованием этих функций:

#define DIG1 4
#define DIG2 5
#define A 6
#define B 7
#define C 8
#define D 9
#define E 10
#define FF 11
#define G 12
#define TAKT 10
#define BRIGHT 2

int dig1 = 0;
int dig2 = 0;

void setup() {                
  pinMode(A, OUTPUT); pinMode(B, OUTPUT);
  pinMode(C, OUTPUT); pinMode(D, OUTPUT);
  pinMode(E, OUTPUT); pinMode(FF, OUTPUT);
  pinMode(G, OUTPUT); pinMode(DIG1, OUTPUT);
  pinMode(DIG2, OUTPUT);
  digitalWrite(A,HIGH); digitalWrite(B,HIGH);
  digitalWrite(C,HIGH); digitalWrite(D,HIGH);
  digitalWrite(E,HIGH); digitalWrite(FF,HIGH);
  digitalWrite(G,HIGH); digitalWrite(DIG1,HIGH);
  digitalWrite(DIG2,HIGH);
}

void loop() {
  DisplayMath(34);
  DisplayShow();
}

void DisplayMath(int data) {
  dig1 = dig2 = 0;
  if (data < 100) {
    while (data >= 10) {
      data -= 10;
      dig1++;
    }
    dig2 = data;
  }
}

void DisplayShow() {
  digitalWrite(DIG1,LOW);
  Show(dig1);
  delay(BRIGHT);
  Clean();
  digitalWrite(DIG1,HIGH);
  delay(TAKT-BRIGHT);
  digitalWrite(DIG2,LOW);
  Show(dig2);
  delay(BRIGHT);
  Clean();
  digitalWrite(DIG2,HIGH);
  delay(TAKT-BRIGHT);
}

void Show(int digit) {
  switch(digit) {
    case 0: {
      digitalWrite(A,LOW); digitalWrite(B,LOW);
      digitalWrite(C,LOW); digitalWrite(D,LOW);
      digitalWrite(E,LOW); digitalWrite(FF,LOW);
    }
    break;
    case 1: {
      digitalWrite(B,LOW); digitalWrite(C,LOW);
    }
    break;
    case 2: {
      digitalWrite(A,LOW); digitalWrite(B,LOW);
      digitalWrite(D,LOW); digitalWrite(E,LOW);
      digitalWrite(G,LOW);
    }
    break;
    case 3: {
      digitalWrite(A,LOW); digitalWrite(B,LOW);
      digitalWrite(C,LOW); digitalWrite(D,LOW);
      digitalWrite(G,LOW);
    }
    break;
    case 4: {
      digitalWrite(B,LOW); digitalWrite(C,LOW);
      digitalWrite(FF,LOW); digitalWrite(G,LOW);
    }
    break;
    case 5: {
      digitalWrite(A,LOW); digitalWrite(C,LOW);
      digitalWrite(D,LOW); digitalWrite(FF,LOW);
      digitalWrite(G,LOW);
    }
    break;
    case 6: {
      digitalWrite(A,LOW); digitalWrite(C,LOW);
      digitalWrite(D,LOW); digitalWrite(E,LOW);
      digitalWrite(FF,LOW); digitalWrite(G,LOW);
    }
    break;
    case 7: {
      digitalWrite(A,LOW); digitalWrite(B,LOW);
      digitalWrite(C,LOW);
    }
    break;
    case 8: {
      digitalWrite(A,LOW); digitalWrite(B,LOW);
      digitalWrite(C,LOW); digitalWrite(D,LOW);
      digitalWrite(E,LOW); digitalWrite(FF,LOW);
      digitalWrite(G,LOW);
    }
    break;
    case 9: {
      digitalWrite(A,LOW); digitalWrite(B,LOW);
      digitalWrite(C,LOW); digitalWrite(D,LOW);
      digitalWrite(FF,LOW); digitalWrite(G,LOW);
    }
    break;
  }
}

void Clean() {
    digitalWrite(A,HIGH); digitalWrite(B,HIGH);
    digitalWrite(C,HIGH); digitalWrite(D,HIGH);
    digitalWrite(E,HIGH); digitalWrite(FF,HIGH);
    digitalWrite(G,HIGH);
}

Обратите внимание насколько прост основной цикл loop(). В нем всего две строки. Если вы измените значение 34 на любое другое, то оно будет отображено на индикаторе.
Для демонстрации работы индикатора запустим счетчик с произвольной скоростью и будем выводить его состояние. Замените основной цикл и добавьте две переменных:

int value = 0;
int i = 0;

void loop() {
  i++;
  if (i == 7) {
    i = 0;
    value ++;
    if (value == 100) value = 0;
  }
  DisplayMath(value);
  DisplayShow();
}

Вы увидите как на экране побегут цифры от 0 до 99.

Заключение

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

Индивидуальные задания

  1. Увеличьте модуль счета. Подключите четыре дополнительных светодиода на выводах A0-A5 и допишите программу так, чтобы счетчик считал от 0 до 699.
  2. Если в старшем разряде 0, то его нет смысла показывать. Доработайте программу так, чтобы старший разряд был погашен, если нужно показать число меньше 10
  3. Сделайте так, чтобы если функции DisplayMath() передано число больше 99 на дисплее отображалось -0 (overflow, переполнение)

Остальные статьи цикла можно найти здесь.

Мы будем очень рады, если вы поддержите наш ресурс и посетите магазин наших товаров shop.customelectronics.ru.

Метки: , , , Просмотров: 16534