设计背景:
计算器是设计中经常用到的一个操作软件,设计和学习计算器使我们亲密的联系所学的各模块, 对我们的学习有很大的帮助和提升。希望大家来学习
设计原理:
本次的设计主要通过矩阵键盘来实现按键的加减乘除运算,通过按下有效键值来当被加数或者被除数等等,按下10 -- 13等数字来表示对应的运算符。按键键值15表示等于号。
此次的设计是通过数码管来实现显示的,通过按下对应的按键来显示到数码管上,百位十位个位等等。当按下运算算符的时候显示清0不显示东西,之后通过继续按下别的键值来显示出对应的加数和除数等等,之后通过按下对应的键值15表示等于后,然后数码管清0之后立马显示出对应的等于的数。
这样来完成我们此次的设计。
设计架构图:
设计代码:
顶层模块
0 module calc(clk,rst_n,row,col,sel,seg7); //端口列表
1 input clk; //时钟
2 input rst_n; //复位
3 input [3:0] row; //行信号
4
5 output [3:0] col; //列信号
6 output [2:0] sel; //数码管位选信号
7 output [7:0] seg7; //数码管段选信号
8
9 wire [23:0] data;
10
11 //例化数码管模,和矩阵键盘模块
12 key_borad key_borad_dut(
13 .clk(clk),
14 .rst_n(rst_n),
15 .row(row),
16 .col(col),
17 .data(data)
18 );
19 seg seg_dut(
20 .clk(clk),
21 .rst_n(rst_n),
22 .sel(sel),
23 .seg7(seg7),
24 .data_in(data)
25 );
26
27 endmodule
设计模块
0 module key_borad(clk,rst_n,row,col,data);
1 input clk; //时钟 50M
2 input rst_n; //复位
3 input [3:0] row; //输入行信号
4
5 output reg [3:0] col; //输出列信号
6 output reg [23:0] data;
7
8 //状态变量,表示
9 parameter s0 = 3'b00;
10 parameter s1 = 3'b01;
11 parameter s2 = 3'b10;
12 parameter s3 = 3'b11;
13 parameter s4 = 3'b100;
14 parameter s5 = 3'b101;
15
16 parameter T1ms = 50000; //扫描间隔
17 //parameter T1ms = 2;
18 parameter T10ms= 500_000; //按键消抖时间
19 //parameter T10ms = 20;
20
21 wire flag;
22 reg [15:0] count;
23 always @ (posedge clk or negedge rst_n)
24 if(!rst_n)
25 begin
26 count <= 16'd0;
27 end
28 else
29 begin
30 if(count < T1ms - 1 ) //计数1K的频率时间
31 count <= count + 1'b1;
32 else
33 begin
34 count <= 16'b0;
35 end
36 end
37
38 assign flag = (count == T1ms - 1) ? 1'b1 : 1'b0; //计数到了就给一个高脉冲,反之低脉冲
39
40 reg [2:0] state;
41 reg [7:0] row_col;
42 reg [18:0] cnt;
43 reg data_flag;
44 always @ (posedge clk or negedge rst_n)
45 if(!rst_n)
46 begin
47 state <= 3'b0;
48 row_col <= 8'b1111_1111;
49 data_flag <= 1'b0;
50 col <= 4'b0000;
51 cnt <= 19'b0;
52 end
53 else
54 begin
55 case (state)
56 s0: begin
57 if(row == 4'b1111) //如果没有按下
58 begin
59 data_flag <= 1'b0;
60 col <= 4'b0000;
61 end
62 else //表示按下,跳转下一个状态
63 begin
64 data_flag <= 1'b0;
65 state <= s1;
66 end
67 end
68 s1: begin
69 if(row == 4'b1111) //如果是抖动跳转0状态
70 begin
71 cnt <= 19'b0;
72 state <= s0;
73 end
74 else
75 begin
76 if(cnt < T10ms - 1) //计数相应的时间,消抖处理
77 begin
78 cnt <= cnt + 1'b1;
79 end
80 else
81 begin
82 cnt <= 19'b0;
83 state <= s2;
84 col <= 4'b0111; //消抖完表示按键有效
85 end
86 end
87 end
88 s2: begin
89 if (row != 4'b1111) //表示导通
90 begin
91 state <= s3; //导通后跳转下一个状态
92 row_col <= {row,col}; //拼接行和列信号
93 end
94 else //行信号不导通,开始进行列扫描
95 begin
96 if(flag)
97 begin
98 col <= {col[2:0],col[3]}; //1ms进行一次列扫描
99 end
100 else
101 begin
102 col <= col;
103 end
104 end
105 end
106 s3:begin
107 if(row == 4'b1111) //按键抬起
108 begin
109 state <= s0;
110 data_flag <= 1'b1; //表示一次成功的按键,输出一个高脉冲
111 end
112 else
113 begin
114 state <= s3;
115 end
116 end
117 default: state <= s0;
118 endcase
119 end
120
121 reg [3:0] key_num;
122 //键值的翻译模块的表示
123 always @ (posedge clk or negedge rst_n)
124 if(!rst_n)
125 key_num = 4'd0;
126 else
127 case ({row_col})
128 8'b0111_0111:key_num = 4'hf;
129 8'b0111_1011:key_num = 4'he;
130 8'b0111_1101:key_num = 4'hd;
131 8'b0111_1110:key_num = 4'hc;
132
133 8'b1011_0111:key_num = 4'hb;
134 8'b1011_1011:key_num = 4'ha;
135 8'b1011_1101:key_num = 4'h9;
136 8'b1011_1110:key_num = 4'h8;
137
138 8'b1101_0111:key_num = 4'h7;
139 8'b1101_1011:key_num = 4'h6;
140 8'b1101_1101:key_num = 4'h5;
141 8'b1101_1110:key_num = 4'h4;
142
143 8'b1110_0111:key_num = 4'h3;
144 8'b1110_1011:key_num = 4'h2;
145 8'b1110_1101:key_num = 4'h1;
146 8'b1110_1110:key_num = 4'h0;
147 default: ;
148 endcase
149
150
151
152 //计算模块的表示
153 reg [2:0] state_s; //状态变量
154 reg [23:0] num1,num2,data_in,data_t; //信号变量
155 reg [3:0]flag_s; //运算符
156 always @ (posedge clk or negedge rst_n)
157 begin
158 if(!rst_n)
159 begin
160 data <= 24'b0;
161 state_s <= s0;
162 num1 <= 24'b0;
163 num2 <= 24'b0;
164 data_t <= 24'b0;
165 flag_s <= 4'b0;
166 data_in <= 24'b0;
167 end
168 else
169 begin
170 case (state_s)
171 s0:begin
172 if(data_flag) //如果有一次按下
173 begin
174 if(key_num < 4'd9) //键值小于9便是有效
175 begin
176 num1 <= num1*10 + key_num; //BCD码转为2进制
177 data <= {data[19:0],key_num}; //数码管移位
178 end
179 if(key_num > 4'd9 && key_num < 4'd14) //10 -- 13 表示运算符
180 begin
181 data <= 24'b0;
182 state_s <= s1;
183 flag_s <= key_num;
184 end
185 else //否则无效信号
186 state_s <= s0;
187 end
188 end
189 s1:begin
190 if(data_flag)//如果有一次按下
191 begin
192 if(key_num <4'd9 ) //键值小于9便是有效
193 begin
194 num2 <= 10*num2 +key_num;//BCD码转为2进制
195 data <= {data[19:0],key_num};//数码管移位
196 end
197 if(key_num > 4'd9 && key_num < 4'd14)//10 -- 13 表示运算符
198 begin
199 state_s <= s1;
200 end
201 if(key_num == 15) //表示等于
202 begin
203 state_s <= s2;
204 end
205 end
206 end
207 s2:begin
208 state_s <= s3;
209 case (flag_s)
210
211 4'd10 :begin //加运算
212 data_in <= num1 + num2;
213 state_s <= s3;
214 end
215
216 4'd13 :begin //乘运算
217 data_in <= num1 * num2;
218 state_s <= s3;
219 end
220 endcase
221 end
222 s3:begin //二进制转为BCD码显示到对应的数码管上
223 data[3:0] = data_in % 10;
224 data[7:4] = data_in / 10 % 10;
225 data[11:8] = data_in / 100 % 10;
226 data[15:12] = data_in / 1000 % 10;
227 data[19:16] = data_in / 10000 % 10;
228 data[23:20] = data_in / 100000;
229 state_s <= s0;
230 data_in <= 24'b0;
231 end
232 default: state_s <= s0;
233 endcase
234 end
235 end
236
237
258 endmodule
测试模块
0 `timescale 1ns/1ps
1
2 module calc_tb();
3 reg clk;
4 reg rst_n;
5 reg [4:0] pressnum;
6 wire [3:0] row;
7
8 wire [3:0] col;
9 wire [3:0] key_num;
10
11 initial begin
12 clk = 1'b1;
13 rst_n = 1'b0;
14 pressnum = 5'd16;
15
16 #200.1
17 rst_n = 1'b1;
18 #2000
19 pressnum = 5'd16;
20
21 #1000
22 pressnum = 5'd5;
23
24 #1000
25 pressnum = 5'd16;
26
27 #1250
28 pressnum = 5'd11;
29 #1250
30 pressnum = 5'd16;
31 #1250
32 pressnum = 5'd2;
33 #1250
34 pressnum = 5'd16;
35 #1250
36 pressnum = 5'd15;
37 #1250
38 pressnum = 5'd16;
39 #2000
40 #2000
41 $stop;
42
43 end
44 always #10 clk = ~clk;
45
46 calc calc_dut(
47 .clk(clk),
48 .rst_n(rst_n),
49 .row(row),
50 .col(col),
51 .sel(sel),
52 .seg7(seg7)
53 );
54 yingjian yingjian_dut(
55 .clk(clk),
56 .rst_n(rst_n),
57 .col(col),
58 .row(row),
59 .pressnum(pressnum)
60 );
61 endmodule
仿真图:
从仿真图中可以看出,在放着中我们设置的是先按下5,再10,之后2,然后按下等于15.通过观察仿真正确,之后由于设计中我们10是表示加法,那么5 + 2 = 7 :结果显示正确。
全部0条评论
快来发表一下你的评论吧 !