Reputation: 9
I try to design simple circuit, I have two push buttons as an input and 8 leds as an output, whenever I press one of them I want to shift the bits to the left and the last bit will be also set to 1, if other push button is pressed the bits will be shift to right. Here is my code.
module project1(leds, pushbutton1, pushbutton2);
output reg [7:0] leds;
input pushbutton1, pushbutton2 ;
reg pb1, pb2;
always @(pushbutton1 or pushbutton2)
begin
pb1<=pushbutton1;
pb2<=pushbutton2;
if ((pb1==1)&&(pb2==0))
leds<=(leds<<1)+1;
else if ((pb1==0)&&(pb1==1))
leds<=(leds>>1);
else if (((pb1==0)&&(pb2==0)) ||((pb1==1)&&(pb2==1)))
leds<=leds;
end
initial begin
leds = 8'h00;
end
endmodule
I have read many pages and I guess there will be bouncing problem. To solve it I tried to use posedge
always @(posedge pushbutton1 or posedge pushbutton2)
but in this case I get an error message "Error (10200): Verilog HDL Conditional Statement error at myfirstproject.v(14): cannot match operand(s) in the condition to the corresponding edges in the enclosing event control of the always construct"
When I tried to implement just one push button I had no problem and the below code worked well
module project1(leds, pushbutton1);
output reg [7:0] leds;
input pushbutton1;
always @(posedge pushbutton1)
begin
if (leds==8'hFF)
leds<=8'h00;
else
leds<=(leds<<1)+1;
end
initial begin
leds=8'h00;
end
endmodule
I think If-else statements cover all possible conditions but it doesn't work. How can I check two inputs at the same time in one always block? I know it is not possible to change the value of any variable that is defined in different always block but is there any way to implement it by using two or more different always block like
always @(posedge pushbutton1)
..........
always @(posedge pushbutton2)
.........
Also I tried to use the system clock to trigger the button change like that, but still doesn't work
module project1 (leds, pushbutton1, pushbutton2, clk);
output reg [7:0] leds;
input clk, pushbutton1, pushbutton2 ;
always @(posedge clk)
begin
if (pushbutton1==1 && pushbutton2==0)
begin
if (leds==8'h00)
leds<=8'h01;
else if (leds==8'hff)
leds<=8'h00;
else
leds<= (leds<<1)+1;
end
if (pushbutton1==0 && pushbutton2==1)
begin
if ((leds==8'h00) ||(leds==8'h01))
leds<= 8'h00;
else
leds<=(leds>>1);
end
else
leds<=leds;
end
initial begin
leds = 8'h00;
end
endmodule
Upvotes: 0
Views: 571
Reputation: 9
I have solved the problem by using FSM. I also want to share some info that I have learned when I tried to solve the problem. Push buttons of FPGA DE-0 Nano have Schmitt Triggered debounced circuit and they are active low. The circuit is sequential circuit so we don't need to write all cases in case block.
module clock_ex (leds, pb1, pb2, clk);
input clk;
input pb1, pb2;
output reg [7:0] leds;
reg [1:0] state;
wire [1:0] buttons;
assign buttons={~pb1,~pb2};
always @(posedge clk)
begin
case (state)
2'b00:
begin
case(buttons)
2'b01:
begin
state<=2'b01;
leds<={leds[6:0],1'b1};
end
2'b10:
begin
state<=2'b10;
leds<={1'b0,leds[7:1]};
end
endcase
end
2'b01:
begin
if (buttons==2'b00)
state<=2'b00;
end
2'b10:
begin
if (buttons==2'b00)
state<=2'b00;
end
endcase
end
initial
begin
leds=8'b111;
state=2'b00;
end
endmodule
Upvotes: 0
Reputation: 354
You might want to include some debouncing logic, as well as some synchronizers in order to avoid metastability problems. I took this from a project of mine, this should solve the problem:
localparam NUM_SYNC = 3;
localparam DEBOUNCE = 16;
localparam DBNC_WDTH = $clog2(DEBOUNCE + 1);
integer i;
reg [NUM_SYNC-1:0] button_a_sync;
reg [NUM_SYNC-1:0] button_b_sync;
reg [DBNC_WDTH-1:0] debounce_counter;
wire button_pushed, button_released;
//..debouncing fsm
reg button_state;
localparam IDLE = 0;
localparam ACTION = 0;
//..control signals to use:
reg shift_right;
reg shift_left;
/* synchronizers */
always @ (posedge clk_i, negedge arstn_i) begin
if(~arstn_i) begin
for(i=0; i<NUM_SYNC; i=i+1) begin
button_a_sync[i] <= 1'b0;
button_b_sync[i] <= 1'b0;
end
end
else begin
for(i=0; i<NUM_SYNC; i=i+1) begin
if(i==0) begin
button_a_sync[i] <= button_a_i;
button_b_sync[i] <= button_b_i;
end
else begin
button_a_sync[i] <= button_a_sync[i-1];
button_b_sync[i] <= button_b_sync[i-1];
end
end
end
end
/* button change */
assign button_pushed = button_a_sync[NUM_SYNC-1] | button_b_sync[NUM_SYNC-1];
assign button_released = ~button_pushed;
/* button state control */
always @ (posedge clk_i, negedge arstn_i) begin
if(~arstn_i) begin
shift_right <= 0;
shift_left <= 0;
debounce_counter <= 0;
button_state <= IDLE;
end
else begin
case(button_state)
IDLE: begin
if(button_pushed) begin //..a button has been pushed
if(debounce_counter == DEBOUNCE) begin
shift_right <= button_a_sync[NUM_SYNC-1];
shift_left <= button_b_sync[NUM_SYNC-1];
debounce_counter <= 0;
button_state <= ACTION;
end
else
debounce_counter <= debounce_counter + 1;
end
else
debounce_counter <= 0;
end
ACTION: begin
shift_right <= 0;
shift_left <= 0;
if(button_released) begin //..the buttons are released
if(debounce_counter == DEBOUNCE) begin
debounce_counter <= 0;
button_state <= IDLE;
end
else
debounce_counter <= debounce_counter + 1;
end
else
debounce_counter <= 0;
end
endcase
end
end
//..shift logic
always @ (posedge clk_i, negedge arstn_i) begin
if(~arstn_i)
leds <= 0;
else begin
case({shift_left, shift_right})
2'b01: begin //..shift right
leds[7] <= 1'b1;
leds[6:0] <= leds[7:1];
end
2'b10: begin //..shift left
leds[0] <= 1'b1;
leds[7:1] <= leds[6:0];
end
default: begin //..don't do anything
leds <= leds;
end
endcase
end
end
Upvotes: 0