当前位置: 首页 > article >正文

FPGA状态机设计:流水灯实现、Modelsim仿真、HDLBits练习

一、状态机思想

1.概念

状态机(Finite State Machine, FSM)是计算机科学和工程领域中的一种抽象模型,用于描述系统在不同状态之间的转换逻辑。其核心思想是将复杂的行为拆解为有限的状态,并通过事件触发状态间的转移

2.状态机的分类
(1)Moore型状态机
输出仅由当前状态决定。
例如:交通灯的颜色(状态)直接决定输出。

(2)Mealy型状态机
输出由当前状态和输入事件共同决定。
例如:自动售货机根据投币金额(事件)和当前状态计算找零。

二、状态机思想实现LED流水灯

1.用状态机思想重写LED流水灯的FPGA代码

实现功能与我之前文章(FPGA实现LED流水灯(开发板为DE2-115)-CSDN博客)中实现的流水灯效果相同。

代码如下:

module led_state_machine(input        clk,      // 50MHz时钟(PIN_Y2)input        rst_n,    // 复位信号(PIN_M23,低有效)input        key1,     // 启动按键(PIN_M21)input        key2,     // 停止按键(PIN_N21)output reg [5:0] led   // 高电平有效LED(PIN_E21~G20)
);// 系统参数定义
parameter CLK_FREQ = 50_000_000;    // 50MHz时钟频率
parameter DEBOUNCE_CYCLES = 1_000_000; // 20ms消抖周期// 状态机状态定义
localparam S0 = 3'd0,  // LED0亮S1 = 3'd1,  // LED1亮S2 = 3'd2,  // LED2亮S3 = 3'd3,  // LED3亮S4 = 3'd4,  // LED4亮S5 = 3'd5;  // LED5亮reg [2:0] current_state, next_state;
reg [25:0] counter;
reg run_enable;// 按键同步与消抖逻辑
reg [1:0] key1_sync, key2_sync;
reg key1_stable, key2_stable;
reg [19:0] key1_cnt, key2_cnt;always @(posedge clk or negedge rst_n) beginif (!rst_n) beginkey1_sync <= 2'b11;key2_sync <= 2'b11;key1_stable <= 1'b1;key2_stable <= 1'b1;key1_cnt <= 0;key2_cnt <= 0;end else begin// 按键同步链key1_sync <= {key1_sync[0], key1};key2_sync <= {key2_sync[0], key2};// KEY1消抖逻辑if (key1_sync[1] != key1_stable) beginkey1_cnt <= (key1_cnt == DEBOUNCE_CYCLES) ? 0 : key1_cnt + 1;if (key1_cnt == DEBOUNCE_CYCLES) key1_stable <= key1_sync[1];end else beginkey1_cnt <= 0;end// KEY2消抖逻辑if (key2_sync[1] != key2_stable) beginkey2_cnt <= (key2_cnt == DEBOUNCE_CYCLES) ? 0 : key2_cnt + 1;if (key2_cnt == DEBOUNCE_CYCLES) key2_stable <= key2_sync[1];end else beginkey2_cnt <= 0;endend
end// 运行控制逻辑
always @(posedge clk or negedge rst_n) beginif (!rst_n) beginrun_enable <= 1'b0;end else begincase ({key2_stable, key1_stable})2'b10: run_enable <= 1'b1;  // KEY1按下启动2'b01: run_enable <= 1'b0;  // KEY2按下停止default: ;                   // 保持状态endcaseend
end// 状态转移控制
always @(posedge clk or negedge rst_n) beginif (!rst_n) begincurrent_state <= S0;counter <= 0;end else begin// 1秒定时器if (run_enable) begincounter <= (counter == CLK_FREQ-1) ? 0 : counter + 1;// 状态转移条件if (counter == CLK_FREQ-1)current_state <= next_state;endend
end// 状态转移逻辑
always @(*) begincase (current_state)S0: next_state = S1;S1: next_state = S2;S2: next_state = S3;S3: next_state = S4;S4: next_state = S5;S5: next_state = S0;default: next_state = S0;endcase
end// 输出逻辑
always @(posedge clk or negedge rst_n) beginif (!rst_n) beginled <= 6'b000001;end else begincase (current_state)S0: led <= 6'b000001;S1: led <= 6'b000010;S2: led <= 6'b000100;S3: led <= 6'b001000;S4: led <= 6'b010000;S5: led <= 6'b100000;default: led <= 6'b000001;endcaseend
endendmodule

具体过程看之前的文章 ,此处不再过多赘述。

在DE2-115板子上的效果如下:

状态机思想LED流水灯

2.写出仿真测试代码并用Modelsim进行仿真分析 

仿真测试代码

`timescale 1ns/1psmodule tb_led_state_machine();reg clk;
reg rst_n;
reg key1;
reg key2;
wire [5:0] led;// 实例化被测模块,调整参数以加速仿真
led_state_machine #(.CLK_FREQ(10),          // 原CLK_FREQ=50_000_000改为10.DEBOUNCE_CYCLES(10)    // 原DEBOUNCE_CYCLES=1_000_000改为10
) uut (.clk(clk),.rst_n(rst_n),.key1(key1),.key2(key2),.led(led)
);// 生成50MHz时钟(周期20ns)
always #10 clk = ~clk;initial begin// 初始化信号clk = 0;rst_n = 0;      // 复位有效key1 = 1;       // 按键未按下(高电平)key2 = 1;// 释放复位信号#100;rst_n = 1;#20; // 等待稳定// 验证复位后初始状态if (led !== 6'b000001)$display("错误:复位后初始状态应为S0,LED=000001,实际值为%b", led);else$display("测试1:复位成功,LED=000001");// 测试启动按键(key1)#20;key1 = 0;       // 按下key1#200;           // 等待消抖完成(200ns)key1 = 1;       // 释放key1// 验证状态转换(每个状态持续200ns)#200; // S1if (led === 6'b000010)$display("测试2:成功转换到S1,LED=000010");else$display("错误:应为S1,LED=%b", led);#200; // S2if (led === 6'b000100)$display("测试3:成功转换到S2,LED=000100");else$display("错误:应为S2,LED=%b", led);#200; // S3if (led === 6'b001000)$display("测试4:成功转换到S3,LED=001000");else$display("错误:应为S3,LED=%b", led);#200; // S4if (led === 6'b010000)$display("测试5:成功转换到S4,LED=010000");else$display("错误:应为S4,LED=%b", led);#200; // S5if (led === 6'b100000)$display("测试6:成功转换到S5,LED=100000");else$display("错误:应为S5,LED=%b", led);#200; // S0if (led === 6'b000001)$display("测试7:成功返回S0,LED=000001");else$display("错误:应为S0,LED=%b", led);// 测试停止按键(key2)key2 = 0;       // 按下key2#200;key2 = 1;#400; // 等待两个周期,状态应保持不变if (led === 6'b000001)$display("测试8:成功停止,保持S0");else$display("错误:停止后状态异常,LED=%b", led);// 再次启动key1 = 0;#200;key1 = 1;#200; // 应进入S1if (led === 6'b000010)$display("测试9:重新启动成功,进入S1");else$display("错误:重启失败,LED=%b", led);$display("所有测试完成");$finish;
endendmodule

三、CPLD和FPGA芯片的主要技术区别以及适用场合(借助deepseek)

1.CPLD和FPGA芯片对比​​

​特性​​CPLD​​FPGA​
​核心架构​基于乘积项(Product-Term)结构,逻辑单元通过全局互连连接基于查找表(LUT)结构,逻辑单元通过细粒度互连网络连接
​逻辑资源规模​较小(通常为数千至数万门)较大(数万门至数百万门)
​存储技术​基于非易失性存储器(EEPROM/Flash)基于易失性存储器(SRAM),需外挂配置芯片
​时序确定性​固定延迟(信号路径可预测)可变延迟(依赖布线路径)
​功耗特性​静态功耗低,适合低功耗场景静态功耗较高,动态功耗依赖逻辑复杂度
​启动时间​瞬时启动(配置信息内置)需要从外部加载配置(毫秒级延迟)
​灵活性​适合固定逻辑和简单状态机支持复杂算法、并行计算和动态重构

2. CPLD和FPGA芯片适用场合

(1)CPLD适用场景​​
​​低复杂度控制逻辑​​
        工业控制系统的接口管理(如PLC信号转换)
        通信协议转换(UART转SPI/I2C)
        简单的状态机实现(如电梯控制逻辑)
​​确定性时序要求​​
        实时控制系统(电机驱动时序控制)
        高速信号译码(如键盘扫描电路)
​​低功耗与高可靠性​​
        便携式设备的电源管理
        汽车电子中的传感器接口电路
​​(2)FPGA适用场景​​
​​高复杂度数据处理​​
        通信系统(5G基带处理、光纤通信编解码)
        图像处理(实时视频压缩、医学影像增强)
        人工智能加速(CNN推理、边缘计算)
​​动态可重构需求​​
        软件定义无线电(SDR)的硬件重配置
        数据中心网络加速(动态负载均衡)
​​高性能计算​​
        金融高频交易算法加速
        科学仿真(流体力学、分子动力学)

四、hdlbits网站中组合逻辑(combinational logic)题

4.1 2选1多路复用器(MUX)

1位宽 2选1多路复用器(MUX)是数字电路中最基础的逻辑单元之一,其核心功能是 根据选择信号(sel)从两个输入(a和b)中选择一个输出。它的作用可以类比为一个“数据开关”

问题描述:

解决方案:

module top_module(input a,input b,input sel,output out
);assign out = sel ? b : a;  // 三元运算符实现
endmodule

说明: sel ?b:a;是条件运算符,等价于 if - else 的逻辑,这是最简洁的组合逻辑实现方式。

用于测试用例的时序图:Selab 之间进行选择

4.2 256:1 多路复用器

是2对1多路复用器的升级版

问题描述:

代码 :

module top_module (input [255:0] in,input [7:0] sel,output out
);assign out = in[sel];  // 直接使用 sel 作为索引
endmodule

4.3 半加器设计

真值表:

absumcout
0000
0110
1010
1101

 问题描述:

代码:

module top_module (input a, b,output sum, cout
);assign sum = a ^ b;   // 异或:本位和assign cout = a & b;  // 与:进位
endmodule

4.4 全加器设计

全加器将两个1位二进制数和一个进位输入相加,产生和(sum)和进位输出(carry out)。

问题描述:  

代码: 

module top_module( input a, b, cin,output cout, sum );// 全加器实现assign sum = a ^ b ^ cin;               // 和的计算assign cout = (a & b) | (a & cin) | (b & cin);  // 进位输出的计算endmodule

结果:

4.5 4位BCD加法器

这个加法器可以处理两个4位BCD数字(每个数字0-9,共16位输入)和一个进位输入,产生4位BCD和和进位输出。

问题描述:

代码:

module top_module( input [15:0] a, b,input cin,output cout,output [15:0] sum );// 定义中间进位信号wire c1, c2, c3;// 实例化4个bcd_fadd模块,形成波纹进位链bcd_fadd add0 (.a(a[3:0]),.b(b[3:0]),.cin(cin),.cout(c1),.sum(sum[3:0]));bcd_fadd add1 (.a(a[7:4]),.b(b[7:4]),.cin(c1),.cout(c2),.sum(sum[7:4]));bcd_fadd add2 (.a(a[11:8]),.b(b[11:8]),.cin(c2),.cout(c3),.sum(sum[11:8]));bcd_fadd add3 (.a(a[15:12]),.b(b[15:12]),.cin(c3),.cout(cout),.sum(sum[15:12]));endmodule

说明(工作原理):

·最低位BCD加法器(add0)接收cin作为进位输入

·每个加法器的进位输出连接到下一个高位加法器的进位输入

·最高位BCD加法器(add3)的进位输出作为整个模块的cout

·每个加法器产生的4位和组合成最终的16位sum输出

测试用例的时序图:

4.6 100位二进制加法器

使用波纹进位(Ripple Carry)结构,该加法器将两个100位二进制数和一个进位输入相加,产生100位和和一个进位输出。

问题描述:

代码:

module top_module( input [99:0] a, b,input cin,output cout,output [99:0] sum );// 定义中间进位信号wire [100:0] carry;// 初始进位设为输入进位assign carry[0] = cin;// 生成100个全加器实例genvar i;generatefor (i = 0; i < 100; i = i + 1) begin : adder_chain// 每个全加器实例full_adder fa (.a(a[i]),.b(b[i]),.cin(carry[i]),.cout(carry[i+1]),.sum(sum[i]));endendgenerate// 最终进位输出assign cout = carry[100];endmodule// 全加器模块定义
module full_adder(input a, b, cin,output cout, sum
);assign sum = a ^ b ^ cin;assign cout = (a & b) | (a & cin) | (b & cin);
endmodule

相关文章:

FPGA状态机设计:流水灯实现、Modelsim仿真、HDLBits练习

一、状态机思想 1.概念 状态机&#xff08;Finite State Machine, FSM&#xff09;是计算机科学和工程领域中的一种抽象模型&#xff0c;用于描述系统在不同状态之间的转换逻辑。其核心思想是将复杂的行为拆解为有限的状态&#xff0c;并通过事件触发状态间的转移。 2.状态机…...

2024年第十五届蓝桥杯CC++大学A组--成绩统计

2024年第十五届蓝桥杯C&C大学A组--成绩统计 题目&#xff1a; 动态规划&#xff0c; 对于该题&#xff0c;考虑动态规划解法&#xff0c;先取前k个人的成绩计算其方差&#xff0c;并将成绩记录在数组中&#xff0c;记录当前均值&#xff0c;设小蓝已检查前i-1个人的成绩&…...

WinForm真入门(13)——ListBox控件详解

WinForm ListBox 详解与案例 一、核心概念 ‌ListBox‌ 是 Windows 窗体中用于展示可滚动列表项的控件&#xff0c;支持单选或多选操作&#xff0c;适用于需要用户从固定数据集中选择一项或多项的场景‌。 二、核心属性 属性说明‌Items‌管理列表项的集合&#xff0c;支持动…...

Kotlin 学习-集合

/*** kotlin 集合* List:是一个有序列表&#xff0c;可通过索引&#xff08;下标&#xff09;访问元素。元素可以在list中出现多次、元素可重复* Set:是元素唯一的集合。一般来说 set中的元素顺序并不重要、无序集合* Map:&#xff08;字典&#xff09;是一组键值对。键是唯一的…...

解决java使用easyexcel填充模版后,高度不一致问题

自定义工具&#xff0c;可以通过获取上一行行高设置后面所以行的高度 package org.springblade.modules.api.utils;import com.alibaba.excel.write.handler.RowWriteHandler; import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; import com.alibaba.excel.wr…...

数据结构与算法之ACM Fellow-算法4.3 最小生成树

数据结构与算法之ACM Fellow-算法4.3 最小生成树 加权图 是一种为每条边关联一个 权值 或是 成本 的图模型。这种图能够自然地表示许多应用。在一幅航空图中&#xff0c;边表示航线&#xff0c;权值则可以表示距离或是费用。在一幅电路图中&#xff0c;边表示导线&#xff0c;…...

使用POCO库进行ZIP压缩和解压

使用POCO库进行ZIP压缩和解压 POCO C Libraries提供了一个ZIP模块&#xff0c;可以方便地进行文件和数据流的压缩与解压操作。下面我将介绍如何使用POCO的ZIP模块进行这些操作。 1. 基本ZIP文件操作 压缩文件/目录到ZIP #include <Poco/Zip/Compress.h> #include <…...

自动驾驶的未来:多模态感知融合技术最新进展

作为自动驾驶领域的专业人士&#xff0c;我很高兴与大家分享关于多模态感知融合技术的前沿研究和实践经验。在迅速发展的自动驾驶领域&#xff0c;多模态感知融合已成为提升系统性能的关键技术。本文将深入探讨基于摄像头和激光雷达的多模态感知融合技术&#xff0c;重点关注最…...

亮相2025全球分布式云大会,火山引擎边缘云落地AI新场景

4 月 9 日&#xff0c;2025 全球分布式云大会暨 AI 基础设施大会在深圳成功举办&#xff0c;火山引擎边缘云产品解决方案高级总监沈建发出席并以《智启边缘&#xff0c;畅想未来&#xff1a;边缘计算新场景落地与 Al 趋势新畅想》为主题&#xff0c;分享了边缘计算在 AI 技术趋…...

XCode集成第三方framework步骤

一、添加 .framework 文件到项目 ‌拖拽或手动添加‌ 在Xcode中&#xff0c;直接将 .framework 文件拖入项目导航器的目标文件夹中, 确保 .framework 文件被复制到项目目录内&#xff08;非外部路径&#xff09;‌。或通过菜单操作&#xff1a; ‌General → Frameworks, Libra…...

无损分区管理,硬盘管理的“瑞士军刀”!

打工人们你们好&#xff01;这里是摸鱼 特供版~ 今天给大家带来一款简单易用、功能强大的无损分区软件——分区助手技术员版&#xff0c;让你的硬盘管理变得轻松又高效&#xff01; 推荐指数&#xff1a;★★★★★ 软件简介 分区助手技术员版是一款功能强大的硬盘分区工具&…...

VS Code下开发FPGA——FPGA开发体验提升__下

上一篇&#xff1a;IntelliJ IDEA下开发FPGA-CSDN博客 Type&#xff1a;Quartus 一、安装插件 在应用商店先安装Digtal IDE插件 安装后&#xff0c;把其他相关的Verilog插件禁用&#xff0c;避免可能的冲突。重启后&#xff0c;可能会弹出下面提示 这是插件默认要求的工具链&a…...

ffmpeg播放音视频流程

文章目录 &#x1f3ac; FFmpeg 解码播放流程概览&#xff08;以音视频文件为例&#xff09;1️⃣ 创建结构体2️⃣ 打开音视频文件3️⃣ 查找解码器并打开解码器4️⃣ 循环读取数据包&#xff08;Packet&#xff09;5️⃣ 解码成帧&#xff08;Frame&#xff09;6️⃣ 播放 / …...

SpringCloud微服务: 分布式架构实战

# SpringCloud微服务: 分布式架构实战 第一章&#xff1a;理解SpringCloud微服务架构 什么是SpringCloud微服务架构&#xff1f; 在当今互联网应用开发中&#xff0c;微服务架构已经成为业界的主流趋势。SpringCloud是一个基于Spring Boot的快速开发微服务架构的工具&#xff0…...

AI预测3D新模型百十个定位预测+胆码预测+去和尾2025年4月11日第49弹

从今天开始&#xff0c;咱们还是暂时基于旧的模型进行预测&#xff0c;好了&#xff0c;废话不多说&#xff0c;按照老办法&#xff0c;重点8-9码定位&#xff0c;配合三胆下1或下2&#xff0c;杀1-2个和尾&#xff0c;再杀6-8个和值&#xff0c;可以做到100-300注左右。 (1)定…...

Spring其它知识点

33.Spring 源码用到了哪些设计模式&#xff1f; 工厂模式&#xff1a;通过BeanFactory或者ApplicationContext创建Bean对象。BeanFactory是延迟注入&#xff0c;使用到Bean的时候才注入。ApplicationContext是在容器启动时&#xff0c;一次性创建所有的Bean。单例模型&#xf…...

【models】Transformer 之 各种 Attention 原理和实现

Transformer 之 各种 Attention 原理和实现 本文将介绍Transformer 中常见的Attention的原理和实现&#xff0c;其中包括&#xff1a; Self Attention、Spatial Attention、Temporal Attention、Cross Attention、Grouped Attention、Tensor Product Attention、FlashAttentio…...

C++ 学习资源整理

awesome-cpp&#xff08;C 资源大全&#xff09; &#x1f517; https://github.com/fffaraz/awesome-cpp 收集了各种 C 库、框架、教程和示例代码。 CPlusPlusThings&#xff08;C 基础知识整理&#xff09; &#x1f517; https://github.com/Light-City/CPlusPlusThings 包…...

opengrok搭建与配置

前提条件 需要配置好docker与docker-compose环境 1.代码准备 mkdir -p /data/opengrok/{etc,src,data} cd /data/opengrok/src/ # 克隆一个测试项目 git clone https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git 2.创建docker-compose.yml文件&…...

老硬件也能运行的Win11 IoT LTSC (OEM)物联网版

#记录工作 Windows 11 IoT Enterprise LTSC 2024 属于物联网相关的版本。 Windows 11 IoT Enterprise 是为物联网设备和场景设计的操作系统版本。它通常针对特定的工业控制、智能设备等物联网应用进行了优化和定制&#xff0c;以满足这些领域对稳定性、安全性和长期支持的需求…...

JavaScript 代码混淆与反混淆技术详解

一、代码混淆&#xff1a;让别人看不懂你的代码 混淆技术就是一种“代码伪装术”&#xff0c;目的是让别人很难看懂你的代码逻辑&#xff0c;从而保护你的核心算法或敏感信息。 1. 变量名压缩 原理&#xff1a;把变量名改成乱码&#xff0c;比如把calculatePrice改成a&#…...

数据库守护神-WAL机制

什么是WAL机制&#xff1f; WAL&#xff08;Write-Ahead Logging&#xff0c;预写日志&#xff09;是一种保证数据库操作原子性和持久性的核心机制。其核心原则可概括为&#xff1a; 任何数据修改操作&#xff0c;必须在对应的日志记录持久化到磁盘之后&#xff0c;才能将实际…...

Git开发

目录 Linux下Git安装Git基本指令分支管理远程仓库与本地仓库标签管理多人协作同一分支下不同分支下 企业级开发模型 -- git flow 模型 在现实中&#xff0c;当我们完成一个文档的初稿后&#xff0c;后面可能还需要对初稿进行反复修改&#xff0c;从而形成不同版本的文档。显然&…...

verilog有符号数的乘法

无符号整数的乘法 1、单周期乘法器&#xff08; 无符号整数 &#xff09; 对于低速要求的乘法器&#xff0c;可以简单的使用 * 实现。 module Mult(input wire [7:0] multiplicand ,input wire [7:0] multipliter ,output wire [7:0] product);as…...

【蓝桥杯】动态规划:背包问题

这篇文章主要记录动态规划方面的学习。 动态规划的核心思想: 把大问题分解成小问题,记住小问题的解,避免重复计算。 动态规划(DP)的三大特点: ①最优子结构:大问题的最优解可以由小问题的最优解推导出来 ②重叠子问题:在求解过程中会反复遇到相同的小问题 ③无后效…...

DevDocs:抓取并整理技术文档的MCP服务

GitHub&#xff1a;https://github.com/cyberagiinc/DevDocs 更多AI开源软件&#xff1a;发现分享好用的AI工具、AI开源软件、AI模型、AI变现 - 小众AI DevDocs 是一个完全免费的开源工具&#xff0c;由 CyberAGI 团队开发&#xff0c;托管在 GitHub 上。它专为程序员和软件开发…...

第十四届蓝桥杯大赛软件赛国赛Python大学B组题解

文章目录 弹珠堆放划分偶串交易账本背包问题翻转最大阶梯最长回文前后缀贸易航线困局 弹珠堆放 递推式 a i a i − 1 i a_ia_{i-1}i ai​ai−1​i&#xff0c; n 20230610 n20230610 n20230610非常小&#xff0c;直接模拟 答案等于 494 494 494 划分 因为总和为 1 e 6 1e6…...

折叠屏手机:技术进步了,柔性OLED面板测试技术需求跟上了吗?

全球智能手机市场陷入创新焦虑&#xff0c;折叠屏手机被寄予厚望&#xff0c;2023 年出货量同比增长 62%。但在供应链技术狂欢背后&#xff0c;存在诸多问题。消费端数据显示&#xff0c;用户使用频率低&#xff0c;定价策略反常。产业链重构虽让部分企业获利&#xff0c;却推高…...

30天学Java第九天——线程

并行与并发的区别 并行是多核 CPU 上的多任务处理&#xff0c;多个任务在同一时间真正的同时执行并发是单核 CPU 上的多任务处理&#xff0c;多个任务在同一时间段内交替执行&#xff0c;通过时间片轮转实现交替执行&#xff0c;用于解决 IO 密集型任务的瓶颈 线程的创建方式…...

kotlin的takeIf使用

takeIf用于判断指定对象是否满足条件&#xff0c;满足就返回该对象自身&#xff0c;不满足返回null。因为可以返回对象自身&#xff0c;所以可以用作链式调用&#xff0c;以简化代码&#xff0c;又因takeIf可能返回空&#xff0c;所以常常和let结合使用&#xff0c;示例如下&am…...