Что понимают под понятием семисегментный код
Перейти к содержимому

Что понимают под понятием семисегментный код

  • автор:

Семисегментный индикатор

Пояснение причин и обсуждение — на странице Википедия:К объединению/18 сентября 2012.
Обсуждение длится одну неделю (или дольше, если оно идёт медленно).
Дата начала обсуждения — 2012-09-18.
Если обсуждение не требуется (очевидный случай), используйте другие шаблоны.
Не удаляйте шаблон до подведения итога обсуждения.

Семисегментный светодиодный индикатор с десятичной запятой

Семисегме́нтный индика́тор — устройство отображения цифровой информации. Это — наиболее простая реализация индикатора, который может отображать арабские цифры. Для отображения букв используются более сложные многосегментные и матричные индикаторы.

Концепция и внешний вид

Таблица, отображающая все 128 вариантов состояния сегментов

Обозначение сегментов индикатора

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

Цифры, 6, 7 и 9 имеют по два разных представления на семисегментном индикаторе. В ранних калькуляторах Casio и Электроника цифра 0 отображалась в нижней половине индикатора.

Сегменты обозначаются буквами от A до G; восьмой сегмент — десятичная точка ( decimal point, DP ), предназначенная для отображения дробных чисел.

Изредка на семисегментном индикаторе отображают буквы.

В современных индикаторах светодиоды изготавливают в форме сегментов, поэтому светодиодные индикаторы имеют предельно простую, унифицированную форму: чем меньше разных светодиодов, тем дешевле устройство. В жидкокристаллических, газорязрядных, вакуумно-люминесцентных (катодно-люминесцентных) и других индикаторах дизайнеры находят место для вариации формы сегментов.

История

Чертёж из патента Вуда

Сегментный индикатор был запатентован в 1910 году ( U.S. Patent 974 943 ) Фрэнком Вудом. Эта реализация была восьмисегментной — был дополнительный косой сегмент для отображения четвёрки. Патент был практически забыт — вплоть до 1960-х годов радиолюбителям приходилось применять для отображения цифр знаковые индикаторы тлеющего разряда или просто десять лампочек.

В 1970 году американская компания RCA выпустила семисегментную лампу накаливания «Нумитрон» [1] .

Для отображения букв появились четырнадцатисегментные индикаторы и шестнадцатисегментные индикаторы, но сейчас их почти повсеместно заменили матричные (точечные) индикаторы. И лишь там, где нужно отображать только цифровую информацию, семисегментные индикаторы остались незаменимыми — из-за простоты, контраста и узнаваемости.

Реализации

Ранний индикатор с семью нитями накала

Механическое 7-сегментное табло для отображения цен на бензин

Большинство одноразрядных семисегментных индикаторов устроены на светодиодах, хотя существуют и альтернативы — лампы тлеющего разряда, электровакуумные индикаторы (катодолюминесцентные, накаливаемые), лампы накаливания, жидкие кристаллы и т. д. На больших табло наподобие цен на бензин всё ещё применяются механические индикаторы, или блинкерные индикаторы, переключающиеся с помощью электромагнитов.

В обычном светодиодном индикаторе девять выводов: один идёт к катодам всех сегментов, и остальные восемь — к аноду каждого из сегментов. Эта схема называется «схема с общим катодом», существуют также схемы с общим анодом. Часто делают не один, а два общих вывода на разных концах цоколя — это упрощает разводку, не увеличивая габаритов.

Многоразрядные индикаторы часто работают по динамическому принципу: выводы одноимённых сегментов всех разрядов соединены вместе. Чтобы выводить информацию на такой индикатор, управляющая микросхема должна циклически подавать ток на общие выводы всех разрядов, в то время как на выводы сегментов ток подаётся в зависимости от того, зажжён ли данный сегмент в данном разряде. Таким образом, чтобы получить десятиразрядный экран микрокалькулятора, нужны всего восемнадцать выводов (8 анодов и 10 катодов) — а не 81. Сходным образом сканируется клавиатура калькулятора.

Существуют специальные микросхемы семисегментных дешифраторов, переводящие четырёхбитный код в его семисегментное представление. К примеру, отечественные (КР)514ид1 для индикаторов с общим катодом или (КР)514ид2 с общим анодом. Иногда дешифраторы встраивают прямо в индикатор. В настоящее время, в связи с широким распространением однокристальных микроконтроллеров с GPIO, семисегментные светодиодные индикаторы подключаются напрямую к выводам микроконтроллера.

Часто на ценниках применяются закрашиваемые фломастером сегменты. Также встречаются трафареты в виде семисегментных индикаторов для изображения цен или телефонных номеров.

Отображение букв

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

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

On
Off
Track

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

В массовой культуре

  • Инопланетянин из фильма «Хищник» носил устройство с индикаторами, похожими на семисегментные, но предназначенными для отображения инопланетных цифр, естественно имеющими другое расположение сегментов.
  • Машина времени в фильме «Назад в будущее» имела табло из четырех семисегментных индикаторов с цветами, соответствующими цветам ламп из фильма «Машина времени».

См. также

  • Девятисегментный индикатор
  • Еггогология
  • Матричный индикатор

Примечания

Литература

  • Батушев В. А. Электронные приборы: Учебник для вузов. — 2-е, перераб. и доп. — М .: Высшая школа, 1980. — С. 302-303. — 383 с.
Семисегментный индикатор на Викискладе ?

Вы можете улучшить статью, внеся более точные указания на источники.

На органических светодиодах (OLED) (Гибкий • Активная матрица • Фосфоресцирующий) • SED • FED • Ферроэлектрический (FLD) • На интерферометрическом модуляторе (IMOD) • Электролюминисцентная технология тонкоплёночного диэлектрика (TDEL) • Нанокристаллический • На квантовых точках (QDLED) • На мультиплексном оптическом затворе (TMOS) • Оптический пиксельный (TPD) • Жидкокристаллический лазер (LCL) • Лазерный фосфорный (LPD) • На органических светотранзисторах (OLET) • ClearBlack

Электромеханический (Блинкерное табло • Перекидное табло) • Матричный индикатор • Семисегментный индикатор • Электронная бумага • Гибкий экран • Матрица ламп накаливания • Газоразрядный индикатор

Изображение в свободном пространстве • Телевизионные технологии с большим экраном • Телевидение высокой чёткости • Изображение с высоким динамическим диапазоном (HDRI) • Сенсорный экран • Образцы дисплеев • Сравнение дисплейных технологий

Пассивные твердотельные Резистор · Переменный резистор · Подстроечный резистор · Варистор · Конденсатор · Переменный конденсатор · Подстроечный конденсатор · Катушка индуктивности · Кварцевый резонатор · Предохранитель · Самовосстанавливающийся предохранитель · Трансформатор
Активные твердотельные Диод · Светодиод · Фотодиод · Полупроводниковый лазер · Диод Шоттки · Стабилитрон · Стабистор · Варикап · Вариконд · Диодный мост · Лавинно-пролётный диод · Туннельный диод · Диод Ганна
Транзистор · Биполярный транзистор · Полевой транзистор · КМОП-транзистор · Однопереходный транзистор · Фототранзистор · Составной транзистор · Баллистический транзистор
Интегральная схема · Цифровая интегральная схема · Аналоговая интегральная схема
Тиристор · Симистор · Динистор · Мемристор
Пассивные вакуумные Бареттер
Активные вакуумные и газоразрядные Электронная лампа · Электровакуумный диод · Триод · Тетрод · Пентод · Гексод · Гептод · Пентагрид · Октод · Нонод · Механотрон · Клистрон · Магнетрон · Амплитрон · Платинотрон · Электронно-лучевая трубка · Лампа бегущей волны
Устройства отображения Электронно-лучевая трубка · ЖК-дисплей · Светодиод · Газоразрядный индикатор · Вакуумно-люминесцентный индикатор · Флажковый индикатор · Семисегментный индикатор
Акустические устройства и датчики Микрофон · Громкоговоритель · Тензорезистор
Термоэлектрические устройства Термистор · Термопара · Элемент Пельтье
  • Устройства отображения информации
  • Светодиоды

Wikimedia Foundation . 2010 .

  • Витвинин
  • Питер Левис Кингстон Вентц Третий/Temp

Полезное

Смотреть что такое «Семисегментный индикатор» в других словарях:

  • семисегментный индикатор — — [http://www.iks media.ru/glossary/index.html?glossid=2400324] Тематики электросвязь, основные понятия EN seven segment display … Справочник технического переводчика
  • Газоразрядный индикатор — Эту статью следует викифицировать. Пожалуйста, оформите её согласно правилам оформления статей … Википедия
  • Матричный индикатор — Принцип формирования изображения, используемый в матричных индикаторах Мáтричный индикáтор разновидность знакосинтезирующего индикатора, в котором элементы индикации сгруппированы по строкам и столбцам. Матричный индикатор предназначен для… … Википедия
  • Электронный индикатор — Светодиодный индикатор (компьютерная модель) Электрóнный индикáтор (лат. indicator указатель) это электронное показ … Википедия
  • Дискретный шкальный индикатор — … Википедия
  • Цифровой индикатор — Цифровой индикатор прибор для отображения значения числовой величины в цифровом виде. Имеют фиксированный набор элементов отображения (сегментов), расположенных как произвольно, так и сгруппированных по несколько цифр. Принцип действия … Википедия
  • Девятисегментный индикатор — Эту страницу предлагается объединить с Семисегментный индикатор. Пояснение причин и обсуждение на стра … Википедия
  • Вакуумно-люминесцентный индикатор — Вакуумно лиминесцентный индикатор Вакуумно люминесцентный индикатор (ВЛИ), или катодолюминесцентный индикатор (КЛИ) (vacuum fluorescent display (VF … Википедия
  • Электронное устройство — Эта статья должна быть полностью переписана. На странице обсуждения могут быть пояснения … Википедия
  • Дисплей — У этого термина существуют и другие значения, см. Дисплей (значения). Монохромный дисплей телефона … Википедия
  • Обратная связь: Техподдержка, Реклама на сайте
  • �� Путешествия

Экспорт словарей на сайты, сделанные на PHP,
WordPress, MODx.

  • Пометить текст и поделитьсяИскать в этом же словареИскать синонимы
  • Искать во всех словарях
  • Искать в переводах
  • Искать в ИнтернетеИскать в этой же категории

Введение

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

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

Динамическое управление (динамическая индикация) подразумевает поочередное зажигание разрядов индикатора с частотой, не воспринимаемой человеческим глазом. Схема подключения индикатора в этом случае на порядок экономичнее благодаря тому, что одинаковые сегменты разрядов индикатора объединены.

Эксперименты с семисегментным индикатором

Рассмотрим простейший случай управления индикатором – вывод одной цифры. Схема для наших экспериментов приведена ниже.

Чтобы зажечь на индикаторе какую-то цифру нужно настроить порты, к которым подключен индикатор, в режим выхода, “открыть” транзистор (в данном случае подать на базу “единицу”) и установить в порту микроконтроллера её код.
В зависимости от того, куда подключены сегменты индикатора – коды могут быть разные. Для нашего случая коды цифр будут выглядеть так.

unsigned char number[] =
0x3f, //0
0x06, //1
0x5b, //2
0x4f, //3
0x66, //4
0x6d, //5
0x7d, //6
0x07, //7
0x7f, //8
0x6f //9
>;

Используя десятичные цифры от 0 до 9 в качестве индекса массива, легко выводить в порт нужные коды.

Пример 1. Вывод цифр от 0 до 9
#include
#include

unsigned char number[] =
0x3f, //0
0x06, //1
0x5b, //2
0x4f, //3
0x66, //4
0x6d, //5
0x7d, //6
0x07, //7
0x7f, //8
0x6f //9
>;

unsigned char count = 0;
int main( void )
//порт, к которому подкл. сегменты
PORTB = 0xff;
DDRB = 0xff;

//вывод, к которому подкл. катод
PORTD |= (1 <<0);
DDRD |= (1<<0);

while (1) PORTB = number[count];
count++;
if (count == 10) count = 0;
__delay_cycles (8000000);
>
return 0;
>
Эта программа каждую секунду выводит значение переменной count на семисегментный индикатор. Индикация в данном случае — статическая.

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

Пример2. Вывод цифр от 0 до 99
#include
#include

unsigned char number[] =
0x3f, //0
0x06, //1
0x5b, //2
0x4f, //3
0x66, //4
0x6d, //5
0x7d, //6
0x07, //7
0x7f, //8
0x6f //9
>;

unsigned char
count = 0;

//числа для вывода на индикатор
unsigned char data1 = 2;
unsigned char data2 = 5;

int main( void )
//порт, к которому подкл. сегменты
PORTB = 0xff;
DDRB = 0xff;

//порт, к которому подкл. катод
PORTD = 0;
DDRD = (1<<1)|(1<<0);

while (1)

//выводим в порт код цифры
//и зажигаем следующий разряд
if (count == 0) PORTB = number[data2];
PORTD |= (1 <<1);
>
if (count == 1) PORTB = number[data1];
PORTD |= (1 <<0);
>

count++;
if (count == 2) count = 0;

//частота смены разрядов будет 100 Гц при кварце 8МГц
__delay_cycles (800000);
>
return 0;
>
Эта программа просто выводит любое поразрядно заданное число от 0 до 99.
Частота смены разрядов семисегментного индикатора задается с помощью программной задержки __delay_cycles(). Это не самое удачное решение, потому что добавление каких-нибудь других задач в цикл while будет мешать выводу на индикатор. Давайте организуем смену разрядов индикатора с помощью аппаратного таймера/счетчика Т0

Пример3. Вывод цифр от 0 до 99. Смена разрядов выполняется в прерывании таймера
#include
#include

unsigned char number[] =
0x3f, //0
0x06, //1
0x5b, //2
0x4f, //3
0x66, //4
0x6d, //5
0x7d, //6
0x07, //7
0x7f, //8
0x6f //9
>;

//числа для вывода на индикатор
volatile unsigned char data1 = 0;
volatile unsigned char data2 = 0;

int main( void )
//порт, к которому подкл. сегменты
PORTB = 0xff;
DDRB = 0xff;

//порт, к которому подкл. катод
PORTD = 0;
DDRD |= (1<<1)|(1<<0);

//инициализация таймера Т0
//частота прерываний 100Гц при кварце 8МГц
TIMSK = (1 <TCCR0 = (1 <TCNT0 = 0xb2;

__enable_interrupt ();
while (1) //программный счетчик секунд
data1++;
if (data1 == 10) data1 = 0;
data2++;
if (data2 == 10) data2 = 0;
>
__delay_cycles (8000000);
>
return 0;
>

//прерывания таймера Т0 — вывод на индикатор
#pragma vector = TIMER0_OVF_vect
__interrupt void Timer0_Ovf( void )
static unsigned char count = 0;
TCNT0 = 0xb2;

//выводим в порт код цифры
//и зажигаем следующий разряд
if (count == 0) PORTB = number[data2];
PORTD |= (1 <<1);
>
if (count == 1) PORTB = number[data1];
PORTD |= (1 <<0);
>

count++;
if (count == 2) count = 0;
>
Переменные data1, data2 объявлены с ключевым словом volatile, потому что они используются и в основном коде и в прерывании. В проекте под GCC я забыл поставить его поставить, и компилятор выкинул обе переменные, посчитав их ненужными!

Прерывания таймера происходят параллельно выполнению цикла while. Это позволяет выполнять в цикле какую-нибудь полезную задачу. В данном примере с помощью двух переменных в цикле организован программный счетчик от 0 до 99.
Использовать две восьмиразрядные переменные для организации счетчика от 0 до 99 неудобно и расточительно, ведь такой счетчик можно сделать и на одной переменной типа unsigned char. Хорошо, счетчик мы сделаем, а как вывести его значение на семисегментный индикатор? Нужен код “разбивающий” десятичное число на отдельные разряды и вот как он выглядит:

//программный счетчик
unsigned char counterProg = 35;

//”разбиваем” значение счетчика на отдельные разряды
data1 = counterProg % 10;
data2 = counterProg/10;

data1 = counterProg % 10 – это операция деления по модулю 10 (деление с остатком). Результатом этого выражения будет остаток от деления переменной counterProg на 10, то есть для нашего случая 5.

counterProg/10 – это целочисленное деление на 10. Результатом этого выражения будет число 3.

Таким образом, в переменные data2, data1 будут записаны числа 3 и 5 соответственно, значение счетчика counterProg при этом не изменится.

Пример 4. Вывод цифр от 0 до 99.
Преобразование двоичных чисел в двоично-десятичные (BCD)

#include
#include

unsigned char number[] =
0x3f, //0
0x06, //1
0x5b, //2
0x4f, //3
0x66, //4
0x6d, //5
0x7d, //6
0x07, //7
0x7f, //8
0x6f //9
>;

//числа для вывода на индикатор
volatile unsigned char data1 = 0;
volatile unsigned char data2 = 0;

//программный счетчик секунд
unsigned char counterProg = 0;

int main( void )
//порт, к которому подкл. сегменты
PORTB = 0xff;
DDRB = 0xff;

//порт, к которому подкл. катод
PORTD = 0;
DDRD |= (1<<1)|(1<<0);

__enable_interrupt ();
while (1) //программный счетчик секунд
counterProg++;
if (counterProg == 100) counterProg = 0;
data1 = counterProg % 10;
data2 = counterProg/10;
__delay_cycles (8000000);
>
return 0;
>

//прерывания таймера Т0 — вывод на индикатор
#pragma vector = TIMER0_OVF_vect
__interrupt void Timer0_Ovf( void )
static unsigned char count = 0;
TCNT0 = 0xb2;

//выводим код цифры в порт
//и зажигаем следующий разряд
if (count == 0) PORTB = number[data2];
PORTD |= (1 <<1);
>
if (count == 1) PORTB = number[data1];
PORTD |= (1 <<0);
>

count++;
if (count == 2) count = 0;
>
Следующий этап работы над программой – выделение кода обслуживающего светодиодный семисегментный индикатор в отдельные функции. Какой минимальный набор функций нам необходим? Функция инициализации, функция вывода на индикатор и функция преобразования чисел и записи их в буфер.

Функция инициализации

#define PORT_IND PORTB
#define DDR_IND DDRB
#define PORT_K PORTD
#define DDR_K DDRD
#define KAT1 0
#define KAT2 1

volatile unsigned char data[2];

void IND_Init( void )
//порт к которому подкл. сегменты
PORT_IND = 0xff;
DDR_IND = 0xff;

//очистка буфера
data[0] = 0;
data[1] = 0;
>

Порты, к которым подключен семисегментный индикатор, определены с помощью директивы #define – в будущем это позволит быстро править код. Вместо двух переменных data1, data2 удобнее использовать массив unsigned char data[2].

Функция преобразования

void IND_Conv( unsigned char value)
unsigned char tmp;
tmp = value % 10;
data[0] = number[tmp];
tmp = value/10;
data[1] = number[tmp];
>

Процедура преобразования чисел аналогична описанной выше. Единственное отличие – в буфере (data[]) мы теперь сохраняем не результат преобразования, а коды цифр. Зачем делать в прерывании то, что можно сделать в основном цикле программы?

Функция вывода на индикатор

void IND_Update( void )
static unsigned char count = 0;

//выводим в порт код цифры
PORT_IND = data[count];

//зажигаем нужный разряд
if (count == 0) PORT_K |= (1 < if (count == 1) PORT_K |= (1<

count++;
if (count == 2) count = 0;
>

Эта функция будет вызываться в прерывании таймера. В принципе, для экономии ресурсов ее можно было бы сделать встраиваемой.

Пример 5. Код программы с использованием этих функций //программный счетчик секунд
unsigned char counterProg = 0;

int main( void )
IND_Init();

__enable_interrupt ();
while (1) counterProg++;
if (counterProg == 100) counterProg = 0;
IND_Conv(counterProg);
__delay_cycles (8000000);
>
return 0;
>

//прерывания таймера Т0 – вывод на индикатор
#pragma vector = TIMER0_OVF_vect
__interrupt void Timer0_Ovf( void )
TCNT0 = 0xb2;
IND_Update();
>
И, наконец – разбиение программы на модули.

Создаем два файла – indicator.h и indicator.c. Сохраняем их в папке проекта.
В хидер файле у нас будут директивы условной компиляции, макроопределения и прототипы функций.

#ifndef INDICATOR_H
#define INDICATOR_H

#define PORT_IND PORTB
#define DDR_IND DDRB
#define PORT_K PORTD
#define DDR_K DDRD
#define KAT1 0
#define KAT2 1

void
IND_Init( void );
void IND_Conv( unsigned char value);
void IND_Update( void );

#endif //INDICATOR_H

В сишном файле – #include “indicator.h”, объявления переменных и реализация трех функций. Функции описаны выше, поэтому здесь их не привожу.

Подключаем файл indicator.c к проекту.
В файл main.c инклюдим заголовочный файл нашего драйвера семисегментного индикатора — #include “indicator.h”

Все. Теперь мы можем использовать функции для работы с индикатором в файле main.
Полный код драйвера смотрите в проектах.

Продолжение следует… Скоро будет дополнение к этой статье — описание вольтметра на микроконтроллере – в проекте используется 4-ех разрядный семисегментный индикатор.

Прикладне програмування з нуля.

JavaFX, C, JavaScript, Embedded Systems and Web applications.

Семи сегментный индикатор и AVR. Динамическая индикация. Программа на Си. Шаг №5

Опубликовано 22.12.2012 автором admin137

Обновлено 3.04.15. Всем привет. В прошлой статье мы с Вами рассмотрели алгоритм общения с ЖКИ, а также вывод информациина нее, и протестировали в симуляторе. В этой записи я кратенько расскажу о “недорогом” способе вывода информации — это семисегментный индикатор, который является наиболее простым из индикаторов, для отображения арабских цифр, а также некоторых символов, которые возможно на нем вывести. Также рассмотрим программу на Си для AVR, и подключение в железе и симуляторе.

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

Анодный и катодный семи сегментный индикатор

Если индикаторов несколько, следовательно и управляются катоды несколькими ножками МК. . Но всегда используйте транзисторы, т.к. порты ввода-вывода могут сгореть из-за относительно большого тока. Я использовал обычные 315 транзисторы. На рисунке ниже я отобразил примерное подключение, через них, управляющего вывода индикатора и контроллера. Для монтажа нам потребуется 11 ножек микроконтроллера, т.е. для отображения информации на сегментах 8 ножек (7 +точка) и по одной ножки на каждый индикатор для его управления, у меня их три, поэтому и ножки управления тоже три. Ниже я привел и описал программу. Для управления сегментами будем использовать пины одного порта, что б не путаться. Писал под микроконтроллер ATmega8. Если Вы хотите отвязаться от “камня” то это не проблема, например в разбиваем код на библиотеки, где без проблем можно изменить настройки под другой “камень”, в основном это номера пинов и портов. Там же описаны общие правила универсальности и переноса.

Рисунок подключения транзистора к МК и индикатору.

Перейдем к программе. В этой небольшой программе (на Си) я привел пример включения трех элементов индикатора и вывод числа с запятой. Использование таймера и прерывания для вывода на индикатор. В ходе написания программы мы должны определиться какой пин порта должен соответствовать сегменту на индикаторе. Сам элемент индикатора приведен на рисунке ниже. Сбоку описание подключения выводов к сегментам элемента индикатора(пин порта – номер ножки элемента (рис. выше) – буква сегмента – число в массиве, отвечающее за включение сегментов на элементе).

семисегментный-элемент ЖК - индикатора

PB0 — 12 — управление первым элементом

PB6 — 9 — управление вторым элементом
PB7 — 8 — управление третьим элементом
PD7 – 11 — (A) — 128
PD6 – 10 — (F) — 64
PD5 – 7 — (B) — 32
PD4 – 5 — (G) — 16
PD3 – 4 — © — 8
PD2 – 3 — (DP) — 4
PD1 – 2 — (D) — 2
PD0 – 1 — (E) — 1

Управление семисегментным дисплеем с помощью ПЛИС

Привет, Хабр! Хочу внести свою посильную лепту в продвижение ПЛИС. В этой статье я постараюсь объяснить, как на языке VHDL описать устройство, управляющее семисегментным дисплеем. Но перед тем как начать, хочу кратко рассказать о том как я пришел к ПЛИС и почему я выбрал язык VHDL.

Где-то пол года назад решил попробывать свои силы в программировании ПЛИС. До этого со схемотехникой никогда не сталкивался. Был небольшой опыт использования микроконтроллеров (Atmega328p, STM32). Сразу после решения освоиться с ПЛИС, встал вопрос выбора языка, который я буду использовать. Выбор пал на VHDL из-за его строгой типизации. Мне, как новичку, хотелось как можно больше возможных проблем отловить на этапе синтеза, а не на рабочем устройстве.

Почему именно семисегментный дисплей? Мигать светодиодом уже надоело, да и логика мигания им не представляет из себя ничего интересного. Логика управления дисплеем с одной стороны сложнее, чем мигание светодиодом (т. е. писать ее интереснее), а с другой достаточно простая в реализации.

Что я использовал в процессе создания устройства:

  • ПЛИС Altera Cyclone II (знаю, что он безнадежно устарел, зато у китайцев его можно купить за копейки)
  • Quartus II версии 13.0.0 (на сколько я знаю это последняя версия поддерживающая Cyclone II)
  • Симулятор ModelSim
  • Семисегментный дисплей со сдвиговым регистром

Задача

Создать устройство, которое будет в цикле показывать числа 0 — 9. Раз в секунду отображаемое на дисплее значение должно увеличиваться на 1.

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

Модули

  • Данное устройство должно уметь отсчитывать время. Для подсчета времени я создал модуль «delay». Этот модуль имеет 1 входящий и 1 исходящий сигнал. Модуль принимает частотный сигнал ПЛИС и, через указанное количество периодов входящего сигнала, меняет значение исходящего сигнала на противоположное.
  • Устройство должно считать от 0 до 9. Для этого будет использоваться модуль bcd_counter.
  • Для того, чтобы зажечь сегмент на дисплее, нужно выставить в сдвиговом регистре дисплея соответствующий сегменту бит в 0, а для того, чтобы погасить сегмент в бит нужно записать 1 (мой дисплей имеет инвертированную логику). Установкой и сбросом нужных битов будет заниматься декодер bcd_2_7seg.
  • За передачу данных будет отвечать модуль transmitter.

Для наглядности, привожу схему данного устройства

схема

Как видно из схемы устройство имеет 1 входящий сигнал (clk) и 3 исходящих сигнала (sclk, dio, rclk). Сигнал clk приходит в 2 делителя сигнала (sec_delay и transfer_delay). Из устройства sec_delay выходит исходящий сигнал с периодом 1с. По переднему фронту этого сигнала счетчик (bcd_counter1) начинает генерировать следующее число для отображения на дисплее. После того, как число сгенерировано, декодер (bcd_2_7seg1) преобразует двоичное представление числа в горящие и не горящие сегменты на дисплее. Которые, с помощью передатчика (transmitter1), передаются на дисплей. Тактирование передатчика осуществляется с помощью устройства transfer_delay.

Код

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

Вот как выглядит entity устройства delay

entity delay is -- При объявлении entity, поле generic не является обязательным generic (delay_cnt: integer); -- Описываем входные и выходные сигналы устройства port(clk: in std_logic; out_s: out std_logic := '0'); end entity delay; 

Через поле generic мы можем задать устройству нужную задержку. А в поле ports описываем входящие и исходящие сигналы устройства.

Архитектура устройства delay выглядит следующим образом

-- В секции architecture описывается то, как устройство будет работать -- С одной entity может быть связано 0 или более архитектур architecture delay_arch of delay is begin delay_proc: process(clk) variable clk_cnt: integer range 0 to delay_cnt := 0; variable out_v: std_logic := '0'; begin -- Если имеем дело с передним фронтом сигнала if(rising_edge(clk)) then clk_cnt := clk_cnt + 1; if(clk_cnt >= delay_cnt) then -- switch/case в языке VHDL case out_v is when '0' => out_v := '1'; when others => out_v := '0'; end case; clk_cnt := 0; -- Устанавливаем в сигнал out_s значение переменной out_v out_s  

Код внутри секции process исполняется последовательно, любой другой код исполняется параллельно. В скобках, после ключевого слова process указываются сигналы, по изменению которых данный процесс будет запускаться (sensivity list).

Устройство bcd_counter в плане логики выполнения идентично устройству delay. Поэтому на нем я подробно останавливаться не буду.

Вот как выглядит entity и architecture декодера

entity bcd_to_7seg is port(bcd: in std_logic_vector(3 downto 0) := X"0"; disp_out: out std_logic_vector(7 downto 0) := X"00"); end entity bcd_to_7seg; architecture bcd_to_7seg_arch of bcd_to_7seg is signal not_bcd_s: std_logic_vector(3 downto 0) := X"0"; begin not_bcd_s  

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

В устройстве transmitter я комбинирую последовательную и параллельную логику

entity transmitter is port(enable: in boolean; clk: in std_logic; digit_pos: in std_logic_vector(7 downto 0) := X"00"; digit: in std_logic_vector(7 downto 0) := X"00"; sclk, dio: out std_logic := '0'; ready: buffer boolean := true); end entity transmitter; architecture transmitter_arch of transmitter is constant max_int: integer := 16; begin sclk  

В сигнал sclk я перенаправляю значение входящего в передатчик сигнала clk, но только в том случае, если устройство в данный момент выполняет передачу данных (сигнал ready = false). В противном случае значение сигнала sclk будет равно 0. В начале передачи данных (сигнал enable = true), я объединяю данные из двух входящих в устройство 8-и битных векторов (digit_pos и digit) в 16-и битный вектор (data_v) и передаю данные из этого вектора по одному биту за такт, устанавливая значение передаваемого бита в исходящий сигнал dio. Из интересного в этом устройстве хочу отметить то, что данные в dio устанавливаются на задний фронт сигнала clk, а в сдвиговый регистр дисплея данные с пина dio будут записаны по приходу переднего фронта сигнала sclk. По завершению передачи, установкой сигнала ready
Вот как выглядит entity и architecture устройства display

entity display is port(clk: in std_logic; sclk, rclk, dio: out std_logic := '0'); end entity display; architecture display_arch of display is component delay is generic (delay_cnt: integer); port(clk: in std_logic; out_s: out std_logic := '0'); end component; component bcd_counter is port(clk: in std_logic; bcd: out std_logic_vector(3 downto 0)); end component; component bcd_to_7seg is port(bcd: in std_logic_vector(3 downto 0); disp_out: out std_logic_vector(7 downto 0)); end component; component transmitter is port(enable: in boolean; clk: in std_logic; digit_pos: in std_logic_vector(7 downto 0); digit: in std_logic_vector(7 downto 0); sclk, dio: out std_logic; ready: buffer boolean); end component; signal sec_s: std_logic := '0'; signal bcd_counter_s: std_logic_vector(3 downto 0) := X"0"; signal disp_out_s: std_logic_vector(7 downto 0) := X"00"; signal tr_enable_s: boolean; signal tr_ready_s: boolean; signal tr_data_s: std_logic_vector(7 downto 0) := X"00"; -- Этот флаг, совместно с tr_ready_s контролирует -- установку и сброс rclk сигнала signal disp_refresh_s: boolean; signal transfer_clk: std_logic := '0'; begin sec_delay: delay generic map(25_000_000) port map(clk, sec_s); transfer_delay: delay generic map(10) port map(clk, transfer_clk); bcd_counter1: bcd_counter port map(sec_s, bcd_counter_s); bcd_to_7seg1: bcd_to_7seg port map(bcd_counter_s, disp_out_s); transmitter1: transmitter port map(tr_enable_s, transfer_clk, X"10", tr_data_s, sclk, dio, tr_ready_s); tr_proc: process(transfer_clk) variable prev_disp: std_logic_vector(7 downto 0); variable rclk_v: std_logic := '0'; begin if(rising_edge(transfer_clk)) then -- Если передатчик готов к передаче следующей порции данных if(tr_ready_s) then -- Если передаваемые данные не были только что переданы if(not (prev_disp = disp_out_s)) then prev_disp := disp_out_s; -- Помещаем передаваемые данные в шину данных передатчика tr_data_s  

Это устройство управляет другими устройствами. Здесь, перед объявлением вспомогательных сигналов, я объявляю компоненты которые буду использовать. В самой архитектуре (после ключевого слова begin) я создаю экземпляры устройств:

  • sec_delay — экземпляр компонента delay. Исходящий сигнал направляется в сигнал sec_s.
  • transfer_delay — экземпляр компонента delay. Исходящий сигнал направляется в сигнал transfer_clk.
  • bcd_counter1 — экземпляр компонента bcd_counter. Исходящий сигнал направляется в сигнал bcd_counter_s.
  • bcd_to_7seg1 — экземпляр компонента bcd_to_7seg. Исходящий сигнал направляется в сигнал disp_out_s.
  • transmitter1 — экземпляр компонента transmitter. Исходящие сигналы направляются в сигналы sclk, dio, tr_ready_s.

Если передатчик не занят, то процесс инициализирует начало передачи данных

 if(tr_ready_s) then if(not (prev_disp = disp_out_s)) then prev_disp := disp_out_s; -- Помещаем передаваемые данные в -- шину данных передатчика tr_data_s  

Устанавливает и сбрасывает сигнал rclk после завершения передачи данных

 if(rclk_v = '1') then disp_refresh_s  

Временная диаграмма

Вот как выглядит временная диаграмма передачи числа 1 на первую позицию дисплея

timing diagram

Сначала передаются данные “10011111“. Затем передается позиция числа на дисплее “00010000“ (этот параметр приходит в передатчик, как константа X”10”). В обоих случаях первым передается крайний правый бит (lsb).

Весь код можно посмотреть на github. Файлы с припиской *_tb.vhd — это отладочные файлы для соответствующих компонентов (например transmitter_tb.vhd — отладочный файл для передатчика). Их я на всякий случай тоже залил на github. Данный код был загружен и работал на реальной плате. Кому интересно, иллюстрацию работы кода можно посмотреть вот тут (начиная с 15:30). Спасибо за внимание.

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

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