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

相关文章

Qt实现对Word网页的读取功能

《Qt实现对Word网页的读取功能》文章介绍了几种在Qt中实现Word文档(.docx/.doc)读写功能的方法,包括基于QAxObject的COM接口调用、DOCX模板替换及跨平台解决方案,重点讨论... 目录1. 核心实现方式2. 基于QAxObject的COM接口调用(Windows专用)2.1 环境

MySQL查看表的历史SQL的几种实现方法

《MySQL查看表的历史SQL的几种实现方法》:本文主要介绍多种查看MySQL表历史SQL的方法,包括通用查询日志、慢查询日志、performance_schema、binlog、第三方工具等,并... 目录mysql 查看某张表的历史SQL1.查看MySQL通用查询日志(需提前开启)2.查看慢查询日志3.

Java实现字符串大小写转换的常用方法

《Java实现字符串大小写转换的常用方法》在Java中,字符串大小写转换是文本处理的核心操作之一,Java提供了多种灵活的方式来实现大小写转换,适用于不同场景和需求,本文将全面解析大小写转换的各种方法... 目录前言核心转换方法1.String类的基础方法2. 考虑区域设置的转换3. 字符级别的转换高级转换

使用Python实现局域网远程监控电脑屏幕的方法

《使用Python实现局域网远程监控电脑屏幕的方法》文章介绍了两种使用Python在局域网内实现远程监控电脑屏幕的方法,方法一使用mss和socket,方法二使用PyAutoGUI和Flask,每种方... 目录方法一:使用mss和socket实现屏幕共享服务端(被监控端)客户端(监控端)方法二:使用PyA

MyBatis-Plus逻辑删除实现过程

《MyBatis-Plus逻辑删除实现过程》本文介绍了MyBatis-Plus如何实现逻辑删除功能,包括自动填充字段、配置与实现步骤、常见应用场景,并展示了如何使用remove方法进行逻辑删除,逻辑删... 目录1. 逻辑删除的必要性编程1.1 逻辑删除的定义1.2 逻辑删php除的优点1.3 适用场景2.

C#借助Spire.XLS for .NET实现在Excel中添加文档属性

《C#借助Spire.XLSfor.NET实现在Excel中添加文档属性》在日常的数据处理和项目管理中,Excel文档扮演着举足轻重的角色,本文将深入探讨如何在C#中借助强大的第三方库Spire.... 目录为什么需要程序化添加Excel文档属性使用Spire.XLS for .NET库实现文档属性管理Sp

Python+FFmpeg实现视频自动化处理的完整指南

《Python+FFmpeg实现视频自动化处理的完整指南》本文总结了一套在Python中使用subprocess.run调用FFmpeg进行视频自动化处理的解决方案,涵盖了跨平台硬件加速、中间素材处理... 目录一、 跨平台硬件加速:统一接口设计1. 核心映射逻辑2. python 实现代码二、 中间素材处

Java数组动态扩容的实现示例

《Java数组动态扩容的实现示例》本文主要介绍了Java数组动态扩容的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录1 问题2 方法3 结语1 问题实现动态的给数组添加元素效果,实现对数组扩容,原始数组使用静态分配

Python实现快速扫描目标主机的开放端口和服务

《Python实现快速扫描目标主机的开放端口和服务》这篇文章主要为大家详细介绍了如何使用Python编写一个功能强大的端口扫描器脚本,实现快速扫描目标主机的开放端口和服务,感兴趣的小伙伴可以了解下... 目录功能介绍场景应用1. 网络安全审计2. 系统管理维护3. 网络故障排查4. 合规性检查报错处理1.

Python轻松实现Word到Markdown的转换

《Python轻松实现Word到Markdown的转换》在文档管理、内容发布等场景中,将Word转换为Markdown格式是常见需求,本文将介绍如何使用FreeSpire.DocforPython实现... 目录一、工具简介二、核心转换实现1. 基础单文件转换2. 批量转换Word文件三、工具特性分析优点局