FPGA学习系列:26. 计算器的设计

描述

设计背景:

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

 

设计原理: 

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

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

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

 

设计架构图:

FPGA

设计代码:

顶层模块

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 :结果显示正确。


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

全部0条评论

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

×
20
完善资料,
赚取积分