状态机学习之:利用三段式状态机来生成一个七分频器


前言

本文将通过三个部分,状态机概念,状态机模型,以及状态机设计来向大家分享一下学习思路,同时以一个七分频器作为例子来简单实战


一、状态机概念

Verilog是并行执行的,

对于一些需要顺序执行的语句则需要借助状态机
示例:

8023密码锁

状态转换图
在这里插入图片描述
状态机(State Machine)
有限状态机(Finite State Machine):在有限个状态之间按照一定的规律转换的时序电路

二、状态机模型

状态机分为两类
Mealy型和Moore型,唯一的区别在于,Moore型输出仅有当前状态决定,不由输入决定
状态寄存器由一组触发器组成,用来记忆状态机当前所处的状态的改变,状态的改变只发生在时钟的跳变沿

Mealy型状态机
在这里插入图片描述

Moore型状态机
在这里插入图片描述

三、状态机设计

状态机设计可看成四段论,通过这样方法设计出来的状态机叫做三段式状态机

状态空间定义,状态跳转 ,下个状态判断,各个状态下的动作

1.状态空间定义

二进制编码

//define state space
parameter SLEEP = 2'b00;
parameter STUDY = 2'b01;
parameter EAT 	= 2'b10;
parameter AMUSE = 2'b11;

//initial variable
reg [1:0] current_state;
reg [1:0] next_state;

独热码:每个状态机只有一个寄存器置位,译码逻辑简单.推荐!

//define state space
parameter SLEEP = 4'b1000;
parameter STUDY = 4'b0100;
parameter EAT 	= 4'b0010;
parameter AMUSE = 4'b0001;

//initial variable
reg [3:0] current_state;
reg [3:0] next_state;

2.状态跳转(时序逻辑)

//transition
always @(posedge clk or negedge rst_n)
	begin 
		if(!rst_n) //_n表示低电平有效
			current_state <= SLEEP;
		else 
			current_state <= next_state;
	end

3.下个状态判断(输入组合逻辑)

在组合逻辑中,always敏感信号表里需要包含所有case语句右边表达式中的变量以及if,else语句条件中的变量
也可以直接用*代替

 always @(current_state or input_signals)
	begin
		case(current_state)
			SLEEP:
				begin
					if(clock_alarm) next_state = STUDY;
					else next_state = SLEEP;//组合逻辑,用阻塞赋值
				end
			STUDY:
				begin 
					if (lunch_time)	next_state = EAT;
					else	next_state = STUDY; //if_else要配对以避免latch的产生
				end	
			EAT:  ...; //笔者省略了部分代码,如需要,可在评论区问我
			AMUSE: ...;
			default: ...;
		endcase
	end

latch是一个边沿触发的锁存器,如果出现
1.if_else没配对

2.case语句没表达全

这两个问题,会导致电路出现锁存器,导致产生很多毛刺,影响电路性能
锁存器只在组合逻辑下产生

4.各个状态下的动作(输出组合逻辑)

//action
wire read_book;
assign read_book = (current_state == STUDY) ? 1'b1 : 1'b0;

//另一种表达方法
always @ (current_state)
	begin 
		if(current_state == STUDY) read_book = 1;
		else read_book = 0;//阻塞赋值
	end

需要注意的是,有时候不一定是组合逻辑,后面加了一个输出寄存器之后就变成时序逻辑输出了;
好处是:

1.可以有效的滤去组合逻辑输出产生的毛刺;

2.可以有效的进行时序计算和约束;

3.另外对于总线形式的输出信号来说,容易使总线数据对齐,从而减少总线数据间的偏移,减少接受端数据采样出错的频率

在这里插入图片描述

实例:利用状态机来生成一段七分频器

module divider_7_fsm(
input 	sys_clk;
input 	sys_rst_n;

output	reg	clk_divide_7
);

//reg difine
reg [6:0]		curr_st;
reg [6:0]		next_st;

//wire difine

//parameter difine;
parameter WIDTH = 1;

//热独码
parameter s0 = 7'b0000_000;
parameter s1 = 7'b0000_001;
parameter s2 = 7'b0000_010;
parameter s3 = 7'b0000_100;
parameter s4 = 7'b0001_000;
parameter s5 = 7'b0010_000;
parameter s6 = 7'b0100_000;

always @(posedge sys_clk or negedge sys_rst_n)
	begin
		if(!sys_rst_n)  curr_st <= 7'b0;
		else next_st = curr_st;
	end
	
//FSM state logic
always @(*) //*简化一下
	begin
		case(curr_st)
			s0:
				begin next_st = s1; end //阻塞赋值
			s1 :
				begin next_st = s2; end
			s2 :
				begin next_st = s3; end
			s3 :
				begin next_st = s4; end
			s4 :
				begin next_st = s5; end
			s5	:
				begin next_st = s6; end
			s6	:
				begin next_st = s0; end
		endcase
	end

//contron divide clock offset
always @(posedge sys_clk or sys_rst_n) //这里采用的是时序逻辑的写法
	begin
		if(sys_rst_n == 1'b0) clk_divide_7 <= 1'b0;
		else if ((curr_st == s0) | (curr_st == s1) | (curr_st == s2) | (curr_st == s3)) clk_divide_7 <= 1'b0;
		else if ((curr_st == s4) | (curr_st == s5) | (curr_st == s6)) clk_divide_7 <= 1'b1;
		else;
	end	
endmodule
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值