FPGA project : complex_fsm

module top (
    input           wire                sys_clk     ,
    input           wire                sys_rst_n   ,
    input           wire                one         ,
    input           wire                half        ,

    output          wire   [03:00]     led  
);

    wire                one_out_w  ;
    wire                half_out_w ;
    wire                po_cola    ;
    wire                po_money   ;
key_filter key_filter_insert(
    .sys_clk                            ( sys_clk   ) ,
    .sys_rst_n                          ( sys_rst_n ) ,
    .one                                ( one       ) ,
    .half                               ( half      ) ,

    .one_out                            ( one_out_w ) ,
    .half_out                           ( half_out_w)    
);

complex_fsm complex_fsm_insert (
    .sys_clk                            ( sys_clk   ) ,
    .sys_rst_n                          ( sys_rst_n ) ,
    .money_one                          ( one_out_w ) ,
    .money_half                         ( half_out_w) ,

    .po_cola                            ( po_cola   ) , 
    .po_money                           ( po_money  ) , 
    .led                                ( led       )        
);


endmodule

module key_filter
#(
    parameter MAX_CNT_20MS = 20'd100_0000 
)(
    input           wire    sys_clk     ,
    input           wire    sys_rst_n   ,
    input           wire    one         ,
    input           wire    half        ,

    output          reg     one_out     ,
    output          reg     half_out    
);
/*****************************************************
* 计数器的要素是什么?
* 1 开始计数的条件 什么时候开始计数
* 2 计数归零的条件 什么时候结束计数
* 3 计数寄存器的位宽
* 要点:
* 如何产生这两个条件是关键。
* ***************************************************/
    // wire define
    wire    [01:00]     key     ;

    wire                nege    ;
    wire                pose    ;
    wire                add_cnt_20ms ;
    wire                end_cnt_20ms ;

    // reg define
    reg     [19:00]     cnt_20ms ;
    reg     [01:00]     key_r1   ;
    reg     [01:00]     key_r2   ;
    reg                 add_cnt_flag ;

    // key
    assign      key = {one, half} ;
    // key_r1 
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) begin
            key_r1 <= 1'b1 ;
        end else begin
            key_r1 <= key ;
        end
    end
    // key_r2 
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) begin
            key_r2 <= 1'b1 ;
        end else begin
            key_r2 <= key_r1 ;
        end
    end

    // nege pose
    assign nege = | ( ~key_r1 &  key_r2 ) ; // 都需要按位操作
    assign pose = | (  key_r1 & ~key_r2 ) ;

    // add_cnt_flag
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) begin
            add_cnt_flag <= 1'b0 ;
        end else begin
            if(nege) begin
                add_cnt_flag <= 1'b1 ;
            end else begin
                if( pose || end_cnt_20ms ) begin
                    add_cnt_flag <= 1'b0 ;
                end else begin
                    add_cnt_flag <= add_cnt_flag ;
                end
            end 
        end
    end

    // cnt_20ms add_cnt_20ms end_cnt_20ms
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) begin
            cnt_20ms <= 20'd0 ;
        end else begin
            if(add_cnt_20ms) begin
                if(end_cnt_20ms) begin
                    cnt_20ms <= 20'd0 ;
                end else begin
                    cnt_20ms <= cnt_20ms + 20'd1 ;
                end
            end else begin
                cnt_20ms <= 20'd0 ;
            end
        end
    end
    assign add_cnt_20ms = add_cnt_flag ;
    assign end_cnt_20ms = add_cnt_20ms && cnt_20ms == ( MAX_CNT_20MS - 1'b1 ) ;

    // one_out 
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) begin
            one_out <= 1'b0 ;
        end else begin
            if(end_cnt_20ms) begin
                one_out <= ~key_r2[1] ;
            end else begin
                one_out <= 1'b0 ;
            end
        end
    end

    // half_out 
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) begin
            half_out <= 1'b0 ;
        end else begin
            if(end_cnt_20ms) begin
                half_out <= ~key_r2[0] ;
            end else begin
                half_out <= 1'b0 ;
            end
        end
    end
endmodule

// `timescale  1ns/1ns
// 
// // Author        : EmbedFire
// // Create Date   : 2019/03/15
// // Module Name   : key_filter
// // Project Name  : key_filter
// // Target Devices: Altera EP4CE10F17C8N
// // Tool Versions : Quartus 13.0
// // Description   : 按键消抖模块
// //
// // Revision      : V1.0
// // Additional Comments:
// // 
// // 实验平台: 野火_征途Pro_FPGA开发板
// // 公司    : http://www.embedfire.com
// // 论坛    : http://www.firebbs.cn
// // 淘宝    : https://fire-stm32.taobao.com
// 


// module  key_filter
// #(
//     parameter CNT_MAX = 20'd999_999 //计数器计数最大值
// )
// (
//     input   wire    sys_clk     ,   //系统时钟50Mhz
//     input   wire    sys_rst_n   ,   //全局复位
//     input   wire    key_in      ,   //按键输入信号

//     output  reg     key_flag        //key_flag为1时表示消抖后检测到按键被按下
//                                     //key_flag为0时表示没有检测到按键被按下
// );

// //********************************************************************//
// //****************** Parameter and Internal Signal *******************//
// //********************************************************************//
// //reg   define
// reg     [19:0]  cnt_20ms    ;   //计数器

// //********************************************************************//
// //***************************** Main Code ****************************//
// //********************************************************************//

// //cnt_20ms:如果时钟的上升沿检测到外部按键输入的值为低电平时,计数器开始计数
// always@(posedge sys_clk or negedge sys_rst_n)
//     if(sys_rst_n == 1'b0)
//         cnt_20ms <= 20'b0;
//     else    if(key_in == 1'b1)
//         cnt_20ms <= 20'b0;
//     else    if(cnt_20ms == CNT_MAX && key_in == 1'b0)
//         cnt_20ms <= cnt_20ms;
//     else
//         cnt_20ms <= cnt_20ms + 1'b1;

// //key_flag:当计数满20ms后产生按键有效标志位
// //且key_flag在999_999时拉高,维持一个时钟的高电平
// always@(posedge sys_clk or negedge sys_rst_n)
//     if(sys_rst_n == 1'b0)
//         key_flag <= 1'b0;
//     else    if(cnt_20ms == CNT_MAX - 1'b1)
//         key_flag <= 1'b1;
//     else
//         key_flag <= 1'b0;

// endmodule
module complex_fsm 
#(
    parameter CNT_1US =  6'd50   ,
              CNT_1K  = 10'd1000 
)(
    input           wire                sys_clk         ,
    input           wire                sys_rst_n       ,
    input           wire                money_one       ,
    input           wire                money_half      ,

    output          reg                 po_cola         , 
    output          reg                 po_money        , 
    output          reg     [03:00]     led        
);
    // define wire signal
    wire    [01:00]     money   ;
    wire                clear   ;
    // define reg  signal
    reg     [06:00]     state   ;
    reg                 ctrl    ;
    reg     [03:00]     water_led ;
    // counter
    reg     [05:00]     cnt_1us ;
    wire                add_cnt_1us ;
    wire                end_cnt_1us ;
    reg     [09:00]     cnt_1ms ;
    wire                add_cnt_1ms ;
    wire                end_cnt_1ms ;
    reg     [09:00]     cnt_1s ;
    wire                add_cnt_1s ;
    wire                end_cnt_1s ;
    reg     [03:00]     cnt_10s ;
    wire                add_cnt_10s ;
    wire                end_cnt_10s ;
    // define localparam 
    localparam          IDLE     = 7'b0000001 ,
                        HALF     = 7'b0000010 ,
                        ONE      = 7'b0000100 ,
                        ONE_HALF = 7'b0001000 ,
                        TWO      = 7'b0010000 ,
                        WATER_R  = 7'b0100000 ,
                        WATER_C  = 7'b1000000 ;
    // money
    // assign money = ( money_half ) ? 2'b01 : ( money_one ) ? 2'b10 : 2'b00 ;
	assign money = {money_one,money_half} ;
    // counter 
    // cnt_1us
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) begin
            cnt_1us <= 0 ;
        end else begin
            if(clear) begin
                cnt_1us <= 0 ;
            end else begin
                if(add_cnt_1us) begin                       // 状态机在非 IDLE 状态下开始计数
                    if(end_cnt_1us) begin                   // 状态机在 状态转换后 与 计满后,需要清零,重新计数
                        cnt_1us <= 0 ;
                    end else begin
                        cnt_1us <= cnt_1us + 1'b1 ;
                    end
                end else begin
                    cnt_1us <= 0 ;                          // 状态机在 IDLE 状态下计数值归零
                end
            end
        end
    end
    assign clear = (state != IDLE && state != WATER_R && state != WATER_C && money != 2'b00) ;
    assign add_cnt_1us = state != IDLE ;
    assign end_cnt_1us = add_cnt_1us && cnt_1us == ( CNT_1US - 1'b1 );
                                                        //|| (state == WATER_R  && end_cnt_10s) || (state == WATER_C  && end_cnt_10s) 由于进入IDLE会归零,所以这两句不用写。
    // cnt_1ms
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) begin
            cnt_1ms <= 0 ;
        end else begin
            if(clear) begin
                cnt_1ms <= 0 ;
            end else begin
                if(add_cnt_1ms) begin
                    if(end_cnt_1ms) begin
                        cnt_1ms <= 0 ;
                    end else begin
                        cnt_1ms <= cnt_1ms + 1'b1 ;
                    end
                end else begin
                    cnt_1ms <= cnt_1ms ;        // 这里明显不能再归零了,需要保持。
                end
            end
        end
    end
    assign add_cnt_1ms = end_cnt_1us ;      // 级联
    assign end_cnt_1ms = add_cnt_1ms && cnt_1ms == ( CNT_1K - 1'b1 )  ;
    // cnt_1s
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) begin
            cnt_1s <= 0 ;
        end else begin
            if(clear) begin
                cnt_1s <= 0 ;
            end else begin
                if(add_cnt_1s) begin
                    if(end_cnt_1s) begin
                        cnt_1s <= 0 ;
                    end else begin
                        cnt_1s <= cnt_1s + 1'b1 ;
                    end
                end else begin
                    cnt_1s <= cnt_1s ;
                end
            end
        end
    end
    assign add_cnt_1s = end_cnt_1ms ;
    assign end_cnt_1s = add_cnt_1s && cnt_1s == ( CNT_1K - 1'b1 ) ;
    // cnt_10s
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) begin
            cnt_10s <= 0 ;
        end else begin 
            if(clear) begin
                cnt_10s <= 0 ;
            end else begin
                if(add_cnt_10s) begin
                    if(end_cnt_10s) begin
                        cnt_10s <= 0 ;
                    end else begin
                        cnt_10s <= cnt_10s + 1'b1 ;
                    end
                end else begin
                    cnt_10s <= cnt_10s ;
                end
            end
        end
    end
    assign add_cnt_10s = end_cnt_1s ;
    assign end_cnt_10s = add_cnt_10s && cnt_10s == ( 4'd10 - 4'b1 ) ;
    // state 
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) begin
            state <= IDLE ;
        end else begin
            case ( state )
            IDLE     : begin
                if(money == 2'b01) begin
                    state <= HALF ;
                end else begin
                    if(money == 2'b10) begin
                        state <= ONE ;
                    end else begin
                        state <= IDLE ;
                    end
                end
            end
            HALF     : begin 
                if(end_cnt_10s) begin
                    state <= IDLE ;
                end else begin
                    if(money == 2'b01) begin
                        state <= ONE ;
                    end else begin
                        if(money == 2'b10) begin
                            state <= ONE_HALF ;
                        end else begin
                            state <= HALF ;
                        end
                    end
                end
            end
            ONE      : begin 
                if(end_cnt_10s) begin
                    state <= IDLE ;
                end else begin
                    if(money == 2'b01) begin
                        state <= ONE_HALF ;
                    end else begin
                        if(money == 2'b10) begin
                            state <= TWO ;
                        end else begin
                            state <= ONE ;
                        end
                    end
                end
            end
            ONE_HALF : begin 
                if(end_cnt_10s) begin
                    state <= IDLE ;
                end else begin
                    if(money == 2'b01) begin
                        state <= TWO ;
                    end else begin
                        if(money == 2'b10) begin
                            state <= WATER_R ; // 正好 2.5 元 进入右流水的状态
                        end else begin
                            state <= ONE_HALF ;
                        end
                    end
                end
            end
            TWO      : begin 
                if(end_cnt_10s) begin
                    state <= IDLE ;
                end else begin
                    if(money == 2'b01) begin
                        state <= WATER_R ;      // 正好 2.5 元 进入右流水的状态
                    end else begin
                        if(money == 2'b10) begin
                            state <= WATER_C ; 
                        end else begin
                            state <= TWO ;
                        end
                    end
                end
            end
            WATER_R  : begin 
                if(end_cnt_10s) begin
                    state <= IDLE ;
                end else begin
                    state <= WATER_R ; 
                end
            end
            WATER_C  : begin 
                if(end_cnt_10s) begin
                    state <= IDLE ;
                end else begin
                    state <= WATER_C ; 
                end
            end
            default  : state <= IDLE ;
            endcase 
        end
    end
    // ctrl
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) begin
            ctrl <= 1'b1 ;
        end else begin
            if(water_led == 4'b1110) begin
                ctrl <= 1'b0 ;
            end else begin
                if(water_led == 4'b0111) begin
                    ctrl <= 1'b1 ;
                end else begin
                    ctrl <= ctrl ;
                end
            end
        end
    end
    // water_led
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) begin
            water_led <= 4'b0111 ;
        end else begin
            case (state)
            WATER_R : begin
                if(end_cnt_1s) begin
                    water_led <= { led[0], led[03:01] } ;
                end else begin
                    water_led <= water_led ;
                end
            end    
            WATER_C : begin
                if(end_cnt_1s) begin
                    if( ctrl && end_cnt_1s ) begin // 这里需要一个使能或者控制信号 需要与上end_cnt_1s 以维持led 1110 状态 1s
                        water_led <= { led[0], led[03:01] } ;
                    end else begin
                        water_led <= { led[02:00], led[3] } ;
                    end
                end else begin
                    water_led <= water_led ;
                end
            end
                default: water_led <= 4'b0111 ; // 不用的时候 不变 节省功耗。
            endcase
        end
    end
    // led 
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) begin
            led <= 4'b1010 ;
        end else begin
            case (state)
            IDLE     : begin
                led <= 4'b1111 ;
            end     
            HALF     : begin
                led <= 4'b1110 ;
            end     
            ONE      : begin
                led <= 4'b1100 ;
            end     
            ONE_HALF : begin
                led <= 4'b1000 ;
            end     
            TWO      : begin
                led <= 4'b0000 ;
            end     
            WATER_R  : begin
                led <= water_led ;
            end     
            WATER_C  : begin
                led <= water_led ;
            end     
                default: led <= 4'b0101 ;
            endcase
        end
    end
    // po_cola 
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) begin
            po_cola <= 0 ;
        end else begin
            if( (state == ONE_HALF && money == 2'b10) || (state == TWO && money != 2'b00) ) begin
                po_cola <= 1'b1 ;
            end else begin
                po_cola <= 0 ;
            end
        end
    end
    // po_money
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) begin
            po_money <= 0 ;
        end else begin 
            if(state == TWO && money == 2'b10) begin
                po_money <= 1 ;
            end else begin
                po_money <= 0 ;
            end
        end
    end
endmodule
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值