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

相关文章

使用Redis快速实现共享Session登录的详细步骤

《使用Redis快速实现共享Session登录的详细步骤》在Web开发中,Session通常用于存储用户的会话信息,允许用户在多个页面之间保持登录状态,Redis是一个开源的高性能键值数据库,广泛用于... 目录前言实现原理:步骤:使用Redis实现共享Session登录1. 引入Redis依赖2. 配置R

SpringBoot实现RSA+AES自动接口解密的实战指南

《SpringBoot实现RSA+AES自动接口解密的实战指南》在当今数据泄露频发的网络环境中,接口安全已成为开发者不可忽视的核心议题,RSA+AES混合加密方案因其安全性高、性能优越而被广泛采用,本... 目录一、项目依赖与环境准备1.1 Maven依赖配置1.2 密钥生成与配置二、加密工具类实现2.1

在Java中实现线程之间的数据共享的几种方式总结

《在Java中实现线程之间的数据共享的几种方式总结》在Java中实现线程间数据共享是并发编程的核心需求,但需要谨慎处理同步问题以避免竞态条件,本文通过代码示例给大家介绍了几种主要实现方式及其最佳实践,... 目录1. 共享变量与同步机制2. 轻量级通信机制3. 线程安全容器4. 线程局部变量(ThreadL

python使用Akshare与Streamlit实现股票估值分析教程(图文代码)

《python使用Akshare与Streamlit实现股票估值分析教程(图文代码)》入职测试中的一道题,要求:从Akshare下载某一个股票近十年的财务报表包括,资产负债表,利润表,现金流量表,保存... 目录一、前言二、核心知识点梳理1、Akshare数据获取2、Pandas数据处理3、Matplotl

分布式锁在Spring Boot应用中的实现过程

《分布式锁在SpringBoot应用中的实现过程》文章介绍在SpringBoot中通过自定义Lock注解、LockAspect切面和RedisLockUtils工具类实现分布式锁,确保多实例并发操作... 目录Lock注解LockASPect切面RedisLockUtils工具类总结在现代微服务架构中,分布

Java使用Thumbnailator库实现图片处理与压缩功能

《Java使用Thumbnailator库实现图片处理与压缩功能》Thumbnailator是高性能Java图像处理库,支持缩放、旋转、水印添加、裁剪及格式转换,提供易用API和性能优化,适合Web应... 目录1. 图片处理库Thumbnailator介绍2. 基本和指定大小图片缩放功能2.1 图片缩放的

Python使用Tenacity一行代码实现自动重试详解

《Python使用Tenacity一行代码实现自动重试详解》tenacity是一个专为Python设计的通用重试库,它的核心理念就是用简单、清晰的方式,为任何可能失败的操作添加重试能力,下面我们就来看... 目录一切始于一个简单的 API 调用Tenacity 入门:一行代码实现优雅重试精细控制:让重试按我

Redis客户端连接机制的实现方案

《Redis客户端连接机制的实现方案》本文主要介绍了Redis客户端连接机制的实现方案,包括事件驱动模型、非阻塞I/O处理、连接池应用及配置优化,具有一定的参考价值,感兴趣的可以了解一下... 目录1. Redis连接模型概述2. 连接建立过程详解2.1 连php接初始化流程2.2 关键配置参数3. 最大连

Python实现网格交易策略的过程

《Python实现网格交易策略的过程》本文讲解Python网格交易策略,利用ccxt获取加密货币数据及backtrader回测,通过设定网格节点,低买高卖获利,适合震荡行情,下面跟我一起看看我们的第一... 网格交易是一种经典的量化交易策略,其核心思想是在价格上下预设多个“网格”,当价格触发特定网格时执行买

python设置环境变量路径实现过程

《python设置环境变量路径实现过程》本文介绍设置Python路径的多种方法:临时设置(Windows用`set`,Linux/macOS用`export`)、永久设置(系统属性或shell配置文件... 目录设置python路径的方法临时设置环境变量(适用于当前会话)永久设置环境变量(Windows系统