DE2-115 开发板
Cyclone IV EP4CE115F29器件
一、任务要求
-
闪烁的数码管
在HEX0上连续循环地显示数字0~9,每秒刷新一次显示。使用计数器产生1 s的时间间隔,这个计数器的时钟由DE2-115平台上的50 MHz时钟提供。注意:这个设计中只允许使用DE2-115平台上的50 MHz时钟,而不允许使用其他时钟,并保证所有的触发器都直接使用这个50 MHz时钟。 -
用移位寄存器与FSM实现“HELLO”的循环显示
使用移位寄存器并结合FSM实现DE2-115平台上的“HELLO”循环显示。在HEX7~HEX0上循环显示“HELLO”,使所有字母从右向左移动,每秒移动一次, -
移动速度可控的“HELLO”的自动循环显示
用KEY0作为低电平有效同步清除输入
当KEY1按下时,移动速度增加一倍;
当KEY2按下时,移动速度减小一半。KEY2和KEY1是经过去抖处理的,能够产生一个精确的脉冲,但脉冲的长度是任意的。
二、问题分析
DE2-115 配有八个七段数码管。它们被分成两组,每组四个,用来作为数字 显示用。正如图 所示,七段数码管的每个引脚(共阳模式)均连接到 Cyclone IV E FPGA。FPGA 输出低电压的时候,对应的字码段点亮,反之则熄灭。每个数 码管的字段都从 0 到 6 依次编号
所以将8个7位寄存器按流水线的形式排列
output reg [56:0] hex
三、代码实现
1. 任务一
seg_led_09模块
/*
闪烁的数码管
在HEX0上连续循环地显示数字0~9,
每秒刷新一次显示。
*/
module seg_led_09(
input wire clk,
input wire rst_n,
input wire sec_1,
output reg [55:0] hex //对于任务一,其实完全不用56位宽,在HEX0上连续循环地显示数字0~9
// 7位就可,只是因为我的任务都是同一个项目完成,
// 任务二,三都会用到所有数码管,所以就用56位宽
);
reg [3:0] value;
//每次通知信号sec_05到达时,数码管计数加1
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
value<=4'h0;
end
else if(sec_1)begin
if(value<4'h9)
value<=value+1'h1;
else
value<=4'h0;
end
else
value<=value;
end
//根据数码管显示的数值,控制段选信号
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
hex<=56'b0;
else begin
case(value)
4'h0: hex <= {{49{1'b1}},7'b100_0000};
4'h1: hex <= {{49{1'b1}},7'b111_1001};
4'h2: hex <= {{49{1'b1}},7'b010_0100};
4'h3: hex <= {{49{1'b1}},7'b011_0000};
4'h4: hex <= {{49{1'b1}},7'b001_1001};
4'h5: hex <= {{49{1'b1}},7'b001_0010};
4'h6: hex <= {{49{1'b1}},7'b000_0010};
4'h7: hex <= {{49{1'b1}},7'b111_1000};
4'h8: hex <= {{49{1'b1}},7'b000_0000};
4'h9: hex <= {{49{1'b1}},7'b001_0000};
default : hex <= {{49{1'b1}},7'b100_0000};
endcase
end
end
endmodule
time_count模块
module time_count(
input wire clk,//时钟,50MHZ
input wire rst_n,//复位信号,下降沿有效
output reg sec_1//1s脉冲信号
);
parameter MAX_NUM=26'd49_999_999;//记最大数,时间1s
reg [25:0] cnt;//计数寄存器
//1s计时
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt<=26'd0;
end
else if(cnt<MAX_NUM)begin
cnt<=cnt+1'd1;
end
else
cnt<=26'd0;
end
//1s脉冲信号
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
sec_1<=1'b0;
end
else if(cnt==MAX_NUM)begin
sec_1<=1'b1;
end
else begin
sec_1<=1'b0;
end
end
endmodule
digital_tube_top模块
module digital_tube_top(
input wire clk,
input wire rst_n,
input wire [1:0] key,
output wire [56:0] hex
);
wire sec_1;
wire [1:0] flag;
wire [1:0] key_value;
//每隔1s产生一个时钟周期的脉冲信号
time_count inst_time_count(
.clk (clk) , //50MHz时钟信号
.rst_n (rst_n), //复位信号
.sec_1 (sec_1)//一个时钟周期的脉冲信号
);
//每当脉冲信号到达时,使数码管显示的数值加1
seg_led_09 inst_seg_led_09(
.clk (clk),
.rst_n (rst_n),
.sec_1 (sec_1),
.hex (hex)
);
endmodule
效果展示
2. 任务二
/*
循环显示的“HELLO”
设计一个电路实现在HEX7~HEX0上循环显示“HELLO”,
使所有字母从右向左移动,每秒移动一次,
*/
module seg_led_r_l(
input wire clk,
input wire rst_n,
input wire sec_1,
output reg [55:0] hex
);
//控制数码管位选信号(注:低电平有效),选中所有的数码管
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
hex<=56'b1111111_1111111_1111111_0001001_0000110_1000111_1000111_1000000;
end
else begin
if(sec_1)
hex<={hex[48:0],hex[55:49]};
else
hex<=hex;
end
end
endmodule
digital_tube_top
module digital_tube_top(
input wire clk,
input wire rst_n,
input wire [1:0] key,
output wire [56:0] hex
);
wire sec_1;
wire [1:0] flag;
wire [1:0] key_value;
//每隔1s产生一个时钟周期的脉冲信号
time_count inst_time_count(
.clk (clk) , //50MHz时钟信号
.rst_n (rst_n), //复位信号
.sec_1 (sec_1)//一个时钟周期的脉冲信号
);
seg_led_r_l inst_seg_led_r_l(
.clk (clk ),
.rst_n (rst_n),
.sec_1 (sec_1),
.hex (hex )
);
endmodule
效果展示
3. 任务三
seg_led_FSM模块
module seg_led_FSM(
input wire clk,
input wire rst_n,
input wire [1:0] key,
output reg [55:0] hex
);
parameter RATE1=99_999_999;//2s
parameter RATE2=49_999_999;//1s
parameter RATE3=12_499_999;//0.25s
reg [26:0] cnt;//计数寄存器
reg flag1;//key0是否按下标志
reg flag2;//key1是否按下标志
reg [26:0] c_state,n_state;
reg [1:0] key_r;
always@(posedge clk,negedge rst_n)begin
if(!rst_n)begin
flag1<=1'b0;
flag2<=1'b0;
end
else begin
case(key)
2'b00:begin
flag1<=1'b0;
flag2<=1'b0;
end
2'b10:begin
flag1<=1'b1;
flag2<=1'b0;
end
2'b01:begin
flag1<=1'b0;
flag2<=1'b1;
end
2'b11:begin
flag1<=1'b0;
flag2<=1'b0;
end
default:begin
flag1<=1'b0;
flag2<=1'b0;
end
endcase
end
end
always@(posedge clk,negedge rst_n)begin
if(!rst_n)
c_state<=RATE2;
else
c_state<=n_state;
end
always@(posedge clk,negedge rst_n)begin
if(!rst_n)
n_state<=RATE2;
else
case(c_state)
RATE1:begin
if(flag1)
n_state<=RATE2;
else if(flag2)
n_state<=RATE1;
else
n_state<=n_state;
end
RATE2:begin
if(flag1)
n_state<=RATE3;
else if(flag2)
n_state<=RATE1;
else
n_state<=n_state;
end
RATE3:begin
if(flag1)
n_state<=RATE3;
else if(flag2)
n_state<=RATE2;
else
n_state<=n_state;
end
default:n_state<=n_state;
endcase
end
//计时
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt<=27'd0;
end
else if(cnt<c_state)begin
cnt<=cnt+1'd1;
end
else
cnt<=27'd0;
end
//控制数码管位选信号(注:低电平有效),选中所有的数码管
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
hex<=56'b1111111_1111111_1111111_0001001_0000110_1000111_1000111_1000000;
end
else begin
if(cnt==c_state)
hex<={hex[48:0],hex[55:49]};
else
hex<=hex;
end
end
endmodule
按键消抖模块
module key_debounce(
input wire clk,
input wire rst_n,
input wire key,
output reg flag,// 0抖动, 1抖动结束
output reg key_value//key抖动结束后的值
);
parameter MAX_NUM = 20'd1_000_000;
reg [19:0] delay_cnt;//1_000_000
reg key_reg;//key上一次的值
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
key_reg <= 1;
delay_cnt <= 0;
end
else begin
key_reg <= key;
//当key为1 key 为0 表示按下抖动,开始计时
if(key_reg != key ) begin
delay_cnt <= MAX_NUM ;
end
else begin
if(delay_cnt > 0)
delay_cnt <= delay_cnt -1;
else
delay_cnt <= 0;
end
end
end
//当计时完成,获取key的值
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
flag <= 0;
key_value <= 1;
end
else begin
// 计时完成 处于稳定状态,进行赋值
if(delay_cnt == 1) begin
flag <= 1;
key_value <= key;
end
else begin
flag <= 0;
key_value <= key_value;
end
end
end
endmodule
digital_tube_top模块
module digital_tube_top(
input wire clk,
input wire rst_n,
input wire [1:0] key,
output wire [56:0] hex
);
wire sec_1;
wire [1:0] flag;
wire [1:0] key_value;
key_debounce inst_key_debounce1(
.clk (clk ), //1s震荡50_000_000次
.rst_n (rst_n ),
.key (key[0] ),
.flag (flag[0] ), //判断抖动是否消除的标志信号,0为抖动,1为抖动消除
.key_value(key_value[0])
);
key_debounce inst_key_debounce2(
.clk (clk ), //1s震荡50_000_000次
.rst_n (rst_n ),
.key (key[1] ),
.flag (flag[1] ), //判断抖动是否消除的标志信号,0为抖动,1为抖动消除
.key_value(key_value[1])
);
seg_led_FSM inst_seg_led_FSM(
.clk (clk),
.rst_n (rst_n),
.key ({flag[1]&&key_value[1],flag[0]&&key_value[0]}),
.hex (hex)
);
endmodule
效果展示