1 理论
时序电路的设计就是已知命题,设计出完成该命题的电路,时钟同步状态机的设计过程大致可以分为以下几个步骤:
- 根据题目要求,构造原始的状态图或构造原始的状态表;
- 构建状态转移表,进行状态化简;
- 根据状态转移表画卡诺图求解,求出电路的状态方程、激励方程和输出方程;
- 若有未用的状态还需要判断状态是否自启动,若不能自启动需要修改状态转移表;
- 用HDL语言描述电路。
2 举例说明
设计一个序列发生器,在时钟的作用下,要求产生一个11001这样的一个序列。
2.1 状态转移图
"/“左边表示当前状态是“000”,”/"右边表示输出。
2.2 状态转移表
由此可以得到其状态转移表
2.3 卡诺图化简
Q0的次态:
Q1的次态:
Q2的次态
由此可得转移方程:
Q0* = Q1 Q2
Q1* = Q1 Q2’ + Q1’ Q2
Q2* = Q0’ Q2’
以及输出方程 Z= Q1‘
2.4 判断是否有自启动
由于是三位二进制数Q0、Q1、Q2的状态转换,故一共有8种状态,这里出现了五种状态,还有101、110、111这三种状态未使用。
根据转移方程可以知道,这三种未用状态分别对应:
101 ——> 010
110 ——> 010
111 ——> 100
由此可以看出未用状态不能自己构成一个闭合的回路,那么该电路可以自启动。
3 用Verilog HDL实现序列发生器
module div_clk(
input clk,
input rst,
output led
);
reg [25:0] cnt;
reg q0 = 0;
reg q1 = 0;
reg q2 = 0;
//分频
always @(posedge clk) begin
if(~rst)
cnt <= 26'b0;
else if (cnt == 26'd50) //原来是50_000_000,考虑仿真方便,更改为50,同理下面的25也类似
cnt <= 26'b0;
else
cnt <= cnt + 26'b1;
end
wire clk_1hz = (cnt>26'd25) ? 1'b1 : 1'b0;
//根据转移方程和状态方程进行设计
assign led = ~q1;
always @(posedge clk_1hz) begin
if (~rst) begin
q0 <= 0;
q1 <= 0;
q2 <= 0;
end
else begin
q0 <= q1 & q2;
q1 <= ~q1 & q2 | q1 & ~q2;
q2 <= ~q0 & ~q2;
end
end
endmodule
另一种方式实现分频:
`timescale 1us/1us
module clk1hz(
input clk,
input rst,
output led
);
reg [25:0] clk_1hz;
reg [25:0] cnt;
reg q0 = 0;
reg q1 = 0;
reg q2 = 0;
//always @(posedge clk) begin和end之间的代码,执行频率是50Mhz,每0.02us(20ns)执行一次
//分频
always @(posedge clk) begin
if (~rst) begin
cnt <= 0;
clk_1hz <= 0;
end
else if(cnt == 26'd250) begin //25_000_000
clk_1hz <= ~clk_1hz; //
cnt <= 0;
end
else
cnt <= cnt + 1'b1;
end
//根据转移方程和状态方程进行设计
assign led = ~q1;
always @(posedge clk_1hz) begin
if (~rst) begin
q0 <= 0;
q1 <= 0;
q2 <= 0;
end
else begin
q0 <= q1 & q2;
q1 <= ~q1 & q2 | q1 & ~q2;
q2 <= ~q0 & ~q2;
end
end
endmodule
4 仿真
`timescale 1us/1us
module test_1;
reg clk;
reg reset;
wire led;
div_clk uut(
clk,
reset,
led
);
initial begin
clk = 0;
reset = 1'b1;
#35 reset = 1'b0;
#60 reset = 1'b1;
end
always #10 clk = ~clk;
endmodule
根据仿真截图中的led的变化,可以知道已经实现了11001这一序列发生器;
根据仿真截图中q0、q1、q2的变化,可以知道一共包含五种状态的变化。