Главная Новости

Подключение семисегментных индикаторов к AVR. Динамическая индикация

Опубликовано: 01.09.2018

видео Подключение семисегментных индикаторов к AVR. Динамическая индикация

Подключение семисегментного индикатора к микроконтроллеру atmega8

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



На рисунке 1 изображен внешний вид индикатора. Принято каждый сегмент индикатора обозначать латинской буквой: a, b, c, d, e, f, g. Точка обозначается буквой h.

По схеме включения семисегментные индикаторы подразделяются на индикаторы с общим катодом и с общим анодом. Схемы включения приведены на рисунке 2.


Подключение 7 сегментных светодиодных индикаторов (динамическая индикация)

Подключить один семисегментный индикатор и управлять им с помощью микроконтроллера процедура несложная. Для этого достаточно сегменты индикатора подключить к порту микроконтроллера через токоограничительные резисторы по 150 Ом. Общий вывод подключить к линии другого порта микроконтроллера. В зависимости от того какую цифру надо вывести, в порт выводим двоичный код этой цифры, ссылаясь на тип подключенного индикатора (с общим анодом или катодом) на общий провод подаем плюс или минус. Для удобства можно сделать таблицу кодов для индикатора. Если подключение такое: PD7-h, PD6-g, PD5-f, PD4-e, PD3-d, PD2-c, PD1-b, PD0-a, то для отображения цифры 1 в порт D нужно вывести такой двоичный код: 0b00000110 .

Для отображения цифровых данных одного семисегментного индикатора обычно недостаточно. В таких случаях к микроконтроллеру подключают сразу несколько индикаторов. Однако, из-за отсутствия достаточного количества выводов у микроконтроллера применяют специальные методы. Один из таких методов это динамическая индикация. Режим динамической индикации применяют для построения многоразрядных индикаторов . При таком режиме разряды индикатора работают не одновременно, а по очереди. Переключение разрядов происходит с большой скоростью ( 50 Гц ), из-за этого человеческий глаз не замечает , что индикаторы работают по очереди. Так как у светодиодов очень малая инерционность, сменяющиеся разряды сливаютя в одно изображение. В этом режиме в каждый момент времени работает только один разряд, включаются по очереди начиная с первого заканчивая последним, затем все начинается сначала.

Сделаем простой секундомер. Отсчет секунд будет производится на четырехразрядном индикаторе (с общим анодом) от 0 до 9999. В нашей программе используем процедуру прерывания по таймеру, т.е. смена разряда индикатора будет происходить каждый раз когда таймер досчитает до конца(до 255). Используем восьмиразрядный таймер/счетчик Т2 , он будет работать  в нормальном режиме. Но обычно для реализации динамической индикации используют режим СТС (сброс при совпадении), это режим, при котором частота возникновения прерываний по совпадению значений счетчика таймера и регистра OCR2 определяется содержимым OCR2 и предделителем тактовой частоты таймера. При таком режиме работы таймера можно легко изменять частоту обновления разрядов, записывая в регистр сравнения OCR2 необходимое значение, предварительно расчитанное. Частоту обновления разрядов делают обычно 50Hz или больше, так как у нас 4 разряда, частота обновления будет равна 200Hz . Подсчитаем частоту обновления для нашего примера: тактовая частота равна 8MHz, предделитель сделаем на 8. На вход таймера будут поступать импульсы частотой 1MHz. Тогда таймер будет увеличивать значение каждые 1 микросекунду, переполняться он будет каждые 255*0,000001 = 255 мкс. Частота обновления будет равна 1/255мкс = 3921Hz.

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

Цифра

PD7 (H)

PD6 (G)

PD5 (F)

PD4 (E)

PD3 (D)

PD2 (C)

PD1 (B)

PD0 (A)

HEX  

0 0 0 1 1 1 1 1 1 0x3F
1 0 0 0 0 0 1 1 0 0x06
2 0 1 0 1 1 0 1 1 0x5B
3 0 1 0 0 1 1 1 1 0x4F
4 0 1 1 0 0 1 1 0 0x66
5 0 1 1 0 1 1 0 1 0x6D
6 0 1 1 1 1 1 0 1 0x7D
7 0 0 0 0 0 1 1 1 0x07
8 0 1 1 1 1 1 1 1 0x7F
9 0 1 1 0 1 1 1 1 0x6F
h 1 0 0 0 0 0 0 0 0x80

Массив с кодами цифр получится такой:

unsigned char SEGMENTE[ ] = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F};

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

switch ( выражение ) { case значение1: ...... break; case значение2: ...... break; ...... default: ...... }

Данный оператор производит выбор по выражению, обычно это число. Если выражение присутствует в значении case , то выполняются команды после case до break , иначе выполняется код после default .

Ниже приведен полный текст программы:

// Подключение семисегментных индикаторов к AVR. Динамическая индикация #include <avr/io.h> #include <avr/interrupt.h> #include <util/delay.h> //---------------------------0-----1-----2-----3-----4-----5-----6-----7-----8------9 unsigned char SEGMENTE[] = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F}; unsigned char segcounter = 0; volatile int display = 0; // Обработчик прерывания по переполнению таймера 2 ISR(TIMER2_OVF_vect) { PORTD = 0xFF; // Гасим все разряды PORTB = (1 << segcounter); // Выбираем следующий разряд switch(segcounter) { case 0: PORTD = ~(SEGMENTE[display % 10000 / 1000]); // Раскладываем число на разряды break; case 1: PORTD = ~(SEGMENTE[display % 1000 / 100]); break; case 2: PORTD = ~(SEGMENTE[display % 100 / 10]); break; case 3: PORTD = ~(SEGMENTE[display % 10]); break; } if(segcounter++ > 2) segcounter = 0; } // Главная функция int main(void) { DDRB = 0xFF; // Порт B - выход PORTB = 0x00; DDRD = 0xFF; // Порт D - выход PORTD = 0x00; TCCR2 |= (1 << CS21); // Предделитель на 8 TIMSK |= (1 << TOIE2); // Разрешение прерывания по таймеру 2 sei(); // Глобально разрешаем прерывания while(1) { display++; // Увеличиваем счет от 0000 до 9999 _delay_ms(100); // Задержка } }
rss