各位好我是Toporanger 本人只会写代码 不会教人 毕竟自己的代码也是改来改去最终成功的
如果有不够精简的地方还请见谅
我会先贴下代码 然后贴上管脚的绑定图 无论是拿来救急还是作为参考都希望帮助到你们
题目:设计一个全加器,并用该全加器实现4位串行进位加法器。(拓展:用七段数码管显示两个加数,按键显示相加的结果)。要求:
1. 一定要满足题目要求。
2. 用Verilog HDL实现并在FPGA开发板上验证。
代码:
`timescale 1ns / 1ps
// 模块 hw_5: 根据输入的开关值计算和并在7段显示上显示结果
module hw_5 (
input clk, rst, // 时钟和复位信号
input sw1, sw2, sw3, sw4, // 输入开关,用于数字输入
input key1, key2, // 控制按键
output reg [8:0] seg_led1, // 第一个7段显示的输出
output reg [8:0] seg_led2, // 第二个7段显示的输出
output [4:0] sum // 计算结果的输出
);
// 定义寄存器和变量
reg [3:0] a, b; // 输入数字的寄存器
reg flag1, flag2; // 控制标志
reg [8:0] seg [9:0]; // 7段显示编码数组
reg c1, c2, c3, c4; // 未使用的控制信号
reg [3:0] n, m; // 用于存储计算结果的十位和个位
wire key1_pulse, key2_pulse;// 去抖后的按键信号
// 初始化7段显示的编码
initial begin
seg[0] = 9'h3f; // 0
seg[1] = 9'h06; // 1
seg[2] = 9'h5b; // 2
seg[3] = 9'h4f; // 3
seg[4] = 9'h66; // 4
seg[5] = 9'h6d; // 5
seg[6] = 9'h7d; // 6
seg[7] = 9'h07; // 7
seg[8] = 9'h7f; // 8
seg[9] = 9'h6f; // 9
end
// 主控制逻辑
always @(posedge clk) begin
if (!rst) begin
// 复位逻辑
a <= 4'b0000;
b <= 4'b0000;
flag1 <= 1'b1;
flag2 <= 1'b1;
c1 <= 1'b0;
c2 <= 1'b0;
c3 <= 1'b0;
c4 <= 1'b0;
end
if (flag1 && !key1_pulse) begin
// 根据输入开关设置a的值,并更新第一个7段显示
a <= {sw1, sw2, sw3, sw4};
seg_led1 <= seg[a];
end
if (flag2 && !key2_pulse) begin
// 根据输入开关设置b的值,并更新第二个7段显示
b <= {sw1, sw2, sw3, sw4};
seg_led2 <= seg[b];
end
if (key1_pulse) begin
// 按下key1时的逻辑
flag1 <= 1'b0;
end
if (key2_pulse) begin
// 按下key2时的逻辑,计算和显示结果
flag2 <= 1'b0;
m <= sum / 4'd10; // 计算十位
n <= sum % 4'd10; // 计算个位
seg_led1 <= seg[m]; // 显示十位
seg_led2 <= seg[n]; // 显示个位
end
end
// 加法器模块实例化
adder_4 u1 (
.clk(clk),
.a(a),
.b(b),
.s(sum),
.ci(0) // 这里假设加法器有一个进位输入,暂时置为0
);
// 去抖模块实例化(假设已实现)
debounce a1 (
.clk(clk),
.rst(rst),
.key(key1),
.key_pulse(key1_pulse)
);
debounce a2 (
.clk(clk),
.rst(rst),
.key(key2),
.key_pulse(key2_pulse)
);
endmodule
全加器:
module adder_4(clk,a,b,s,ci);
input [3:0] a;
input [3:0] b;
input ci;
input clk;
output [4:0] s;
wire c1,c2,c3,c4,c5;
adder u0(.clk(clk),.a(a[0]),.b(b[0]),.ci_1(ci),.si(s[0]),.ci(c1));
adder u1(.clk(clk),.a(a[1]),.b(b[1]),.ci_1(c1),.si(s[1]),.ci(c2));
adder u2(.clk(clk),.a(a[2]),.b(b[2]),.ci_1(c2),.si(s[2]),.ci(c3));
adder u3(.clk(clk),.a(a[3]),.b(b[3]),.ci_1(c3),.si(s[3]),.ci(s[4]));
//adder u4(.clk(clk),.a(0),.b(0),.ci_1(c4),.si(s[4]),.ci(c5));
endmodule
消抖:
module debounce (clk,rst,key,key_pulse);
parameter N = 1; //要消除的按键的数量
input clk;
input rst;
input [N-1:0] key; //输入的按键
output [N-1:0] key_pulse; //按键动作产生的脉冲
reg [N-1:0] key_rst_pre; //定义一个寄存器型变量存储上一个触发时的按键值
reg [N-1:0] key_rst; //定义一个寄存器变量储存储当前时刻触发的按键值
wire [N-1:0] key_edge; //检测到按键由高到低变化是产生一个高脉冲
//利用非阻塞赋值特点,将两个时钟触发时按键状态存储在两个寄存器变量中
always @(posedge clk or negedge rst)
begin
if (!rst) begin
key_rst <= {N{1'b1}}; //初始化时给key_rst赋值全为1,{}中表示N个1
key_rst_pre <= {N{1'b1}};
end
else begin
key_rst <= key; //第一个时钟上升沿触发之后key的值赋给key_rst,同时key_rst的值赋给key_rst_pre
key_rst_pre <= key_rst; //非阻塞赋值。相当于经过两个时钟触发,key_rst存储的是当前时刻key的值,key_rst_pre存储的是前一个时钟的key的值
end
end
assign key_edge = key_rst_pre & (~key_rst);//脉冲边沿检测。当key检测到下降沿时,key_edge产生一个时钟周期的高电平
reg [17:0] cnt; //产生延时所用的计数器,系统时钟12MHz,要延时20ms左右时间,至少需要18位计数器
//产生20ms延时,当检测到key_edge有效是计数器清零开始计数
always @(posedge clk or negedge rst)
begin
if(!rst)
cnt <= 18'h0;
else if(key_edge)
cnt <= 18'h0;
else
cnt <= cnt + 1'h1;
end
reg [N-1:0] key_sec_pre; //延时后检测电平寄存器变量
reg [N-1:0] key_sec;
//延时后检测key,如果按键状态变低产生一个时钟的高脉冲。如果按键状态是高的话说明按键无效
always @(posedge clk or negedge rst)
begin
if (!rst)
key_sec <= {N{1'b1}};
else if (cnt==18'h3ffff)
key_sec <= key;
end
always @(posedge clk or negedge rst)
begin
if (!rst)
key_sec_pre <= {N{1'b1}};
else
key_sec_pre <= key_sec;
end
assign key_pulse = key_sec_pre & (~key_sec);
endmodule
管脚图