用FPGA设计计算器

电子说

1.3w人已加入

描述

设计背景:

计算器是设计中经常用到的一个操作软件,设计和学习计算器使我们亲密的联系所学的各模块, 对我们的学习有很大的帮助和提升。希望大家来学习

设计原理:

本次的设计主要通过矩阵键盘来实现按键的加减乘除运算,通过按下有效键值来当被加数或者被除数等等,按下10 -- 13等数字来表示对应的运算符。按键键值15表示等于号。

此次的设计是通过数码管来实现显示的,通过按下对应的按键来显示到数码管上,百位十位个位等等。当按下运算算符的时候显示清0不显示东西,之后通过继续按下别的键值来显示出对应的加数和除数等等,之后通过按下对应的键值15表示等于后,然后数码管清0之后立马显示出对应的等于的数。

这样来完成我们此次的设计。

设计架构图:

FPGA

设计代码:

顶层模块

0module 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

27endmodule

设计模块

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   outputreg[3:0] col;  //输出列信号

6   outputreg[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 ornegedge 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 ornegedge 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 ornegedge 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 ornegedge 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

258endmodule

测试模块

0`timescale1ns/1ps

1

2module 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 initialbegin

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  );

61endmodule

仿真图:

从仿真图中可以看出,在放着中我们设置的是先按下5,再10,之后2,然后按下等于15.通过观察仿真正确,之后由于设计中我们10是表示加法,那么5 + 2 = 7 :结果显示正确。

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分