文章目录
- 一.试验任务
- 二.用移位寄存器与FSM实现“HELLO”的循环显示
- ①设计按键消抖模块
- ②设计数码管显示模块
- ③设计顶层模块
- ④设计仿真文件
- ⑤查看RTL门级电路
- ⑥仿真波形
- 三.用FSM实现“HELLO”的自动循环显示
- ①设计计数器模块
- ②设计数码管显示模块
- ③设计顶层模块
- ④编写仿真文件
- ⑤查看RTL门级电路
- ⑥仿真波形
- 四.移动速度可控的“HELLO”的自动循环显示
- ①设计计数器模块
- ②设计按键消抖模块
- ③设计数码管显示模块
- ④设计顶层模块
- ⑤查看RTL门级电路
- ⑥编写仿真模块
- ⑦仿真波形
一.试验任务
1.用移位寄存器与FSM实现“HELLO”的循环显示
本练习使用移位寄存器并结合FSM实现DE2-115平台上 的“HELLO”循环显示。在HEX7~HEX0上循环显示
“HELLO”,根据手动时钟输入脉冲的控制,每接收到一 个脉冲,显示左移一位,当“HELLO”移出左边后,从右 边重新开始显示。
将8个7位寄存器按流水线的形式排列,即第一个寄存器 的输出作为第二个寄存器的输入,第二个寄存器的输出作为
第三个寄存器的输入,依此类推。每个寄存器的输出同时驱 动七段数码管的显示。请设计一个状态机对寄存器流水线进 行以下控制: (1)
在前8个时钟,FSM将字符“H,E,L,L,O, , , ”分别插入8个7位寄存器。 (2)
第(1)步完成后,将寄存器流水线配置成循环模式, 即最后一个寄存器的输出作为第一个寄存器的输入,使字符 可以无限循环显示。
建立一个新的Quartus Ⅱ工程,完成以上的任务。用 DE2-115平台上的KEY0作为FSM及移位寄存器的手动时钟 输入,用SW0作为低电平有效同步清除输入,并按照代码 6.7所示的架构实现所要求的电路。工程编译完成后,将电 路下载到FPGA中测试其功能。
2.用FSM实现“HELLO”的自动循环显示
对上一个练习的内容加以改动,字符的移动以1 s为间 隔自动进行,在HEX7~HEX0上循环显示“HELLO”,
“HELLO”从左边移出后,再从右边重新开始显示。建立 一个新的Quartus Ⅱ工程,完成此任务,用DE2-115平台上的 50
MHz时钟(CLOCK_50)作为FSM及移位寄存器的时钟输入, 并确保所有的触发器都采用CLOCK_50作为时钟,用KEY0
作为低电平有效同步清除输入,并参照代码6.7所示的架构 实现所要求的电路。工程编译完成后,将电路下载到FPGA 中进行功能测试。
3.移动速度可控的“HELLO”的自动循环显示
对上一个练习的内容加以改动,使“HELLO”移动的 速度可以控制:当KEY1按下时,移动速度增加一倍;当 KEY2按下时,移动速度减小一半。
KEY2和KEY1是经过去抖处理的,能够产生一个精确 的脉冲,但脉冲的长度是任意的。建议另外增加一个FSM以
监测按键的状态,这个FSM的输出可以作为调整移动时间间 隔的一个变量。KEY2和KEY1是异步输入的,因此在FSM
中使用时应先与系统时钟同步。 电路复位后,字符每秒移动一次。当连续按KEY1键时, 字符最快以每秒4次的速度移动;当连续按KEY2键时,字
符最慢以每秒一次的速度移动。 建立一个新的Quartus Ⅱ工程,完成以上任务,并在 DE2-115开发板上测试其功能。
二.用移位寄存器与FSM实现“HELLO”的循环显示
使用三段式写状态机
①设计按键消抖模块
这里使用按键时需要消抖,否则不稳定状态会导致按下一次产生多次按下效果。
key_debounce.v
module key_debounce(
input wire clk,
input wire rst_n,
input wire key,
output reg flag, //判断抖动是否消除的标志信号,0为抖动,1为抖动结束
output reg key_value //消抖后稳定的按键值给到蜂鸣器模块和LED模块
);
//定义20ms延迟计数器,0.2s,1_000_000次
reg [19:0] delay_cnt;
//寄存依次key的值用来判断按键是否消抖成功
reg key_reg;
//按下按键20ms延时计数器
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
begin
key_reg <= 1'b1; //复位信号,设置按键无效
delay_cnt <= 1'b0; //计数器设置为0
end
else
begin
key_reg <= key;
if(key_reg ^ key) //当这一次key值和上一次key值不一样,证明正在抖动
delay_cnt <= 20'd1000; //延迟时间20ms(1_000_000) 仿真用20000ns(1000)
else if(delay_cnt > 0)
delay_cnt <= delay_cnt - 1; //没有抖动,开始20ms倒计时
else
delay_cnt <= 1'b0;
end
end
//根据延时计数器获取按键状态以及按键值
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
begin
flag <= 1'b0; //复位信号,设置信号标志为抖动
key_value <= 1'b1; //设置抽样值为1
end
else
begin
if(delay_cnt == 20'd1) //倒计时1_000_000到1
begin
flag <= 1'b1;
key_value <= key; //稳定20ms后将key值给到key_value
end
else
begin
flag <= 1'b0;
key_value <= key_value; //20ms内先不取样
end
end
end
endmodule
②设计数码管显示模块
fsm_hello.v
module fsm_hello(
input wire clk,//时钟
input wire rst_n,//复位
input wire key,//手动脉冲信号
output wire [6:0] seg0,//7位数码管段选信号
output wire [6:0] seg1,
output wire [6:0] seg2,
output wire [6:0] seg3,
output wire [6:0] seg4,
output wire [6:0] seg5,
output wire [6:0] seg6,
output wire [6:0] seg7
);
reg [3:0] cstate;//现态
reg [3:0] nstate;//次态
//状态划分
localparam st_HELLO = 0;
localparam st_ELLO0 = 1;
localparam st_LLO00 = 2;
localparam st_LO000 = 3;
localparam st_O0000 = 4;
localparam st_00000 = 5;
localparam st_0000H = 6;
localparam st_000HE = 7;
localparam st_00HEL = 8;
localparam st_0HELL = 9;
reg [6:0] seg_r0;
reg [6:0] seg_r1;
reg [6:0] seg_r2;
reg [6:0] seg_r3;
reg [6:0] seg_r4;
reg [6:0] seg_r5;
reg [6:0] seg_r6;
reg [6:0] seg_r7;
reg [3:0] cnt;//记录8个时钟
reg flag;//计时标志
wire key_posedge;//key上升沿
reg key1,key2;//两拍
//key上升沿检测
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
key1 <= 1'b0;
key2 <= 1'b0;
end
else begin
key1 <= key;//key1得到上一个时钟的key
key2 <= key1;//key2得到上一个时钟key1,也就是上上个时钟的key
end
end
assign key_posedge = key1 && ~key2;
//8个时钟计数器
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt <= 4'd0;
end
else if(flag == 1'b1)begin
if(cnt == 4'd8)begin
cnt <= 1'd0;
end
else begin
cnt <= cnt + 1'd1;
end
end
else begin
cnt <=4'd0;
end
end
//第一段:现态跟随次态,时序逻辑,非阻塞赋值
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cstate <= st_HELLO;
end
else begin
cstate <= nstate;
end
end
//第二段:组合逻辑,阻塞赋值
always@(*)begin
if(!rst_n)begin
nstate = st_HELLO;
end
else begin
case(cstate)
st_HELLO:begin
if(key_posedge == 1'b1)begin
nstate = st_ELLO0;
end
else begin
nstate = nstate;
end
end
st_ELLO0:begin
if(key_posedge == 1'b1)begin
nstate = st_LLO00;
end
else begin
nstate = nstate;
end
end
st_LLO00:begin
if(key_posedge == 1'b1)begin
nstate = st_LO000;
end
else begin
nstate = nstate;
end
end
st_LO000:begin
if(key_posedge == 1'b1)begin
nstate = st_O0000;
end
else begin
nstate = nstate;
end
end
st_O0000:begin
if(key_posedge == 1'b1)begin
nstate = st_00000;
end
else begin
nstate = nstate;
end
end
st_00000:begin
if(key_posedge == 1'b1)begin
nstate = st_0000H;
end
else begin
nstate = nstate;
end
end
st_0000H:begin
if(key_posedge == 1'b1)begin
nstate = st_000HE;
end
else begin
nstate = nstate;
end
end
st_000HE:begin
if(key_posedge == 1'b1)begin
nstate = st_00HEL;
end
else begin
nstate = nstate;
end
end
st_00HEL:begin
if(key_posedge == 1'b1)begin
nstate = st_0HELL;
end
else begin
nstate = nstate;
end
end
st_0HELL:begin
if(key_posedge == 1'b1)begin
nstate = st_HELLO;
end
else begin
nstate = nstate;
end
end
default:;
endcase
end
end
//三段式:跟随状态输出
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
flag <= 1'b1;
seg_r0 <= 7'b111_1111;
seg_r1 <= 7'b111_1111;
seg_r2 <= 7'b111_1111;
seg_r3 <= 7'b111_1111;
seg_r4 <= 7'b111_1111;
seg_r5 <= 7'b111_1111;
seg_r6 <= 7'b111_1111;
seg_r7 <= 7'b111_1111;
end
else if(flag)begin
case(cnt)
4'd0:seg_r0 <= 7'b100_0000;
4'd1:seg_r1 <= 7'b100_0111;
4'd2:seg_r2 <= 7'b100_0111;
4'd3:seg_r3 <= 7'b000_0110;
4'd4:seg_r4 <= 7'b000_1001;
4'd5:seg_r5 <= 7'b111_1111;
4'd6:seg_r6 <= 7'b111_1111;
4'd7:seg_r7 <= 7'b111_1111;
4'd8:flag <= 1'b0 ;
default:;
endcase
end
else begin
case(cstate)
st_HELLO:begin
if(key_posedge)begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0,seg_r7};
end
else begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0};
end
end
st_ELLO0:begin
if(key_posedge)begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0,seg_r7};
end
else begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0};
end
end
st_LLO00:begin
if(key_posedge)begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0,seg_r7};
end
else begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0};
end
end
st_LO000:begin
if(key_posedge)begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0,seg_r7};
end
else begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0};
end
end
st_O0000:begin
if(key_posedge)begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0,seg_r7};
end
else begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0};
end
end
st_00000:begin
if(key_posedge)begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0,seg_r7};
end
else begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0};
end
end
st_0000H:begin
if(key_posedge)begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0,seg_r7};
end
else begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0};
end
end
st_000HE:begin
if(key_posedge)begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0,seg_r7};
end
else begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0};
end
end
st_00HEL:begin
if(key_posedge)begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0,seg_r7};
end
else begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0};
end
end
st_0HELL:begin
if(key_posedge)begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0,seg_r7};
end
else begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0};
end
end
default:;
endcase
end
end
assign {seg7,seg6,seg5,seg4,seg3,seg2,seg1,seg0} = {seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0};
endmodule
③设计顶层模块
fsm_hello_top.v
module fsm_hello_top(
input wire clk,
input wire rst_n,
input wire key,
output wire [6:0] seg0,//7位数码管段选信号
output wire [6:0] seg1,
output wire [6:0] seg2,
output wire [6:0] seg3,
output wire [6:0] seg4,
output wire [6:0] seg5,
output wire [6:0] seg6,
output wire [6:0] seg7
);
wire key_value;
wire flag;
//例化按键key消抖模块
key_debounce inst_key_debounce(
.clk (clk ),
.rst_n (rst_n ),
.key (key ),
.flag (flag ),
.key_value (key_value)
);
//例化HELLO状态机模块
fsm_hello inst_fsm_hello(
.clk (clk),//时钟
.rst_n(rst_n),//复位
.key (~key_value && flag),//手动脉冲信号
.seg0 (seg0),//7位数码管段选信号
.seg1 (seg1),
.seg2 (seg2),
.seg3 (seg3),
.seg4 (seg4),
.seg5 (seg5),
.seg6 (seg6),
.seg7 (seg7)
);
endmodule
④设计仿真文件
fsm_hello_top_tb.v
`timescale 1ns/1ns //时间单位和时间精度,两者最多一样大,精度不能大于单位
module fsm_hello_top_tb();
parameter DELAY = 50000;
reg clk_50M; //wire型改为reg类型,可以起不同的名字
reg rst_n;
reg key;
wire [6:0] seg0;
wire [6:0] seg1;
wire [6:0] seg2;
wire [6:0] seg3;
wire [6:0] seg4;
wire [6:0] seg5;
wire [6:0] seg6;
wire [6:0] seg7;
//激励信号
always #10 clk_50M = ~clk_50M; //每过10ns,时钟取反,总是执行
//信号初始化
initial begin
clk_50M = 1'b0;
rst_n = 1'b0;
#10; //复位信号延迟10纳秒变为无效
rst_n = 1'b1;
#200;
key = 1'b1;
#DELAY
key = 1'b0;//第1次按下
#DELAY
key = 1'b1;
#DELAY
key = 1'b0;//第2次按下
#DELAY
key = 1'b1;
#DELAY
key = 1'b0;//第3次按下
#DELAY
key = 1'b1;
#DELAY
key = 1'b0;//第4次按下
#DELAY
key = 1'b1;
#DELAY
key = 1'b0;//第5次按下
#DELAY
key = 1'b1;
#DELAY
key = 1'b0;//第6次按下
#DELAY
key = 1'b1;
#DELAY
key = 1'b0;//第7次按下
#DELAY
key = 1'b1;
#DELAY
key = 1'b0;//第8次按下
#DELAY
key = 1'b1;
#DELAY
key = 1'b0;//第9次按下
#DELAY
key = 1'b1;
#DELAY
//延迟后停止
$stop;
end
fsm_hello_top inst_fsm_hello_top(
.clk (clk_50M),
.rst_n (rst_n),
.key (key),
.seg0 (seg0),//7位数码管段选信号
.seg1 (seg1),
.seg2 (seg2),
.seg3 (seg3),
.seg4 (seg4),
.seg5 (seg5),
.seg6 (seg6),
.seg7 (seg7)
);
endmodule
⑤查看RTL门级电路
⑥仿真波形
可以看见付复位号后,所有数码管寄存器初始化值为111_1111。在前面8个时钟周期,分别为每个寄存器赋值
此后0~7号寄存器分别赋值给7,0,1,2,3,4,5,6号寄存器,实现数码管的移动显示
可以看见key每按下一次,HELLO就移动一次
三.用FSM实现“HELLO”的自动循环显示
①设计计数器模块
同实验1
time_count.v
module time_count(
input wire clk, //时钟,50MHZ
input wire rst_n, //复位信号,下降沿有效,negative
output wire sec_1//1s输出一个脉冲信号
);
parameter MAX_NUM = 26'd49_999;//记最大数1s,50_000_000次 仿真使用1ms
reg [25:0] cnt_1;//计数寄存器
reg sec_1_r;
//1s计时器
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_1 <= 26'd0;
end
else if(cnt_1 == MAX_NUM)begin
cnt_1 <= 26'd0;
end
else begin
cnt_1 <= cnt_1 + 1'd1;
end
end
//1s脉冲信号
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
sec_1_r <= 1'b0;
end
else if(cnt_1 == MAX_NUM)begin
sec_1_r <= 1'b1;
end
else begin
sec_1_r <= 1'b0;
end
end
assign sec_1 = sec_1_r;//当右边改变,立马赋值给左边 assign和always并行
endmodule
②设计数码管显示模块
fsm_hello.v
module fsm_hello(
input wire clk,//时钟
input wire rst_n,//复位
input wire sec_1,//1s脉冲信号
output wire [6:0] seg0,//7位数码管段选信号
output wire [6:0] seg1,
output wire [6:0] seg2,
output wire [6:0] seg3,
output wire [6:0] seg4,
output wire [6:0] seg5,
output wire [6:0] seg6,
output wire [6:0] seg7
);
reg [3:0] cstate;//现态
reg [3:0] nstate;//次态
//状态划分
localparam st_HELLO = 0;
localparam st_ELLO0 = 1;
localparam st_LLO00 = 2;
localparam st_LO000 = 3;
localparam st_O0000 = 4;
localparam st_00000 = 5;
localparam st_0000H = 6;
localparam st_000HE = 7;
localparam st_00HEL = 8;
localparam st_0HELL = 9;
reg [6:0] seg_r0;
reg [6:0] seg_r1;
reg [6:0] seg_r2;
reg [6:0] seg_r3;
reg [6:0] seg_r4;
reg [6:0] seg_r5;
reg [6:0] seg_r6;
reg [6:0] seg_r7;
reg [3:0] cnt;
reg flag;
//8个时钟计数器
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt <= 4'd0;
end
else if(flag == 1'b1)begin
if(cnt == 4'd8)begin
cnt <= 1'd0;
end
else begin
cnt <= cnt + 1'd1;
end
end
else begin
cnt <=4'd0;
end
end
//第一段:现态跟随次态,时序逻辑,非阻塞赋值
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cstate <= st_HELLO;
end
else begin
cstate <= nstate;
end
end
//第二段:组合逻辑,阻塞赋值
always@(*)begin
if(!rst_n)begin
nstate = st_HELLO;
end
else begin
case(cstate)
st_HELLO:begin
if(sec_1 == 1'b1)begin
nstate = st_ELLO0;
end
else begin
nstate = nstate;
end
end
st_ELLO0:begin
if(sec_1 == 1'b1)begin
nstate = st_LLO00;
end
else begin
nstate = nstate;
end
end
st_LLO00:begin
if(sec_1 == 1'b1)begin
nstate = st_LO000;
end
else begin
nstate = nstate;
end
end
st_LO000:begin
if(sec_1 == 1'b1)begin
nstate = st_O0000;
end
else begin
nstate = nstate;
end
end
st_O0000:begin
if(sec_1 == 1'b1)begin
nstate = st_00000;
end
else begin
nstate = nstate;
end
end
st_00000:begin
if(sec_1 == 1'b1)begin
nstate = st_0000H;
end
else begin
nstate = nstate;
end
end
st_0000H:begin
if(sec_1 == 1'b1)begin
nstate = st_000HE;
end
else begin
nstate = nstate;
end
end
st_000HE:begin
if(sec_1 == 1'b1)begin
nstate = st_00HEL;
end
else begin
nstate = nstate;
end
end
st_00HEL:begin
if(sec_1 == 1'b1)begin
nstate = st_0HELL;
end
else begin
nstate = nstate;
end
end
st_0HELL:begin
if(sec_1 == 1'b1)begin
nstate = st_HELLO;
end
else begin
nstate = nstate;
end
end
default:;
endcase
end
end
//三段式:跟随状态输出
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
flag <= 1'b1;
seg_r0 <= 7'b111_1111;
seg_r1 <= 7'b111_1111;
seg_r2 <= 7'b111_1111;
seg_r3 <= 7'b111_1111;
seg_r4 <= 7'b111_1111;
seg_r5 <= 7'b111_1111;
seg_r6 <= 7'b111_1111;
seg_r7 <= 7'b111_1111;
end
else if(flag)begin
case(cnt)
4'd0:seg_r0 <= 7'b100_0000;
4'd1:seg_r1 <= 7'b100_0111;
4'd2:seg_r2 <= 7'b100_0111;
4'd3:seg_r3 <= 7'b000_0110;
4'd4:seg_r4 <= 7'b000_1001;
4'd5:seg_r5 <= 7'b111_1111;
4'd6:seg_r6 <= 7'b111_1111;
4'd7:seg_r7 <= 7'b111_1111;
4'd8:flag <= 1'b0 ;
default:;
endcase
end
else begin
case(cstate)
st_HELLO:begin
if(sec_1)begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0,seg_r7};
end
else begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0};
end
end
st_ELLO0:begin
if(sec_1)begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0,seg_r7};
end
else begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0};
end
end
st_LLO00:begin
if(sec_1)begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0,seg_r7};
end
else begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0};
end
end
st_LO000:begin
if(sec_1)begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0,seg_r7};
end
else begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0};
end
end
st_O0000:begin
if(sec_1)begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0,seg_r7};
end
else begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0};
end
end
st_00000:begin
if(sec_1)begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0,seg_r7};
end
else begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0};
end
end
st_0000H:begin
if(sec_1)begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0,seg_r7};
end
else begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0};
end
end
st_000HE:begin
if(sec_1)begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0,seg_r7};
end
else begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0};
end
end
st_00HEL:begin
if(sec_1)begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0,seg_r7};
end
else begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0};
end
end
st_0HELL:begin
if(sec_1)begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0,seg_r7};
end
else begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0};
end
end
default:;
endcase
end
end
assign {seg7,seg6,seg5,seg4,seg3,seg2,seg1,seg0} = {seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0};
endmodule
③设计顶层模块
fsm_hello_top.v
module fsm_hello_top(
input wire clk,
input wire rst_n,
output wire [6:0] seg0,//7位数码管段选信号
output wire [6:0] seg1,
output wire [6:0] seg2,
output wire [6:0] seg3,
output wire [6:0] seg4,
output wire [6:0] seg5,
output wire [6:0] seg6,
output wire [6:0] seg7
);
wire sec_1;
time_count inst_time_count(
.clk (clk), //时钟,50MHZ
.rst_n(rst_n), //复位信号,下降沿有效,negative
.sec_1 (sec_1)//1s输出一个脉冲信号
);
//例化HELLO状态机模块
fsm_hello inst_fsm_hello(
.clk (clk),//时钟
.rst_n (rst_n),//复位
.sec_1 (sec_1),//手动脉冲信号
.seg0 (seg0),//7位数码管段选信号
.seg1 (seg1),
.seg2 (seg2),
.seg3 (seg3),
.seg4 (seg4),
.seg5 (seg5),
.seg6 (seg6),
.seg7 (seg7)
);
endmodule
④编写仿真文件
fsm_hello_top_tb.v
`timescale 1ns/1ns //时间单位和时间精度,两者最多一样大,精度不能大于单位
module fsm_hello_top_tb();
parameter DELAY = 1000000;//1ms
reg clk_50M; //wire型改为reg类型,可以起不同的名字
reg rst_n;
wire [6:0] seg0;
wire [6:0] seg1;
wire [6:0] seg2;
wire [6:0] seg3;
wire [6:0] seg4;
wire [6:0] seg5;
wire [6:0] seg6;
wire [6:0] seg7;
//激励信号
always #10 clk_50M = ~clk_50M; //每过10ns,时钟取反,总是执行
//信号初始化
initial begin
clk_50M = 1'b0;
rst_n = 1'b0;
#10; //复位信号延迟10纳秒变为无效
rst_n = 1'b1;
#(DELAY * 10);
//延迟后停止
$stop;
end
fsm_hello_top inst_fsm_hello_top(
.clk (clk_50M),
.rst_n (rst_n),
.seg0 (seg0),//7位数码管段选信号
.seg1 (seg1),
.seg2 (seg2),
.seg3 (seg3),
.seg4 (seg4),
.seg5 (seg5),
.seg6 (seg6),
.seg7 (seg7)
);
endmodule
⑤查看RTL门级电路
⑥仿真波形
可以看到每隔1_000_000nsHELLO移动一次。
四.移动速度可控的“HELLO”的自动循环显示
①设计计数器模块
这里要使用三种速度实现数码管切换,计数器模块输出0.5,1,2s脉冲信号
time_count.v
module time_count(
input wire clk ,//时钟,50MHZ
input wire rst_n ,//复位信号,下降沿有效,negative
output wire sec_05 ,//0.5s输出一个脉冲信号
output wire sec_1 ,//1s输出一个脉冲信号
output wire sec_2 //2s输出一个脉冲信号
);
parameter MAX_NUM = 26'd24_999;//记最大数0.5s,25_000_000次 仿真使用0.5ms
parameter MAX_NUM1 = 2 ;
reg [25:0] cnt_05 ;//0.5s计数寄存器
reg [1:0] cnt_1 ;//1s计数寄存器
reg [1:0] cnt_2 ;//2s计数寄存器
reg sec_05_r;
reg sec_1_r ;
reg sec_2_r ;
//0.5s计时器
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_05 <= 26'd0;
end
else if(cnt_05 == MAX_NUM)begin
cnt_05 <= 26'd0;
end
else begin
cnt_05 <= cnt_05 + 1'd1;
end
end
//1s计时器
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_1 <= 2'd0;
end
else if(cnt_1 < MAX_NUM1)begin
if(cnt_05 == MAX_NUM)begin
cnt_1 <= cnt_1 + 1'd1;
end
else begin
cnt_1 <= cnt_1;
end
end
else begin
cnt_1 <= 2'd0;
end
end
//2s计时器
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_2 <= 2'd0;
end
else if(cnt_2 < MAX_NUM1)begin
if(cnt_1 == MAX_NUM1)begin
cnt_2 <= cnt_2 + 1'd1;
end
else begin
cnt_2 <= cnt_2;
end
end
else begin
cnt_2 <= 2'd0;
end
end
//0.5s脉冲信号
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
sec_05_r <= 1'b0;
end
else if(cnt_05 == MAX_NUM)begin
sec_05_r <= 1'b1;
end
else begin
sec_05_r <= 1'b0;
end
end
//1s脉冲信号
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
sec_1_r <= 1'b0;
end
else if(cnt_1 == MAX_NUM1)begin
sec_1_r <= 1'b1;
end
else begin
sec_1_r <= 1'b0;
end
end
//1s脉冲信号
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
sec_2_r <= 1'b0;
end
else if(cnt_2 == MAX_NUM1)begin
sec_2_r <= 1'b1;
end
else begin
sec_2_r <= 1'b0;
end
end
assign sec_05 = sec_05_r;//当右边改变,立马赋值给左边 assign和always并行
assign sec_1 = sec_1_r ;
assign sec_2 = sec_2_r ;
endmodule
②设计按键消抖模块
key_debounce.v
module key_debounce(
input wire clk,
input wire rst_n,
input wire key,
output reg flag, //判断抖动是否消除的标志信号,0为抖动,1为抖动结束
output reg key_value //消抖后稳定的按键值给到蜂鸣器模块和LED模块
);
//定义20ms延迟计数器,0.2s,1_000_000次
reg [19:0] delay_cnt;
//寄存依次key的值用来判断按键是否消抖成功
reg key_reg;
//按下按键20ms延时计数器
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
begin
key_reg <= 1'b1; //复位信号,设置按键无效
delay_cnt <= 1'b0; //计数器设置为0
end
else
begin
key_reg <= key;
if(key_reg ^ key) //当这一次key值和上一次key值不一样,证明正在抖动
delay_cnt <= 20'd1000; //延迟时间20ms(1_000_000) 仿真用20000ns(1000)
else if(delay_cnt > 0)
delay_cnt <= delay_cnt - 1; //没有抖动,开始20ms倒计时
else
delay_cnt <= 1'b0;
end
end
//根据延时计数器获取按键状态以及按键值
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
begin
flag <= 1'b0; //复位信号,设置信号标志为抖动
key_value <= 1'b1; //设置抽样值为1
end
else
begin
if(delay_cnt == 20'd1) //倒计时1_000_000到1
begin
flag <= 1'b1;
key_value <= key; //稳定20ms后将key值给到key_value
end
else
begin
flag <= 1'b0;
key_value <= key_value; //20ms内先不取样
end
end
end
endmodule
③设计数码管显示模块
fsm_key_speed_hello.v
module fsm_key_speed_hello(
input wire clk ,//时钟
input wire rst_n ,//复位
input wire sec_05,//0.5s脉冲信号
input wire sec_1 ,//1s脉冲信号
input wire sec_2 ,//2s脉冲信号
input wire [1:0] key ,//按键
output wire [6:0] seg0,//7位数码管段选信号
output wire [6:0] seg1,
output wire [6:0] seg2,
output wire [6:0] seg3,
output wire [6:0] seg4,
output wire [6:0] seg5,
output wire [6:0] seg6,
output wire [6:0] seg7
);
reg [3:0] cstate;//现态
reg [3:0] nstate;//次态
//状态划分
localparam st_HELLO = 0;
localparam st_ELLO0 = 1;
localparam st_LLO00 = 2;
localparam st_LO000 = 3;
localparam st_O0000 = 4;
localparam st_00000 = 5;
localparam st_0000H = 6;
localparam st_000HE = 7;
localparam st_00HEL = 8;
localparam st_0HELL = 9;
reg [6:0] seg_r0;
reg [6:0] seg_r1;
reg [6:0] seg_r2;
reg [6:0] seg_r3;
reg [6:0] seg_r4;
reg [6:0] seg_r5;
reg [6:0] seg_r6;
reg [6:0] seg_r7;
reg [3:0] cnt ;
reg flag ;
reg [1:0] speed ;//HELLO移动速度3种
//8个时钟计数器
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt <= 4'd0;
end
else if(flag == 1'b1)begin
if(cnt == 4'd8)begin
cnt <= 1'd0;
end
else begin
cnt <= cnt + 1'd1;
end
end
else begin
cnt <=4'd0;
end
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
speed <= 2'd0;
end
else if(key[0])begin
speed <= 2'd1;
end
else if(key[1])begin
speed <= 2'd2;
end
else begin
speed <= speed;
end
end
//第一段:现态跟随次态,时序逻辑,非阻塞赋值
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cstate <= st_HELLO;
end
else begin
cstate <= nstate;
end
end
//第二段:组合逻辑,阻塞赋值
always@(*)begin
if(!rst_n)begin
nstate = st_HELLO;
end
else begin
case(speed)
2'd0:begin
case(cstate)
st_HELLO:begin
if(sec_1 == 1'b1)begin
nstate = st_ELLO0;
end
else begin
nstate = nstate;
end
end
st_ELLO0:begin
if(sec_1 == 1'b1)begin
nstate = st_LLO00;
end
else begin
nstate = nstate;
end
end
st_LLO00:begin
if(sec_1 == 1'b1)begin
nstate = st_LO000;
end
else begin
nstate = nstate;
end
end
st_LO000:begin
if(sec_1 == 1'b1)begin
nstate = st_O0000;
end
else begin
nstate = nstate;
end
end
st_O0000:begin
if(sec_1 == 1'b1)begin
nstate = st_00000;
end
else begin
nstate = nstate;
end
end
st_00000:begin
if(sec_1 == 1'b1)begin
nstate = st_0000H;
end
else begin
nstate = nstate;
end
end
st_0000H:begin
if(sec_1 == 1'b1)begin
nstate = st_000HE;
end
else begin
nstate = nstate;
end
end
st_000HE:begin
if(sec_1 == 1'b1)begin
nstate = st_00HEL;
end
else begin
nstate = nstate;
end
end
st_00HEL:begin
if(sec_1 == 1'b1)begin
nstate = st_0HELL;
end
else begin
nstate = nstate;
end
end
st_0HELL:begin
if(sec_1 == 1'b1)begin
nstate = st_HELLO;
end
else begin
nstate = nstate;
end
end
default:nstate = st_HELLO;
endcase
end
2'd1:begin
case(cstate)
st_HELLO:begin
if(sec_05 == 1'b1)begin
nstate = st_ELLO0;
end
else begin
nstate = nstate;
end
end
st_ELLO0:begin
if(sec_05 == 1'b1)begin
nstate = st_LLO00;
end
else begin
nstate = nstate;
end
end
st_LLO00:begin
if(sec_05 == 1'b1)begin
nstate = st_LO000;
end
else begin
nstate = nstate;
end
end
st_LO000:begin
if(sec_05 == 1'b1)begin
nstate = st_O0000;
end
else begin
nstate = nstate;
end
end
st_O0000:begin
if(sec_05 == 1'b1)begin
nstate = st_00000;
end
else begin
nstate = nstate;
end
end
st_00000:begin
if(sec_05 == 1'b1)begin
nstate = st_0000H;
end
else begin
nstate = nstate;
end
end
st_0000H:begin
if(sec_05 == 1'b1)begin
nstate = st_000HE;
end
else begin
nstate = nstate;
end
end
st_000HE:begin
if(sec_05 == 1'b1)begin
nstate = st_00HEL;
end
else begin
nstate = nstate;
end
end
st_00HEL:begin
if(sec_05 == 1'b1)begin
nstate = st_0HELL;
end
else begin
nstate = nstate;
end
end
st_0HELL:begin
if(sec_05 == 1'b1)begin
nstate = st_HELLO;
end
else begin
nstate = nstate;
end
end
default:nstate = st_HELLO;
endcase
end
2'd2:begin
case(cstate)
st_HELLO:begin
if(sec_2 == 1'b1)begin
nstate = st_ELLO0;
end
else begin
nstate = nstate;
end
end
st_ELLO0:begin
if(sec_2 == 1'b1)begin
nstate = st_LLO00;
end
else begin
nstate = nstate;
end
end
st_LLO00:begin
if(sec_2 == 1'b1)begin
nstate = st_LO000;
end
else begin
nstate = nstate;
end
end
st_LO000:begin
if(sec_2 == 1'b1)begin
nstate = st_O0000;
end
else begin
nstate = nstate;
end
end
st_O0000:begin
if(sec_2 == 1'b1)begin
nstate = st_00000;
end
else begin
nstate = nstate;
end
end
st_00000:begin
if(sec_2 == 1'b1)begin
nstate = st_0000H;
end
else begin
nstate = nstate;
end
end
st_0000H:begin
if(sec_2 == 1'b1)begin
nstate = st_000HE;
end
else begin
nstate = nstate;
end
end
st_000HE:begin
if(sec_2 == 1'b1)begin
nstate = st_00HEL;
end
else begin
nstate = nstate;
end
end
st_00HEL:begin
if(sec_2 == 1'b1)begin
nstate = st_0HELL;
end
else begin
nstate = nstate;
end
end
st_0HELL:begin
if(sec_2 == 1'b1)begin
nstate = st_HELLO;
end
else begin
nstate = nstate;
end
end
default:nstate = st_HELLO;
endcase
end
default:;
endcase
end
end
//三段式:跟随状态输出
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
flag <= 1'b1;
seg_r0 <= 7'b111_1111;
seg_r1 <= 7'b111_1111;
seg_r2 <= 7'b111_1111;
seg_r3 <= 7'b111_1111;
seg_r4 <= 7'b111_1111;
seg_r5 <= 7'b111_1111;
seg_r6 <= 7'b111_1111;
seg_r7 <= 7'b111_1111;
end
else if(flag)begin
case(cnt)
4'd0:seg_r0 <= 7'b100_0000;
4'd1:seg_r1 <= 7'b100_0111;
4'd2:seg_r2 <= 7'b100_0111;
4'd3:seg_r3 <= 7'b000_0110;
4'd4:seg_r4 <= 7'b000_1001;
4'd5:seg_r5 <= 7'b111_1111;
4'd6:seg_r6 <= 7'b111_1111;
4'd7:seg_r7 <= 7'b111_1111;
4'd8:flag <= 1'b0 ;
default:;
endcase
end
else begin
case(speed)
2'd0:begin
case(cstate)
st_HELLO:begin
if(sec_1)begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0,seg_r7};
end
else begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0};
end
end
st_ELLO0:begin
if(sec_1)begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0,seg_r7};
end
else begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0};
end
end
st_LLO00:begin
if(sec_1)begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0,seg_r7};
end
else begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0};
end
end
st_LO000:begin
if(sec_1)begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0,seg_r7};
end
else begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0};
end
end
st_O0000:begin
if(sec_1)begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0,seg_r7};
end
else begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0};
end
end
st_00000:begin
if(sec_1)begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0,seg_r7};
end
else begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0};
end
end
st_0000H:begin
if(sec_1)begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0,seg_r7};
end
else begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0};
end
end
st_000HE:begin
if(sec_1)begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0,seg_r7};
end
else begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0};
end
end
st_00HEL:begin
if(sec_1)begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0,seg_r7};
end
else begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0};
end
end
st_0HELL:begin
if(sec_1)begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0,seg_r7};
end
else begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0};
end
end
default:;
endcase
end
2'd1:begin
case(cstate)
st_HELLO:begin
if(sec_05)begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0,seg_r7};
end
else begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0};
end
end
st_ELLO0:begin
if(sec_05)begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0,seg_r7};
end
else begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0};
end
end
st_LLO00:begin
if(sec_05)begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0,seg_r7};
end
else begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0};
end
end
st_LO000:begin
if(sec_05)begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0,seg_r7};
end
else begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0};
end
end
st_O0000:begin
if(sec_05)begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0,seg_r7};
end
else begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0};
end
end
st_00000:begin
if(sec_05)begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0,seg_r7};
end
else begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0};
end
end
st_0000H:begin
if(sec_05)begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0,seg_r7};
end
else begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0};
end
end
st_000HE:begin
if(sec_05)begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0,seg_r7};
end
else begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0};
end
end
st_00HEL:begin
if(sec_05)begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0,seg_r7};
end
else begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0};
end
end
st_0HELL:begin
if(sec_05)begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0,seg_r7};
end
else begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0};
end
end
default:;
endcase
end
2'd2:begin
case(cstate)
st_HELLO:begin
if(sec_2)begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0,seg_r7};
end
else begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0};
end
end
st_ELLO0:begin
if(sec_2)begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0,seg_r7};
end
else begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0};
end
end
st_LLO00:begin
if(sec_2)begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0,seg_r7};
end
else begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0};
end
end
st_LO000:begin
if(sec_2)begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0,seg_r7};
end
else begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0};
end
end
st_O0000:begin
if(sec_2)begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0,seg_r7};
end
else begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0};
end
end
st_00000:begin
if(sec_2)begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0,seg_r7};
end
else begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0};
end
end
st_0000H:begin
if(sec_2)begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0,seg_r7};
end
else begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0};
end
end
st_000HE:begin
if(sec_2)begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0,seg_r7};
end
else begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0};
end
end
st_00HEL:begin
if(sec_2)begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0,seg_r7};
end
else begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0};
end
end
st_0HELL:begin
if(sec_2)begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0,seg_r7};
end
else begin
{seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0} <= {seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0};
end
end
default:;
endcase
end
default:;
endcase
end
end
assign {seg7,seg6,seg5,seg4,seg3,seg2,seg1,seg0} = {seg_r7,seg_r6,seg_r5,seg_r4,seg_r3,seg_r2,seg_r1,seg_r0};
endmodule
④设计顶层模块
fsm_key_speed_hello_top.v
module fsm_key_speed_hello_top(
input wire clk ,
input wire rst_n,
input wire [1:0] key ,
output wire [6:0] seg0 ,//7位数码管段选信号
output wire [6:0] seg1 ,
output wire [6:0] seg2 ,
output wire [6:0] seg3 ,
output wire [6:0] seg4 ,
output wire [6:0] seg5 ,
output wire [6:0] seg6 ,
output wire [6:0] seg7
);
wire sec_05 ;
wire sec_1 ;
wire sec_2 ;
wire [1:0] flag ;
wire [1:0] key_value;
key_debounce inst_key_debounce(
.clk (clk ),
.rst_n (rst_n ),
.key (key[0] ),
.flag (flag[0]), //判断抖动是否消除的标志信号,0为抖动,1为抖动结束
.key_value (key_value[0]) //消抖后稳定的按键值给到蜂鸣器模块和LED模块
);
key_debounce inst_key_debounce1(
.clk (clk ),
.rst_n (rst_n ),
.key (key[1] ),
.flag (flag[1]), //判断抖动是否消除的标志信号,0为抖动,1为抖动结束
.key_value (key_value[1]) //消抖后稳定的按键值给到蜂鸣器模块和LED模块
);
time_count inst_time_count(
.clk (clk) , //时钟,50MHZ
.rst_n(rst_n) , //复位信号,下降沿有效,negative
.sec_05(sec_05),//0.5s输出一个脉冲信号
.sec_1 (sec_1) ,//1s输出一个脉冲信号
.sec_2 (sec_2) //2s输出一个脉冲信号
);
//例化HELLO状态机模块
fsm_key_speed_hello inst_fsm_key_speed_hello(
.clk (clk ),//时钟
.rst_n (rst_n ),//复位
.sec_05 (sec_05),
.sec_1 (sec_1 ),
.sec_2 (sec_2 ),
.key ({~key_value[1]&&flag[1],~key_value[0]&&flag[0]}),
.seg0 (seg0 ),//7位数码管段选信号
.seg1 (seg1 ),
.seg2 (seg2 ),
.seg3 (seg3 ),
.seg4 (seg4 ),
.seg5 (seg5 ),
.seg6 (seg6 ),
.seg7 (seg7 )
);
endmodule
⑤查看RTL门级电路
⑥编写仿真模块
fsm_key_speed_hello_top_tb.v
`timescale 1ns/1ns //时间单位和时间精度,两者最多一样大,精度不能大于单位
module fsm_key_speed_hello_top_tb();
parameter DELAY = 1000000;//1ms
reg clk_50M; //wire型改为reg类型,可以起不同的名字
reg rst_n;
reg [1:0] key;
wire [6:0] seg0;
wire [6:0] seg1;
wire [6:0] seg2;
wire [6:0] seg3;
wire [6:0] seg4;
wire [6:0] seg5;
wire [6:0] seg6;
wire [6:0] seg7;
//激励信号
always #10 clk_50M = ~clk_50M; //每过10ns,时钟取反,总是执行
//信号初始化
initial begin
clk_50M = 1'b0 ;
rst_n = 1'b0 ;
#10 ; //复位信号延迟10纳秒变为无效
rst_n = 1'b1 ;
key = 2'b11; //以速度1ms移动
#(DELAY * 4) ; //以速度1ms延迟4ms
key = 2'b10; //按下KEY0键,以速度0.5ms移动
#(DELAY * 4) ; //以速度0.5ms延迟4ms
key = 2'b11; //弹起KEY0键,以速度1ms移动
#(DELAY * 4) ; //以速度1ms延迟4ms
key = 2'b01; //按下KEY1键,以速度2ms移动
#(DELAY * 4) ; //以速度2ms延迟4ms
//延迟后停止
$stop;
end
fsm_key_speed_hello_top inst_fsm_key_speed_hello_top(
.clk (clk_50M),
.rst_n (rst_n),
.key (key ),
.seg0 (seg0),//7位数码管段选信号
.seg1 (seg1),
.seg2 (seg2),
.seg3 (seg3),
.seg4 (seg4),
.seg5 (seg5),
.seg6 (seg6),
.seg7 (seg7)
);
endmodule