Часы на Verilog

Материал из SRNS
Перейти к: навигация, поиск

Содержание

Введение

Для освоения программирования ПЛИС на языке 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: unable to open image `/app/images/0/0d/_new.jpg': No such file or directory @ error/blob.c/OpenBlob/2641.
convert: no images defined `/tmp/transform_3a6a38d33952-1.jpg' @ error/convert.c/ConvertImageCommand/3044.


Основными частями реализации являются счетчики:
- счетчик суммы времени нажатия до одной секунды;
- счетчик времени нажатий в секундах;
- счетчики для работы семисегментного индикатора.
Алгоритм работы счетчика таков:
1. При нажатии на кнопку происходит начинается счет тактовых сигналов;
2. При достижении количества сигналов, равного 10^8 в счетчике суммы прибавляется одна секунда, счетчик импульсов сбрасывается в ноль;
3. Далее с регистра, содержащего информацию о количестве секунд, эти значению передаются на дальнейшую обработку для передачи на семисегментные индикаторы.
4. Реализация работы семисегментных индикаторов была произведена с помощью циклов.

Подробнее про работу с семисегментными индикаторами.
Так как индикаторов 4 а катоды к ним общие, то принято было работать по следующему алгоритму. Есть 2 счетчика. Один счетчик считает количество тактовых сигналов. Когда это количество становится равным 200000 то на втором счетчике прибавляется единица. В зависимости от значения на втором счетчике выбирается тот анод, на котором будет низкий уровень и значит загорится этот индикатор. Так как время циклов очень мало, то мы мы не замечаем мигание индикаторов. Второй счетчик в схеме имеет 2 разряда, поэтому сбрасывать его нет необходимости.

Ошибка создания миниатюры: convert: unable to open image `/app/images/f/f1/_.jpg': No such file or directory @ error/blob.c/OpenBlob/2641.
convert: no images defined `/tmp/transform_a41546152df9-1.jpg' @ error/convert.c/ConvertImageCommand/3044.


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

Ошибка создания миниатюры: convert: unable to open image `/app/images/c/c7/_.jpg': No such file or directory @ error/blob.c/OpenBlob/2641.
convert: no images defined `/tmp/transform_6d2399b59372-1.jpg' @ error/convert.c/ConvertImageCommand/3044.


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


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
Pmod.jpg
Высокий уровень(на вход подана 1)
RTOScreenshot 2014-12-22 0 122926.png
Низкий уровень(на вход подан 0)
RTOScreenshot 2014-12-22 1 123056.png
--Belyanushkin (обсуждение) 00:20, 25 ноября 2014 (MSK)

Персональные инструменты
Пространства имён

Варианты
Действия
SRNS Wiki
Рабочие журналы
Приватный файлсервер
QNAP Сервер
Инструменты