ЧАСЫ С LCD ИНДИКАТОРОМ.
Первые часы у нас будут с использованием LCD индикатора. Нет, не тех многосимвольно-многострочных с контроллером на борту, а простые "стекляшки". Главное, чтобы они были без мультиплексирования и рабочее напряжение совпадало с питанием CPLD. Как правило, большинство без проблем работают от 5 вольт. И многие из них работают и от 3-х вольт. Конечно, лучше использовать такие у которых металлические выводы, а не просто площадки на стекле, к которым даже не подпаяться. Неплохо, чтобы дисплей имел 4 семисегментных разряда с красивыми разделительными точками, напоминающими знак деления. Конечно, такие найти труднее, чем на "три с половиной" разряда (в четвертом разряде только 2 сегмента для цифры "1" - они годятся для АЦП 572ПВ5). В качестве тактового генератора, нам потребуется источник частоты 32768 Гц. Для этого можно взять "часовой" кварц и микросхему с парочкой инверторов - главное чтобы инверторы работали от того напряжения, которое мы будем использовать для питания микросхемы программируемой логики. Например, к561ла7. Кто желает большую точность хода часов, может раскошелиться на Далласовский (или Максимовский) генератор ds32kHz - одна микросхема, для которой заявлена точность чуть ли не 20 секунд в год. Приведу схему для к561ла7, те кто будет использовать ds32khz - воспользуйтесь даташитом.
Основные компоненты, надеюсь, собраны: Питание 5 или 3.3 вольта, тактовый генератор, LCD индикатор и микросхема. Мне доступна микросхема xc9572xl-pc44, поэтому я буду использовать её. Начнём с запуска ISE WebPack. Откроем новый проект и назовем его LCD_clock. В качестве target укажем свою микросхему и в качестве верхнего уровня укажем schematic. Схема, которую мы запрограммируем будет выглядеть так:
Спойлер
Входную частоту 32 кГц мы поделим десяти-разрядным счетчиком на 2^10, т.е. на 1024. На выходе получим частоту 32 Гц, которую и будем в дальнейшем использовать. Эта частота будет использоваться и для питания подложки индикатора, и как основа для всей остальной схемы. Остальная схема используя эту частоту в модуле counter_sec поделит её на 32 и получит секундные импульсы, которые будут выходить на выход divider и этот сигнал будет управлять разделительными точками на дисплее. Далее в том же модуле эта частота далее будет делиться на 60 и выдавать минутные импульсы на выход переноса 'tc'. Эти импульсы пройдя на вход модуля counter60 будут позволять раз в минуту увеличивать своё значение на 1 пока, как следует из названия, счетчик не досчитает до 60. Тогда, уже на выходе этого счётчика сформируется сигнал переноса, который раз в час разрешит считать часы. Без модуля manual часы уже работоспособны. Но для своего удобства мы его будем использовать для установки времени, чтобы не ждать ночь напролёт наступления полночи, чтобы торжественно включать часы. Модуль manual позволит в ручном режиме установить текущее время. Посколько счетчикам counter60 и counter24 удобнее считать время не в том виде, в котором нам приятно его видеть, а в совершенно несуразном двоичном счете, ну или в качестве компромисса - двоично-десятичном, придется между счетчиком и выходом на дисплей поставить дешифратор, который двоичный код переведет в более удобоваримый семисегментный. Ой! Совсем забыл про установку времени. Оказывается, нам потребуются ещё три кнопки без фиксации для установки времени (и три резистора по 10 кОм).
Возвращаемся к ISE WebPack-у и начинаем. Следующим шагом ISE WebPack попросит добавить модули: schematic назовём так же, как и проект - lcd_clock. Там где предложат добавить другие исходники - пропустим, можно и после это сделать. В конце, нам дадут редактировать схему... Но ни одного компонента мы добавить не можем, так как их в списке нет, за исключением простеньких ibuf, inv, obuf, and2b, xor2 и gnd. Поэтому пока просто сохраним пустую схему и займемся добавлением остальных исходников. Удобнее всего распаковать содержимое архива в каталог проекта и используя команды Project -> Add Source всех их последовательно добавить. Все добавляемые модули имеют расширение ".vhd", и это значит, что это текстовый файл с описанием модуля на языке VHDL. Можно было бы вышеупомянутые модули описать схемой, но во-первых - так описание компактнее. Во-вторых, стиль формирования связей несколько отличается от конструкций, которые мы привыкли использовать при использовании микросхем малой степени интеграции. Например, если нарисовать RS-триггер из двух элементов И-НЕ - такая схема не сможет синтезироваться, или вот делитель на 2^10: можно поставить 10 D-триггеров друг за другом, выход предыдущего подключив на вход C следующего - это будет работать, но ресурсы логики будут использованы крайне неэффективно. Поэтому модуль divider1024 у нас будет выглядеть так:
- Код:
entity divider1024 is
Port ( clk_input : in STD_LOGIC;
out32 : out STD_LOGIC);
end divider1024;
architecture Behavioral of divider1024 is
signal counter: std_logic_vector (9 downto 0);
begin
process (clk_input)
begin
if (clk_input'event and clk_input='1') then
counter <= counter+1;
End if;
end process;
out32 <= counter(9);
end Behavioral;
Раздел entity описывает какие входы и выходы у модуля имеются. В данном случае только один вход clk_input и один выход out32. А раздел architecture behavioral описывает поведение модуля. Оно включает в себя описание сигнала из 10-разрядной шины, которая при фронте импульса clk_input (описывается строчкой clk_input'event and clk_input='1') значение на шине counter увеличивает на 1. Нас же интересует только старший разряд этой шины который мы и выведем наружу командой out32 <= counter(9). Как видите, вместо рисования 10 триггеров и формирования из них счетчика мы написали от-силы 10 строк, с которыми САПРу гораздо удобнее работать, чем с нашим чертежом.
Рассмотрим следующий модуль - bin2seg. Очень типовой модуль предназначенный для преобразования двоичного кода в семисегментный.
- Код:
entity bin2seg is
Port ( arg : in STD_LOGIC_VECTOR (3 downto 0);
polarity : in STD_LOGIC;
seg_out : out STD_LOGIC_VECTOR (6 downto 0));
end bin2seg;
architecture Behavioral of bin2seg is
signal decoded: STD_LOGIC_VECTOR (6 downto 0);
begin
with arg select
decoded <= "0111111" when "0000",
"0000110" when "0001",
"1011011" when "0010",
"1001111" when "0011",
"1100110" when "0100",
"1101101" when "0101",
"1111101" when "0110",
"0000111" when "0111",
"1111111" when "1000",
"1101111" when "1001",
"0000000" when "1111",
"-------" when others;
seg_out <= decoded when polarity = '0' else not decoded;
end Behavioral;
Здесь описана чисто комбинационная логика: что должно быть на выходе в зависимости от того что на входе. Только следует помнить, что в случае использования оператора select должны быть перебраны ВСЕ комбинации входного сигнала. Поэтому если все комбинации нас не интересуют, можно использовать ключевое слово others. В данном случае, я ещё и указал, что значение выхода мне совешенно не важно. Таким образом при синтезе логических выражений не будет требоваться лишняя логика, чтобы отфильтровать неприемлемые входные значения. Вероятнее всего при подаче их будут зажигаться какие-либо сегменты, но мы этого не увидим, потому что этого никогда в нашей конструкции не случится. Добавлю только, что в этом модуле специально определена комбинация, когда на входе одни единицы "1111" или 0x0F - ни один сегмент не светится. Это нужно для гашения разряда.
Остальные модули предлагаю изучить самостоятельно. Только несколько замечаний: в счётчиках десятков часов и минут несоответствие ширины шины. На выход идёт 4-х разрядная шина (нужно для совместимости с 4-х разрядным входом модуля bin2seg), а счетчик 3-х или даже 2-х разрядный. Поэтому неиспользуемые разряды имеют постоянный уровень лог.0. Ещё в счетчике десятков часов сделано так, чтобы при состоянии этого счетчика "0" на дешифратор шла комбинация "1111" - т.е. этот разряд не светился (я предпочитаю видеть "7:01" больше, чем "07:01"). В этих счетчиках введены сигналы сброса и open_exit - которые в данных конструкциях не используются (в схеме они намертво подключены к лог.0). Модуль manual делает так, что, во-первых, подавляет дребезг контактов. Во-вторых, если кнопка удерживается более 1 секунды - начинается автоповтор нажатия с частотой около 3-х раз в секунду.
После добавления модулей, для каждого из них можно провести проверку синтаксиса (панель Processes -> Check Syntax) и обязательно надо выполнить там же Design Utilities -> Create Schematic Symbol. Это создаст символы, которые мы сможем поместить в схему. Так что можно, наконец, открывать схему, накидать символов, и соединять всё это между собой. Некоторую сложность может вызвать элемент "obuf", который подключены к семиразрядным выходам модуля bin2seg. Он семиразрядный, а в списке компонентов есть только одно-, четырёх-, восьми- и шестнадцатиразрядные. Повторение компонента для увеличения его разрядности называется Instatiating и делается так: берем обычный одноразрядный элемент obuf и ставим в схему. После чего выбираем его properties и в поле InstName к имени добавляем "(6:0)" и только после этого подключаем к нему цепи. Первому я сделал это значение видимым. В данном случае имя XLXI_9 надо заменить на XLXI_9(6:0). Незабудьте также поименовать входные и выходные цепи, впоследствии, это вам облегчит жизнь. Когда схема будет завершена, не забудьте провести проверку Tools -> Check Schematic. Ошибок быть недолжно. По завершении, панель исходных файлов проекта должна выглядеть так:
Теперь, осталось сделать двойной клик на команде "Implement Design" в панели Processes и дождаться окончания работы САПР. Если вы за целевой кристалл выбрали xc9572(xl), как и я, вас наверняка ждёт разочарование в виде красного креста напротив позиции "Fit" и сообщение об ошибке, намекающее о том, что ваш проект требует 74 макроячейки, а в выбранном кристалле наличествует только 72. Тем, кому повезло, и использовали более ёмкий кристалл, могут пропустить этот абзац. Несчастливчикам придётся же подумать где можно сэкономить эту пару макроячеек. Сэкономить возможно на том, что все семь выходов для отображения самого старшего разряда не нужны. Сегмент "F" никогда не зажигается (при "0" у нас ничего не светится, а при "1" и "2" - этот сегмент тоже погашен). Итого, один выход, а с ним и макроячейку уже сэкономили. Ого! оказывается здесь целое поле для экономии! Сегменты "D", "E" и "G" зажигаются тогда же, когда и сегмент "A". Следовательно, они тоже не нужны - соединяем их вместе. Таким образом нам нужно переделать выход на 4 разряд индикаторов следующим образом:
[если есть интерес, завтра продолжу, а нет - пожалуйтесь и модераторы этот графоманский бред удалят]
- Вложения
-
- proj_nav.png
- (16.9 KiB) Скачиваний: 1934
-
- lcd_schematic.png
- (56 KiB) Скачиваний: 1201
-
- maket.jpg
- (153.24 KiB) Скачиваний: 2060