FPGA 课程设计,果断选择最简单的花式点灯
实验要求
一、设计一个8路流水灯控制电路
二、有多种变化方式:
1)自左向右逐次点亮,或自右向左逐次点亮,到终点后在从头开始;
2)自左向右逐次熄灭,或自右向左逐次熄灭,到终点后再从头开始;
3)按一定间隔(自定义)逐次点亮;
4)灯工作时间可调;
三、设置复位键,独立流水灯工作模式控制键,独立流水灯速度键;
四、时钟信号为开发板上时源。
完成任务1)-4)的得分不超过65分,有扩展到内容酌情增加得分。
OK,虽然看起来很复杂,但拆分一下要求的话核心是以下几点:
基础流水灯 *、方向控制键 **、速度控制键 **、复位键 ***(*代表优先级)
实验平台
对于流水灯实验,都不需要开发板选型,随便抄起手边现有的板子就直接开始,这里我用的是安路科技的 EF2L45BG256_MINI_DEV3 开发板,原理图如下。我这里LED是低电平点亮,按键按下去是"0",按键释放是"1",拨码开关拨上ON 是"0",拨到OFF 是"1"。
学校里常用的应该是Xilinx或者Altera的板子,但其实影响不大,不同板子只需要对照原理图修改部分代码(LED是低电平点亮还是高电平点亮、按键按下是0还是1)以及管脚约束文件就可以。
设计思路
按键检测
按键开关和拨码开关不同,需要你一直按着才能保持,一旦松手就检测不到’'0"了,这里我为了达到和拨码开关一样的效果(按一下之后就可以松手了),当然你如果想一直按着按键保持流水灯点亮可以忽略这一部分。
因为按下后弹起会有一个从"0"到"1"的上升沿,通过检测这个上升沿就可以判断按键是否被按下后又弹起:
reg key1_d0,key2_d0,key3_d0;
reg key1_out,key2_out,key3_out;
// 检测按键是否弹起
assign key1_up = key[0] & ~key1_d0;
assign key2_up = key[1] & ~key2_d0;
assign key3_up = key[2] & ~key3_d0;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
key1_d0 <= 1'b1;
key2_d0 <= 1'b1;
key2_d0 <= 1'b1;
end
else begin
key1_d0 <= key[0];
key2_d0 <= key[1];
key3_d0 <= key[2];
end
end
// 每次检测到按键弹起,令对应的key_out取反,即开/关状态切换
always@(posedge clk or negedge rst_n) begin
if(!rst_n)begin
key1_out <= 0;
key2_out <= 0;
key3_out <= 0;
end
else if(key1_up)
key1_out <= ~key1_out;
else if(key2_up)
key2_out <= ~key2_out;
else if(key3_up)
key3_out <= ~key3_out;
end
流水灯控制
这一部分基本都是大同小异的,先设置一个计数器,再设置一个状态控制,当计数到一定值(可以通过设置这个值来改变速度)的时候令状态+1,之后再根据按键选择状态即可:
// 控制流水灯方向
always @ (posedge clk or negedge rst_n) begin
if(!rst_n)
direction <= 1'd0;
else if(!switch[0])
direction <= 1'd1;
else
direction <= 1'd0;
end
// key3控制流水灯速度
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
speed <= 25'd24_999_999;
else if(key3_out)
speed <= 25'd4_999_999;
else
speed <= 25'd24_999_999;
end
// 计数器,控制流水灯速度
always @ (posedge clk or negedge rst_n) begin
if(!rst_n)
cnt <= 25'd0;
else if(cnt < speed)
cnt<=cnt+1;
else
cnt<=0;
end
// 控制流水灯状态
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
led_control <= 3'b000;
else if(cnt == speed)
led_control <= led_control + 1'b1;
else
led_control <= led_control;
end
完整代码
module key_led(
input clk ,
input rst_n,
input [1:0] switch, // switch[0]:控制方向 switch[1]:控制间隔点亮
input [2:0] key, // key[0]/key[1]:流水灯点亮/熄灭 key[2]:控制速度
output reg [7:0] led
);
reg key1_d0,key2_d0,key3_d0;
reg key1_out,key2_out,key3_out;
reg direction;
reg [24:0] cnt;
reg [2:0] led_control;
reg [24:0] speed;
// 按键弹起
wire key1_up,key2_up,key3_up;
// 检测按键是否弹起
assign key1_up = key[0] & ~key1_d0;
assign key2_up = key[1] & ~key2_d0;
assign key3_up = key[2] & ~key3_d0;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
key1_d0 <= 1'b1;
key2_d0 <= 1'b1;
key2_d0 <= 1'b1;
end
else begin
key1_d0 <= key[0];
key2_d0 <= key[1];
key3_d0 <= key[2];
end
end
always@(posedge clk or negedge rst_n) begin
if(!rst_n)begin
key1_out <= 0;
key2_out <= 0;
key3_out <= 0;
end
else if(key1_up)
key1_out <= ~key1_out;
else if(key2_up)
key2_out <= ~key2_out;
else if(key3_up)
key3_out <= ~key3_out;
end
// 用拨码开关控制流水灯方向
always @ (posedge clk or negedge rst_n) begin
if(!rst_n)
direction <= 1'd0;
else if(!switch[0])
direction <= 1'd1;
else
direction <= 1'd0;
end
// key3控制流水灯速度,时钟25M,24_999_999=1s
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
speed <= 25'd24_999_999;
else if(key3_out)
speed <= 25'd4_999_999;
else
speed <= 25'd24_999_999;
end
// 计数器,控制流水灯速度
always @ (posedge clk or negedge rst_n) begin
if(!rst_n)
cnt <= 25'd0;
else if(cnt < speed)
cnt<=cnt+1;
else
cnt<=0;
end
// 控制流水灯状态
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
led_control <= 3'b000;
else if(cnt == speed)
led_control <= led_control + 1'b1;
else
led_control <= led_control;
end
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
led<=8'b0000_0000;
end
else if(key1_out & direction & switch[1]) // 从左向右点亮
case (led_control)
3'b000 : led<=8'b1111_1110;
3'b001 : led<=8'b1111_1101;
3'b010 : led<=8'b1111_1011;
3'b011 : led<=8'b1111_0111;
3'b100 : led<=8'b1110_1111;
3'b101 : led<=8'b1101_1111;
3'b110 : led<=8'b1011_1111;
3'b111 : led<=8'b0111_1111;
default : led<=8'b1111_1111;
endcase
else if (key1_out & !direction & switch[1]) // 从右向左点亮
case (led_control)
3'b000 : led<=8'b0111_1111;
3'b001 : led<=8'b1011_1111;
3'b010 : led<=8'b1101_1111;
3'b011 : led<=8'b1110_1111;
3'b100 : led<=8'b1111_0111;
3'b101 : led<=8'b1111_1011;
3'b110 : led<=8'b1111_1101;
3'b111 : led<=8'b1111_1110;
default : led<=8'b1111_1111;
endcase
else if (key2_out & direction & switch[1]) // 从左向右熄灭
case (led_control)
3'b000 : led<=8'b0000_0000;
3'b001 : led<=8'b0000_0001;
3'b010 : led<=8'b0000_0011;
3'b011 : led<=8'b0000_0111;
3'b100 : led<=8'b0000_1111;
3'b101 : led<=8'b0001_1111;
3'b110 : led<=8'b0011_1111;
3'b111 : led<=8'b0111_1111;
default : led<=8'b1111_1111;
endcase
else if (key2_out & !direction & switch[1]) // 从右向左熄灭
case (led_control)
3'b000 : led<=8'b0000_0000;
3'b001 : led<=8'b1000_0000;
3'b010 : led<=8'b1100_0000;
3'b011 : led<=8'b1110_0000;
3'b100 : led<=8'b1111_0000;
3'b101 : led<=8'b1111_1000;
3'b110 : led<=8'b1111_1100;
3'b111 : led<=8'b1111_1110;
default : led<=8'b1111_1111;
endcase
else if (key2_out & direction & !(switch[1])) // 从左向右间隔熄灭
case (led_control)
3'b000 : led<=8'b0000_0000;
3'b001 : led<=8'b0000_0001;
3'b010 : led<=8'b0000_0101;
3'b011 : led<=8'b0001_0101;
3'b100 : led<=8'b0101_0101;
3'b101 : led<=8'b0000_0001;
3'b110 : led<=8'b0000_0101;
3'b111 : led<=8'b0001_0101;
default : led<=8'b0101_0101;
endcase
else if (key2_out & !direction & !(switch[1])) // 从右向左间隔熄灭
case (led_control)
3'b000 : led<=8'b0000_0000;
3'b001 : led<=8'b0100_0000;
3'b010 : led<=8'b0101_0000;
3'b011 : led<=8'b0101_0100;
3'b100 : led<=8'b0101_0101;
3'b101 : led<=8'b0100_0000;
3'b110 : led<=8'b0101_0000;
3'b111 : led<=8'b0101_0100;
default : led<=8'b0101_0101;
endcase
else if (key1_out & direction & !(switch[1])) // 从左向右间隔点亮
case (led_control)
3'b000 : led<=8'b1111_1110;
3'b001 : led<=8'b1111_0111;
3'b010 : led<=8'b1011_1111;
3'b011 : led<=8'b1111_1110;
3'b100 : led<=8'b1111_0111;
3'b101 : led<=8'b1011_1111;
3'b110 : led<=8'b1111_1110;
3'b111 : led<=8'b0111_0111;
default : led<=8'b1011_1111;
endcase
else if (key1_out & !direction & !(switch[1])) // 从右向左间隔点亮
case (led_control)
3'b000 : led<=8'b0111_1111;
3'b001 : led<=8'b1110_1111;
3'b010 : led<=8'b1111_1101;
3'b011 : led<=8'b1011_1111;
3'b100 : led<=8'b1111_0111;
3'b101 : led<=8'b1111_1110;
3'b110 : led<=8'b1101_1111;
3'b111 : led<=8'b0111_1011;
default : led<=8'b0111_1111;
endcase
else
led<=8'b1111_1111;
end
endmodule