差别

这里会显示出您选择的修订版和当前版本之间的差别。

到此差别页面的链接

后一修订版
前一修订版
book_excise_caculator [2020/11/01 13:58]
gongyu 创建
book_excise_caculator [2021/08/19 15:26] (当前版本)
zili
行 1: 行 1:
-### 计算器实验+## 计算器实验 
 + 
 +### 1. 实验内容 
 +本实验要求实现一个两位十进制数加减乘除运算的计算器,运算数和运算符(加、减、乘、除)由按键来控制,4×4键盘按键分配如图11-1所示。 
 +{{ :​图11-1.png |图11-1 ​ 4×4键盘按键分配图}} 
 +<WRAP centeralign>​ 
 +**图11-1 ​ 4×4键盘按键分配图** 
 +</​WRAP>​ 
 +运算数和计算结果通过8个八段数码管显示。每个运算数使用两个数码管显示,左侧显示十位数,右侧显示个位数。输入两位十进制数时,最高位先在右侧显示,然后其跳变到左侧的数码管上,低位在刚才高位占据的数码管上显示。各数码管所显示的内容对应如表 11-1所示。 
 +<WRAP centeralign>​ 
 +**表 11-1 数码管显示内容** 
 +</​WRAP>​ 
 +|运算数一|L7,L8| 
 +|运算数二|L9,​L10| 
 +|运算结果|L11,​L12,​L13,​L14| 
 + 
 +\\ 
 +\\ 
 +### 2. 实验原理 
 +本实验以前面的键盘扫描和数码管显示为基础。利用按键输入两个十进制运算数和运算符(加、减、乘、除),然后进行相应的运算。其中对除法运算只能得到整数部分。由于输入的是十进制数,因此在运算时要先将十进制数转换为二进制数。在得到结果后,再将结果转换为十进制数,显示在八位数码管上。本程序的关键在于状态机的设计,计算器要求根据不同的按键输入来决定状态迁移。 
 + 
 +\\ 
 +\\ 
 +### 3. 实验设计 
 +#### 3.1 总体框架 
 +本设计的顶层模块是calculator,包括以下子模块(图11 1):\\ 
 +1. Scan_clk模块产生键盘扫描和数码管显示所需要的扫描时钟。\\ 
 +2. Scan模块完成按键的扫描,获取用户按键。\\ 
 +3. Datain模块是程序的核心模板,完成按键和操作符及运算数的对应,完成用户要求的运算。\\ 
 +4. Data_2_disp和disp_scan模块负责运算数和运算结果的译码及显示,这个与前面键盘扫描实验一样。 
 +{{ :​图11-2.png |图11-2 计算器程序模块图}} 
 +<WRAP centeralign>​ 
 +**图11-2 计算器程序模块图** 
 +</​WRAP>​ 
 +下面主要介绍Datain模块,其它模块在前面程序中已经介绍过。 
 + 
 + 
 +#### 3.2 datain模块(datain.v) 
 +datain对键盘扫描到的按键进行处理,获得运算数和运算符,并得出结果。输入输出接口如下: 
 +<code verilog>  
 + 
 +input clk, reset;​ //​时钟和复位信号。 
 +input   ​keyout_en; ​              //​按键输入使能。  
 +input [3:​0]add_r, ​            //​按键行线输入 
 +input   ​[3:​0]add_c;​  ​       //​按键列线输入 
 +output [7:​0]dec_a;​ //​运算数一输出 
 +output [7:​0]dec_b;​ //​运算数二输出 
 +output [15:​0]dec_o; ​            //​运算结果输出 
 + 
 +</​code>​ 
 + 
 +datain模块的主状态机为State,State的状态图如图11 3所示。State有四个状态:操作数1(operand1)、操作数2(operand2)、运算符(operate_ch)、结果(equal):\\ 
 +1. operand1是系统的初始状态。在Operand1状态,系统等待用户输入。当有数字输入时,状态继续在operand1状态,等待下一个输入输入;如果输入为“加”、“减”、“乘”、“除”中的任意一个运算符,则进入operate_ch状态。\\ 
 +2. 在operate_ch状态,如果输入仍为运算符,则继续停留在operate_ch状态;如果输入为数字,则进入operand2状态,等待操作数2更多的输入;如果此时输入为“清零”,则回到operand1状态,恢复到初始状态。\\ 
 +3. 在operand2状态,如果输入为数字,则继续停留在operand2状态,并记录输入的数字;如果输入为“=”,则计算结果并进入equal状态;如果输入为“清零”,则回到operand1状态,恢复到初始状态。\\ 
 +4. 在equal状态,如果输入为“清零”,则回到operand1状态,恢复到初始状态;否则维持在原状态。 
 + 
 +{{ :​图11-3.png |图11-3 State状态机状态转移图}} 
 +<WRAP centeralign>​ 
 +**图11-3 State状态机状态转移图** 
 +</​WRAP>​ 
 + 
 +下面为详细代码分析。要控制状态机首先要识别输入的按键: 
 +<code verilog>  
 + 
 +always @(posedge clk or negedge reset) begin 
 + if(!reset) begin 
 + reg_in <= 4'​b0000;​  
 + mode <= 4'​b0000;​ 
 + end 
 + else begin 
 +     keyout_en_delay <= keyout_en; ​ //​状态机在keyout_en_delay控制下工作,keyout_en_delay将按键输入使能延迟一个时钟周期,以便在按键识别后控制状态机, 
 + if((add_r != 4'​b1111)&&​(add_c != 4'​b1111)) 
 +       //​根据输入的键盘行值和列值判断按键。 
 + case(add_r)  
 + 4'​b0100:​  
 + case(add_c)//​7,​8,​9,/​ 
 + 4'​b0100:​ reg_in <= 4'​b0111; ​ //​reg_in记录了输入的数字,​输入为7。 
 + 4'​b0011:​ reg_in <= 4'​b1000; ​ //​输入为8。 
 + 4'​b0010:​ reg_in <= 4'​b1001;​ // 输入为9。 
 + 4'​b0001:​ begin reg_in <= 4'​b0000;​ mode <= 4'​b1000;​ end //​输入为除法。mode记录了运算符,4’b1000表示除法。 
 + default:​ begin reg_in <= 4'​b0000;​ mode <= 4'​b0000;​ end 
 + endcase 
 + 4'​b0011:​ 
 + case(add_c)//​4,​5,​6,​* 
 + 4'​b0100:​ reg_in <= 4'​b0100; ​ //​输入为4。 
 + 4'​b0011:​ reg_in <= 4'​b0101; ​ //​输入为5。 
 + 4'​b0010:​ reg_in <= 4'​b0110; ​ //​输入为6。 
 + 4'​b0001:​ begin reg_in <= 4'​b0000;​ mode <= 4'​b0100;​ end 
 + //​输入为乘法。 
 + default: begin reg_in <= 4'​b0000;​ mode <= 4'​b0000;​ end 
 + endcase 
 + 4'​b0010:​ 
 + case(add_c)//​1,​2,​3,​- 
 + 4'​b0100:​ reg_in <= 4'​b0001; ​ //​输入为1。 
 + 4'​b0011:​ reg_in <= 4'​b0010; ​ //​输入为2。 
 + 4'​b0010:​ reg_in <= 4'​b0011; ​ //​输入为3。 
 + 4'​b0001:​ begin reg_in <= 4'​b0000;​ mode <= 4'​b0010;​ end  
 + //​输入为减法。 
 + default: begin reg_in <= 4'​b0000;​ mode <= 4'​b0000;​ end 
 + endcase 
 + 4'​b0001://​0、清零、=、+ 
 + case(add_c) 
 + 4'​b0100:​ reg_in <= 4'​b0000; ​   //​输入为0; 
 + 4'​b0011:​ begin reg_in <= 4'​b0000;​ clear <= 1; end//​输入为清零。 
 + 4'​b0010:​ begin reg_in <= 4'​b0000;​ calc <= 1;  end //​输入为等于。 
 + //​clear为高表示清零,calc为高表示要求输出计算结果。 
 + 4'​b0001:​ begin reg_in <= 4'​b0000;​ mode <= 4'​b0001;​end //​输入为加法。 
 + default: begin reg_in <= 4'​b0000;​ mode <= 4'​b0000;​ end 
 + endcase  
 + end 
 +end 
 +状态机跳转分析: 
 +always @ (posedge clk or negedge reset) 
 +begin  
 +if( !reset ) begin 
 + dec_a <= 8'​b0000_0000;​ 
 + dec_b <= 8'​b0000_0000;​ 
 + dec_o <= 16'​b0;​ 
 + state <= operand1; 
 + end 
 + else begin  
 + if ( clear ) begin //​如果输入的按键是清零,则回到operand1状态。 
 + dec_a <= 8'​b0000_0000;​ 
 + dec_b <= 8'​b0000_0000;​ 
 + dec_o <= 16'​b0;​ 
 + state <= operand1; 
 + end  
 + else 
 +if(keyout_en_delay) ​            //​如果有按键输入。 
 +case(state) ​ //​进入状态机控制部分。 
 + operand1:​ begin //​输入第一个运算数 
 +// 当扫描到第四列的键盘时,说明有运算符输入,则下个周期进入operate_ch状态 
 + if(add_c == 4'​b0001) 
 +state <= operate_ch; ​      
 + else 
 + begin 
 + state <= operand1; ​  
 + //​将输入数字赋值给dec_a的低四位。同时原来的低四位进位到高四位。 dec_a <= {dec_a[3:​0],​reg_in};​  
 + end 
 + end 
 + operate_ch:​ begin //​输入运算符 
 + if(add_c != 4'​b0001) begin 
 +state <= operand2; ​   //​当扫描到键盘不在第四列时,则下个周期进入operand2状态,输入第二个运算数。 
 +dec_b <= {dec_b[3:​0],​reg_in};//​记录输入的运算数。 
 +end 
 + end 
 + operand2: begin  
 + if( calc ) begin  //​如果输入的是等号,则输出计算结果。 
 + state <= equal;  
 + dec_o <= result; ​ //​result为计算结果。 
 + end 
 + else begin        //​否则记录新输入的数字。 
 + state <= operand2; 
 + dec_b <= {dec_b[3:​0],​reg_in};​ 
 + end  
 + end 
 + equal: ​ //​在equal状态维持不变。 
 + begin 
 + end 
 + default:  
 + begin state <= operand1;​ end ​             //​默认状态为operand1 
 +endcase 
 + 
 +</​code>​ 
 + 
 +#### 3.3 calculate模块(calculate.v) 
 +Calculate模块完成两位十进制整数的四则运算,此模块为datain模块的子模块,输入输出接口如下: 
 +<code verilog>​ 
 +  
 +input clk,​reset;​ //​时钟和复位。 
 +input [3:​0]mode; ​                     //​四则运算符输入。 
 +input [IN_WIDTH-1:​0]dec_a; ​           //​运算数一输入。 
 + input [IN_WIDTH-1:​0]dec_b; ​           //​运算数二输入。 
 +output [O_WIDTH-1:​0]result; ​           //​运算结果 输出。 
 +  
 +assign hex_a = dec_a[7:​4]*4'​b1010 + dec_a[3:​0];​ //​dec_a的前四位是十进制数的十位数,后四位是十进制数的个位数。将dec_a转换为二进制数 hex_a。 
 +assign hex_b = dec_b[7:​4]*4'​b1010 + dec_b[3:​0];​ 
 +  
 +always @ (posedge clk or negedge reset) begin 
 +if(!reset) 
 + temp <= 16'​b0;​ 
 + else begin 
 + case(mode) 
 + 4'​b0001:​ temp <= hex_a + hex_b;​ //​加法操作 
 + 4'​b0010:​ begin //​减法操作 
 + if(hex_a>​=hex_b) 
 + temp <= hex_a - hex_b;  
 + else 
 + temp <= hex_b - hex_a; 
 + end  
 + 4'​b0100:​ temp <= hex_a * hex_b;​ //​乘法操作 
 + 4'​b1000:​ temp <= hex_a / hex_b;​ //​除法操作 
 + default: temp <= 16'​b0;​ 
 + endcase  
 + end 
 +end 
 +//​将二进制数转换为十进制数 
 +assign result[15:​12] = temp/​1000;​ //​千位数。 
 +assign result[11:​8] = (temp%1000)/​100;​ //​百位数。 
 +assign result[7:​4] = (temp%100)/​10; ​   //​十位数。 
 +assign result[3:​0] = temp%10; ​         //​各位数。 
 + 
 +</​code>​ 
 +\\ 
 +\\ 
 +### 4. 仿真结果 
 +在此程序中的核心模块是datain,​其它模块都是复用了前面几个程序中的模块,​所以仿真时只对datain模块进行仿真,​以提高仿真效率。仿真的激励文件为test_din.v,在激励文件中产生datain模块需要的addr_r、addr_c、keyout_en等信号,分别对“加”、“减”、“乘”、“除”进行仿真,从图11 4到图11 7分别给出了“加”、“减”、“乘”、“除”的仿真结果,下面对加法运算做详细解释。 
 + 
 +由左至右观测图11-4中的光标,在最左边光标处,模拟用户按下了按键“4”;在第2个光标处,模拟用户按下了按键“3”,那么用户输入的加数为“43”,在dec_a中十位和各位分别用高四位和低四位保存,因此,dec_a为67。在第3个光标处,用户输入操作符“+”。在第4个光标处,用户按下了按键“9”;在第5个光标处,用户按下了按键“8”,因此用户输入的被加数是“98”,和加数一样,被加数由dec_b的高四位和低四位保存,因此dec_b为152。在第6个光标处,Calculate运算出结果为141。在第7个光标处用户按键“=”键,则输出结果给dec_o;同样141在dec_o中为16进制,转换成10进制则为321,结果正确。 
 + 
 +其它的运算的仿真与加法类似:图11 5的乘法为:8×20=160;图11 6的减法为76-15=61;图11 7的除法为84÷41=4。 
 +{{ :​图11-4.png |图11-4 加法运算仿真波形}} 
 +<WRAP centeralign>​ 
 +**图11-4 加法运算仿真波形** 
 +</​WRAP>​ 
 + 
 +{{ :​图11-5.png |图11-5 乘法运算仿真波形}} 
 +<WRAP centeralign>​ 
 +**图11-5 乘法运算仿真波形** 
 +</​WRAP>​ 
 + 
 +{{ :​图11-6.png |图11-6 减法仿真波形}} 
 +<WRAP centeralign>​ 
 +**图11-6 减法仿真波形** 
 +</​WRAP>​ 
 + 
 +{{ :​图11-7.png |图11-7 除法仿真波形}} 
 +<WRAP centeralign>​ 
 +**图11-7 除法仿真波形** 
 +</​WRAP>​ 
 +\\ 
 +\\ 
 +### 5. 演示程序文件说明 
 +|文件名|功能|类型、对应模块| 
 +|calculator.v|主程序|顶层文件| 
 +|datain.v|从键盘读取数据,进行计算,得到结果|...| 
 +|calculate.v|进行四则运算|...| 
 +|scan_clk.v|键盘扫描时钟|...| 
 +|scan.vv|扫描键盘|...| 
 +|data_2_disp.v|数码管译码|...| 
 +|disp_scan.v|数码管扫描|...| 
 +|test_din.v|测试程序|用于modelsim仿真,对datain.v进行仿真| 
 + 
 +\\ 
 +\\ 
 +### 6. 演示程序使用 
 +演示设备要求:核心板,扩展板 
 + 
 +演示步骤:把程序下载到开发系统上后,参照键盘分配图按下4*4键盘区的相应键,即可做整数四则运算,以及清零。按下的键值和预期的运算结果可在八个数码管上显示出来。核心板Reset按键为复位键。 
 + 
 + 
 + 
 + 
  
-#### 实验内容 
-#### 实验原理 
-#### 程序设计 
-#### 仿真结果 
-#### 演示程序文件说明 
-#### 演示程序使用