状态机与时钟分频
描述
题目描述:
使用状态机实现时钟分频,要求对时钟进行四分频,占空比为0.25
信号示意图:
clk为时钟
rst为低电平复位
clk_out 信号输出
Ps 本题题解是按照1000的状态转移进行的,不按照此状态进行,编译器可能报错但没有影
波形示意图:
输入描述:
clk为时钟
rst为低电平复位
输出描述:
clk_out 信号输出
解题思路
根据波形图的描述可得
本题中采用的时钟分频的状态机本质上可以视为生成"1000"序列的序列发生器;
因此我们使用传统的有限状态机的三段式写法:
①进程一:同步时序always模块,格式化描述次态寄存器迁移到现态寄存器;
cpp
always @(posedge clk or negedge rst) begin
if (!rst) current_state <= IDLE;
else current_state <= next_state;
end
②进程二:组合逻辑always模块,描述次态转移条件判断
cpp
always @(*) begin
case(current_state)
IDLE: next_state = S1;
S1: next_state = S2;
S2: next_state = S3;
S3: next_state = IDLE;
default:next_state = IDLE;
endcase
end
③进程三:同步时序always模块,格式化描述次态寄存器输出
cpp
always @(posedge clk or negedge rst) begin
if (!rst) clk_out <= 1'b0;
else begin
case (next_state)
IDLE: clk_out <= 1'b0;
S1: clk_out <= 1'b1;
S2: clk_out <= 1'b0;
S3: clk_out <= 1'b0;
default:clk_out <= 1'b0;
endcase
end
end
问题:
对于进程三,当使用如下代码时,会出现结果错误:
cpp
always @(posedge clk or negedge rst) begin
if (!rst) clk_out <= 1'b0;
else begin
case (next_state)
IDLE: clk_out <= 1'b1;
S1: clk_out <= 1'b0;
S2: clk_out <= 1'b0;
S3: clk_out <= 1'b0;
default:clk_out <= 1'b0;
endcase
end
end
而将case中的next_state换成current_state时,不会报错:
cpp
always @(posedge clk or negedge rst) begin
if (!rst) clk_out <= 1'b0;
else begin
case (current_state)
IDLE: clk_out <= 1'b1;
S1: clk_out <= 1'b0;
S2: clk_out <= 1'b0;
S3: clk_out <= 1'b0;
default:clk_out <= 1'b0;
endcase
end
end
完整代码如下:
cpp
`timescale 1ns/1ns
module huawei7(
input wire clk ,
input wire rst ,
output reg clk_out
);
//*************code***********//
reg [1:0] current_state, next_state;
//设置状态名称
parameter [1:0] IDLE = 2'b00;
parameter [1:0] S1 = 2'b01;
parameter [1:0] S2 = 2'b11;
parameter [1:0] S3 = 2'b10;
always @(posedge clk or negedge rst) begin
if (!rst) current_state <= IDLE;
else current_state <= next_state;
end
always @(*) begin
case(current_state)
IDLE: next_state = S1;
S1: next_state = S2;
S2: next_state = S3;
S3: next_state = IDLE;
default:next_state = IDLE;
endcase
end
always @(posedge clk or negedge rst) begin
if (!rst) clk_out <= 1'b0;
else begin
case (next_state)
IDLE: clk_out <= 1'b0;
S1: clk_out <= 1'b1;
S2: clk_out <= 1'b0;
S3: clk_out <= 1'b0;
default:clk_out <= 1'b0;
endcase
end
end
//*************code***********//
endmodule