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

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

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

Подключить один семисегментный индикатор и управлять им с помощью микроконтроллера процедура несложная. Для этого достаточно сегменты индикатора подключить к порту микроконтроллера через токоограничительные резисторы по 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;
unsigned 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++; // Увеличиваем счет от 0 до 9999
if(display > 9999) display = 0;
_delay_ms(10); // Задержка
}
}

Комментарии  

0 #61 kostya_unix 06.01.2020 04:00
Цитирую uuu000:
Прошу объяснить подробнее назначение переменных segcounter и display.Как происходит раскладывание на разряды и вывод на портD.
Может подскажете где можно прочитать более подробно об этом процессе.

А вот display - это переменная для отображения числового значения от 0 до 9999, но на индикатор ( на каждый индикатор) мы выводим только по одной цифре и математикой
Код: PORTD = ~(SEGMENTE[display % 10]);
в этом выражении PORTD _ принимает значение единицы из 9999;
Код: PORTD = ~(SEGMENTE[display % 100 / 10]);
в этом выражении PORTD _ принимает значение десятки (второй с права) из 9999;
и так далее....
Опять-же переключение индикаторов происходит гораздо быстрее( настолько быстро, что мы не замечаем как происходит переключение между индикаторам и нам кажется, что они не гаснут (динамическая индикация используется потому, что в отображении цифр на четырех индикаторах участвует только один порт (PORTD)), а счет, значение переменной display, притормаживается задержкой Код:_delay_ms(100);
Это, что бы мы видели в привычном для нас виде изменения числового значения на индикаторах.
Сообщить модератору
0 #62 kostya_unix 06.01.2020 04:10
Цитирую uuu000:
Прошу объяснить подробнее назначение переменных segcounter и display.Как происходит раскладывание на разряды и вывод на портD.
Может подскажете где можно прочитать более подробно об этом процессе.

И опять же не стесняйтесь задавать вопросы когда что-то не понятно. Пусть не всегда вовремя получите ответы на них, но, что получите ответ, это точно.
По поводу почитать подробнее....
Есть хорошая книга Евстифеева А.В. (avr.ru/docs/books/avr), и есть других автором, но так как мы учимся самостоятельно, то в первую очередь нужно пытаться многое проверять на практике ( ну или аналитически ( в голове), но это не про меня), изучать -> проверять, изучать -> проверять и никак иначе. И читать, читать, читать учебники, форумы. Если сегодня не понятно, через некоторое время решение придет и все встанет на свои места.
Сообщить модератору
+1 #63 oleg76 04.03.2020 22:58
Цитирую Georgy:
Заметил интересное поведение прошивки - если выставить яркость равную 185 или любое ближайшее значение, то младший разряд светится ярче чем два старших. Подменял процессор и индикаторы, но эффект не ушёл. Не могу понять где собака порылась:)

Такая же проблема, подскажите где копать?
Сообщить модератору

Последние комментарии

Сейчас на сайте

Сейчас на сайте 105 гостей и нет пользователей