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

相关文章

SpringBoot集成redisson实现延时队列教程

《SpringBoot集成redisson实现延时队列教程》文章介绍了使用Redisson实现延迟队列的完整步骤,包括依赖导入、Redis配置、工具类封装、业务枚举定义、执行器实现、Bean创建、消费... 目录1、先给项目导入Redisson依赖2、配置redis3、创建 RedissonConfig 配

Python的Darts库实现时间序列预测

《Python的Darts库实现时间序列预测》Darts一个集统计、机器学习与深度学习模型于一体的Python时间序列预测库,本文主要介绍了Python的Darts库实现时间序列预测,感兴趣的可以了解... 目录目录一、什么是 Darts?二、安装与基本配置安装 Darts导入基础模块三、时间序列数据结构与

Python使用FastAPI实现大文件分片上传与断点续传功能

《Python使用FastAPI实现大文件分片上传与断点续传功能》大文件直传常遇到超时、网络抖动失败、失败后只能重传的问题,分片上传+断点续传可以把大文件拆成若干小块逐个上传,并在中断后从已完成分片继... 目录一、接口设计二、服务端实现(FastAPI)2.1 运行环境2.2 目录结构建议2.3 serv

C#实现千万数据秒级导入的代码

《C#实现千万数据秒级导入的代码》在实际开发中excel导入很常见,现代社会中很容易遇到大数据处理业务,所以本文我就给大家分享一下千万数据秒级导入怎么实现,文中有详细的代码示例供大家参考,需要的朋友可... 目录前言一、数据存储二、处理逻辑优化前代码处理逻辑优化后的代码总结前言在实际开发中excel导入很

SpringBoot+RustFS 实现文件切片极速上传的实例代码

《SpringBoot+RustFS实现文件切片极速上传的实例代码》本文介绍利用SpringBoot和RustFS构建高性能文件切片上传系统,实现大文件秒传、断点续传和分片上传等功能,具有一定的参考... 目录一、为什么选择 RustFS + SpringBoot?二、环境准备与部署2.1 安装 RustF

Nginx部署HTTP/3的实现步骤

《Nginx部署HTTP/3的实现步骤》本文介绍了在Nginx中部署HTTP/3的详细步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学... 目录前提条件第一步:安装必要的依赖库第二步:获取并构建 BoringSSL第三步:获取 Nginx

MyBatis Plus实现时间字段自动填充的完整方案

《MyBatisPlus实现时间字段自动填充的完整方案》在日常开发中,我们经常需要记录数据的创建时间和更新时间,传统的做法是在每次插入或更新操作时手动设置这些时间字段,这种方式不仅繁琐,还容易遗漏,... 目录前言解决目标技术栈实现步骤1. 实体类注解配置2. 创建元数据处理器3. 服务层代码优化填充机制详

Python实现Excel批量样式修改器(附完整代码)

《Python实现Excel批量样式修改器(附完整代码)》这篇文章主要为大家详细介绍了如何使用Python实现一个Excel批量样式修改器,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一... 目录前言功能特性核心功能界面特性系统要求安装说明使用指南基本操作流程高级功能技术实现核心技术栈关键函

Java实现字节字符转bcd编码

《Java实现字节字符转bcd编码》BCD是一种将十进制数字编码为二进制的表示方式,常用于数字显示和存储,本文将介绍如何在Java中实现字节字符转BCD码的过程,需要的小伙伴可以了解下... 目录前言BCD码是什么Java实现字节转bcd编码方法补充总结前言BCD码(Binary-Coded Decima

SpringBoot全局域名替换的实现

《SpringBoot全局域名替换的实现》本文主要介绍了SpringBoot全局域名替换的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一... 目录 项目结构⚙️ 配置文件application.yml️ 配置类AppProperties.Ja