赞
踩
可以说是最经典的题目了,数电课本上的题目,涉及到状态机的设计,出现频率非常高,这里分别采用两种方式实现:
1.状态机
2.移位寄存器
使用verilog代码,设计电路,检测序列为1001,检测到的时候输出1,没检测到的时候输出0
分析:检测四位,那么就会有五个状态。分别为 0 1 10 100 1001。显然是一个摩尔型状态机。当到达第五个状态时,输出1.对五个状态进行状态编码,IDLE = 3'b000 , s1 = 3'b001 , s2 = 3'b011 ,s3 = 3'b010, s4 = 3'b110;可以使用格雷码编码,并画出状态转移图。
至此,我们可以根据这个状态转移图去写两段式状态机了。
两段式要点:parameter 状态声明 ; 第一段 当前状态转移成下一状态 ;第二段 组合逻辑 根据输入,对当前状态进行case变换;第三段 组合逻辑 检测是否到最后一个输出状态。?:
- module moduleName1 (
- input clk,
- input rst_n,
- input seq,
- output wire detect
- );
- parameter IDLE = 3'b000 , s1 = 3'b001 , s2 = 3'b011 ,s3 = 3'b010, s4 = 3'b110;
- reg [2:0] cstate,nstate;
- always @(posedge clk or negedge rst_n) begin
- if(!rst_n)
- cstate <= IDLE;
- else
- cstate <= nstate;
- end
-
- always @(*) begin
- case (cstate)
- IDLE : nstate = seq ? s1 : IDLE;
- s1 : nstate = seq ? s1 : s2 ;
- s2 : nstate = seq ? s1 : s3 ;
- s3 : nstate = seq ? s4 : IDLE;
- s4 : nstate = seq ? s1 : IDLE;
- default: nstate = IDLE;
- endcase
- end
-
- assign detect = nstate == s4 ? 1 : 0 ;
- endmodule
用移位寄存器的方法比状态机的方法代码要轻简很多,先说一下原理:
①先定义一个4位的变量用来移位——shift = 4’b0000;
②然后每输入一位x,移位放至shift中——shift <= {shift[2:0], x};
③检测shift是否等于1001.
至于为什么移位是这样的表达,大家可以看下面的这个图。
这样代码就简单了不少,如下所示:
- module moduleName2 (
- input clk,
- input rst_n,
- input seq,
- output wire detect
- );
- reg [3:0] shift;
- always @(posedge clk or negedge rst_n) begin
- if(!rst_n)
- shift <= 4'b0000;
- else
- shift <= {shift[2:0],seq};
- end
- assign detect = shift == 4'b1001 ? 1 : 0;
- endmodule
编写一个模块,实现循环输出序列001011。
分析:这里需要循环输出序列001011,显然定义一个reg[5:0] 去存储001011,然后按照时钟一拍一拍的把他的最高位读出即可。由于这里需要循环输出,所以当读到100000的时候,需要重新写入reg的值。
- module moduleName (
- input clk,
- input rst_n,
- output reg data
- );
- reg [5:0]data_r;
- always @(posedge clk or negedge rst_n) begin
- if(!rst_n)
- data_r <= 6'b001011;
- else if (data_r == 6'b100000) // 加括号
- data_r <= 6'b001011;
- else
- data_r <= (data_r << 1 ); // 加括号
- end
- always @(posedge clk or negedge rst_n) begin
- if(!rst_n)
- data <= 1'b0;
- else
- data <= data_r[5];
- end
- endmodule
用状态机的思路也比较简单,可以设计 s0 = 0 , s1 = 00 ,s2 = 001, s3= 0010,s4 =00101,s5= 001011 这六个状态,并进行状态编码,每个状态都可以对应一个输出,而且状态机的转换与输入没有关系,case当前是s1,那么无条件跳到s2,并且可以对应data输出,s0对应输出0,s1对应输出0,s2对应输出1,s3对应0,等等。
- module moduleName2 (
- input wire clk;
- input wire rst_n;
- output reg data
- );
- reg [2:0] cstate,nstate;
- parameter s0 = 3'b000, s1 = 3'b001 , s2 = 3'b011 ,s3 = 3'b010, s4 = 3'b110, s5= 3'b111;
- always @(posedge clk or negedge rst_n) begin
- if(!rst_n)
- cstate <= s0;
- else
- cstate <= nstate;
- end
- always @(*) begin
- case (cstate)
- s0 : begin nstate = s1; data <= 1'b0;end
- s1 : begin nstate = s2; data <= 1'b0;end
- s2 : begin nstate = s3; data <= 1'b1;end
- s3 : begin nstate = s4; data <= 1'b0;end
- s4 : begin nstate = s5; data <= 1'b1;end
- s5 : begin nstate = s0; data <= 1'b1;end
- default: begin nstate = s0; data <= 1'b0;end
- endcase
- end
- endmodule
使用verilog代码,设计电路,判断输入序列能否被三整除,能的时候输出1,不能的时候输出0。
思路:首先,一个数去除以3,其余数只有0 1 2 三种状态,我们再加一个IDLE状态,对这四个状态进行编码。IDLE = 2‘b00,s0 = 2‘b01,s1 = 2‘b11,s2= 2'b10。分别对应余0,余1,余2三种状态。
这个题目是判断输入序列能不能被三整除,所以我们要推断出,输入与状态转换之间的关系。每输入一位,就相当于现在的序列左移一位,在加上输入的数。
所以,当输入为0时,序列值变成前一刻的值x的二倍 2x 。当输入序列为1时,序列值变成 2x + 1。这样我们可以推断出余数的状态转移图。
对于s0,可以看做是3x。
来一个1时,变成2*(3x)+ 1,则余1,转到s1态。
来一个0时,变成2*(3x) ,则余0,转到s0态。
对于s1,可以看做是3x+1。
来一个1时,变成2*(3x+1)+ 1,则余0,转到s0态。
来一个0时,变成2*(3x+1) ,则余2,转到s2态。
对于s2,可以看做是3x+2。
来一个1时,变成2*(3x+2)+ 1,则余2,转到s2态。
来一个0时,变成2*(3x+2) ,则余1,转到s1态。
最后判断是否为s0态,输出检测信号高电平。
- module moduleName (
- input clk,
- input rst_n,
- input data,
- output wire mod0
- );
- parameter IDLE = 2'b00,s0 = 2'b01,s1 = 2'b11,s2 = 2'b10;
- reg[1:0] cstate,nstate;
- always @(posedge clk or negedge rst_n) begin
- if(!rst_n)
- cstate <= IDLE;
- else
- cstate <= nstate;
- end
- always @(*) begin
- case (cstate)
- IDLE : nstate = data ? s1 : s0 ;
- s0 : nstate = data ? s1 : s0 ;
- s1 : nstate = data ? s0 : s2 ;
- s2 : nstate = data ? s2 : s1 ;
- default: nstate = IDLE;
- endcase
- end
- assign mod0 = (cstate == s0) ? 1 : 0;
- endmodule
使用Verilog设计电路,完成以下功能:每瓶饮料1.5元,一次只能投入一个硬币,可投入0.5与1.0两种硬币,具有找零功能。
分析:首先就要进行 状态的划分。状态数值为售卖机里面的钱,一共有IDLE,0.5,1,1.5,2五个状态。
具体描述一下:(只会找零0.5元)
- IDLE:复位状态,表示饮料机中的余额为0元
- s1:饮料机的余额为0.5元
- s2:饮料机中的余额为1元
- s3:饮料机中的余额为1.5元(输出饮料,不找零)
- s4:饮料集中的余额为2元(输出饮料,找零0.5元)
-
- 这个设计不会找零1元
这个题目的不同点在于,有两个输入信号,决定状态机的转换,所以第二段的组合逻辑,状态转换时需要先考虑第一个输入,再考虑第二个输入。才决定状态转换。
那么对于这个状态机的输入和输出来说
输入:两位input代表投入的硬币,input[1]拉高意味着投入1元,input[0]拉高意味着投入0.5 元,默认一次只能投入一枚硬币。
输出:drink代表输出饮料,coin代表输出硬币。
先判断是否有input[1],再去判断input[2].
画出状态转移图,红色代表input[1],蓝色代表input[0],
s3,s4 收到0的时候,返回IDLE。
- module moduleName (
- input clk,
- input rst_n,
- input [1:0] money,
- output wire drink,
- output wire coin
- );
- parameter IDLE = 3'b000,s1 = 3'b001,s2 =3'b010,s3 = 3'b011,s4 = 3'b100;
- reg[2:0] cstate,nstate;
- always @(posedge clk or negedge rst_n) begin
- if(!rst_n)
- cstate <= IDLE;
- else
- cstate <= nstate;
-
- end
- always @(*) begin
- case (cstate)
- IDLE : nstate = money[1] ? s2 : (money[0] ? s1 : IDLE) ;
- s1 : nstate = money[1] ? s3 : (money[0] ? s2 : s1 ) ;
- s2 : nstate = money[1] ? s4 : (money[0] ? s3 : s2 ) ;
- s3 : nstate = money[1] ? s2 : (money[0] ? s1 : IDLE) ;
- s4 : nstate = money[1] ? s2 : (money[0] ? s1 : IDLE) ;
- default: nstate = IDLE ;
- endcase
- end
- assign drink = (cstate == s3) || (cstate == s4) ;
- assign cion = (cstate == s4) ? 1 : 0 ;
- endmodule
题目描述:
设计一个自动贩售机,输入货币有两种,为0.5/1元,饮料价格是1.5/2.5元,要求进行找零,找零只会支付0.5元。
ps:
1、投入的货币会自动经过边沿检测并输出一个在时钟上升沿到1,在下降沿到0的脉冲信号
2、此题忽略出饮料后才能切换饮料的问题
注意rst为低电平复位
信号示意图:
d1 0.5 d2 1 sel 选择饮料 out1 饮料1 out2 饮料2 out3 零钱
题目分析:
与上题不同的是。多了一个选择信号,这个选择信号可以选择购买不同的饮料。
首先,我们确定状态个数。
IDLE : 贩卖机里累计0元。
s1 : 贩卖机里累计0.5元。
s2 : 贩卖机里累计1元。
s3 : 贩卖机里累计1.5元。
s4 : 贩卖机里累计2元。
s5 : 贩卖机里累计2.5元。
s6 : 贩卖机里累计3元。
第一种思路: 当贩售机内金额大于1.5时,也就是S3
及以后的状态,还应根据饮料种类做判断。如果选择的是饮料1,sel=0
,则返回S0
状态;如果选择的是饮料2,sel=1
,则根据投入的货币继续向下转移状态。即s3以后的状态,三目运算符会多一点点。
第二种思路:分别两个状态机,由sel信号一开始就决定进入哪个状态机。
第一种思路:
- module moduleName (
- input wire clk ,
- input wire rst_n ,
- input wire d1 ,
- input wire d2 ,
- input wire sel ,
-
- output reg out1,
- output reg out2,
- output reg out3
- );
- parameter IDLE = 3'b000, s0_5 = 3'b001,s1 =3'b010,s1_5 = 3'b011,s_2 = 3'b100;
- parameter s2_5 = 3'b101, s3 = 3'b110;
- reg[2:0] cstate,nstate;
- always @(posedge clk or negedge rst_n) begin
- if(!rst_n)
- cstate <= IDLE;
- else
- cstate <= nstate;
- end
- always @(*) begin
- case (cstate)
- IDLE : nstate = d1 ? s0_5 : (d2 ? s1 : IDLE) ;
- s0_5 : nstate = d1 ? s1 : (d2 ? s1_5 : s1) ;
- s1 : nstate = d1 ? s1_5 : (d2 ? s_2 : s1) ;
- s1_5 : nstate = !sel ? IDLE : d1 ? s_2 : (d2 ? s2_5 : s1_5);
- s_2 : nstate = !sel ? IDLE : d1 ? s2_5 : (d2 ? s3 : s_2);
- s2_5 : nstate = IDLE ;
- s3 : nstate = IDLE ;
- default: nstate = IDLE ;
- endcase
- end
- always@(posedge clk or negedge rst_n)begin
- if(rst_n == 1'b0)begin
- out1 <= 1'b0;
- out2 <= 1'b0;
- out3 <= 1'b0;
- end
- else begin
- if(!sel)begin
- case (nstate)
- s1_5: begin out1 <= 1'b1;out2 <= 1'b0;out3 <= 1'b0;end
- s_2: begin out1 <= 1'b1;out2 <= 1'b0;out3 <= 1'b1;end
- default:begin out1 <= 1'b0;out2 <= 1'b0;out3 <= 1'b0;end
- endcase
- end
- else begin
- case (nstate)
- s1_5: begin out1 <= 1'b0;out2 <= 1'b1;out3 <= 1'b0;end
- s_2: begin out1 <= 1'b0;out2 <= 1'b1;out3 <= 1'b1;end
- default:begin out1 <= 1'b0;out2 <= 1'b0;out3 <= 1'b0;end
- endcase
- end
- end
- end
- endmodule
第二种思路:
- module seller2(
- input wire clk ,
- input wire rst ,
- input wire d1 ,
- input wire d2 ,
- input wire sel ,
-
- output reg out1,
- output reg out2,
- output reg out3
- );
-
- parameter S0 = 'd0, S1 = 'd1, S2 = 'd2, S3 = 'd3 , S4 = 'd4, S5 = 'd5, S6 = 'd6;
- reg [2:0] current_state;
- reg [2:0] next_state;
- wire [1:0] input_state;
- assign input_state = {d1,d2};
-
- always@(posedge clk or negedge rst)begin
- if(rst == 1'b0)begin
- current_state <= S0;
- end
- else begin
- current_state <= next_state;
- end
- end
-
- always@(*)begin
- if (!sel) begin
- case(current_state)
- S0:begin
- case(input_state)
- 2'b10 :next_state = S1 ;
- 2'b01 :next_state = S2 ;
- default:next_state = next_state;
- endcase
- end
- S1:begin
- case(input_state)
- 2'b10 :next_state = S2 ;
- 2'b01 :next_state = S3 ;
- default:next_state = next_state;
- endcase
- end
- S2:begin
- case(input_state)
- 2'b10 :next_state = S3 ;
- 2'b01 :next_state = S4 ;
- default:next_state = next_state;
- endcase
- end
- default: next_state = S0;
- endcase
- end
- else begin
- case(current_state)
- S0:begin
- case(input_state)
- 2'b10 :next_state = S1 ;
- 2'b01 :next_state = S2 ;
- default:next_state = next_state;
- endcase
- end
- S1:begin
- case(input_state)
- 2'b10 :next_state = S2 ;
- 2'b01 :next_state = S3 ;
- default:next_state = next_state;
- endcase
- end
- S2:begin
- case(input_state)
- 2'b10 :next_state = S3 ;
- 2'b01 :next_state = S4 ;
- default:next_state = next_state;
- endcase
- end
- S3:begin
- case(input_state)
- 2'b10 :next_state = S4 ;
- 2'b01 :next_state = S5 ;
- default:next_state = next_state;
- endcase
- end
- S4:begin
- case(input_state)
- 2'b10 :next_state = S5 ;
- 2'b01 :next_state = S6 ;
- default:next_state = next_state;
- endcase
- end
- default: next_state = S0;
- endcase
-
-
- end
- end
-
- always@(posedge clk or negedge rst)begin
- if(rst == 1'b0)begin
- out1 <= 1'b0;
- out2 <= 1'b0;
- out3 <= 1'b0;
- end
- else begin
- if(!sel)begin
- case (next_state)
- S3: begin out1 <= 1'b1;out2 <= 1'b0;out3 <= 1'b0;end
- S4: begin out1 <= 1'b1;out2 <= 1'b0;out3 <= 1'b1;end
- default:begin out1 <= 1'b0;out2 <= 1'b0;out3 <= 1'b0;end
- endcase
- end
- else begin
- case (next_state)
- S5: begin out1 <= 1'b0;out2 <= 1'b1;out3 <= 1'b0;end
- S6: begin out1 <= 1'b0;out2 <= 1'b1;out3 <= 1'b1;end
- default:begin out1 <= 1'b0;out2 <= 1'b0;out3 <= 1'b0;end
- endcase
- end
- end
- end
-
- endmodule
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。