Moore和mealy序集(并行输入的例子,三段式实现)

2023-11-10 22:10

本文主要是介绍Moore和mealy序集(并行输入的例子,三段式实现),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

之前的那个讲解配的是一个八位串行输入,总感觉怪怪的,这次我们看一个并行输入的例子。

检测一个不定长度的串中01011字串的个数并在一个数码管上显示。
我们有一个控制输入的按键开关,还有一个异步清零&状态归零的复位键。

分析

一位数码管最大显示数也就是0Fh,相当于十六进制的15,所以我们需要一个四位数的计数器。
将计数部分拿出来作为一个单独的模块,将四位数使用数码管显示的模块也单独拿出来当然这里的数码管显示没有之前那么复杂。

信号还需要一个除颤模块(点击查看之前的讲解),我也尝试过没有除颤,状态会发生跳动,确实是不稳定。(除颤还需要一个1KHZ的分频子模块)

主模块只需要将这些模块串起来,然后调整中间变量即可。

另外我们这个例子是不可覆盖的,如果是101这样的序列我们还需要考虑一下是否是覆盖的
(10101算几个?)

所以主要的部分还是计数的状态机。

这里先使用Moore来进行。(主模块还添加一个led灯判断状态正确与否)

Moore实现

之前说了,上一篇讲状态机的博客采用的是单个状态变量,其实我们也可以用两个变量来实现,即现态和次态分开,但是在输入的过程中因为我们的状态受输入的控制,所以现态是比输入晚一拍的,所以我们不需要两个状态即可实现。

白嫖上一篇博客的状态转换:
在这里插入图片描述
首先我们还是采用三段式来描述:

  1. 处理输入的模块
  2. 每次读入一个数据,我们进行一次状态转化,记住只有一次
  3. 如果状态正确,我们就将个数加一

我们也说过正经的状态机都是一个时序部分(状态转换),两个组合(输入输出),但是我们这老不当人的,因为是拨码开关的输入,所以我们还是需要将拨码开关信号作为时钟信号来进行处理。

题外话

我们是可以将任意信号作为时钟端进行处理,但是如果是像这样的将输入控制使能端作为always块唯一的posedge,那么就会显示一个报错:

[fil[Place 30-574] Poor placement for routing between an IO pin and BUFG. If this sub optimal condition is acceptable for this design, you may use the CLOCK_DEDICATED_ROUTE constraint in the .xdc file to demote this message to a WARNING. However, the use of this override is highly discouraged. These examples can be used directly in the .xdc file to override this clock rule.
< set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets set_i_IBUF] >

set_i_IBUF_inst (IBUF.O) is locked to IOB_X1Y34and set_i_IBUF_BUFG_inst (BUFG.I) is provisionally placed by clockplacer on BUFGCTRL_X0Y0

每一个人的报错可能不一样,但是内容相差不大,原因就是因为将信号作为了时钟信号,所以我们需要在约束文件中添加尖括号里面的内容:
set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets set_i_IBUF]
在这里插入图片描述

上代码:(计数部分)
`timescale 1ns / 1ps
module count(input clk_i,				//时钟信号input rst_i,				//重置使能,高有效input set_i,				//输入使能input data_i,output [3:0]number,			//输出的个数output [2:0]state_o         //led灯,判断一下状态转换);reg in = 1'b1;              //读入的数据,初始化为1防止1011reg if_in1  = 1'b0;         //输入端使能reg if_in2  = 1'b0;reg if_add1 = 1'b0;         //自增使能reg if_add2 = 1'b0;reg [3:0]counter = 4'b0000;	//下面四句为处理输出变量赋初值问题的reg [2:0]state = 3'b001; assign number = counter;assign state_o = state;always @(posedge set_i)		//读入beginin <= data_i;if_in1 <= ~if_in1;end//状态转换,因为是异步清零,所以需要将rst信号也放上去always @(posedge clk_i or posedge rst_i)beginif(rst_i)beginstate <= 3'b001;endelse if(if_in2 != if_in1)beginif_in2 <= if_in1;case({in,state})4'b0000:state <= 3'b000;4'b0001:state <= 3'b000;4'b0010:state <= 3'b011;4'b0011:state <= 3'b000;4'b0100:state <= 3'b011;4'b0101:state <= 3'b000;4'b1000:state <= 3'b010;4'b1001:state <= 3'b001;4'b1010:state <= 3'b001;4'b1011:state <= 3'b100;4'b1100:state <= 3'b101;4'b1101:state <= 3'b001;default;endcaseif(state == 3'b101)if_add1 <= ~if_add1;	//表示需要计数器自增else;endelse;endalways @(posedge clk_i)beginif(rst_i)counter <= 4'b0000;else if(if_add1 != if_add2)begincounter <= counter+1'b1;if_add2 <= if_add1;endelsecounter <= counter;end
endmodule
代码分析

最让人头疼的应该就是if_in和if_add两组变量了,我们分别来讲解。
if_in的功能是判断是否有输入,因为我们说过每一次读入只能发生一次状态改变,所以我们需要设置一个变量作为使能信号给状态转变always块,但是这样我们就需要在两个模块都修改使能信号的值,所以我的方式就是设置两个变量实现在两个模块中进行修改。

同样,递增信号也是如此,我们的输出模块是时钟信号,但是当我们进入状态5没有下一个输入就会一直保持,导致一次会进行很多次的自增,所以我们也需要这样一组变量进行处理。

那两个assign语句,是因为我们的输入变量没有合适的在always语句块初始化条件,所以我创建了两个新的变量来进行修改、赋值。

剩下的部分

显示模块就是简单的数码管显示,看懂了上面链接的博客应该就没什么问题了。
这里我们采用的是输入四位数据,然后进行一个译码即可。

`timescale 1ns / 1ps
module light(input [3:0]number,output [3:0]en,output reg [7:0]led_o);assign en = 4'b0001;always@(*)begincase (number)4'b0000 : led_o = 8'b1111_1100;4'b0001 : led_o = 8'b0110_0000;4'b0010 : led_o = 8'b1101_1010;4'b0011 : led_o = 8'b1111_0010;4'b0100 : led_o = 8'b0110_0110;4'b0101 : led_o = 8'b1011_0110;4'b0110 : led_o = 8'b1011_1110;4'b0111 : led_o = 8'b1110_0000;4'b1000 : led_o = 8'b1111_1110;4'b1001 : led_o = 8'b1111_0110;4'b1010 : led_o = 8'b1110_1110;4'b1011 : led_o = 8'b0011_1110;4'b1100 : led_o = 8'b0001_1010;4'b1101 : led_o = 8'b0111_1010;4'b1110 : led_o = 8'b1001_1110;4'b1111 : led_o = 8'b1000_1110;default; endcaseend
endmodule

顶层模块:(真没啥了,不想说了)

`timescale 1ns / 1psmodule ex5_plus(input rst_n_i,input clk_i,input set_i,input data_i,output [3:0]leden_o,output [7:0]ledcx_o,output [2:0]led);wire [3:0]number;wire set;chuchan cc(set_i,clk_i,set);
count counter(clk_i,rst_n_i,set,data_i,number,led);
light lighter(number,leden_o,ledcx_o);
endmodule
写在最后

如果真的是下板验证,会发现在正确输入后板子不会有反应,这是因为我们采用的是非阻塞赋值的方式,需要等到下一个时钟上升沿(这里的时钟信号是set_i),所以我们需要再次进行输入,才能看到计数器的变化。
led灯显示的是状态转变,可以考虑看一下。

mealy型

在这里插入图片描述
我们在之前的思路其实也差不多,只要将上面的几个细节想清楚,剩下的都还好,所以我们也是直接上代码:

`timescale 1ns / 1ps
module count(input clk,input rst,input set,input data,output [3:0]number,output [2:0]state);//设置初始状态初始状态reg [2:0]led = 3'b001 ;     reg [3:0]num = 4'b0000;assign state = led;assign number= num;reg if_in1  = 1'b0;         //输入端使能reg if_in2  = 1'b0;reg if_add1 = 1'b0;         //自增使能reg if_add2 = 1'b0;reg in = 1'b1;//读入语句块always @(posedge set)beginin <= data;if_in1 <= ~if_in1;end//状态转换,因为是异步清零,所以需要将rst信号也放上去always @(posedge clk or posedge rst)beginif(rst)beginled <= 3'b001;endelse if(if_in2 != if_in1)beginif_in2 <= if_in1;case({in,led})4'b0000:led <= 3'b000;4'b0001:led <= 3'b000;4'b0010:led <= 3'b011;4'b0011:led <= 3'b000;4'b0100:led <= 3'b011;4'b1000:led <= 3'b010;4'b1001:led <= 3'b001;4'b1010:led <= 3'b001;4'b1011:led <= 3'b100;4'b1100:led <= 3'b001;default;endcaseif(led == 3'b100 && in == 1'b1)if_add1 <= ~if_add1;else;endelse;endalways @(posedge clk)beginif(rst)num <= 4'b0000;else if(if_add1 != if_add2)beginnum <= num+1'b1;if_add2 <= if_add1;endelsenum <= num;end
endmodule

这里因为是mealy型,需要同时看输入和状态,所以我们不需要等一个周期才能看到数码管的变化。
(其实也相当于再次按下输入,因为在自增的过程中状态从4到了1)

这篇关于Moore和mealy序集(并行输入的例子,三段式实现)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/385610

相关文章

Spring Security自定义身份认证的实现方法

《SpringSecurity自定义身份认证的实现方法》:本文主要介绍SpringSecurity自定义身份认证的实现方法,下面对SpringSecurity的这三种自定义身份认证进行详细讲解,... 目录1.内存身份认证(1)创建配置类(2)验证内存身份认证2.JDBC身份认证(1)数据准备 (2)配置依

利用python实现对excel文件进行加密

《利用python实现对excel文件进行加密》由于文件内容的私密性,需要对Excel文件进行加密,保护文件以免给第三方看到,本文将以Python语言为例,和大家讲讲如何对Excel文件进行加密,感兴... 目录前言方法一:使用pywin32库(仅限Windows)方法二:使用msoffcrypto-too

C#使用StackExchange.Redis实现分布式锁的两种方式介绍

《C#使用StackExchange.Redis实现分布式锁的两种方式介绍》分布式锁在集群的架构中发挥着重要的作用,:本文主要介绍C#使用StackExchange.Redis实现分布式锁的... 目录自定义分布式锁获取锁释放锁自动续期StackExchange.Redis分布式锁获取锁释放锁自动续期分布式

springboot使用Scheduling实现动态增删启停定时任务教程

《springboot使用Scheduling实现动态增删启停定时任务教程》:本文主要介绍springboot使用Scheduling实现动态增删启停定时任务教程,具有很好的参考价值,希望对大家有... 目录1、配置定时任务需要的线程池2、创建ScheduledFuture的包装类3、注册定时任务,增加、删

SpringBoot整合mybatisPlus实现批量插入并获取ID详解

《SpringBoot整合mybatisPlus实现批量插入并获取ID详解》这篇文章主要为大家详细介绍了SpringBoot如何整合mybatisPlus实现批量插入并获取ID,文中的示例代码讲解详细... 目录【1】saveBATch(一万条数据总耗时:2478ms)【2】集合方式foreach(一万条数

使用Python实现矢量路径的压缩、解压与可视化

《使用Python实现矢量路径的压缩、解压与可视化》在图形设计和Web开发中,矢量路径数据的高效存储与传输至关重要,本文将通过一个Python示例,展示如何将复杂的矢量路径命令序列压缩为JSON格式,... 目录引言核心功能概述1. 路径命令解析2. 路径数据压缩3. 路径数据解压4. 可视化代码实现详解1

PyQt6/PySide6中QTableView类的实现

《PyQt6/PySide6中QTableView类的实现》本文主要介绍了PyQt6/PySide6中QTableView类的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学... 目录1. 基本概念2. 创建 QTableView 实例3. QTableView 的常用属性和方法

PyQt6/PySide6中QTreeView类的实现

《PyQt6/PySide6中QTreeView类的实现》QTreeView是PyQt6或PySide6库中用于显示分层数据的控件,本文主要介绍了PyQt6/PySide6中QTreeView类的实现... 目录1. 基本概念2. 创建 QTreeView 实例3. QTreeView 的常用属性和方法属性

Android使用ImageView.ScaleType实现图片的缩放与裁剪功能

《Android使用ImageView.ScaleType实现图片的缩放与裁剪功能》ImageView是最常用的控件之一,它用于展示各种类型的图片,为了能够根据需求调整图片的显示效果,Android提... 目录什么是 ImageView.ScaleType?FIT_XYFIT_STARTFIT_CENTE

pandas中位数填充空值的实现示例

《pandas中位数填充空值的实现示例》中位数填充是一种简单而有效的方法,用于填充数据集中缺失的值,本文就来介绍一下pandas中位数填充空值的实现,具有一定的参考价值,感兴趣的可以了解一下... 目录什么是中位数填充?为什么选择中位数填充?示例数据结果分析完整代码总结在数据分析和机器学习过程中,处理缺失数