Меню

Двоично десятичный счетчик verilog



Двоично-десятичный счетчик (Binary-Coded Decimal counter)

Двоично-десятичный счетчик (BCD counter) имеет 10 состояний.

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

Цифра 8 4 2 1
0 0 0 0
0 0 0 1
0 0 1 0
0 0 1 1
0 1 0 0
0 1 0 1
0 1 1 0
0 1 1 1
1 0 0 0
1 0 0 1

Коды 1010 – 1111 для кодирования не используются.

Двоично-десятичные счетчики могут быть построены рассмотренным выше способом. Схема одного разряда десятичного представлена на рис. 26. Счетик реализован на основе двоичного 4-разтрядного счетчика с модулем счета 16, асинхронным сбросом и синхронной загрузкой.

Схема 2-разрядного двоично-десятичного счетчика представлена на рис.27.

Пример описания суммирующего двоично-десятичного двухразрядного счетчика на Verilog.

module BCD_counter (clk, en, reset, out);

inputclk, en, reset;

output[7:0] out;

reg[3:0] out1,out2;

reg en1;

always@ (posedge clk or negedgereset)

begin if(!reset) out1

Дата добавления: 2015-09-11 ; просмотров: 9 | Нарушение авторских прав

Источник

Часы на ПЛИС с применением Quartus II и немного Verilog

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

Значит, что мы имеем:
1) Отладочную плату Terasic DE0-Nano с Cyclone IV на борту.

2) Макетку с распаянным на ней семисегментным индикатором, на который мы будем выводить часы и минуты/
По этим двум пунктам полная свобода выбора практически любая ПЛИС подойдет, да и макетку с индикатором каждый сделает так, как сделает.

Теперь о проекте.
Будем идти по порядку. Перво-наперво зададимся вопросом: что такое часы? Часы — это прибор, который отсчитывает время. Для того, чтобы его отсчитывать, нам нужен точный источник. На нашей плате есть генератор тактового сигнала 50 МГц. Многовато, поэтому нам нужно его разделить на 50 000 000, чтобы получить частоту 1 Гц(один «тик» в секунду). Как поделить? Я сделал это в два этапа: используя PLL, поделил на 50 и используя счетчик, поделил на миллион.
Что такое PLL? Грубо говоря, это такая штука, которая может изменять тактовый сигнал: умножать, делить, сдвигать по фазе, менять скважность. В Cyclone IV их 4 штуки, так почему бы не воспользоваться одной…

Для этого открываем MegaWizard Plugin Manager и используем ALT_PLL из раздела IO:
1) Устанавливаем входную частоту 50 МГц:

2) Отключаем ненужные входы:

3)Три раза жмем Next и попадаем в окно выбора параметров сигнала, где задаем коэффициент деления 50:

Дальше можно смело нажимать Finish, сохранять и вставлять в проект.
Вот такую красоту мы получили:

Слева вход 50 МГц, справа 1 МГц.
Теперь нам нужно поделить еще на миллион — для этого используем счетчик по модулю 1000000. Модуль счета — это количество возможных состояний счетчика.
Создаем его с помощью того же MegaWizard, используя LPM_Counter.
Задаем разрядность — 20 бит, и выбираем modulus, with a count modulus of 1000000.
Получаем вот что:

Теперь у нас аккуратненькие 1 Гц, которые можно получить с старшего (19) разряда.

Дальше нам необходимо реализовать каскад из 3-х счетчиков: два по модулю 60 (минуты и секунды), и один по модулю 24(очевидно, часы).
Секундный счетчик — с асинхронным сбросом, который происходит при нажатии любой кнопки(установка часов/минут):

Как видно, использован выход Carry Out (перенос при переполнении в следующий счетчик), а секунды выводятся на светодиоды.

Следующие 2 счетчика строятся аналогично, за одним исключением: для установки времени необходимо подавать тактовый сигнал побыстрее 1 Гц, для того, чтобы не уснуть при настройке. 🙂
Для этого используем мультиплексоры, управляемые кнопками:

Читайте также:  Сроки плановой проверки газовых счетчиков

Верхний мультиплексор используется для выбора, какую частоту подавать на вход счетчика, а нижний — выбирает, что подавать на вход cin: перенос из cout секундного счетчика, или просто уровень лог. «1».
Суть входа cin в том, что счетчик считает только при наличии на этом входе уровня логической единицы. То есть, когда счетчик секунд переполняется, он поднимает cout в единицу. Эта «1» поступает на вход cin следующего счетчика и он отчитывает одну минуту, и так далее.
Таким образом, при отпущенной кнопке key[0] минутный счетчик считает 1 раз в минуту(что логично), а при нажатой — где-то 4 раза в секунду.

Аналогично для часового счетчика:

Верхний мультиплексор заведует переносом, а нижний частотой, за исключением одного момента: при нажатой кнопке key[0] тактовые сигналы на вод счетчика не поступают(это сделано для того, чтобы он часы не сбивались при настройке минут). Это сделано за счет элемента AND, на вход которого подается тактовый сигнал и key[0]. При отпущенной кнопке на key[0] высокий уровень и q[19] проходит через него, при нажатой — уровень «0» и на выходе тоже «0». В принципе, можно было бы включить у счетчика вход «count enable» и отключать счетчик через него — в данной задаче это непринципиально.

Теперь нам надо выводить данные с счетчиков. Для этого нам необходимо сделать преобразователь из двоичного кода в двоично-десятичный. Это такое представление десятичного числа в двоичном коде, когда каждая десятичная цифра задается отдельным 4мя двоичными разрядами.
Пример:
738 = 0111 0011 1000.

Для этого преобразования воспользуемся алгоритмом double-dabble.
Суть алгоритма:
1) Сдвинуть двоичное число влево на один разряд.
2) Если 4 сдвига — число BCD в колонках «десятки» и «единицы». Конец алгоритма
3) Если в любой колонке число больше 4 — прибавить 3.
Перейти к п1.

Вот иллюстрация:

А вот то, что нам нужно реализовать, чтобы это преобразование выполнялось без задержек:
s16.radikal.ru/i191/1107/a4/59618e3101ca.png
Каждый модуль С прибавляет к входным данным 3, если на входе число, большее, чем 4.

Вот он сам и таблица истинности его работы:

Для реализации всего этого хозяйства пишем вот два таких модуля на verilog:

module add3(in,out);
input [3:0] in;
output [3:0] out;
reg [3:0] out;

always @ (in)
case (in)
4’b0000: out
Сохраняем и вставляем в проект в количестве двух штук:

Один будет для часов, другой — для минут.

Теперь необходимо сделать лирическое отступление касательно нашего индикатора.
Я использовал Lite-On ltc-4727js.
Согласно даташиту, у него сегменты с общим катодом для каждой цифры + входы анодов сегментов каждой цифры объединены. Это значит, что мы сможем одновременно зажигать только 1 цифру. Не беда, будем зажигать их по-очереди, только переключать будем очень быстро. Так быстро, что даже Чак Норрис не заметит мерцания 😉
Самые интересные части из даташита:

и

Как я это все подключил?
А вот используя такие пины:

С сегментами, думаю, все ясно, а вот что такое загадочное digit[4..0]… Всё просто — digit[4..1] —
это наши цифры, а digit[0] — это вспомогательные сегменты(двоеточие между 2 и 3 цифрами). Скажу вам, самое трудное — это правильно подключить все и правильно поставить соответствие между выходами ПЛИС и нашими пинами!

Разберем теперь механизм вывода на индикатор.
Занимается этим вот такая монструозная конструкция:

Слева у нас конверторы bin-to-BCD. В центре внимания — мультиплексор на 5 входов шириной 4 бита. Первые 4 входа — цифры, пятый вход — для зажигания точек(которые мигают раз в секунду). Внизу виднеется схемка, которая на этот секундный вход подает 1111 или 1110. О том, почему именно так — немного дальше. В зависимости от того, какая комбинация приходит на управляющий вход мультиплексора, он выводит нужный разряд на дешифратор(устройство которого рассмотрим чуть позже). Выше него — девайс, который выбирает, на какой катод подавать «0», чтобы загорался нужный сегмент. Вот его внутренности:

Читайте также:  Как считать электрический счетчик день ночь

module segment_select (in,out,sel);
input in;
output reg [4:0] out;
output reg [2:0] sel;

always @ (posedge in)
if (sel == 4)
sel = 0;
else sel = sel + 1;

always @(*)
case (sel)
0: out
Обратите внимание на запись вида 5’b0zzzz. Здесь 5’b означает, что мы задаем 5 бит в двоичном виде, 0 — уровень нуля, z — высокоомное состояние(ток в пин не течет). А почему именно 0? Да потому, что у нас общий катод на цифре, ток течет от анода к катоду, или от 1 к 0. Вот и задаем на катоде 0, а на аноде 1.

Теперь устройство дешифратора:

module decoder_7seg (BCD, segA, segB, segC, segD, segE, segF, segG, segDP);

input [3:0] BCD;
output segA, segB, segC, segD, segE, segF, segG, segDP;
reg [7:0] SevenSeg;
always @(BCD)
case(BCD)
4’h0: SevenSeg = 8’b11111100;
4’h1: SevenSeg = 8’b01100000;
4’h2: SevenSeg = 8’b11011010;
4’h3: SevenSeg = 8’b11110010;
4’h4: SevenSeg = 8’b01100110;
4’h5: SevenSeg = 8’b10110110;
4’h6: SevenSeg = 8’b10111110;
4’h7: SevenSeg = 8’b11100000;
4’h8: SevenSeg = 8’b11111110;
4’h9: SevenSeg = 8’b11110110;
4’b1111: SevenSeg = 8’b11000000;
default: SevenSeg = 8’b00000000;
endcase

assign = SevenSeg;
endmodule
Тут в зависимости от того, какая цифра нам нужна, выбирается, какие сегменты зажигать.
Интересуют два момента — default и число 1111. Когда у нас BCD принимает значение, отличное от заданных(1110, о котором говорилось ранее) — то все сегменты выключены. Когда у нас приходит 1111 — то зажигаются сегменты A и B. Как можно видеть из даташита, они же подключены к точкам L1 и L2.

Вот, собственно, и все.
Собираем все в одну кучу один проект, назначаем пины, компилируем(ага, используется менее 1% нашего могучего камушка) и заливаем в ПЛИС.

Вот проект:
ifolder.ru/24865983
Необходимо выбрать вашу ПЛИС, и переназначить пины. Правда, я использовал PLL… Поэтому при переносе проекта на другую ПЛИС необходимо будет вашу входную частоту(не факт, что у вас там будет 50 МГЦ) поделить самостоятельно.
Вот видео:

Спасибо за внимание, надеюсь, кому-нибудь пригодится!
UPD
Спасибо за комментарии всем!
Я не знаю, как оно оказалось в этом блоге. Я хотел перепилить, залить картинки норм, переделать кое-чего… Но я сегодня вообще на Хабр не заходил!
Есть идея о том, чтобы сделать получение времени извне, например по NTP.
Про хостинг — мне в личку посоветовали, перелью туда.
Это мой первый топик, до этого опыта публикаций не было, картинки залил на первый вспомнившийся хостинг.
Я только сегодня оказался в родном городе и с нормальным интернетом. Завтра перепилю с учетом пожеланий!

Источник

Язык описания аппаратуры Verilog HDL

В этой статье я постараюсь рассказать про счетчики, про их описание на Verilog и их схемотехническое представление в RTLViever.

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

Двоичный счетчик.

Вот это просто двоичный счетчик. На входе данных группы триггеров стоит сумматор. Одно из слагаемых для сумматора — это предыдущее значение счетчика, а второе слагаемое — константа «единица».

reg [3:0]counter;
always @( posedge clk)
counter

Вот представление этого счетчика в RTLViewer:

К сожалению симулировать такой счетчик не получится, так как симулятору не известно начальное значение регистров counter[3:0] , значит он не сможет вычислить и все последующие значения счетчика. Чтобы провести симуляцию нам нужен двоичный счетчик с ассинхронным сбросом.

Читайте также:  Счетчик реактивной энергии трехфазный 100а

Двоичный счетчик с асинхронным сбросом.

reg [3:0]counter;
always @( posedge clk or posedge reset)
if (reset)
counter else
counter

Вот его схемотехническое представление в RTLViewer:

И вот его временная диаграмма:

Видно, что по фронту тактовой частоты в регистры счетчика будет записываться очередное значение, на единицу большее, чем предыдущее. Если в коде Verilog использовать минус, вместо плюса, то счетчик будет считать в обратную сторону.

Еще раз подчеркну, что ассинхронный сброс или установка как правило используются только в самом начале работы устройства.

Двоичный счетчик с синхронным сбросом.

Здесь обнуление регистров счетчика происходит по фронту тактовой частоты. В схеме появляется мультиплексор, который выбирает для записи в регистры счетчика либо следующее значение, либо ноль.

always @( posedge clk)
if (reset)
counter else
counter

Вот представление в RTL:

И его временная диаграмма:

Счетчик с асинхронным сбросом и входом разрешения и сигналом загрузки.
Чтобы как-то разнообразить описание счетчиков я решил в этом примере дать более «осмысленные» имена сигналам. Представим себе, что мы разрабатываем свой процессор:

  • В процессоре есть указатель на исполняемую инструкцию instr_ptr[15:0] .
  • После сброса системы по сигналу reset этот указатель instr_ptr устанавливается на инструкцию по адресу ноль.
  • С каждым тактом исполнение программы движется вперед — значение instr_ptr увеличивается и каждый раз выбирается следующая команда.
  • Предположим, что некоторые инструкции исполняются дольше других. Это могут быть какие нибудь сложные команды типа умножения или деления. В этом случае АЛУ процессора (арифметико-логическое устройство) выдает нам сигнал cpu_wait вставляя такты ожидания. В эти такты ожидания instr_ptr не изменяется.
  • Если же в какой-то момент времени дешифратор команд увидит команду безусловного перехода ( jmp ) или условного перехода ( jz , jnz , jc и т.д.) и нужно перейти на другой адрес, то нам приходит сигнал branch_cond и в счетчик команд загружается адрес перехода branch_addr .

Вот так это все может быть записано на Verilog:

always @( posedge clk or posedge reset)
begin
if (reset)
instr_ptr else
if (

cpu_wait)
begin
if (branch_cond)
instr_ptr else
instr_ptr end
end

Давайте рассмотрим, что представляет из себя этот код в RTLViewer:

А вот временная диаграмма:

На этой диаграмме, как пример, видно такт ожидания на инструкции процессора по адресу 3 и переход с адреса 6 на адрес 35.

Еще счетчики могут быть не только двоичными. Вот, например:

Счетчик по модулю 10.

В этом примере максимальное число в регистре счетчика — это девять. Сигнал cout активен в этот последний такт счета. Следующий такт записывает в регистр ноль. Всего тактов, включая нулевой, получается десять. Отсюда и название — по модулю 10.

Понятно, что аналогично можно строить счетчики по любому модулю.

wire cout;
reg [3:0]counter;

always @( posedge clk or posedge reset)
begin
if (reset)
counter else
if (counter==4’d9)
counter else
counter end

assign cout = (counter==4’d9);

В представлении RTL видно, что кроме собственно регистра у нас есть еще сумматор и компаратор. Сумматор подготавливает для записи следующее значение счетчика, то есть counter+1 . Компаратор сравнивает текущее значение счетчика с последним в последовательности (у нас это число 9).

Считает эта схема вот так:

Сигнал cout удобно использовать, например, для каскадного соединения счетчиков как сигнал разрешения счета для старших десятичных разрядов.

В следующей статье я хотел рассказать про сдвиговые регистры.

Источник

Adblock
detector