Подключение семисегментных индикаторов к AVR. Динамическая индикация
Семисегментные индикаторы широко применяются в цифровой технике: в бытовых приборах, измерительной технике, в промышленных устройствах. По сравнению с жидкокристаллическими индикаторами светодиодные имеют свои преимущества, это контрастность отображения информации, малое потребление энергии. Семисегментный индикатор представляет собой матрицу из семи светодиодов, размещенных таким образом, чтобы зажигая их в разных сочетаниях, можно было бы отобразить любую десятичную цифру, а также специальные символы. Кроме этого индикатор дополняется еще одним сегментом, который предназначен для отображения десятичной точки.
На рисунке 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
Массив с кодами цифр получится такой:
1.
char
SEGMENT[ ] = {0x3F, 0x06, 0x5B, 0x4F, 0x66,
2.
0x6D, 0x7D, 0x07, 0x7F, 0x6F};
В обработчике прерываний мы используем оператор switch, этот оператор позволяет заменить сложную функцию из операторов if. В общем виде он выглядит так:
01.
switch
( выражение )
02.
{
03.
case
значение1:
04.
......
05.
break
;
06.
case
значение2:
07.
......
08.
break
;
09.
......
10.
default
:
11.
......
12.
}
Данный оператор производит выбор по выражению, обычно это число. Если выражение присутствует в значении case, то выполняются команды после case до break, иначе выполняется код после default.
Ниже приведен полный текст программы:
01.
/***Использование динамической индикации***/
02.
#include <avr/io.h>
03.
#include <avr/interrupt.h>
04.
#include <util/delay.h>
05.
char
SEGMENT[ ] = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F};
06.
07.
volatile
unsigned
char
segcounter = 0;
08.
volatile
int
display1 = 0;
09.
10.
// Обработчик прерывания по переполнению таймера2
11.
ISR (TIMER2_OVF_vect)
12.
{
13.
PORTD = 0xFF;
//гасим все разряды
14.
PORTB = (1 << segcounter);
//выбираем следующий разряд
15.
switch
(segcounter)
16.
{
17.
case
0:
18.
PORTD = ~(SEGMENT[display1 % 10000 / 1000]);
// здесь раскладываем число на разряды
19.
break
;
20.
case
1:
21.
PORTD = ~(SEGMENT[display1 % 1000 / 100]);
22.
break
;
23.
case
2:
24.
PORTD = ~(SEGMENT[display1 % 100 / 10]);
25.
break
;
26.
case
3:
27.
PORTD = ~(SEGMENT[display1 % 10]);
28.
break
;
29.
}
30.
if
((segcounter++) > 2) segcounter = 0;
31.
}
32.
33.
/***Главная функция***/
34.
int
main (
void
)
35.
{
36.
DDRD |= (1 << PD6)|(1 << PD5)|(1 << PD4)|(1 << PD3)|(1 << PD2)|(1 << PD1)|(1 << PD0);
37.
DDRB |= (1 << PB3)|(1 << PB2)|(1 << PB1)|(1 << PB0);
38.
PORTD = 0x00;
39.
PORTB = 0x00;
40.
TIMSK |= (1 << TOIE2);
// разрешение прерывания по таймеру2
41.
TCCR2 |= (1 << CS21);
//предделитель на 8
42.
43.
sei();
//глобально разрешаем прерывания
44.
45.
while
(1)
46.
{
47.
display1++;
// увеличиваем счет от 0000 до 9999
48.
_delay_ms(100);
// задержка
49.
}
50.
}
Источник: http://radioparty.ru/index.php/prog-avr/program-c/279-lesson11-sevensegment