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

相关文章

基于 HTML5 Canvas 实现图片旋转与下载功能(完整代码展示)

《基于HTML5Canvas实现图片旋转与下载功能(完整代码展示)》本文将深入剖析一段基于HTML5Canvas的代码,该代码实现了图片的旋转(90度和180度)以及旋转后图片的下载... 目录一、引言二、html 结构分析三、css 样式分析四、JavaScript 功能实现一、引言在 Web 开发中,

SpringBoot中使用Flux实现流式返回的方法小结

《SpringBoot中使用Flux实现流式返回的方法小结》文章介绍流式返回(StreamingResponse)在SpringBoot中通过Flux实现,优势包括提升用户体验、降低内存消耗、支持长连... 目录背景流式返回的核心概念与优势1. 提升用户体验2. 降低内存消耗3. 支持长连接与实时通信在Sp

Conda虚拟环境的复制和迁移的四种方法实现

《Conda虚拟环境的复制和迁移的四种方法实现》本文主要介绍了Conda虚拟环境的复制和迁移的四种方法实现,包括requirements.txt,environment.yml,conda-pack,... 目录在本机复制Conda虚拟环境相同操作系统之间复制环境方法一:requirements.txt方法

Spring Boot 实现 IP 限流的原理、实践与利弊解析

《SpringBoot实现IP限流的原理、实践与利弊解析》在SpringBoot中实现IP限流是一种简单而有效的方式来保障系统的稳定性和可用性,本文给大家介绍SpringBoot实现IP限... 目录一、引言二、IP 限流原理2.1 令牌桶算法2.2 漏桶算法三、使用场景3.1 防止恶意攻击3.2 控制资源

springboot下载接口限速功能实现

《springboot下载接口限速功能实现》通过Redis统计并发数动态调整每个用户带宽,核心逻辑为每秒读取并发送限定数据量,防止单用户占用过多资源,确保整体下载均衡且高效,本文给大家介绍spring... 目录 一、整体目标 二、涉及的主要类/方法✅ 三、核心流程图解(简化) 四、关键代码详解1️⃣ 设置

Nginx 配置跨域的实现及常见问题解决

《Nginx配置跨域的实现及常见问题解决》本文主要介绍了Nginx配置跨域的实现及常见问题解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来... 目录1. 跨域1.1 同源策略1.2 跨域资源共享(CORS)2. Nginx 配置跨域的场景2.1

Python中提取文件名扩展名的多种方法实现

《Python中提取文件名扩展名的多种方法实现》在Python编程中,经常会遇到需要从文件名中提取扩展名的场景,Python提供了多种方法来实现这一功能,不同方法适用于不同的场景和需求,包括os.pa... 目录技术背景实现步骤方法一:使用os.path.splitext方法二:使用pathlib模块方法三

CSS实现元素撑满剩余空间的五种方法

《CSS实现元素撑满剩余空间的五种方法》在日常开发中,我们经常需要让某个元素占据容器的剩余空间,本文将介绍5种不同的方法来实现这个需求,并分析各种方法的优缺点,感兴趣的朋友一起看看吧... css实现元素撑满剩余空间的5种方法 在日常开发中,我们经常需要让某个元素占据容器的剩余空间。这是一个常见的布局需求

HTML5 getUserMedia API网页录音实现指南示例小结

《HTML5getUserMediaAPI网页录音实现指南示例小结》本教程将指导你如何利用这一API,结合WebAudioAPI,实现网页录音功能,从获取音频流到处理和保存录音,整个过程将逐步... 目录1. html5 getUserMedia API简介1.1 API概念与历史1.2 功能与优势1.3

Java实现删除文件中的指定内容

《Java实现删除文件中的指定内容》在日常开发中,经常需要对文本文件进行批量处理,其中,删除文件中指定内容是最常见的需求之一,下面我们就来看看如何使用java实现删除文件中的指定内容吧... 目录1. 项目背景详细介绍2. 项目需求详细介绍2.1 功能需求2.2 非功能需求3. 相关技术详细介绍3.1 Ja