2024年寒假练 - 基于STEP BaseBoard V4.0实现的两位十进制加、减、乘、除计算器
该项目使用了STEP BaseBoard V4.0,实现了计算器的设计,它的主要功能为:两位十进制加、减、乘、除。
标签
计算器
2024年寒假练
STEP BaseBoard V4.0
冷月烟
更新2024-03-29
190

项目介绍

项目功能介绍

实现一个两位十进制数加、减、乘、除运算的计算器,运算数和运算符(加、减、乘、除)由按键来控制,4×4键盘按键分配如下图所示。

4×4键盘按键分配图

基本要求:

运算数和计算结果通过8个八段数码管显示。每个运算数使用两个数码管显示,左侧显示十位数,右侧显示个位数。输入两位十进制数时,最高位先在右侧显示,然后其跳变到左侧的数码管上,低位在刚才高位占据的数码管上显示。

设计思路

主要分为六部分开发:

  1. 数码管显示部分。
  2. 按键扫描部分。
  3. 按键数据转换部分。
  4. 运算部分部分。
  5. 二进制转BCD部分。
  6. 顶层逻辑部分。



硬件框图

FgLIMTbPPt-dFC9MRQEr5-GkjQCf


软件流程图


硬件介绍

STEP BaseBoard V4.0

STEP BaseBoard V4.0是第4代小脚丫FPGA扩展底板,可以用于全系列小脚丫核心板的功能扩展,采用100mm*161.8mm的黄金比例尺寸,板子集成了存储器、温湿度传感器、接近式传感器、矩阵键盘、旋转编码器、HDMI接口、RGBLCD液晶屏、8个7位数码管、蜂鸣器模块、UART通信模块、ADC模块、DAC模块和WIFI通信模块,配合小脚丫FPGA板能够完成多种实验,是数字逻辑、微机原理、可编程逻辑语言以及EDA设计工具等课程完美的实验平台。 

FheM1anVmLBxLX0YIiIxNkkAIWf6

板载资源:

  • E2PROM芯片AT24C02
  • 温湿度传感器SHT-20
  • 加速度计
  • 环境光和接近式传感器
  • 气压计
  • 4×4矩阵键盘
  • 旋转编码器
  • 电位计
  • HDMI接口
  • RGB LCD液晶屏
  • 8位7段数码管
  • 蜂鸣器模块
  • UART通信模块CH340C
  • ADC功能模块ADC081S101
  • DAC功能模块DAC081S101
  • WIFI功能模块ESP8266-12F
  • PMOD接口

 

实现的功能及图片展示

输入第一位数


输入第二位数


加法


减法


乘法


除法


主要代码片段及说明

1.数码管显示部分

module segment_scan #
(
parameter CNT_40KHz = 300 //分频系数
)
(
input clk, //系统时钟 12MHz
input rst_n, //系统复位 低有效
input [3:0] dat_1, //SEG1 显示的数据输入
input [3:0] dat_2, //SEG2 显示的数据输入
input [3:0] dat_3, //SEG3 显示的数据输入
input [3:0] dat_4, //SEG4 显示的数据输入
input [3:0] dat_5, //SEG5 显示的数据输入
input [3:0] dat_6, //SEG6 显示的数据输入
input [3:0] dat_7, //SEG7 显示的数据输入
input [3:0] dat_8, //SEG8 显示的数据输入
input [7:0] dat_en, //数码管数据位显示使能,[MSB~LSB]=[SEG1~SEG8]
input [7:0] dot_en, //数码管小数点位显示使能,[MSB~LSB]=[SEG1~SEG8]
output reg seg_rck, //74HC595的RCK管脚
output reg seg_sck, //74HC595的SCK管脚
output reg seg_din //74HC595的SER管脚
);

//localparam CNT_40KHz = 300; //分频系数

localparam IDLE = 3'd0;
localparam MAIN = 3'd1;
localparam WRITE = 3'd2;
localparam LOW = 1'b0;
localparam HIGH = 1'b1;

//创建数码管的字库,字库数据依段码顺序有关
//这里字库数据[MSB~LSB]={G,F,E,D,C,B,A}
reg[6:0] seg [15:0];
always @(negedge rst_n) begin
seg[0] = 7'h3f; // 0
seg[1] = 7'h06; // 1
seg[2] = 7'h5b; // 2
seg[3] = 7'h4f; // 3
seg[4] = 7'h66; // 4
seg[5] = 7'h6d; // 5
seg[6] = 7'h7d; // 6
seg[7] = 7'h07; // 7
seg[8] = 7'h7f; // 8
seg[9] = 7'h6f; // 9
seg[10] = 7'h00;//7'h77; // A
seg[11] = 7'h00;//7'h7c; // b
seg[12] = 7'h00;//7'h39; // C
seg[13] = 7'h00;//7'h5e; // d
seg[14] = 7'h00;//7'h79; // E
seg[15] = 7'h00;//7'h71; // F
end

//计数器对系统时钟信号进行计数
reg [9:0] cnt = 1'b0;
always@(posedge clk or negedge rst_n) begin
if(!rst_n) cnt <= 1'b0;
else if(cnt>=(CNT_40KHz-1)) cnt <= 1'b0;
else cnt <= cnt + 1'b1;
end

//根据计数器计数的周期产生分频的脉冲信号
reg clk_40khz = 1'b0;
always@(posedge clk or negedge rst_n) begin
if(!rst_n) clk_40khz <= 1'b0;
else if(cnt<(CNT_40KHz>>1)) clk_40khz <= 1'b0;
else clk_40khz <= 1'b1;
end

//使用状态机完成数码管的扫描和74HC595时序的实现
reg [15:0] data;
reg [2:0] cnt_main;
reg [5:0] cnt_write;
reg [2:0] state = IDLE;
always@(posedge clk_40khz or negedge rst_n) begin
if(!rst_n) begin //复位状态下,各寄存器置初值
state <= IDLE;
cnt_main <= 3'd0; cnt_write <= 6'd0;
seg_din <= 1'b0; seg_sck <= LOW; seg_rck <= LOW;
end else begin
case(state)
IDLE:begin //IDLE作为第一个状态,相当于软复位
state <= MAIN;
cnt_main <= 3'd0; cnt_write <= 6'd0;
seg_din <= 1'b0; seg_sck <= LOW; seg_rck <= LOW;
end
MAIN:begin
cnt_main <= cnt_main + 1'b1;
state <= WRITE; //在配置完发给74HC595的数据同时跳转至WRITE状态,完成串行时序
case(cnt_main)
//对8位数码管逐位扫描
//data [15:8]为段选, [7:0]为位选
3'd0: data <= {{dot_en[7],seg[dat_1]},dat_en[7]?8'hfe:8'hff};
3'd1: data <= {{dot_en[6],seg[dat_2]},dat_en[6]?8'hfd:8'hff};
3'd2: data <= {{dot_en[5],seg[dat_3]},dat_en[5]?8'hfb:8'hff};
3'd3: data <= {{dot_en[4],seg[dat_4]},dat_en[4]?8'hf7:8'hff};
3'd4: data <= {{dot_en[3],seg[dat_5]},dat_en[3]?8'hef:8'hff};
3'd5: data <= {{dot_en[2],seg[dat_6]},dat_en[2]?8'hdf:8'hff};
3'd6: data <= {{dot_en[1],seg[dat_7]},dat_en[1]?8'hbf:8'hff};
3'd7: data <= {{dot_en[0],seg[dat_8]},dat_en[0]?8'h7f:8'hff};
default: data <= {8'h00,8'hff};
endcase
end
WRITE:begin
if(cnt_write >= 6'd33) cnt_write <= 1'b0;
else cnt_write <= cnt_write + 1'b1;
case(cnt_write)
//74HC595是串行转并行的芯片,3路输入可产生8路输出,而且可以级联使用
//74HC595的时序实现,参考74HC595的芯片手册
6'd0: begin seg_sck <= LOW; seg_din <= data[15]; end //SCK下降沿时SER更新数据
6'd1: begin seg_sck <= HIGH; end //SCK上升沿时SER数据稳定
6'd2: begin seg_sck <= LOW; seg_din <= data[14]; end
6'd3: begin seg_sck <= HIGH; end
6'd4: begin seg_sck <= LOW; seg_din <= data[13]; end
6'd5: begin seg_sck <= HIGH; end
6'd6: begin seg_sck <= LOW; seg_din <= data[12]; end
6'd7: begin seg_sck <= HIGH; end
6'd8: begin seg_sck <= LOW; seg_din <= data[11]; end
6'd9: begin seg_sck <= HIGH; end
6'd10: begin seg_sck <= LOW; seg_din <= data[10]; end
6'd11: begin seg_sck <= HIGH; end
6'd12: begin seg_sck <= LOW; seg_din <= data[9]; end
6'd13: begin seg_sck <= HIGH; end
6'd14: begin seg_sck <= LOW; seg_din <= data[8]; end
6'd15: begin seg_sck <= HIGH; end
6'd16: begin seg_sck <= LOW; seg_din <= data[7]; end
6'd17: begin seg_sck <= HIGH; end
6'd18: begin seg_sck <= LOW; seg_din <= data[6]; end
6'd19: begin seg_sck <= HIGH; end
6'd20: begin seg_sck <= LOW; seg_din <= data[5]; end
6'd21: begin seg_sck <= HIGH; end
6'd22: begin seg_sck <= LOW; seg_din <= data[4]; end
6'd23: begin seg_sck <= HIGH; end
6'd24: begin seg_sck <= LOW; seg_din <= data[3]; end
6'd25: begin seg_sck <= HIGH; end
6'd26: begin seg_sck <= LOW; seg_din <= data[2]; end
6'd27: begin seg_sck <= HIGH; end
6'd28: begin seg_sck <= LOW; seg_din <= data[1]; end
6'd29: begin seg_sck <= HIGH; end
6'd30: begin seg_sck <= LOW; seg_din <= data[0]; end
6'd31: begin seg_sck <= HIGH; end
6'd32: begin seg_rck <= HIGH; end //当16位数据传送完成后RCK拉高,输出生效
6'd33: begin seg_rck <= LOW; state <= MAIN; end
default: ;
endcase
end
default: state <= IDLE;
endcase
end
end

endmodule


2.按键扫描部分

module array_keyboard #
(
parameter CNT_200HZ = 60000
)
(
input clk,
input rst_n,
input [3:0] col,
output reg [3:0] row,
output reg [15:0]key_out,
output [15:0]key_pulse
);

localparam STATE0 = 2'b00;
localparam STATE1 = 2'b01;
localparam STATE2 = 2'b10;
localparam STATE3 = 2'b11;

/*
因使用4x4矩阵按键,通过扫描方法实现,所以这里使用状态机实现,共分为4种状态
在其中的某一状态时间里,对应的4个按键相当于独立按键,可按独立按键的周期采样法采样
周期采样时每隔20ms采样一次,对应这里状态机每隔20ms循环一次,每个状态对应5ms时间
对矩阵按键实现原理不明白的,请去了解矩阵按键实现原理
*/

//计数器计数分频实现5ms周期信号clk_200hz,系统时钟12MHz
reg [15:0] cnt;
reg clk_200hz;
always@(posedge clk or negedge rst_n) begin //复位时计数器cnt清零,clk_200hz信号起始电平为低电平
if(!rst_n) begin
cnt <= 16'd0;
clk_200hz <= 1'b0;
end else begin
if(cnt >= ((CNT_200HZ>>1) - 1)) begin //数字逻辑中右移1位相当于除2
cnt <= 16'd0;
clk_200hz <= ~clk_200hz; //clk_200hz信号取反
end else begin
cnt <= cnt + 1'b1;
clk_200hz <= clk_200hz;
end
end
end

reg [1:0] c_state;
//状态机根据clk_200hz信号在4个状态间循环,每个状态对矩阵按键的行接口单行有效
always@(posedge clk_200hz or negedge rst_n) begin
if(!rst_n) begin
c_state <= STATE0;
row <= 4'b1110;
end else begin
case(c_state)
//状态c_state跳转及对应状态下矩阵按键的row输出
STATE0: begin c_state <= STATE1; row <= 4'b1101; end
STATE1: begin c_state <= STATE2; row <= 4'b1011; end
STATE2: begin c_state <= STATE3; row <= 4'b0111; end
STATE3: begin c_state <= STATE0; row <= 4'b1110; end
default:begin c_state <= STATE0; row <= 4'b1110; end
endcase
end
end

reg [15:0] key,key_r;
//因为每个状态中单行有效,通过对列接口的电平状态采样得到对应4个按键的状态,依次循环
always@(negedge clk_200hz or negedge rst_n) begin
if(!rst_n) begin
key_out <= 16'hffff; key_r <= 16'hffff; key <= 16'hffff;
end else begin
case(c_state)
//采集当前状态的列数据赋值给对应的寄存器位
//对键盘采样数据进行判定,连续两次采样低电平判定为按键按下
STATE0: begin key_out[ 3: 0] <= key_r[ 3: 0]|key[ 3: 0]; key_r[ 3: 0] <= key[ 3: 0]; key[ 3: 0] <= col; end
STATE1: begin key_out[ 7: 4] <= key_r[ 7: 4]|key[ 7: 4]; key_r[ 7: 4] <= key[ 7: 4]; key[ 7: 4] <= col; end
STATE2: begin key_out[11: 8] <= key_r[11: 8]|key[11: 8]; key_r[11: 8] <= key[11: 8]; key[11: 8] <= col; end
STATE3: begin key_out[15:12] <= key_r[15:12]|key[15:12]; key_r[15:12] <= key[15:12]; key[15:12] <= col; end
default:begin key_out <= 16'hffff; key_r <= 16'hffff; key <= 16'hffff; end
endcase
end
end

reg [15:0] key_out_r;
//Register low_sw_r, lock low_sw to next clk
always @ ( posedge clk or negedge rst_n )
if (!rst_n) key_out_r <= 16'hffff;
else key_out_r <= key_out; //将前一刻的值延迟锁存

//wire [15:0] key_pulse;
//Detect the negedge of low_sw, generate pulse
assign key_pulse= key_out_r & ( ~key_out); //通过前后两个时刻的值判断

endmodule


3.按键数据转换部分

module key_decode(
input clk,
input rst_n,
input [15:0] key_pulse, //按键消抖后动作脉冲信号
output reg [7:0] decode_num,
output wire decode_pulse
);

//key_pulse transfer to seg_data
always@(posedge clk or negedge rst_n) begin
if(!rst_n) begin
decode_num <= 8'h00;
end else begin
case(key_pulse) //key_pulse脉宽等于clk_in的周期
16'h0001: decode_num <= 8'h07;
16'h0002: decode_num <= 8'h08;
16'h0004: decode_num <= 8'h09;
16'h0008: decode_num <= 8'h18;
16'h0010: decode_num <= 8'h04;
16'h0020: decode_num <= 8'h05;
16'h0040: decode_num <= 8'h06;
16'h0080: decode_num <= 8'h14;
16'h0100: decode_num <= 8'h01;
16'h0200: decode_num <= 8'h02;
16'h0400: decode_num <= 8'h03;
16'h0800: decode_num <= 8'h12;
16'h1000: decode_num <= 8'h00;
16'h2000: decode_num <= 8'h40;
16'h4000: decode_num <= 8'h20;
16'h8000: decode_num <= 8'h11;
default: decode_num <= decode_num; //无按键按下时保持
endcase
end
end

reg [1:0] decode_r;

always@(posedge clk or negedge rst_n) begin
if(!rst_n) begin
decode_r <= 2'b0;
end else begin
if(key_pulse) decode_r <= {decode_r[0], 1'b1};
else decode_r <= {decode_r[0], 1'b0};
end
end

assign decode_pulse = decode_r[1];

endmodule


4.运算部分部分

module calculate(
input clk,
input rst_n,
input [3:0]mode,
input [7:0]num1,
input [7:0]num2,
output reg [15:0]result
);

always @ (posedge clk or negedge rst_n) begin
if(!rst_n)
result <= 16'b0;
else begin
case(mode)
4'h1: result <= num1 + num2; //加法操作
4'h2: begin //减法操作
if(num1>=num2)
result <= num1 - num2;
else
result <= num2 - num1;
end
4'h4: result <= num1 * num2; //乘法操作
4'h8: result <= num1 / num2; //除法操作
default: result <= 16'b0;
endcase
end
end

endmodule


5.二进制转BCD部分

module bin_to_bcd(
input rst_n, //系统复位,低有效
input [15:0] bin_code,//需要进行BCD转码的二进制数据
output reg [19:0] bcd_code //转码后的BCD码型数据输出
);

reg [35:0] shift_reg;
always@(bin_code or rst_n)begin
shift_reg = {20'h0,bin_code};
if(!rst_n)
bcd_code = 0;
else begin
repeat(16) begin //循环16次
//BCD码各位数据作满5加3操作,
if (shift_reg[19:16] >= 5) shift_reg[19:16] = shift_reg[19:16] + 2'b11;
if (shift_reg[23:20] >= 5) shift_reg[23:20] = shift_reg[23:20] + 2'b11;
if (shift_reg[27:24] >= 5) shift_reg[27:24] = shift_reg[27:24] + 2'b11;
if (shift_reg[31:28] >= 5) shift_reg[31:28] = shift_reg[31:28] + 2'b11;
if (shift_reg[35:32] >= 5) shift_reg[35:32] = shift_reg[35:32] + 2'b11;
shift_reg = shift_reg << 1;
end
bcd_code = shift_reg[35:16];
end
end

endmodule


6.顶层逻辑部分

module top(
input sys_clk,
input rst_n,
input [3:0] col,
output [3:0] row,
output seg_rck, //74HC595的RCK管脚
output seg_sck, //74HC595的SCK管脚
output seg_din //74HC595的SER管脚
);

wire [15:0] key_out;
wire [15:0] key_pulse;
wire [7:0] decode_num;
wire decode_pulse;

reg [7:0] num1_bcd;
reg [7:0] num2_bcd;
wire [19:0] result_bcd;

wire [7:0] num1;
wire [7:0] num2;
wire [15:0] result;

reg [1:0] num1_en;
reg [1:0] num2_en;
reg [3:0] result_en;

reg [1:0] state;
reg [3:0] operator;

always@(posedge sys_clk or negedge rst_n) begin
if(!rst_n) begin
state <= 0;
num1_bcd <= 0;
num1_en <= 0;
num2_bcd <= 0;
num2_en <= 0;
result_en <= 0;
operator <= 0;
end else if(decode_pulse) begin
case(decode_num[7:4]) //key_pulse脉宽等于clk_in的周期
4'h0: begin
if(state == 2'b00) begin
num1_bcd <= {num1_bcd[3:0], decode_num[3:0]};
num1_en <= {num1_en[0], 1'b1};
end else if(state == 2'b01) begin
num2_bcd <= {num2_bcd[3:0], decode_num[3:0]};
num2_en <= {num2_en[0], 1'b1};
end
else num1_bcd <= num1_bcd;
end
4'h1: begin
if(state == 3'b00) begin
state <= 3'b01;
operator <= decode_num[3:0];
end else operator <= operator;
end
4'h2: begin
if(result_bcd[15:12]) result_en <= 4'b1111;
else if(result_bcd[11:8]) result_en <= 4'b0111;
else if(result_bcd[7:4]) result_en <= 4'b0011;
else result_en <= 4'b0001;
state <= 3'b10;
end
4'h4: begin
state <= 3'b00;
num1_bcd <= 0;
num1_en <= 0;
num2_bcd <= 0;
num2_en <= 0;
result_en <= 0;
end
default: state <= state;
endcase
end else begin
state <= state;
end
end

assign num1 = (num1_bcd[7:4]<<3) + (num1_bcd[7:4]<<1) + num1_bcd[3:0];
assign num2 = (num2_bcd[7:4]<<3) + (num2_bcd[7:4]<<1) + num2_bcd[3:0];

bin_to_bcd u_bin_to_bcd(
.rst_n(rst_n),
.bin_code(result),
.bcd_code(result_bcd)
);

calculate u_calculate(
.clk(sys_clk),
.rst_n(rst_n),
.mode(operator),
.num1(num1),
.num2(num2),
.result(result)
);

key_decode u_key_decode(
.clk(sys_clk),
.rst_n(rst_n),
.key_pulse(key_pulse),
.decode_num(decode_num),
.decode_pulse(decode_pulse)
);

segment_scan u_segment_scan(
.clk(sys_clk), //系统时钟 12MHz
.rst_n(rst_n), //系统复位 低有效
.dat_1(num1_bcd[7:4]), //SEG1 显示的数据输入
.dat_2(num1_bcd[3:0]), //SEG2 显示的数据输入
.dat_3(num2_bcd[7:4]), //SEG3 显示的数据输入
.dat_4(num2_bcd[3:0]), //SEG4 显示的数据输入
.dat_5(result_bcd[15:12]), //SEG5 显示的数据输入
.dat_6(result_bcd[11:8]), //SEG6 显示的数据输入
.dat_7(result_bcd[7:4]), //SEG7 显示的数据输入
.dat_8(result_bcd[3:0]), //SEG8 显示的数据输入
.dat_en({num1_en, num2_en, result_en}), //数码管数据位显示使能,[MSB~LSB]=[SEG1~SEG8]
.dot_en(8'b0000_0000), //数码管小数点位显示使能,[MSB~LSB]=[SEG1~SEG8]
.seg_rck(seg_rck), //74HC595的RCK管脚
.seg_sck(seg_sck), //74HC595的SCK管脚
.seg_din(seg_din) //74HC595的SER管脚
);

array_keyboard u_array_keyboard(
.clk(sys_clk),
.rst_n(rst_n),
.col(col),
.row(row),
.key_out(key_out),
.key_pulse(key_pulse)
);

endmodule


仿真波形图

1.数码管显示部分

`timescale 1ns / 100ps
module segment_scan_tb();

reg sys_clk = 0;
reg rst_n = 0;
reg [3:0] dat_1;
reg [3:0] dat_2;
reg [3:0] dat_3;
reg [3:0] dat_4;
reg [3:0] dat_5;
reg [3:0] dat_6;
reg [3:0] dat_7;
reg [3:0] dat_8;
reg [7:0] dat_en;
reg [7:0] dot_en;

initial begin
rst_n = 1'b0;
#10;
rst_n = 1'b1;
dat_1 = {$random} % 10;
dat_2 = {$random} % 10;
dat_3 = {$random} % 10;
dat_4 = {$random} % 10;
dat_5 = {$random} % 10;
dat_6 = {$random} % 10;
dat_7 = {$random} % 10;
dat_8 = {$random} % 10;
dat_en = {$random} % 256;
dot_en = {$random} % 256;
#2000;
end

always #1 sys_clk = ~sys_clk;

segment_scan #(.CNT_40KHz(2)) u_segment_scan(
.clk(sys_clk), //系统时钟 12MHz
.rst_n(rst_n), //系统复位 低有效
.dat_1(dat_1), //SEG1 显示的数据输入
.dat_2(dat_2), //SEG2 显示的数据输入
.dat_3(dat_3), //SEG3 显示的数据输入
.dat_4(dat_4), //SEG4 显示的数据输入
.dat_5(dat_5), //SEG5 显示的数据输入
.dat_6(dat_6), //SEG6 显示的数据输入
.dat_7(dat_7), //SEG7 显示的数据输入
.dat_8(dat_8), //SEG8 显示的数据输入
.dat_en(dat_en), //数码管数据位显示使能,[MSB~LSB]=[SEG1~SEG8]
.dot_en(dot_en), //数码管小数点位显示使能,[MSB~LSB]=[SEG1~SEG8]
.seg_rck(seg_rck), //74HC595的RCK管脚
.seg_sck(seg_sck), //74HC595的SCK管脚
.seg_din(seg_din) //74HC595的SER管脚
);

endmodule


2.按键扫描部分

`timescale 1ns / 100ps
//10ms
module array_keyboard_tb();
reg sys_clk;
reg rst_n;
reg [3:0] col;
wire [3:0] row;
wire [15:0] key_out;
wire [15:0] key_pulse;

initial begin
sys_clk=1'b1;
rst_n<=1'b0;
col<=4'b1110;
#10;
rst_n<=1'b1;
#50000;
col<=4'b1101;
#50000;
col<=4'b1011;
#50000;
col<=4'b0111;
#50000;
end

always #1 sys_clk = ~sys_clk;

array_keyboard #(.CNT_200HZ(60)) u_array_keyboard(
.clk(sys_clk),
.rst_n(rst_n),
.col(col),
.row(row),
.key_out(key_out),
.key_pulse(key_pulse)
);


endmodule


3.按键数据转换部分

`timescale 1ns / 100ps
module key_decode_tb();

reg sys_clk = 0;
reg rst_n = 0;
reg [15:0] key_pulse;
wire [5:0] decode_num;
wire decode_pulse;

initial begin
rst_n = 1'b0;
#10;
rst_n = 1'b1;
key_pulse = 0;
#1;
key_pulse = 16'h0001;
#2;
key_pulse = 0;
#10;
key_pulse = 16'h0002;
#2;
key_pulse = 0;
#10;
key_pulse = 16'h0004;
#2;
key_pulse = 0;
#10;
key_pulse = 16'h0008;
#2;
key_pulse = 0;
#10;
key_pulse = 16'h0010;
#2;
key_pulse = 0;
#10;
key_pulse = 16'h0020;
#2;
key_pulse = 0;
#10;
key_pulse = 16'h0040;
#2;
key_pulse = 0;
#10;
key_pulse = 16'h0080;
#2;
key_pulse = 0;
#10;
key_pulse = 16'h0100;
#2;
key_pulse = 0;
#10;
key_pulse = 16'h0200;
#2;
key_pulse = 0;
#10;
key_pulse = 16'h0400;
#2;
key_pulse = 0;
#10;
key_pulse = 16'h0800;
#2;
key_pulse = 0;
#10;
key_pulse = 16'h1000;
#2;
key_pulse = 0;
#10;
key_pulse = 16'h2000;
#2;
key_pulse = 0;
#10;
key_pulse = 16'h4000;
#2;
key_pulse = 0;
#10;
key_pulse = 16'h8000;
#2;
key_pulse = 0;
#10;

end

always #1 sys_clk = ~sys_clk;

key_decode u_key_decode(
.clk(sys_clk),
.rst_n(rst_n),
.key_pulse(key_pulse),
.decode_num(decode_num),
.decode_pulse(decode_pulse)
);

endmodule


4.运算部分部分

`timescale 1ns / 100ps
module calculate_tb();

reg sys_clk = 0;
reg rst_n = 0;
reg [1:0] operator;
reg [7:0] num1;
reg [7:0] num2;
wire [15:0] result;

initial begin
rst_n = 1'b0;
#10;
rst_n = 1'b1;
operator = 2'h0;
num1 = {$random} % 100;
num2 = {$random} % 100;
#10;
operator = 2'h1;
num1 = {$random} % 100;
num2 = {$random} % 100;
#10;
operator = 2'h2;
num1 = {$random} % 100;
num2 = {$random} % 100;
#10;
operator = 2'h3;
num1 = {$random} % 100;
num2 = {$random} % 100;
#10;
end

always #1 sys_clk = ~sys_clk;

calculate u_calculate(
.clk(sys_clk),
.rst_n(rst_n),
.mode(operator),
.num1(num1),
.num2(num2),
.result(result)
);

endmodule


5.二进制转BCD部分

`timescale 1ns / 100ps
module bcd_to_bin_tb();

reg rst_n;
reg [15:0] bin_code;
wire [19:0] bcd_code;

initial begin
rst_n = 1'b0;
#1;
rst_n = 1'b1;
bin_code = 0;
#1;
bin_code = {$random} % 65535;
#1;
bin_code = {$random} % 65535;
#1;
bin_code = {$random} % 65535;
#10;
end

bin_to_bcd u_bin_to_bcd(
.rst_n(rst_n),
.bin_code(bin_code),
.bcd_code(bcd_code)
);

endmodule


FPGA的资源利用说明

Design Summary:
Number of registers: 182 out of 4635 (4%)
PFU registers: 182 out of 4320 (4%)
PIO registers: 0 out of 315 (0%)
Number of SLICEs: 458 out of 2160 (21%)
SLICEs as Logic/ROM: 458 out of 2160 (21%)
SLICEs as RAM: 0 out of 1620 (0%)
SLICEs as Carry: 152 out of 2160 (7%)
Number of LUT4s: 910 out of 4320 (21%)
Number used as logic LUTs: 606
Number used as distributed RAM: 0
Number used as ripple logic: 304
Number used as shift registers: 0
Number of PIO sites used: 13 + 4(JTAG) out of 105 (16%)
Number of block RAMs: 0 out of 10 (0%)
Number of GSRs: 1 out of 1 (100%)
EFB used : No
JTAG used : No
Readback used : No
Oscillator used : No
Startup used : No
POR : On
Bandgap : On
Number of Power Controller: 0 out of 1 (0%)
Number of Dynamic Bank Controller (BCINRD): 0 out of 6 (0%)
Number of Dynamic Bank Controller (BCLVDSO): 0 out of 1 (0%)
Number of DCCA: 0 out of 8 (0%)
Number of DCMA: 0 out of 2 (0%)
Number of PLLs: 0 out of 2 (0%)
Number of DQSDLLs: 0 out of 2 (0%)
Number of CLKDIVC: 0 out of 4 (0%)
Number of ECLKSYNCA: 0 out of 4 (0%)
Number of ECLKBRIDGECS: 0 out of 2 (0%)
Notes:-
1. Total number of LUT4s = (Number of logic LUT4s) + 2*(Number of distributed RAMs) + 2*(Number of ripple logic)
2. Number of logic LUT4s does not include count of distributed RAM and ripple logic.
Number of clocks: 3
Net sys_clk_c: 64 loads, 64 rising, 0 falling (Driver: PIO sys_clk )
Net clk_200hz: 24 loads, 0 rising, 24 falling (Driver: u_array_keyboard/clk_200hz_38 )
Net u_segment_scanclk_40khz_68 )
Number of Clock Enables: 18
Net sys_clk_c_enable_45: 2 loads, 2 LSLICEs
Net sys_clk_c_enable_37: 4 loads, 4 LSLICEs
Net sys_clk_c_enable_14: 2 loads, 2 LSLICEs
Net sys_clk_c_enable_27: 2 loads, 2 LSLICEs
Net sys_clk_c_enable_44: 6 loads, 6 LSLICEs
Net sys_clk_c_enable_36: 2 loads, 2 LSLICEs
Net sys_clk_c_enable_31: 5 loads, 5 LSLICEs
Net u_segment_scan/state_0: 3 loads, 3 LSLICEs
Net u_segment_scan/clk_40khz_enable_26: 10 loads, 10 LSLICEs
Net u_segment_scan/clk_40khz_enable_2: 1 loads, 1 LSLICEs
Net u_segment_scan/clk_40khz_enable_3: 1 loads, 1 LSLICEs
Net u_segment_scan/clk_40khz_enable_9: 1 loads, 1 LSLICEs
Net u_segment_scan/state_1: 2 loads, 2 LSLICEs
Net u_array_keyboard/clk_200hz_N_616_enable_37: 6 loads, 6 LSLICEs
Net u_array_keyboard/clk_200hz_N_616_enable_48: 6 loads, 6 LSLICEs
Net u_array_keyboard/clk_200hz_N_616_enable_41: 6 loads, 6 LSLICEs
Net u_array_keyboard/clk_200hz_N_616_enable_45: 6 loads, 6 LSLICEs
Net u_key_decode/sys_clk_c_enable_18: 4 loads, 4 LSLICEs
Number of LSRs: 9
Net sys_clk_c_enable_45: 1 loads, 1 LSLICEs
Net n16749: 3 loads, 3 LSLICEs
Net sys_clk_c_enable_27: 1 loads, 1 LSLICEs
Net clk_200hz_N_618: 8 loads, 8 LSLICEs
Net u_calculate/n5735: 12 loads, 12 LSLICEs
Net u_segment_scan/n5758: 2 loads, 2 LSLICEs
Net u_segment_scan/n5736: 3 loads, 3 LSLICEs
Net u_segment_scan/cnt_9__N_551: 5 loads, 5 LSLICEs
Net u_array_keyboard/n5747: 1 loads, 1 LSLICEs
Number of nets driven by tri-state buffers: 0
Top 10 highest fanout non-clock nets:
Net rst_n_c: 59 loads
Net cnt_main_0: 39 loads
Net num2_0: 39 loads
Net num2_bcd_7: 35 loads
Net num2_bcd_4: 29 loads
Net num2_bcd_5: 29 loads
Net decode_num_4: 27 loads
Net num1_bcd_7: 26 loads
Net num2_bcd_6: 25 loads
Net cnt_main_1: 24 loads


遇到的主要难题及解决方法

问题:web IDE仿真太难用。

解决办法:优化语句,减少复杂内容。


问题:web IDE有时候综合出来的代码错的离谱。

解决办法:通过修改其他代码写法,观察现象,找到一个能用的。


未来的计划或建议

web IDE还需改进,优化仿真与代码综合功能。


附件下载
代码.zip
烧录固件.jed
团队介绍
评论
0 / 100
查看更多
猜你喜欢
2024年寒假练 - 基于小脚丫FPGA套件STEP BaseBoard V4.0实现两位十进制加、减、乘、除计算器该项目使用了小脚丫FPGA套件STEP BaseBoard V4.0,实现了两位十进制加、减、乘、除计算器的设计,它的主要功能为:两位十进制数加、减、乘、除运算的计算器,运算数和运算符(加、减、乘、除)由按键来控制。。
常钰豪
248
2024年寒假练 - 基于小脚丫FPGA套件STEP BaseBoard V4.0 实现两位十进制加、减、乘、除计算器该项目使用了WebIDE平台以及小脚丫FPGA套件STEP BaseBoard V4.0,实现了两位十进制加、减、乘、除计算器的设计,它的主要功能为:通过读取矩阵键盘的得到操作数和运算符,实现两位十进制加、减、乘、除计算。。
Remo
305
2024寒假练-基于STEP BaseBoard V4.0实现的两位十进制加、减、乘、除计算器该项目使用了STEP BaseBoard V4.0硬件平台、Lattice Diamond软件、Vrerilog语言,实现了两位十进制加、减、乘、除计算器的设计,它的主要功能为:通过4x4键盘来控制运算数和运算符的输入,按键运算数和计算结果通过8个八段数码管显示。每个运算数使用两个数码管显示,左侧显示十位数,右侧显示个位数。输入两位十进制数时,最高位先在右侧显示,然后其跳变到左侧的数码管上,低位在刚才高位占据的数码管上显示。能够实现非负的不超过两位的小数、整数的加减乘除运算。
风飒木萧
263
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2024 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号