【FPGA实验1】FPGA点灯工程师养成记

对于FPGA几个与LED相关的实验(包括按键点灯、流水灯、呼吸灯等)的记录,方便日后查看。这世界上就又多了一个FPGA点灯工程师了😏

成为一个FPGA点灯工程师分三步:

        • 一、按键点灯
          • 1、按键点灯程序
          • 2、硬件实现
        • 二、流水灯
          • 1、流水灯程序
          • 2、仿真
          • 3、硬件实现
        • 三、呼吸灯
          • 1、先“吸”
          • 2、再“呼吸”
          • 3、最后大口地呼吸

一、按键点灯

按键点灯程序比较简单,就不搞仿真了,直接上机

1、按键点灯程序
module led(input wire key_1,
		output reg led_1);
						
 always@*
  led_1=!key_1;
 

endmodule

由程序得到的RTL图:

请添加图片描述

2、硬件实现

(1)引脚分配与接线
引脚分配如下,记得引脚分配后再编译一次,不然可能没有现象。

请添加图片描述

上述引脚分配对应的接线:JX22连接到JP5,JX5连接到JP1。
为什么要这样接线可以参考《【FPGA实验2】二进制转为格雷码》中的【三、实验箱实验】➡️【3、引脚分配】。

在这里插入图片描述

(2)实验现象

具体的实验现象可观看下方的视频😏

二、流水灯

学了点状态机的内容,决定用状态机来写一下这个流水灯的代码。
感谢正点原子的视频,用了一个很好理解的例子讲了状态机是怎么样的一个东西,并总结了写状态机主要有四个步骤(也称四段论):
(1)状态空间定义(定义各个状态)
(2)状态跳转(告诉FPGA:你要跳转。让FPGA知道在什么条件下,你要从现在状态跳转到下一个状态)
(3)下个状态的判断(告诉FPGA:你要怎么跳。给FPGA一个地图,判断现在的情况是什么,然后根据地图确定下一个要跳转的状态)
(4)各个状态下的动作(我理解为状态对应信息的输出)

1、流水灯程序
module WaterLED(input wire clk,
				input wire rst_n,
				output wire [7:0]led_data);
		
		//空间状态定义
		parameter S1=8'b10000000;
		parameter S2=8'b01000000;
		parameter S3=8'b00100000;
		parameter S4=8'b00010000;
		parameter S5=8'b00001000;
		parameter S6=8'b00000100;
		parameter S7=8'b00000010;
		parameter S8=8'b00000001;
		
		reg [7:0]current_state;
		reg[7:0]next_state;
		
		//状态跳转
		always @(posedge clk or negedge rst_n) begin
			if(! rst_n)   current_state<=S1;  //复位,从状态S1开始
			else current_state<=next_state; //不是复位的情况下,到达时钟的上升沿就转到下一个状态
		end
		
		//状态判断
		always @(current_state) begin
			case(current_state) 
				S1:next_state=S2;
				S2:next_state=S3;
				S3:next_state=S4;
				S4:next_state=S5;
				S5:next_state=S6;
				S6:next_state=S7;
				S7:next_state=S8;
				default:next_state=S1;
			endcase
		end
		
	//各个状态下的动作
	assign led_data=current_state;
	
endmodule

得到的RTL图如下:
在这里插入图片描述

2、仿真

流水灯的仿真程序如下:

`timescale 1ns/100ps
module tb_WaterLED;
	reg clk_1;
	reg rst_n_1;
	wire [7:0] led_data_1;
	parameter PERIOD=10;
	
	always #(PERIOD/2) clk_1=~clk_1;

	initial begin
		clk_1=0;
		#200  $stop;
	end
	
	task task_rst;
		begin 
		rst_n_1=0;
		repeat(2) @(negedge clk_1);//两个时钟负跳变之后
		rst_n_1=1;
		end
	endtask

	WaterLED WD_1(.clk(clk_1),.rst_n(rst_n_1),.led_data(led_data_1));
	
	initial begin
	task_rst;
	$display("task_rst ok!!!");
	end
	
	
	endmodule

【如何将仿真程序加入到工程中以及如何仿真可以看上一篇《【FPGA实验0】Quartus建立工程文件以及仿真》)】

仿真结果如下:
在两个时钟下降沿之后,复位线RST置高;之后随着每一个时钟上升沿的到来,开始状态的转换。

在这里插入图片描述

3、硬件实现

在实际的硬件实现中,需要注意两个点:

(1)时钟信号
在仿真中,两个状态之间的切换是在时钟信号的上升沿,因而,每个状态保持的时间是一个时钟信号周期(在上的仿真中,一个时钟信号的周期是10ns)。而如果在实际中要实现流水灯的效果,这样的间隔太小了,由于眼睛的暂存作用,我们看懂的现象是8个LED灯一直在同时亮着,没有流水灯的效果,因而我们必须将时钟周期改得大一点。
请添加图片描述

选择实验箱最大时钟12MHz(接线的话将左侧12M对应的时钟和右侧的任意一个引脚接起来即可),定义一个计数器,计数2400000个时钟周期,一个时钟频率为12MHz,一个时钟周期为83.33ns,2400000个时钟周期就是0.2秒。

	reg [23:0] counter;	
		
	//计数器对系统时钟计数,计时0.2秒
	always @(posedge clk or negedge rst_n) begin
	 if (!rst_n)
		  counter <= 24'd0;
	 else if (counter < 24'd2400_000)  //仿真的时候可以改为 24'd0000_0010,下同
		  counter <= counter + 1'b1;
	 else
		  counter <= 24'd0;
	end

同时,状态跳变部分增加一个条件,修改为:

//状态跳转
always @(posedge clk or negedge rst_n) begin
	if(! rst_n)   current_state<=S1;  //复位,从状态S1开始
	else if (counter==24'd2400_000) current_state<=next_state; //不是复位的情况下,到达时钟的上升沿就转到下一个状态
	else   ;
end

(2)复位键如何使用

复位键一开始需要置1(打到开的位置);
之后置0(下降沿产生出发条件;同时!rst=0,状态为初始状态S1);
完成复位后置1(使此刻的状态在触发之后能跳转到下一个状态)。

整个硬件实现的程序:

module WaterLED(input wire clk,
												input wire rst_n,
												output wire [7:0]led_data);
			
		
		//空间状态定义
		parameter S1=8'b10000000;
		parameter S2=8'b01000000;
		parameter S3=8'b00100000;
		parameter S4=8'b00010000;
		parameter S5=8'b00001000;
		parameter S6=8'b00000100;
		parameter S7=8'b00000010;
		parameter S8=8'b00000001;

		
		reg [7:0]current_state;
		reg[7:0]next_state;
		reg [23:0] counter;
		
	//计数器对系统时钟计数,计时0.2秒
		always @(posedge clk or negedge rst_n) begin
		 if (!rst_n)
			  counter <= 24'd0;
		 else if (counter < 24'd2400_000)  //仿真的时候可以改为 24'd0000_0010,下同
			  counter <= counter + 1'b1;
		 else
			  counter <= 24'd0;
		end
		
		//状态跳转
		always @(posedge clk or negedge rst_n) begin
			if(! rst_n)   current_state<=S1;  //复位,从状态S1开始
			else if (counter==24'd2400_000) current_state<=next_state; //不是复位的情况下,到达时钟的上升沿就转到下一个状态
			else   ;
		end
		
		//状态判断
		always @(current_state) begin
			case(current_state) 
				S1:next_state=S2;
				S2:next_state=S3;
				S3:next_state=S4;
				S4:next_state=S5;
				S5:next_state=S6;
				S6:next_state=S7;
				S7:next_state=S8;
				default:next_state=S1;
			endcase
		end
		
		//各个状态下的动作
	assign led_data=~current_state;//灯为0时亮起,为1时变暗
	
	
endmodule

对应的RTL图:
请添加图片描述

引脚分配与接线:
请添加图片描述

按之前的接线即可,key8为复位键。

上述引脚分配对应的接线:JX22连接到JP5,JX5连接到JP1。
为什么要这样接线可以参考《【FPGA实验2】二进制转为格雷码》中的【三、实验箱实验】➡️【3、引脚分配】。

时钟引脚:左侧的12M时钟引脚接到右侧任意一个引脚即可。总的接线图如下:

在这里插入图片描述

具体现象可以看文末的视频😏

三、呼吸灯

呼吸灯,就是灯的亮度由暗变亮再由亮变暗,像人的呼吸一样。

1、先“吸”

(1)代码

module PWM(           
			input wire clk,
			output wire[9:0] pwma,
			output wire pwmb);

	reg [3:0]counter1=0,counter2=0;
	reg [9:0]pwm_1=10'b0000_0000_00;
	reg[0:0] pwm_2;
	
	always@(posedge clk) begin

			if(counter2==4'd9)  begin
			
					if(counter1==4'd9)  begin
						counter1=0;
						pwm_1=10'b0000_0000_00;					
						end
					else  counter1=counter1+1;							
					pwm_1[counter1]=1;
					counter2=0;
				end
				
			else counter2=counter2+1;
			pwm_2=pwm_1[counter2];
	end
	
	assign pwma=pwm_1;
	assign pwmb=pwm_2;
		
endmodule

(2)仿真文件:

`timescale 1ns/100ps
module tb_PWM;
	
	reg clk;
	wire [9:0]pwma;
	wire [0:0]pwmb;
	parameter PERIOD=10;
	
	always #(PERIOD/2) clk=~clk;
	
	initial begin
		clk=0;
		# 3000 $stop;
		end
		
PWM PWM_1(.clk(clk),.pwma(pwma), .pwmb(pwmb));

endmodule

(3)仿真结果:
在这里插入图片描述

2、再“呼吸”

(1)代码

module PWM(
						input wire clk,
						output wire[9:0] pwma,
						output wire pwmb);

	reg [4:0]counter1=0;
	reg [3:0]counter2=0;
	reg [9:0]pwm_1=10'b0000_0000_00;
	reg[0:0] pwm_2;
	
	always@(posedge clk) begin

			if(counter2==4'd9)  begin
		
					if(counter1==5'd17)   counter1=0;
					else  counter1=counter1+1;	
					$display("counter1:   ",counter1);
					
					case(counter1)
						5'd0  : pwm_1=10'b0000_0000_01;
						5'd1  : pwm_1=10'b0000_0000_11;
						5'd2  : pwm_1=10'b0000_0001_11;
						5'd3  : pwm_1=10'b0000_0011_11;
						5'd4  : pwm_1=10'b0000_0111_11;
						5'd5  : pwm_1=10'b0000_1111_11;
						5'd6  : pwm_1=10'b0001_1111_11;
						5'd7  : pwm_1=10'b0011_1111_11;
						5'd8  : pwm_1=10'b0111_1111_11;
						5'd9  : pwm_1=10'b1111_1111_11;
						5'd10  : pwm_1=10'b0111_1111_11;
						5'd11  : pwm_1=10'b0011_1111_11;
						5'd12  : pwm_1=10'b0001_1111_11;
						5'd13  : pwm_1=10'b0000_1111_11;
						5'd14  : pwm_1=10'b0000_0111_11;
						5'd15  : pwm_1=10'b0000_0011_11;
						5'd16  : pwm_1=10'b0000_0001_11;
						5'd17  : pwm_1=10'b0000_0000_11;
					endcase
					$display("pwm_1:  ",pwm_1);
					counter2=0;
				end
				
			else counter2=counter2+1;
			pwm_2=pwm_1[counter2];
	end
	
	assign pwma=pwm_1;
	assign pwmb=pwm_2;
		
endmodule

(2)tb文件:

`timescale 1ns/100ps
module tb_PWM;
	
	reg clk;
	wire [9:0]pwma;
	wire [0:0]pwmb;
	parameter PERIOD=10;
	
	always #(PERIOD/2) clk=~clk;
	
	initial begin
		clk=0;
		# 3000 $stop;
		end
		
PWM PWM_1(.clk(clk),.pwma(pwma), .pwmb(pwmb));


endmodule

(3)仿真结果:

在这里插入图片描述

3、最后大口地呼吸

呼吸灯的硬件实现,和流水灯的硬件实现一样原理,如果每个亮度的时间跟仿真的时候一样的话,那我们是看不出亮度变化,所以在硬件实现的时候需要在每一个亮度延长一定的时间。具体的实现如下:

(1)代码:

module PWM(
						input wire clk,
						output wire led0,
						output wire led1,
						output wire led2,
						output wire led3,
						output wire led4,
						output wire led5,
						output wire led6,
						output wire led7
						);


	reg [4:0]counter1=0;
	reg [3:0]counter2=0;
	reg [9:0]pwm_1=10'b0000_0000_00;
	reg[0:0] pwm_2;
	reg [20:0] cnt_base;
	parameter T_6ms = 21'd2000_000;

 


	always @(posedge clk ) begin
		if(cnt_base < T_6ms - 1'b1)begin
			cnt_base <= cnt_base + 1'b1;
			pwm_2<=pwm_1[cnt_base%10];
		end
		
		else begin
			cnt_base <= 21'd0;
			if(counter1==5'd17)   counter1=0;
			else  counter1=counter1+1;	
			
			case(counter1)
				5'd0  : pwm_1=10'b0000_0000_01;
				5'd1  : pwm_1=10'b0000_0000_11;
				5'd2  : pwm_1=10'b0000_0001_11;
				5'd3  : pwm_1=10'b0000_0011_11;
				5'd4  : pwm_1=10'b0000_0111_11;
				5'd5  : pwm_1=10'b0000_1111_11;
				5'd6  : pwm_1=10'b0001_1111_11;
				5'd7  : pwm_1=10'b0011_1111_11;
				5'd8  : pwm_1=10'b0111_1111_11;
				5'd9  : pwm_1=10'b1111_1111_11;
				5'd10  : pwm_1=10'b0111_1111_11;
				5'd11  : pwm_1=10'b0011_1111_11;
				5'd12  : pwm_1=10'b0001_1111_11;
				5'd13  : pwm_1=10'b0000_1111_11;
				5'd14  : pwm_1=10'b0000_0111_11;
				5'd15  : pwm_1=10'b0000_0011_11;
				5'd16  : pwm_1=10'b0000_0001_11;
				5'd17  : pwm_1=10'b0000_0000_11;
			endcase
		end

	 end
	 
	 	assign led0=pwm_2;
		assign led1=pwm_2;
		assign led2=pwm_2;
		assign led3=pwm_2;
		assign led4=pwm_2;
		assign led5=pwm_2;
		assign led6=pwm_2;
		assign led7=pwm_2;
		
endmodule
		

(2)对应的RTL图:
请添加图片描述
(3)引脚分配与接线
请添加图片描述
接线同上流水灯的接线。

(4)实验现象:
具体实验现象可以看文末😏

FPGA点灯工程师养成记

Forever young,always tearful. 😏

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/13567.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

智慧医院微信小程序定制开发功能有哪些

无论是哪个时代&#xff0c;人们对于医疗资源的需求都没有消退过&#xff0c;尤其是随着经济条件的提高&#xff0c;人们也越来越关注健康问题。无论是生病就诊还是定期体检都要用到医疗资源。但是平时到医院好像什么时候都人满为患&#xff0c;排很长时间的队&#xff0c;不仅…

ChatGPT4 的体验 一站式 AI工具箱 -—Poe(使用教程)

最近由于人工智能聊天机器人的爆火(ChatGPT)&#xff0c;因此各种各样的AI助手流行与网络&#xff0c;各种各样的都有&#xff0c;不论是什么样的其实都是为了我们更方便的解决问题&#xff0c;今天介绍一款AI工具箱——Poe将多种AI集成与一个界面&#xff0c;大家可以一次感受…

SQL Server基础 第五章 函数的使用(日期、字符串、时间、数学、转换等函数)

前言 在SQL Server中提供了许多内置函数&#xff0c;SQL Server中的内置函数就相当于Java、C#等编程语言中的内置API函数。按照函数种类可以分为聚合函数、数学函数、字符串函数、日期函数和时间函数、转换函数和元数据的数6种。在本章中重点讲解比较常用的4种函数&#xff0c…

在线题库整理及一些刷题注意事项

在线题库整理及一些刷题注意事项 刷题站CSDN编程语言支持 LeetCode编程语言支持数据库语言支持 牛客网编程语言支持数据库语言支持 洛谷编程语言支持 AcWing编程语言支持 蓝桥编程语言支持 做题的两种模式调用模式委托模式 注意事项小结 刷题站 老顾一个人单打独斗太久了&…

如何使用ffmpeg给视频减震去抖

之前自己发过一些记录仪拍下来的画面&#xff0c;你们可能已经看过了&#xff0c;例如&#xff1a; 最适合骑行的罐装饮料 然而&#xff0c;自己这个骑行记录仪&#xff0c;仅仅是很低端的一款&#xff0c;防抖功能很差&#xff0c;远远比不了GoPro那些高端的户外运动记录仪&am…

Qt扫盲-QAbstractSeries理论总结

QAbstractSeries理论总结 一、概述二、常用函数1. 属性2. 设置功能3. 显示隐藏4. 与 绘图的交互 三、信号 一、概述 QAbstractSeries类是所有Qt图表线的基类。通常&#xff0c;特定于序列类型的继承类会被使用&#xff0c;而不是这个基类。这个基类只是提供了一些管理和控制这…

再聊 MySQL 聚簇索引

为什么是再次理解呢&#xff1f;因为松哥之前写过相关的文章介绍过聚簇索引&#xff0c;但是感觉还不够&#xff0c;因此今天想再来和小伙伴们聊一聊这个话题。 1. 什么是聚簇索引 数据库的索引从不同的角度可以划分成不同的类型&#xff0c;聚簇索引便是其中一种。 聚簇索引…

数据库基础篇 《4. 运算符》

目录 1. 算术运算符 1&#xff0e;加法与减法运算符 2&#xff0e;乘法与除法运算符 3&#xff0e;求模&#xff08;求余&#xff09;运算符 2. 比较运算符 1&#xff0e;等号运算符 2&#xff0e;安全等于运算符 3&#xff0e;不等于运算符 4. 空运算符 5. 非空运算…

【架构】微前端

文章目录 概述优劣优点缺点 微前端的整体架构微前端部署平台微前端运行时基于 SPA 的微前端架构 应用生命周期 方案qiankun 主应用qiankun微应用Vue 2 微应用 来源 概述 微前端不是单纯的前端框架或者工具&#xff0c;而是一套架构体系&#xff0c;这个概念最早在 2016 年底被…

helm部署相关服务过程中问题记录

在学习helm部署相关服务过程中出现一些相关问题&#xff0c;自己记录并供大家一起学习&#xff01;&#xff01;&#xff01; 【问题1】部署helm 获取软件包失败 在通过wget https://storage.googleapis.com/kubernetes-helm/helm-v2.13.1-linux-amd64.tar.gz文件过程发现无法…

叔可忍婶不可忍!马斯克3月呼吁暂停人工智能,4月却创立TruthGPT

2018年马斯克退出了OpenAI团队。 2022年11月&#xff0c;ChatGPT在北美大陆问世。 2023年3月21日&#xff0c;马斯克在未来生命&#xff0c;签署并呼吁&#xff0c;暂停高级人工智能的研发。 2023年4月18日马斯克创立了TruthGPT。 同时&#xff0c;亚马逊&#xff0c;也创立了B…

RabbitMQ-消息模型

什么是MQ MQ全称是Message Queue,即消息对列&#xff01;消息队列是典型的&#xff1a;生产者、消费者模型。生产者不断向消息队列中生产消息&#xff0c;消费者不断的从队列中获取消息。因为消息的生产和消费都是异步的&#xff0c;而且只关心消息的发送和接收&#xff0c;没…

AttributeError: ‘LTP‘ object has no attribute ‘init_dict‘解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

Nginx专题-基于多网卡的主机配置

文章目录 Nginx 基于多网卡的主机实现一、虚拟机前置环境准备ifcfg-ens32配置文件的内容参考ifcfg-ens33配置文件的内容 二、案例演示修改nginx.conf配置文件解决中文乱码 Nginx 基于多网卡的主机实现 一、虚拟机前置环境准备 点击虚拟机右下角的 红色标框按钮&#xff0c;然后…

设计模式 -- 迭代器模式

前言 月是一轮明镜,晶莹剔透,代表着一张白纸(啥也不懂) 央是一片海洋,海乃百川,代表着一块海绵(吸纳万物) 泽是一柄利剑,千锤百炼,代表着千百锤炼(输入输出) 月央泽,学习的一种过程,从白纸->吸收各种知识->不断输入输出变成自己的内容 希望大家一起坚持这个过程,也同…

Java的对象克隆

本节我们会讨论 Cloneable 接口&#xff0c;这个接口指示一个类提供了一个安全的 clone() 方法。 Object 类提供的 clone() 方法是 “浅拷贝”&#xff0c;并没有克隆对象中引用的其他对象&#xff0c;原对象和克隆的对象仍然会共享一些信息。深拷贝指的是&#xff1a;在对象中…

关于Netty使用中黏包拆包带来报错问题及解决

文章目录 问题现象解决总结 问题现象 业务场景&#xff1a;雷达作为客户端&#xff0c;平台作为服务端&#xff0c;采用TCP/IP协议的socket连接&#xff0c;数据包采用字节的二进制数据传输平台与雷达的通信和数据解析&#xff0c;在我接手时&#xff0c;已经开发完成&#xf…

如何开发一款用户体验优秀的语音交友app?

在数字时代&#xff0c;人们越来越依赖智能手机上的应用程序来与他人进行交流。其中&#xff0c;语音交友app成为了最受欢迎的应用之一。然而&#xff0c;开发一款成功的语音交友app需要深入了解用户需求与体验。本文将探讨如何开发一款用户体验优秀的语音交友app。 着眼于用户…

文心一格,百度AI作画产品

文章目录 AIGC什么是AI作画&#xff1f;Prompt文心一格使用方法注册账号使用AI绘图 AIGC的未来发展结语 AIGC AIGC&#xff08;AI Generated Content&#xff09;是指利用人工智能生成内容。是利用人工智能来生成你所需要的内容&#xff0c;GC的意思是创作内容。与之相对应的概…

Linux-驱动开发-基础温习

一、裸机开发和驱动开发的区别&#xff1a; 裸机开发&#xff1a;底层&#xff08;相对于linux来说&#xff09;&#xff0c;库 二、linux驱动开发-根据各种框架进行开发 1、 外设比较多&#xff0c;资源多&#xff0c;资料非常少&#xff0c;官方的SDK;直接操作寄存器不显示…