Часы на Verilog
Содержание |
Введение
Для освоения программирования ПЛИС на языке Verilog была поставлена задача написания программы смысл которой заключается в подсчете времени нажатия на кнопку.
Подзадачи
1. Установка программы ISE Design Suite 14.7 на ОС Windows 8.1.
2. Написание простых программ для понимания языка Verilog:
- Счетчик нажатий, выполняющий вывод значений в двоичной системе на диоды;
- Программа для работы нескольких семисегментных индикаторов.
3. Синтез этих программ для того, чтобы решить поставленную задачу.
4. Для отработки навыков реализовать часы.
Реализация всех программ производилась на ПЛИС Xilinx Spartan-6 на отладочной плате DIGILENT NEXYS 3
Проблемы в ходе выполнения подзадач
В ходе решения подзадач возникла проблема с установкой программы ISE Design Suite 14.7 на ОС Windows 8.1.
Проблема заключается в зависании программы при создании нового проекта.
Проблема была решается следующим путем:
Шаг 1: зайти в директорию: C:\Xilinx\14.5\ISE_DS\ISE\lib\nt64
Шаг 2: переименовать файл libPortability.dll в libPortability.dll.orig
Шаг 3: переименовать файл libPortabilityNOSH.dll в libPortability.dll
Шаг 4: скопировать файл libPortability.dll <ctrl+c>
Шаг 5: зайти в директорию C:\Xilinx\14.5\ISE_DS\common\lib\nt64
Шаг 6: вставить файл из шага 4 <libPortability.dll > в данную директорию
Оригинал статьи про проблемы с работой I SE Design Suite 14.7 на ОС Windows 8.1 находится по следующей ссылке
[1]
Описание реализации счетчика времени нажатия кнопки
convert: no images defined `/tmp/transform_106f96e11c99-1.jpg' @ error/convert.c/ConvertImageCommand/3044.
Основными частями реализации являются счетчики:
- счетчик суммы времени нажатия до одной секунды;
- счетчик времени нажатий в секундах;
- счетчики для работы семисегментного индикатора.
Алгоритм работы счетчика таков:
1. При нажатии на кнопку происходит начинается счет тактовых сигналов;
2. При достижении количества сигналов, равного 10^8 в счетчике суммы прибавляется одна секунда, счетчик импульсов сбрасывается в ноль;
3. Далее с регистра, содержащего информацию о количестве секунд, эти значению передаются на дальнейшую обработку для передачи на семисегментные индикаторы.
4. Реализация работы семисегментных индикаторов была произведена с помощью циклов.
Подробнее про работу с семисегментными индикаторами.
Так как индикаторов 4 а катоды к ним общие, то принято было работать по следующему алгоритму. Есть 2 счетчика. Один счетчик считает количество тактовых сигналов. Когда это количество становится равным 200000 то на втором счетчике прибавляется единица. В зависимости от значения на втором счетчике выбирается тот анод, на котором будет низкий уровень и значит загорится этот индикатор. Так как время циклов очень мало, то мы мы не замечаем мигание индикаторов. Второй счетчик в схеме имеет 2 разряда, поэтому сбрасывать его нет необходимости.
convert: no images defined `/tmp/transform_48b1c4e1905d-1.jpg' @ error/convert.c/ConvertImageCommand/3044.
На данном ниже рисунке показана схема подключения катодов и анодов. Из этой схемы наглядно видно, что для того, чтобы зажечь определенный сегмент на одном из индикаторов необходимо подать на соответствующий катод и соответствующий анод низкий уровень.
convert: no images defined `/tmp/transform_17a103558e11-1.jpg' @ error/convert.c/ConvertImageCommand/3044.
На рисунке ниже показано, на какие выводы необходимо подать низкий уровень, чтобы зажечь необходимый сегмент
Текст реализации счетчика времени нажатия
module main( input clk, input BTNS, // кнопка output [3:0] AN, // выводы к анодам для переключения семисегментных индикаторов output [7:0] ind // выводы к катодам семисегментного индикатора ); reg [3:0] assist_AN; // вспомогательный регистр для анодов семисегментных индикаторов reg [7:0] assist_ind; // вспомогательный регистр для катодов семисегментного индикатора reg [26:0] sum; // накапливаемое значение суммы для регистрации нажатия reg [7:0] assist_ld; // сумматор времени нажатия кнопки reg [3:0] nul_r; // младший сегмент индикатора reg [3:0] first_r; // второй сегмент индикатора reg [3:0] second_r; // третий сегмент индикатора reg [17:0] counter; // регистр, хранящий время работы семисегментного индикатора reg [1:0] c; // регистр указателя номера семисегментного индикатора always @(posedge clk) begin if (BTNS) // нажатие кнопки sum <= sum + 1'b1; else sum <= 27'd0; if (sum >= 27'd100000000) // суммирование времени нажатия до 1 секунды begin assist_ld <= assist_ld + 1'b1; // счет количества секунд sum <= 27'd0; end nul_r <= assist_ld % 10; // значение первого семисегментного индикатора first_r <= (assist_ld % 100 - nul_r)/10; // значение второго индикатора second_r <= assist_ld / 100; // значение третьего индикатора counter <= counter + 1'b1; if (counter == 17'd200000) // цикл работы семисегметных индикаторов begin c <= c + 1'b1; counter <= 17'd0; end if (c == 2'b00) // первый семисегментный индикатор begin assist_AN <= 4'b1110; // значение анодов case (nul_r) 4'd0: assist_ind <= 8'b00000011; // значения катодов 4'd1: assist_ind <= 8'b10011111; 4'd2: assist_ind <= 8'b00100101; 4'd3: assist_ind <= 8'b00001101; 4'd4: assist_ind <= 8'b10011001; 4'd5: assist_ind <= 8'b01001001; 4'd6: assist_ind <= 8'b01000001; 4'd7: assist_ind <= 8'b00011111; 4'd8: assist_ind <= 8'b00000001; 4'd9: assist_ind <= 8'b00001001; default: assist_ind <= 8'b11111111; endcase end if (c == 2'b01) // второй семисегментный индикатор begin assist_AN <= 4'b1101; case (first_r) 4'd0: assist_ind <= 8'b00000011; 4'd1: assist_ind <= 8'b10011111; 4'd2: assist_ind <= 8'b00100101; 4'd3: assist_ind <= 8'b00001101; 4'd4: assist_ind <= 8'b10011001; 4'd5: assist_ind <= 8'b01001001; 4'd6: assist_ind <= 8'b01000001; 4'd7: assist_ind <= 8'b00011111; 4'd8: assist_ind <= 8'b00000001; 4'd9: assist_ind <= 8'b00001001; default: assist_ind <= 8'b11111111; endcase end if (c == 2'b10) // третий семисегментный индикатор begin assist_AN <= 4'b1011; case (second_r) 4'd0: assist_ind <= 8'b00000011; 4'd1: assist_ind <= 8'b10011111; 4'd2: assist_ind <= 8'b00100101; default: assist_ind <= 8'b11111111; endcase end end assign AN = assist_AN; // значение на выходах к аноду равно значению вспомогательных регистров assign ind = assist_ind; // значение на выходах к катоду равно значению вспомогательных регистров endmodule
ucf файл с описанием портов ввода-вывода
NET "clk" LOC = V10; NET "BTNS" LOC = B8; NET "AN[0]" LOC = N16; NET "AN[1]" LOC = N15; NET "AN[2]" LOC = P18; NET "AN[3]" LOC = P17; NET "ind[0]" LOC = M13; NET "ind[1]" LOC = L14; NET "ind[2]" LOC = N14; NET "ind[3]" LOC = M14; NET "ind[4]" LOC = U18; NET "ind[5]" LOC = U17; NET "ind[6]" LOC = T18; NET "ind[7]" LOC = T17;
Реализация часов
Реализация часов отличается от счетчика времени нажатия незначительно. Здесь отсутствует кнопка. Отличие в подсчете времени здесь состоит в том, что здесь счетчик времени представляет собой счетчики минут и секунд. Счет происходит до 59 минут 59 секунд, после чего все сбрасывается. В предыдущем случае счет шел до 255 секунд.
Текст реализации
module main( input clk, output [3:0] AN, output [7:0] ind ); reg [3:0] assist_AN; reg [7:0] assist_ind; reg [26:0] sum; reg [5:0] seconds; reg [5:0] minutes; reg [3:0] seconds_jr; // регистр хранения значения первой цифры в счетчике секунд reg [3:0] seconds_sr; // регистр хранения значения второй цифры в счетчике секунд reg [3:0] minutes_jr; // регистр хранения значения первой цифры в счетчике минут reg [3:0] minutes_sr; // регистр хранения значения второй цифры в счетчике минут reg [17:0] counter; reg [1:0] c; always @(posedge clk) begin sum <= sum + 1'b1; if (sum >= 27'd100000000) begin seconds <= seconds + 1'b1; //счетчик секунд sum <= 27'd0; end if (seconds == 6'd60) begin minutes <= minutes +1'b1; // счетчик минут seconds <= 6'd0; end if (minutes == 6'd60) minutes <= 6'd0; seconds_jr <= seconds % 10; // вычисление значения первой цифры в счетчике секунд seconds_sr <= seconds/10; // вычисление значения второй цифры в счетчике секунд minutes_jr <= minutes % 10; // вычисление значения первой цифры в счетчике минут minutes_sr <= minutes/10; // вычисление значения второй цифры в счетчике минут counter <= counter + 1'b1; if (counter == 17'd200000) begin c <= c + 1'b1; counter <= 17'd0; end if (c == 2'b00) begin assist_AN <= 4'b1110; case (seconds_jr) 4'd0: assist_ind <= 8'b00000011; 4'd1: assist_ind <= 8'b10011111; 4'd2: assist_ind <= 8'b00100101; 4'd3: assist_ind <= 8'b00001101; 4'd4: assist_ind <= 8'b10011001; 4'd5: assist_ind <= 8'b01001001; 4'd6: assist_ind <= 8'b01000001; 4'd7: assist_ind <= 8'b00011111; 4'd8: assist_ind <= 8'b00000001; 4'd9: assist_ind <= 8'b00001001; default: assist_ind <= 8'b11111111; endcase end if (c == 2'b01) begin assist_AN <= 4'b1101; case (seconds_sr) 4'd0: assist_ind <= 8'b00000011; 4'd1: assist_ind <= 8'b10011111; 4'd2: assist_ind <= 8'b00100101; 4'd3: assist_ind <= 8'b00001101; 4'd4: assist_ind <= 8'b10011001; 4'd5: assist_ind <= 8'b01001001; default: assist_ind <= 8'b11111111; endcase end if (c == 2'b10) begin assist_AN <= 4'b1011; case (minutes_jr) 4'd0: assist_ind <= 8'b00000010; 4'd1: assist_ind <= 8'b10011110; 4'd2: assist_ind <= 8'b00100100; 4'd3: assist_ind <= 8'b00001100; 4'd4: assist_ind <= 8'b10011000; 4'd5: assist_ind <= 8'b01001000; 4'd6: assist_ind <= 8'b01000000; 4'd7: assist_ind <= 8'b00011110; 4'd8: assist_ind <= 8'b00000000; 4'd9: assist_ind <= 8'b00001000; default: assist_ind <= 8'b11111111; endcase end if (c == 2'b11) begin assist_AN <= 4'b0111; case (minutes_sr) 4'd0: assist_ind <= 8'b00000011; 4'd1: assist_ind <= 8'b10011111; 4'd2: assist_ind <= 8'b00100101; 4'd3: assist_ind <= 8'b00001101; 4'd4: assist_ind <= 8'b10011001; 4'd5: assist_ind <= 8'b01001001; default: assist_ind <= 8'b11111111; endcase end end assign AN = assist_AN; assign ind = assist_ind; endmodule
Здесь ucf файл отличается только отсутствием кнопки BTNS
Pmod
Для понимания того, какие уровни сигнала на выходе Pmod на один из его выходов были поданы высокий и низкий уровни, после чего к этому выходу был подключен осциллограф. Осциллограммы представлены ниже.
Pmod connectors
Высокий уровень(на вход подана 1)
Низкий уровень(на вход подана 0)
--Belyanushkin (обсуждение) 00:20, 25 ноября 2014 (MSK)