java计算器做连续运算_「每周FPGA案例」 至简设计系列_简易计算器设计(一)...

本文为明德扬原创及录用文章,转载请注明出处!

1.1 总体设计1.1.1 概述

计算器是近代人发明的可以进行数字运算的机器。现代的电子计算器能进行数学运算的手持电子机器,拥有集成电路芯片,但结构比电脑简单得多,可以说是第一代的电子计算机,且功能也较弱,但较为方便与廉价,可广泛运用于商业交易中,是必备的办公用品之一。除显示计算结果外,还常有溢出指示、错误指示等。计算器电源采用交流转换器或电池。为了节省电能,计算器都采用CMOS工艺制作的大规模集成电路。

计算器一般由运算器、控制器、存储器、键盘、显示器、电源和一些可选外围设备及电子配件,通过人工或机器设备组成,抵挡计算器的运算器、控制器由数字逻辑电路实现简单的串行运算

计算器是最早的计算工具,例如:古代印加人利用许多颜色的绳结来计数或者记录历史,还有古希腊人的安提凯希拉装置,中国的算盘等。中国古代最早采用的一种计算工具叫筹策,又被叫做算筹。

1.1.2 设计目标

简易计算器支持简单的四则运算(支持负数),在此基础上,添加了连续运算功能。计算器面板如下:

0c070348236769726ff08700e9df8573.png

1、 计算器通过矩阵键盘模拟按键输入,并通过数码管显示。

2、 计算器有“0、1、2、3、4、5、6、7、8、9、+、-、*、/、C、=”共16个按键。

3、 计算器不支持输入负数,运算结果支持负数但不支持小数。

4、 运算数1、运算数2以及运算结果最大支持8位。其中,运算数1和运算结果的位数包括符号位“-”。

5、 运算数1和运算数2的默认值为0.

6、 计算器支持连续运算,允许在输入运算数2后按下运算符,或者得出运算结果后按下运算符。

7、 当运算结果溢出时,数码管显示8个F。

8、 当操作数1或者操作数2的长度溢出时,蜂鸣器会响。

1.1.3 系统结构框图

系统结构框图如下所示:

36d8b71ce3f4d9035653d36c117b341b.png

图一

1.1.4模块功能键盘扫描模块实现功能

1、将外来异步信号打两拍处理,将异步信号同步化。

2、实现20ms按键消抖功能。

3、实现矩阵键盘的按键检测功能,并输出有效按键信号。

工作状态选择模块实现功能

1、 根据接收的不同的按键信号,判断和决定计算器的工作状态。共有5种状态:输入运算数1(OP_1)、运算符(OPER)、输入运算数2(OP_2)、输出结果(RESULT)、结果错误(ERROR)

  • 运算数1模块实现功能

1、 当计算器处于运算数1状态下,任何连续输入的数字(不超过8位)都将存放在该模块中,作为运算数1.

2、 当运算数已经到达8位时,此时无论输入任何数字,运算数1不变。

3、 当计算器经过一次运算后(按下等号或者在运算数2状态下按下运算符),运算数去存放结果result。

  • 运算符模块实现功能

1、 保存最新按下的运算符。

  • 运算数2模块实现功能

1、 当计算器处于运算数2状态下,任何连续输入的数字(不超过8位)都将存放在该模块中,作为运算数2,默认值为0。

2、 当运算数2已经到达8(包括符号位“-”),此时无论输入任何数字,运算数2不变。

  • 运算单元模块实现功能

1、 当计算器处于运算数2状态下按下运算符或者在任何状态下按下等号时,该模块根据此时运算数1、运算数2以及运算符的值,进行运算。

2、 若运算结果溢出,或者长度大于8位(包括符号位“-”)或者除数为0时,输出8个F。

3、 最多保留运算结果整数部分的8个有效数字,不保留任何小数。

  • 显示对象选择模块实现功能

1、 该模块的作用是根据当前计算器的工作状态来选择数码管的显示内容。

  • 数码管显示模块实现功能

1、 该模块的作用是对显示对象选择模块的显示数据输出信号进行数码管显示。

  • 蜂鸣器模块实现功能

1、 该模块的作用是对各种错误输入或输出进行响铃警告。

1.1.5顶层信号

187b71c05bac9c6f5cc9db4cb5e46d4b.png


1.1.6参考代码

module  calc_project(    clk     ,    rst_n   ,    key_col ,    key_row ,    seg_sel ,    segment ,    beep        );    parameter   KEY_WID     =   4   ;    parameter   STATE_WID   =   5   ;    parameter   NUM_WID     =   27  ;    parameter   SEG_NUM     =   8   ;    parameter   SEG_WID     =   8   ;    input                       clk         ;    input                       rst_n       ;    input   [KEY_WID-1:0]       key_col     ;    output  [KEY_WID-1:0]       key_row     ;    output  [SEG_NUM-1:0]       seg_sel     ;    output  [SEG_WID-1:0]       segment     ;    output                      beep        ;    wire    [KEY_WID-1:0]       key_num     ;    wire                        key_vld     ;    wire    [KEY_WID-1:0]       key_num_out ;    wire    [KEY_WID-1:0]       key_vld_out ;    wire    [STATE_WID-1:0]     state_c     ;    wire    [NUM_WID-1:0]       op_1        ;    wire                        op_1_err    ;    wire    [KEY_WID-1:0]       oper        ;    wire    [NUM_WID-1:0]       op_2        ;    wire                        op_2_err    ;    wire    [NUM_WID-1:0]       result      ;    wire                        result_err  ;    wire                        result_neg  ;       wire    [SEG_NUM*4-1:0]     display     ;    wire                        display_vld ;    key_scan   key_scan_prj(                            .clk        (clk    )   ,                            .rst_n      (rst_n  )   ,                            .key_col    (key_col)   ,                            .key_row    (key_row)   ,                            .key_out    (key_num)   ,                            .key_vld    (key_vld)                            );    work_state  work_state_prj(                                .clk        (clk        )   ,                                .rst_n      (rst_n      )   ,                                .key_num    (key_num    )   ,                                .key_vld    (key_vld    )   ,                                .result_err (result_err )   ,                                .key_num_out(key_num_out)   ,                                .key_vld_out(key_vld_out)   ,                                .state_c    (state_c    )                                );    op_1    op_1_prj(                        .clk        (clk        )   ,                        .rst_n      (rst_n      )   ,                        .key_num    (key_num_out)   ,                        .key_vld    (key_vld_out)   ,                        .state_c    (state_c    )   ,                        .result     (result     )   ,                        .op_1       (op_1       )   ,                        .op_1_err   (op_1_err   )                    );    oper    oper_prj(                        .clk        (clk        )   ,                        .rst_n      (rst_n      )   ,                        .key_num    (key_num_out)   ,                        .key_vld    (key_vld_out)   ,                        .state_c    (state_c    )   ,                        .oper       (oper       )                    );        op_2    op_2_prj(                        .clk        (clk        )   ,                        .rst_n      (rst_n      )   ,                        .key_num    (key_num_out)   ,                        .key_vld    (key_vld_out)   ,                        .state_c    (state_c    )   ,                        .op_2       (op_2       )   ,                        .op_2_err   (op_2_err   )                    );    result  result_prj(                        .clk        (clk        )   ,                        .rst_n      (rst_n      )   ,                        .key_num    (key_num_out)   ,                        .key_vld    (key_vld_out)   ,                        .state_c    (state_c    )   ,                        .op_1       (op_1       )   ,                        .oper       (oper       )   ,                        .op_2       (op_2       )   ,                        .result     (result     )   ,                        .result_err (result_err )   ,                        .result_neg (result_neg )                    );    display_sel  display_sel_prj(                                .clk        (clk        )   ,                                .rst_n      (rst_n      )   ,                                .state_c    (state_c    )   ,                                .op_1       (op_1       )   ,                                .op_2       (op_2       )   ,                                .result_neg (result_neg )   ,                                .display    (display    )   ,                                .display_vld(display_vld)                                );    segment  segment_prj(                            .rst_n      (rst_n      )   ,                            .clk        (clk        )   ,                            .display    (display    )   ,                            .display_vld(display_vld)   ,                            .seg_sel    (seg_sel    )   ,                            .segment    (segment    )                          );    beep    beep_prj(                        .clk        (clk        )   ,                        .rst_n      (rst_n      )   ,                        .op_1_err   (op_1_err   )   ,                        .op_2_err   (op_2_err   )   ,                        .result_err (result_err )   ,                        .beep       (beep       )                    );endmodule

1.2 键盘扫描模块设计

1.2.1接口信号

ae66c540fa581c92b5ba359f035b8ea3.png


1.2.2 设计思路

在前面的案例中已经有矩阵键盘的介绍,所以这里不在过多介绍,详细介绍请看下方链接:

http://fpgabbs.com/forum.php?mod=viewthread&tid=310


1.2.3参考代码

always  @(posedge clk or negedge rst_n)begin    if(rst_n==1'b0)begin        key_col_ff0 <= 4'b1111;        key_col_ff1 <= 4'b1111;    end    else begin        key_col_ff0 <= key_col    ;        key_col_ff1 <= key_col_ff0;    endendalways @(posedge clk or negedge rst_n) begin     if (rst_n==0) begin        shake_cnt <= 0;     end    else if(add_shake_cnt) begin        if(end_shake_cnt)            shake_cnt <= 0;         else            shake_cnt <= shake_cnt+1 ;   endendassign add_shake_cnt = key_col_ff1!=4'hf;assign end_shake_cnt = add_shake_cnt  && shake_cnt == TIME_20MS-1 ;always  @(posedge clk or negedge rst_n)begin    if(rst_n==1'b0)begin        state_c <= CHK_COL;    end    else begin        state_c <= state_n;    endendalways  @(*)begin    case(state_c)        CHK_COL: begin                     if(col2row_start )begin                         state_n = CHK_ROW;                     end                     else begin                         state_n = CHK_COL;                     end                 end        CHK_ROW: begin                     if(row2del_start)begin                         state_n = DELAY;                     end                     else begin                         state_n = CHK_ROW;                     end                 end        DELAY :  begin                     if(del2wait_start)begin                         state_n = WAIT_END;                     end                     else begin                         state_n = DELAY;                     end                 end        WAIT_END: begin                     if(wait2col_start)begin                         state_n = CHK_COL;                     end                     else begin                         state_n = WAIT_END;                     end                  end       default: state_n = CHK_COL;    endcaseendassign col2row_start = state_c==CHK_COL  && end_shake_cnt;assign row2del_start = state_c==CHK_ROW  && row_index==3 && end_row_cnt;assign del2wait_start= state_c==DELAY    && end_row_cnt;assign wait2col_start= state_c==WAIT_END && key_col_ff1==4'hf;always  @(posedge clk or negedge rst_n)begin    if(rst_n==1'b0)begin        key_row <= 4'b0;    end    else if(state_c==CHK_ROW)begin        key_row <= ~(1'b1 << row_index);    end    else begin        key_row <= 4'b0;    endendalways @(posedge clk or negedge rst_n) begin     if (rst_n==0) begin        row_index <= 0;     end    else if(add_row_index) begin        if(end_row_index)            row_index <= 0;         else            row_index <= row_index+1 ;   end   else if(state_c!=CHK_ROW)begin       row_index <= 0;   endendassign add_row_index = state_c==CHK_ROW && end_row_cnt;assign end_row_index = add_row_index  && row_index == 4-1 ;always @(posedge clk or negedge rst_n) begin     if (rst_n==0) begin        row_cnt <= 0;     end    else if(add_row_cnt) begin        if(end_row_cnt)            row_cnt <= 0;         else            row_cnt <= row_cnt+1 ;   endendassign add_row_cnt = state_c==CHK_ROW || state_c==DELAY;assign end_row_cnt = add_row_cnt  && row_cnt == 16-1 ;always  @(posedge clk or negedge rst_n)begin    if(rst_n==1'b0)begin        key_col_get <= 0;    end    else if(state_c==CHK_COL && end_shake_cnt ) begin        if(key_col_ff1==4'b1110)            key_col_get <= 0;        else if(key_col_ff1==4'b1101)            key_col_get <= 1;        else if(key_col_ff1==4'b1011)            key_col_get <= 2;        else             key_col_get <= 3;    endendalways  @(posedge clk or negedge rst_n)begin    if(rst_n==1'b0)begin        key_out <= 0;    end    else if(state_c==CHK_ROW && end_row_cnt)begin        key_out <= {row_index,key_col_get};    end    else begin        key_out <= 0;    endendalways  @(posedge clk or negedge rst_n)begin    if(rst_n==1'b0)begin        key_vld <= 1'b0;    end    else if(state_c==CHK_ROW && end_row_cnt && key_col_ff1[key_col_get]==1'b0)begin        key_vld <= 1'b1;    end    else begin        key_vld <= 1'b0;    endend

1.3 工作状态选择模块设计

1.3.1接口信号

2fa890f282bb65de39f34f047dca5c52.png


1.3.2设计思路

该模块的主要功能是根据按下的按键进行不同来判断和决定计算器的工作状态。一条等式可以写成:运算数1+操作符+运算数2+等号+结果的形式。考虑到结果错误的情况,我将本模块的状态划分为5个,分别是:输入运算数1(OP_1)、运算符(OPER)、输入运算数2(OP_2)、输出结果(RESULT)、结果错误(ERROR)。

下图为本模块的状态跳转图:

3d3e65a97aa51cfe2fb8f433c1d9e720.png

复位后,状态机进入OP_1状态,即初始状态为OP_1;

在OP_1状态下:

A. 按下等号,跳到RESULT状态;

B. 按下运算符,跳到OPER状态;

在OPER状态下:

A. 按下数字,跳到OP_2状态;

B. 按下等号,跳到RESULT状态;

在OP_2状态下:

A. 按下等号,跳到RESULT状态;

B. 按下运算符,跳到OPER状态;

在RESULT状态下:

A. 按下数字,跳到OP_1状态;

B. 按下运算符,跳到OPER状态;

C. 按下等号,停留在RESULT状态;

在ERROR状态下:

A. 按下数字,跳到OP_1状态;

B. 按下其他按键,停留在ERROR状态;

无论当前处于什么状态,只要检测到运算结果错误指示信号有效,即可跳转到ERROR状态。

1.3.3参考代码

使用GVIM,在命令模式下输入如下内容,即可生成本模块所需要的状态机代码。

d5d50f137fd4a66f3f410dfc91b97588.png

使用明德扬的状态机模板,可以很快速的写出此模块代码。

always  @(*)begin    case(key_num)        4'd0   :key_num_chg = 4'd7   ;        4'd1   :key_num_chg = 4'd8   ;        4'd2   :key_num_chg = 4'd9   ;        4'd3   :key_num_chg = 4'd10  ;        4'd7   :key_num_chg = 4'd11  ;        4'd8   :key_num_chg = 4'd1   ;        4'd9   :key_num_chg = 4'd2   ;        4'd10  :key_num_chg = 4'd3   ;        4'd11  :key_num_chg = 4'd14  ;        4'd12  :key_num_chg = 4'd0   ;        4'd13  :key_num_chg = 4'd12  ;        4'd14  :key_num_chg = 4'd13  ;        default:key_num_chg = key_num;    endcaseendassign  key_num_en = (key_num_chg==0 || key_num_chg==1 || key_num_chg==2 || key_num_chg==3 || key_num_chg==4 || key_num_chg==5 || key_num_chg==6 || key_num_chg==7 || key_num_chg==8 || key_num_chg==9) && key_vld==1;assign  key_op_en = (key_num_chg==10 || key_num_chg==11 || key_num_chg==12 || key_num_chg==13) && key_vld==1;assign  key_cal_en = key_num_chg==15 && key_vld==1; assign  key_back_en = key_num_chg==14 && key_vld==1;always @(posedge clk or negedge rst_n) begin     if (rst_n==0) begin        state_c <= OP_1 ;    end    else begin        state_c <= state_n;   endendalways @(*) begin    if(result_err)begin       state_n = ERROR;   end    else begin       case(state_c)          OP_1 :begin            if(op_12oper_start)                 state_n = OPER ;            else if(op_12result_start)                 state_n = RESULT ;            else                 state_n = state_c ;        end        OPER :begin            if(oper2op_2_start)                 state_n = OP_2 ;            else if(oper2result_start)                 state_n = RESULT ;            else                 state_n = state_c ;        end        OP_2 :begin            if(op_22oper_start)                state_n = OPER ;            else if(op_22result_start)                 state_n = RESULT ;            else                 state_n = state_c ;        end        RESULT :begin            if(result2op_1_start)                 state_n = OP_1 ;            else if(result2oper_start)                 state_n = OPER ;            else                 state_n = state_c ;        end        ERROR :begin            if(error2op_1_start)                 state_n = OP_1 ;            else                 state_n = state_c ;        end        default : state_n = OP_1 ;    endcaseendendassign op_12oper_start   = state_c==OP_1   && key_op_en ;assign op_12result_start = state_c==OP_1   && key_cal_en;assign oper2op_2_start   = state_c==OPER   && key_num_en;assign oper2result_start = state_c==OPER   && key_cal_en;assign op_22oper_start   = state_c==OP_2   && key_op_en ;assign op_22result_start = state_c==OP_2   && key_cal_en;assign result2op_1_start = state_c==RESULT && key_num_en;assign result2oper_start = state_c==RESULT && key_op_en ;assign error2op_1_start  = state_c==ERROR  && key_num_en;always  @(posedge clk or negedge rst_n)begin    if(rst_n==1'b0)begin        key_num_out <= 0;    end    else begin        key_num_out <= key_num_chg;    endendalways  @(posedge clk or negedge rst_n)begin    if(rst_n==1'b0)begin        key_vld_out <= 0;    end    else begin        key_vld_out <= key_vld;    endend

1.4 运算数1模块设计

1.4.1接口信号

b0d2db03337b89385105fd8fff102678.png

1.4.2设计思路

该模块主要的作用是根据当前状态和输入的按键,来决定运算数1要输出的结果。由于本工程需要实现连续运算的功能,所以在这个模块中要区分是否已经得出了运算结果。

下面是计算完成指示信号flag_calc的设计思路:

1、 该信号为高时,表示完成一次计算过程得到了结果。初始状态为低电平;

2、 当输入操作数2后又按下了等号或者其他操作符的时候,变为高电平,所以变高的条件为(state_c_ff==OP_2 && state_c==OPER) || state_c==RESULT;

3、 当处在操作数1状态时,为低电平,所以变低的条件为state_c==OP_1。其他情况保持不变。

下面是运算数1输出信号op_1的设计思路:

1、 该信号表示运算数1要输出的值。初始状态为0;

2、 在结果错误状态的时候,给一个不超过范围的任意值,此代码中给的10;

3、 在得到计算结果或者计算结果错误的时候,输入数字,输出为按下按键的对应值(key_num_out);

4、 在输入操作数1之后,按下退格键,op_1输出的值除以10进行取整;

5、 在输入操作数1状态下通过键盘输入数字,需要判断是否超过显示范围,如果没有超过的话就需要将当前op_1的值乘以10,然后加上按下的数字的值,进行输出;

6、 当计算完成时,即flag_calc==1,操作数1输出计算的结果result;

7、 其他时候操作数1保持不变。

下面是运算数1溢出信号op_1_err的设计思路:

1、 初始状态为0,表示没有溢出。

2、 当一直处于操作数1状态,按下键盘输入数字之后,操作数1的值溢出了,则将运算数1溢出信号拉高。

3、 其他时刻保持为低电平。

assign  key_num_en = (key_num==0 || key_num==1 || key_num==2 || key_num==3 || key_num==4 || key_num==5 || key_num==6 || key_num==7 || key_num==8 || key_num==9) && key_vld==1;assign  key_op_en = (key_num==10 || key_num==11 || key_num==12 || key_num==13) && key_vld==1;assign  key_cal_en = key_num==15 && key_vld==1; assign  key_back_en = key_num==14 && key_vld==1;always  @(posedge clk or negedge rst_n)begin    if(rst_n==1'b0)begin        state_c_ff <= 0;    end    else begin        state_c_ff <= state_c;    endendalways  @(posedge clk or negedge rst_n)begin    if(rst_n==1'b0)begin        op_2 <= 0;    end    else if(state_c==OPER)begin        op_2 <= 0;    end    else if(state_c_ff==OPER && state_c==OP_2)begin        op_2 <= key_num;    end    else if(state_c==OP_2 && key_back_en==1)begin        op_2 <= op_2 / 10;    end    else if(state_c==OP_2 && key_num_en==1)begin        op_2 <= (op_2>9999999) ? op_2 : (op_2*10+key_num);    end    else begin        op_2 <= op_2;    endendalways  @(posedge clk or negedge rst_n)begin    if(rst_n==1'b0)begin        op_2_err <= 0;    end    else if(state_c==OP_2 && key_num_en==1 && op_2>9999999)begin        op_2_err <= 1'b1;    end    else begin        op_2_err <= 1'b0;    endendendmodule

1.4.3参考代码1.5 运算符模块设计

1.5.1接口信号

f41062477150152f9b99b56aa0902567.png


1.5.2设计思路

本模块的设计思路比较简单,只需要判断哪些按键是运算符,然后在这些运算符被按下的时候,将他们对应的值输出就可以了。

下面是运算符指示信号设计思路:

1、 当“加”“减”“乘”“除”四个按键的任意一个被按下之后,该信号置为高电平;

2、 当“加”“减”“乘”“除”四个按键没有一个被按下的时候,该信号置为低电平。

下面是运算符输出信号oper设计思路:

初始状态,该信号输出0;

1、 当处于操作数1状态时,输出0;

2、 当“加”“减”“乘”“除”任意按键被按下之后,输出该按键对应的值;

3、 其他时候保持不变;

1.5.3参考代码

assign  key_op_en = (key_num==10 || key_num==11 || key_num==12 || key_num==13) && key_vld==1;always  @(posedge clk or negedge rst_n)begin    if(rst_n==1'b0)begin        oper <= 0;    end    else if(state_c==OP_1)begin        oper <= 0;    end    else if(key_op_en==1)begin        oper <= key_num;    end    else begin        oper <= oper;    endend

1.6 运算数2模块设计

1.6.1接口信号

信号 接口方向定义clk输入系统时钟rst_n输入低电平复位信号Key_num_out输入计算器按下位置输出信号,key_vld_out有效时,该信号有效。Key_vld_out输入计算器按键按下有效指示信号,高电平有效。State_c输入计算器工作状态指示信号Op_2输出运算数2输出信号Op_2_err输出运算数2溢出信号


1.6.2设计思路

该模块主要的作用是根据当前状态和输入的按键,来决定运算数2要输出的结果。

下面是运算数2输出信号op_2的设计思路:

1、 该信号表示运算数2要输出的值。初始状态为0;

2、 在运算符状态下,此时数码管不显示运算数2的值,让它输出0;

3、 输入运算符之后,之后再输入的就是运算数2的值,此时运算数2就等于按下按键所对应的数值。

4、 在输入运算数2之后,按下退格键,运算数2的值除以10进行取整;

5、 在输入运算数2状态下通过键盘输入数字,需要判断是否超过显示范围,如果没有超过的话就需要将当前运算数2的值乘以10,然后加上按下的数字的值,进行输出;

6、 其他时候运算数2保持不变。

下面是运算数2溢出信号op_2_err的设计思路:

1、 初始状态为0,表示没有溢出。

2、 当一直处于运算数2状态,按下键盘输入数字之后,运算数2的值溢出了,则将运算数2溢出信号拉高。

3、 其他时刻保持为低电平。

1.6.3参考代码

assign  key_num_en = (key_num==0 || key_num==1 || key_num==2 || key_num==3 || key_num==4 || key_num==5 || key_num==6 || key_num==7 || key_num==8 || key_num==9) && key_vld==1;assign  key_op_en = (key_num==10 || key_num==11 || key_num==12 || key_num==13) && key_vld==1;assign  key_cal_en = key_num==15 && key_vld==1; assign  key_back_en = key_num==14 && key_vld==1;always  @(posedge clk or negedge rst_n)begin    if(rst_n==1'b0)begin        state_c_ff <= 0;    end    else begin        state_c_ff <= state_c;    endendalways  @(posedge clk or negedge rst_n)begin    if(rst_n==1'b0)begin        flag_calc <= 0;    end    else if(state_c==OP_1)begin        flag_calc <= 1'b0;    end    else if(state_c_ff==OP_2 && state_c==OPER || state_c==RESULT)begin        flag_calc <= 1'b1;    end    else begin        flag_calc <= flag_calc;    endendalways  @(posedge clk or negedge rst_n)begin    if(rst_n==1'b0)begin        op_1 <= 0;    end    else if(state_c==ERROR)begin        op_1 <= 10;    end    else if((state_c_ff==RESULT || state_c_ff==ERROR) && state_c==OP_1)begin        op_1 <= key_num;    end    else if(state_c==OP_1 && key_back_en==1)begin        op_1 <= op_1 / 10;    end    else if(state_c==OP_1 && key_num_en==1)begin        op_1 <= (op_1>9999999) ? op_1 : (op_1*10+key_num);    end    else if(flag_calc==1)begin        op_1 <= result;    end    else begin        op_1 <= op_1;    endendalways  @(posedge clk or negedge rst_n)begin    if(rst_n==1'b0)begin        op_1_err <= 0;    end    else if(state_c==OP_1  && key_num_en==1 && op_1>9999999)begin        op_1_err <= 1'b1;    end    else begin        op_1_err <= 1'b0;    endend

由于篇幅限制,本文分为(一)(二)两篇;请接着学习(二)。

本案例提供教学视频和工程源代码,需要的同学请到明德扬论坛进行学习。

6c580f80ab0e0331c92938c4f1d2a089.png
2d30959884deadd444732112ca10c658.png
9f5006925630710c3723e4f3efdbc123.png
ee9ca50525d5626924f0ee385a4d7b14.png
986aa984cc9fccfac333c33444ad833c.png

感兴趣的朋友也可以访问明德扬论坛(http://www.FPGAbbs.cn/)进行FPGA相关工程设计学习,也可以看一下我们往期的文章:

《基于FPGA的密码锁设计》

《波形相位频率可调DDS信号发生器》

《基于FPGA的曼彻斯特编码解码设计》

《基于FPGA的出租车计费系统》

《数电基础与Verilog设计》

《基于FPGA的频率、电压测量》

《基于FPGA的汉明码编码解码设计》

《关于锁存器问题的讨论》

《阻塞赋值与非阻塞赋值》

《参数例化时自动计算位宽的解决办法》

明德扬是一家专注于FPGA领域的专业性公司,公司主要业务包括开发板、教育培训、项目承接、人才服务等多个方向。点拨开发板——学习FPGA的入门之选。
MP801开发板——千兆网、ADDA、大容量SDRAM等,学习和项目需求一步到位。网络培训班——不管时间和空间,明德扬随时在你身边,助你快速学习FPGA。周末培训班——明天的你会感激现在的努力进取,升职加薪明德扬来助你。就业培训班——七大企业级项目实训,获得丰富的项目经验,高薪就业。专题课程——高手修炼课:提升设计能力;实用调试技巧课:提升定位和解决问题能力;FIFO架构设计课:助你快速成为架构设计师;时序约束、数字信号处理、PCIE、综合项目实践课等你来选。项目承接——承接企业FPGA研发项目。人才服务——提供人才推荐、人才代培、人才派遣等服务。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值