Ардуино: динамическая индикация

Динамическая индикация на Ардуино. УрокВ одном из предыдущих уроков мы научились зажигать сегменты светодиодного индикатора. Хотя это можно сделать только с помощью Ардуино, мы использовали в нашем уроке дополнительный компонент — сдвиговый регистр. Эта полезная микросхема сэкономила нам несколько ценных выводов микроконтроллера.

Но один семисегментный индикатор почти бесполезен. Он ведь отображает всего одну цифру. А что если мы хотим вывести большое число, скажем, от 0 до 500? Нам потребуется целых три цифры, а значит и три индикатора.

Как будем подключать их к контроллеру? Можем напрямую, но тогда мы займем 7*3 = 21 вывод! Это очень расточительно. К тому же, нужна будет уже другая плата, так как у Ардуино Уно просто не хватит цифровых выводов.

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

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

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

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

Подключение к Ардуино

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

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

Принципиальная схема

Принципиальная схема для динамической индикации на Ардуино

Внешний вид макета

Макетная схема для динамической индикации на Ардуино

В качестве электронных ключей рекомендуем использовать транзисторы в корпусе TO92, например 2N7000. Для подключения каждого транзистора понадобится два резистора: на 100-150 Ом и на 2.2-10 кОм. Первый резистор призван защитить вывод контроллера от бросков тока, возникающих на затворе во время создания поля. Второй же резистор поможет быстро выключить ключ, когда мы подадим низкий уровень на соответствующий вывод контроллера (через него на землю сольется остаточный заряд затвора).

На каждой линии от регистра к индикатору необходим токозадающий резистор 200-300 Ом, чтобы светодиоды в индикаторе не перегорели. Этот нюанс работы со светодиодами мы рассмотрели на одном из самых первых уроков про светодиоды.

Тщательно собираем схему и переходим к программе.

Программа для динамической индикации

const byte digit_pins[3] = {5,6,7};
const byte data_pin = 2;
const byte sh_pin = 4;
const byte st_pin = 3;

unsigned long tm, next_flick;
const unsigned int to_flick = 1;

byte digit = 0;
unsigned int counter = 125;

const byte digits[10] = {
    B11101110, 
    B10000010, 
    B11011100, 
    B11010110, 
    B10110010, 
    B01110110, 
    B01111110, 
    B11000010, 
    B11111110, 
    B11110110 
};

void fill( byte d ){
    for(char i=0; i<8; i++){
        digitalWrite(sh_pin, LOW);
        digitalWrite(data_pin, digits[d] & (1<<i));
        digitalWrite(sh_pin, HIGH);
    }
    digitalWrite(st_pin, HIGH); 
    digitalWrite(st_pin, LOW);
}

void setDigit( byte digit, unsigned int counter ){
    byte d = 0;
    switch ( digit ){
        case 0:
            digitalWrite(digit_pins[2], LOW);
            d = counter % 10;
            fill(d);
            digitalWrite(digit_pins[0], HIGH);
            break;
        case 1:
            digitalWrite(digit_pins[0], LOW);
            d = (counter % 100) / 10;
            fill(d);
            digitalWrite(digit_pins[1], HIGH);
            break;
        case 2:
            digitalWrite(digit_pins[1], LOW);
            d = ( counter % 1000 ) / 100;
            fill(d);
            digitalWrite(digit_pins[2], HIGH);
            break;
    }
}

void setup() {
    for(int i=0; i<3; i++){
        pinMode(digit_pins[i], OUTPUT);
    }
    pinMode(data_pin, OUTPUT);
    pinMode(sh_pin, OUTPUT);
    pinMode(st_pin, OUTPUT);
    pinMode(13, OUTPUT);
}

void loop() {
    tm = millis();
    if( tm > next_flick ){
        next_flick = tm + to_flick;
        digit++;
        if( digit == 3 )
            digit = 0;
        setDigit( digit, counter );
    }
}

Часть этой программы, включая переменные data_pin, sh_pin, st_pin и функцию fill уже известны нам из урока про сдвиговый регистр.

Массив digits хранит десять комбинаций сегментов для цифр от 0 до 9. Для экономии памяти мы храним каждую комбинацию в одном байте, а для лучшего понимания мы записали их в бинарном виде.

Чтобы переключать индикаторы воспользуемся таймером. Будем каждую миллисекунду заполнять регистр нужной комбинацией и включать соответствующий индикатор. Для этого мы используем функцию setDigit. Аргумент digit — это индекс включаемого в данный момент индикатора, а counter — трехзначное число, которые мы хотим высветить.

Параметр to_flick отвечает за период переключения индикатора. Он равен 1, а значит смена цифр для отображения происходит каждую миллисекунду. Что если увеличить этот параметр? Скажем до 100мс, или даже до 500мс. Эффект инерции зрения пропадет и мы начнем замечать смену цифр.

Динамическая индикация на Ардуино

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

В предыдущем примере переменная counter хранила число 125 по-умолчанию. Попробуем теперь добавить в программу счетчик секунд, чтобы counter увеличивался на единицу каждую секунду, вплоть до числа 999.

const byte digit_pins[3] = {5,6,7};
const byte data_pin = 2;
const byte sh_pin = 4;
const byte st_pin = 3;

unsigned long tm, next_sec, next_flick;
const unsigned int to_sec = 1000;
const unsigned int to_flick = 1;

unsigned int counter = 0;
byte digit = 0;

const byte digits[10] = {
    B11101110, 
    B10000010, 
    B11011100, 
    B11010110, 
    B10110010, 
    B01110110, 
    B01111110, 
    B11000010, 
    B11111110, 
    B11110110 
};

void fill( byte d ){
    for(char i=0; i<8; i++){
        digitalWrite(sh_pin, LOW);
        digitalWrite(data_pin, digits[d] & (1<<i));
        digitalWrite(sh_pin, HIGH);
    }
    digitalWrite(st_pin, HIGH); 
    digitalWrite(st_pin, LOW);
}

void setDigit( byte digit, unsigned int counter ){
    byte d = 0;
    switch ( digit ){
        case 0:
            digitalWrite(digit_pins[2], LOW);
            d = counter % 10;
            fill(d);
            digitalWrite(digit_pins[0], HIGH);
            break;
        case 1:
            digitalWrite(digit_pins[0], LOW);
            d = (counter % 100) / 10;
            fill(d);
            digitalWrite(digit_pins[1], HIGH);
            break;
        case 2:
            digitalWrite(digit_pins[1], LOW);
            d = ( counter % 1000 ) / 100;
            fill(d);
            digitalWrite(digit_pins[2], HIGH);
            break;
    }
}

void setup() {
    for(int i=0; i<3; i++){
        pinMode(digit_pins[i], OUTPUT);
    }
    pinMode(data_pin, OUTPUT);
    pinMode(sh_pin, OUTPUT);
    pinMode(st_pin, OUTPUT);

   pinMode(13, OUTPUT);
}

void loop() {
    tm = millis();
    if( tm > next_sec ){
        next_sec = tm + to_sec;
        counter++;
        if( counter == 1000 )
            counter = 0;
    }

    tm = millis();
    if( tm > next_flick ){
        next_flick = tm + to_flick;
        digit++;
        if( digit == 3 )
            digit = 0;
        setDigit( digit, counter );
    }
}

Загружаем программу на Ардуино и наблюдаем работу счетчика!

Задания

  1. Цифровой секундомер. Собрать схему с трехцифровым индикатором. Добавить в схему кнопку. При нажатии на кнопку, секундомер должен запускать отсчет. При повторном нажатии — останавливать. Дополнительно, к секундомеру можно добавить дробную часть, отображаемую на третьем индикаторе через точку.
  2. Цифровой вольтметр для напряжений от 0 до 10 Вольт. Собрать схему с трехцифровым индикатором. Добавить в схему делитель напряжения из двух резисторов на 10 кОм, подключенный к аналоговому входу Ардуино. Написать программу, которая будет каждые 100 мс считывать значение на аналоговом входе, переводить его в Вольты и выводить на индикатор. Для правильного отображения дробной части, необходимо подключить восьмой сегмент — точку.

Заключение

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

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


Изменено:

Ардуино: динамическая индикация: 3 комментария

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Можно использовать следующие HTML-теги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>