MAX II EPM240T100C5 — двоичный счётчик на 7 светодиодов

В этом примере для CPLD MAX II EPM240T100C5 реализован простой двоичный счётчик. На линейку из 7 светодиодов выводятся числа от 0 до 7 в двоичном виде.

Например, число 3 в двоичном виде выглядит так:

0000011

Это значит, что включены два младших светодиода: LED[0] и LED[1]. Остальные светодиоды выключены.

В проекте используется тактовый вход CLK0, который в Quartus назначен на ножку PIN_12. Семь светодиодов подключены к выводам PIN_15 ... PIN_21.

Готовый Verilog-код

module top (
    input  wire CLK0,
    output wire [6:0] LED
);

    // Делитель частоты.
    // Он нужен, чтобы переключение светодиодов было видно глазами.
    reg [25:0] div_cnt = 26'd0;

    // Основной счётчик числа от 0 до 7.
    reg [2:0] number = 3'd0;

    always @(posedge CLK0) begin

        // Считаем такты входного генератора CLK0.
        div_cnt <= div_cnt + 26'd1;

        // Когда div_cnt переполняется и снова становится 0,
        // меняем число на светодиодах.
        if (div_cnt == 26'd0) begin
            if (number == 3'd7)
                number <= 3'd0;
            else
                number <= number + 3'd1;
        end
    end

    // Вывод числа на 7 светодиодов.
    // LED[0] — младший бит.
    // LED[1] — второй бит.
    // LED[2] — третий бит.
    // LED[3]...LED[6] всегда равны 0.
    assign LED = {4'b0000, number};

    // Если на плате светодиоды включаются логическим 0,
    // строку выше нужно закомментировать,
    // а строку ниже раскомментировать:
    // assign LED = ~{4'b0000, number};

endmodule

Назначение выводов в Quartus

В Pin Planner нужно назначить вход тактирования CLK0 и семь выходов для светодиодов. Для данного примера используются следующие ножки микросхемы MAX II EPM240T100C5:

Сигнал в Verilog Направление Назначение Ножка MAX II I/O Standard
CLK0 Input Тактовый вход PIN_12 3.3-V LVTTL
LED[6] Output Седьмой светодиод PIN_15 3.3-V LVTTL
LED[5] Output Шестой светодиод PIN_16 3.3-V LVTTL
LED[4] Output Пятый светодиод PIN_17 3.3-V LVTTL
LED[3] Output Четвёртый светодиод PIN_18 3.3-V LVTTL
LED[2] Output Третий светодиод PIN_19 3.3-V LVTTL
LED[1] Output Второй светодиод PIN_20 3.3-V LVTTL
LED[0] Output Первый светодиод, младший бит PIN_21 3.3-V LVTTL

Как работает код

1. Главный модуль

module top (
    input  wire CLK0,
    output wire [6:0] LED
);

Это главный модуль проекта. Вход CLK0 используется как тактовый сигнал. Выход LED[6:0] управляет семью светодиодами.

Выходы светодиодов идут от младшего бита к старшему:

LED[0] — первый светодиод, младший бит
LED[1] — второй светодиод
LED[2] — третий светодиод
LED[3] — четвёртый светодиод
LED[4] — пятый светодиод
LED[5] — шестой светодиод
LED[6] — седьмой светодиод

2. Делитель частоты

reg [25:0] div_cnt = 26'd0;

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

Поэтому используется счётчик div_cnt. Он считает такты входного генератора и замедляет переключение светодиодов.

3. Счётчик числа

reg [2:0] number = 3'd0;

Переменная number — это основной счётчик. Он имеет размер 3 бита. Три бита позволяют хранить числа от 0 до 7:

000 = 0
001 = 1
010 = 2
011 = 3
100 = 4
101 = 5
110 = 6
111 = 7

4. Основной always-блок

always @(posedge CLK0) begin

    div_cnt <= div_cnt + 26'd1;

    if (div_cnt == 26'd0) begin
        if (number == 3'd7)
            number <= 3'd0;
        else
            number <= number + 3'd1;
    end

end

Этот блок выполняется на каждом положительном фронте тактового сигнала CLK0. Сначала увеличивается счётчик задержки div_cnt.

Когда div_cnt переполняется и снова становится равным нулю, увеличивается значение number.

Если number дошёл до 7, он снова сбрасывается в 0. Поэтому счёт идёт по кругу:

0 → 1 → 2 → 3 → 4 → 5 → 6 → 7 → 0 → ...

5. Вывод числа на светодиоды

assign LED = {4'b0000, number};

У нас есть 7 светодиодов, а число занимает только 3 бита. Поэтому к числу слева добавляются четыре нуля.

Фигурные скобки { } в Verilog означают объединение битов.

Например, если:

number = 3'b011

Тогда:

{4'b0000, number} = 7'b0000011

То есть на светодиоды выводится двоичное число 3.

Если светодиоды работают наоборот

На некоторых платах светодиоды включаются не логической единицей, а логическим нулём. В таком случае строка:

assign LED = {4'b0000, number};

должна быть заменена на:

assign LED = ~{4'b0000, number};

Символ ~ означает инверсию всех битов.

Что нужно сделать в Quartus

Настройка проекта

  1. Создать новый проект.
  2. Выбрать микросхему EPM240T100C5.
  3. Создать Verilog-файл, например top.v.
  4. Вставить готовый код из этого примера.
  5. Назначить top как верхний модуль проекта.

Назначение ножек

  1. Открыть Assignments → Pin Planner.
  2. Назначить CLK0 на PIN_12.
  3. Назначить LED[6] на PIN_15.
  4. Назначить LED[5] на PIN_16.
  5. Назначить LED[4] на PIN_17.
  6. Назначить LED[3] на PIN_18.
  7. Назначить LED[2] на PIN_19.
  8. Назначить LED[1] на PIN_20.
  9. Назначить LED[0] на PIN_21.
Для всех выводов можно оставить стандарт 3.3-V LVTTL. Ток выхода в Quartus может быть указан как 16mA default.

Краткий принцип работы

CPLD получает тактовый сигнал на вход CLK0. Делитель частоты замедляет переключение, чтобы его было видно глазами. После каждого переполнения делителя число number увеличивается на единицу. Значение number выводится на младшие три светодиода в двоичном виде.

number = 0 → LED = 0000000
number = 1 → LED = 0000001
number = 2 → LED = 0000010
number = 3 → LED = 0000011
number = 4 → LED = 0000100
number = 5 → LED = 0000101
number = 6 → LED = 0000110
number = 7 → LED = 0000111