Как запрограммировать задержку в Verilog?
Я пытаюсь сделать отображение кода Морзе с помощью светодиода. Мне нужен полсекундный импульс света для представления точки и 1,5 секундный импульс для представления тире.
Я действительно застрял здесь. Я сделал счетчик, используя внутренние часы 50 МГц на моей FPGA. Машина, которую я должен сделать, примет в качестве входных данных 3-битное число и переведет его в азбуку Морзе, AH с A 000, B с 001 и так далее. Мне просто нужно выяснить, как сказать FPGA, чтобы индикатор оставался включенным в течение указанного времени, а затем выключался примерно на секунду (это было бы задержкой между точечным импульсом и тире).
Любые советы будут с благодарностью. Кроме того, он должен быть синтезируемым.
Вот мой код Это еще не работает. Сообщение об ошибке, которое он продолжает давать мне:
Ошибка (10028): не удается разрешить несколько постоянных драйверов для сети "c3[0]" в part4.v(149)
module part4 (SELECT, CLK, CLOCK_50, RESET, led);
input [2:0]SELECT;
input RESET, CLK, CLOCK_50;
output reg led=0;
reg [26:0] COUNT=0; //register that keeps track of count
reg [1:0] COUNT2=0; //keeps track of half seconds
reg halfsecflag=0; //goes high every time half second passes
reg dashflag=0; //goes high every time 1 and half second passes
reg [3:0] code; //1 is dot and 0 is dash. There are 4 total
reg [1:0] c3; //keeps track of the index we are on in the code.
reg [3:0] STATE; //register to keep track of states in the state machine
reg done=0; //a flag that goes up when one morse pulse is done.
reg ending=0; //another flag that goes up when a whole morse letter has flashed
reg [1:0] length; //This is the length of the morse letter. It varies from 1 to 4
wire i; // if i is 1, then the state machine goes to "dot". if 0 "dash"
assign i = code[c3];
parameter START= 4'b000, DOT= 4'b001, DASH= 4'b010, DELAY= 4'b011, IDLE=
4'b100;
parameter A= 3'b000, B=3'b001, C=3'b010, D=3'b011, E=3'b100, F=3'b101,
G=3'b110, H=3'b111;
always @(posedge CLOCK_50 or posedge RESET) //making counter
begin
if (RESET == 1)
COUNT <= 0;
else if (COUNT==8'd25000000)
begin
COUNT <= 0;
halfsecflag <= 1;
end
else
begin
COUNT <= COUNT+1;
halfsecflag <=0;
end
end
always @(posedge CLOCK_50 or posedge RESET)
begin
if (RESET == 1)
COUNT2 <= 0;
else if ((COUNT2==2)&&(halfsecflag==1))
begin
COUNT2 = 0;
dashflag=1;
end
else if (halfsecflag==1)
COUNT2= COUNT2+1;
end
always @(RESET) //asynchronous reset
begin
STATE=IDLE;
end
always@(STATE) //State machine
begin
done=0;
case(STATE)
START: begin
led = 1;
if (i) STATE = DOT;
else STATE = DASH;
end
DOT: begin
if (halfsecflag && ~ending) STATE = DELAY;
else if (ending) STATE= IDLE;
else STATE=DOT;
end
DASH: begin
if ((dashflag)&& (~ending))
STATE = DELAY;
else if (ending)
STATE = IDLE;
else STATE = DASH;
end
DELAY: begin
led = 0;
if ((halfsecflag)&&(ending))
STATE=IDLE;
else if ((halfsecflag)&&(~ending))
begin
done=1;
STATE=START;
end
else STATE = DELAY;
end
IDLE: begin
c3=0;
if (CLK) STATE=START;
else STATE=IDLE;
end
default: STATE = IDLE;
endcase
end
always @(posedge CLK)
begin
case (SELECT)
A: length=2'b01;
B: length=2'b11;
C: length=2'b11;
D: length=2'b10;
E: length=2'b00;
F: length=2'b11;
G: length=2'b10;
H: length=2'b11;
default: length=2'bxx;
endcase
end
always @(posedge CLK)
begin
case (SELECT)
A: code= 4'b0001;
B: code= 4'b1110;
C: code= 4'b1010;
D: code= 4'b0110;
E: code= 4'b0001;
F: code= 4'b1011;
G: code= 4'b0100;
H: code= 4'b1111;
default: code=4'bxxxx;
endcase
end
always @(posedge CLK)
begin
if (c3==length)
begin
c3<=0; ending=1;
end
else if (done)
c3<= c3+1;
end
endmodule
2 ответа
Я читал ваш код и есть много проблем:
Код не отформатирован.
Вы не предоставили тестовый стенд. Вы написали один?
"Не удается разрешить несколько постоянных драйверов для сети". Поиск в стеке обмена для сообщения об ошибке. Об этом спрашивали много раз.
Используйте всегда @(*), а не всегда @ (СОСТОЯНИЕ), вам не хватает таких сигналов, как
i, halfsecflag, ending
, Но смотри пункт 6: вы хотите СОСТОЯНИЕ в закрытом разделе.Где вы используете всегда @(posedge CLK), вы должны использовать неблокирующие назначения:
<=
,Есть много мест, где вы используете
always @(posedge CLK)
где вы хотите использоватьalways @(*)
(например, где вы установилиlength
а такжеcode
) Напротив вы хотите использоватьposedge CLK
где вы работаете с вашим государством.Используйте только одни часы и одни часы. Не используйте CLK и CLOCK_50. Используйте один или другой.
Позаботьтесь о ваших векторных размеров. это
8'd25000000
неправильно, так как вы не можете уместить 25000000 в 8 бит.
Ваше использование halfsecflag
отлично! Я много раз видел, где люди думают, что они могут использовать always @(halfsecflag)
что является рецептом катастрофы!
Ниже вы найдете небольшой фрагмент вашего кода, который я переписал.
Все назначения неблокируемые
<=
halfsecflag
важно работать с кодом только каждые полсекунды, поэтому я ставлю это отдельноif
на вершине. Я бы использовал это по всему коду.Все регистры сбрасываются, оба
COUNT2
а такжеdashflag
,dashflag
был установлен в 1, но никогда не возвращался в 0. Я исправил это.Я указал размеры вектора. Это делает код "Lint proof".
Вот:
always @(posedge CLOCK_50 or posedge RESET)
begin
if (RESET == 1'b1)
begin
COUNT2 <= 2'd00;
dashflag <= 1'b0;
end // reset
else if (halfsecflag) // or if (halfsecflag==1'b1)
begin
if (COUNT2==2'd2))
begin
COUNT2 <= 2'd0;
dashflag <=1'b1;
end
else
begin
COUNT2 <= COUNT2+2'd1;
dashflag <=1'b0;
end
end // clocked
end // always
Начните исправлять остальную часть вашего кода таким же образом. Напишите тестовый стенд, смоделируйте и проследите на дисплее формы сигнала, где что-то идет не так.
Обычно вы создаете конечный автомат для получения результата. У этой машины будет несколько этапов, таких как чтение входных данных, сопоставление их с последовательностью элементов кода Морзе, смещение элементов в выходной буфер, ожидание перехода условий к следующему элементу Морзе. Вам понадобится некоторый таймер, который будет производить интервалы времени по одному Морзе, и в зависимости от этапа FSM вы будете ждать одну, три или семь единиц времени. FSM будет вращаться на этапе ожидания, он не "волшебным образом" спит с некоторой задержкой, производимой fpga, таких вещей нет.
Хорошо, год спустя, я точно знаю, что нужно делать, если они хотят создать задержку в своей программе verilog! По сути, вам следует создать таймер, используя один из часов на вашей FPGA. Для меня на Altera DE1-SoC таймер, который я мог бы использовать, - это частота 50 МГц, известная как CLOCK_50. Что вы делаете, так это создаете модуль таймера, который запускается на положительном (или отрицательном, неважно) фронте тактовой частоты 50 МГц. Настройте счетный регистр, содержащий постоянное значение. Например, reg [24:0] timer_limit = 25'd25000000; Это регистр, который может содержать 25 бит. Я установил в этот регистр число 25 миллионов. Идея состоит в том, чтобы немного переворачивать каждый раз, когда значение в этом регистре превышается. Вот несколько псевдокодов, которые помогут вам понять:
//Your variable declarations
reg [24:0] timer_limit = 25'd25000000; //defining our timer limit register
reg [25:0] timer_count = 0; //See note A
reg half_sec_clock;
always@(posedge of CLOCK_50) begin
if timer_count >= timer_limit then begin
reset timer_count to 0;
half_sec_clock = ~half_sec_clock; //toggle your half_sec_clock
end
Примечание A: Установка его в ноль может или не может инициализировать счетчик, всегда лучше включать функцию сброса, которая сбрасывает счет до нуля, потому что вы не знаете, каково начальное состояние, когда вы имеете дело с оборудованием.
Это основная идея того, как ввести время в ваше оборудование. Вам нужно использовать встроенные часы на вашем устройстве, запускать по краю этих часов и создавать свои собственные более медленные часы для измерения таких вещей, как секунды. В приведенном выше примере вы получите часы, которые срабатывают периодически каждые полсекунды. Для меня это позволило мне легко сделать световой индикатор кода Морзе, который мог мигать либо на 1 полсекунды, либо на 3 полсекунды. Мой лучший совет начинающим - работать по модульному принципу. Например, создайте свои полусекундные часы, а затем проверьте их, чтобы увидеть, сможете ли вы включить свет на своей FPGA, чтобы переключаться каждые полсекунды (или любой другой интервал, который вы хотите).:) Я очень надеюсь, что этот ответ вам поможет. Я знаю, что это то, что я искал, когда так давно изначально разместил этот вопрос.