【小月电子】安路国产FPGA开发板系统学习教程-LESSON3 LED流水灯

LED流水灯例程讲解

在这里插入图片描述

若要观看该博客配套的视频教程,可点击此链接

根据多年工作经验,总结出的FPGA的设计流程,概括起来总共有以上12步,其中根据项目难易度可省去其中一些步骤。比如非常简单的项目,我们可以省去虚线框里面的步骤,但是我们的入门级课程,即使再简单,也按照这12个步骤来进行讲解。

1. 需求解读

1.1 需求

实现8个LED灯依次点亮,每100ms点亮1个,直到8个LED灯被全部点亮,然后全部熄灭,再依次点亮。

1.2 知识背景

LED灯简介
LED,又名发光二极管。 LED灯工作电流很小(有的仅零点几毫安即可发光) , 抗 冲击和抗震性能好,可靠性高,寿命长。由于这些优点, LED灯被广泛用在仪器仪表 中作指示灯、 液晶屏背光源等诸多领域。不同材料的发光二极管可以发出红、 橙、 黄、 绿、 青、蓝、 紫、白这八种颜色的光。 如下图所示:

在这里插入图片描述

图2.插件LED灯
这种二极管长的一端是阳极,短的那端是阴极。 开发板上板载的是贴片LED灯,实物 如下图所示:

在这里插入图片描述

图3.贴片LED灯
贴片发光二极管的正面一般都有颜色标记,有标记的那端就是阴极。发光二极管与普通二极管一样具有单向导电性。 给它加上阳极正向电压后,通过 5mA左右的电流就可以使二极管发光。 通过二极管的电流越大, 发出的光亮度越强。 不过我们一般将电流限定在3~20mA之间,否则电流过大就会烧坏二极管。

1.3 硬件设计

在这里插入图片描述
在这里插入图片描述

图4.LED灯原理图及PCB

在这里插入图片描述

图5.有源晶振

在这里插入图片描述

图6.按键电路

发光二极管的原理图如上图4所示, LED1到LED8这8个发光二极管的阳 极都连到3.3V上, 阴极分别与FPGA相应的管脚相连。原理图中LED与地 之间的电阻起到限流作用。通过原理图我们可以看出,LED1与FPGA的管脚 L12相连。在PCB图或实物上我们都标注出了管脚号,所以在绑管脚的时候 可以不用看原理图,直接看板上的丝印就可以,如上图PCB图所示。我们只 点亮一个LED灯(LED1),那我们只用关心LED1的管脚号(L12)。当管脚L12 输出低电平时,LED灯便有电流流过,驱动LED灯发光,如果L12输出高电 平,LED灯没有电流流过,LED不发光。

1.4 接口说明

信号名 方向 FPGA管脚号 说明
CLK50M 输入 B10 时钟信号,50MHZ
KEY1 输入 E4 独立按键,按下低电平,当作复位使用
LED1 输出 L12 与LED灯相连,低电平LED灯亮
LED2 输出 T13 与LED灯相连,低电平LED灯亮
LED3 输出 R12 与LED灯相连,低电平LED灯亮
LED4 输出 T12 与LED灯相连,低电平LED灯亮
LED5 输出 P11 与LED灯相连,低电平LED灯亮
LED6 输出 J11 与LED灯相连,低电平LED灯亮
LED7 输出 K11 与LED灯相连,低电平LED灯亮
LED8 输出 G11 与LED灯相连,低电平LED灯亮

总结:通过上述说明,可以将需求解读成,先点亮LED1(100ms),接着点亮LED2(100ms)…最后点亮LED8,然后全部熄灭。再重复上述操作。

2. 绘制理论波形图

在这里插入图片描述
在这里插入图片描述

3.新建TD工程

为了让工程看起来整洁,同时方便工程移植。我们新建4个文件夹,分别是Project,Source,Sim,Doc。

Project — 工程文件夹,里面放的TD工程
Source — 源代码文件夹,里面放的工程源码(.v文件或.vhd文件)
Sim — 仿真文件夹,里面放的仿真相关的文件
Doc — 存放相关资料,比如数据手册,需求文档等

4.编写代码

///
//QQ:3181961725
//TEL/WX:13540738439
//作者:Mr Wang
//模块介绍:实现LED流水灯
///
module led_flow(
	input				rst_n	,//复位信号,低电平有效
	input				clk		,//时钟信号,50MHZ
	output	reg [7:0] 	led		 //LED灯控制信号
	);
	parameter	time_100ms=5000000;//100mS
	//parameter	time_100ms=2500;
	parameter	IDLE	=4'd0;//初始状态
	parameter	S0      =4'd1;//点亮第1个LED灯					
	parameter	S1      =4'd2;//点亮第1.2两个LED灯				
	parameter	S2      =4'd3;//点亮第1.2.3三个LED灯			
	parameter	S3      =4'd4;//点亮第1.2.3.4四个LED灯			
	parameter	S4      =4'd5;//点亮第1.2.3.4.5四个LED灯		
	parameter	S5      =4'd6;//点亮第1.2.3.4.5.6四个LED灯		
	parameter	S6      =4'd7;//点亮第1.2.3.4.5.6.7四个LED灯	
	parameter	S7      =4'd8;//点亮第1.2.3.4.5.6.7.8四个LED灯	
	parameter	S8		=4'd9;//LED灯全部熄灭					
	reg [3:0]	curr_st;
	reg	[24:0]	led0_cnt,led1_cnt,led2_cnt,led3_cnt;
	reg	[24:0]	led4_cnt,led5_cnt,led6_cnt,led7_cnt;
	reg	[24:0]	all_off_cnt;
//状态机跳转
always@(posedge clk or negedge rst_n)begin
	if(!rst_n)
		curr_st<=IDLE;
	else case(curr_st)
		IDLE:curr_st<=S0;
		S0:begin
			if(led0_cnt==time_100ms-1)//当led0_cnt等于time_500ms-1时,跳转到S1状态
				curr_st<=S1;
			else;
		end
		S1:begin
			if(led1_cnt==time_100ms-1)
				curr_st<=S2;
			else;
		end
		S2:begin
			if(led2_cnt==time_100ms-1)
				curr_st<=S3;
			else;
		end
		S3:begin
			if(led3_cnt==time_100ms-1)
				curr_st<=S4;
			else;
		end
		S4:begin
			if(led4_cnt==time_100ms-1)
				curr_st<=S5;
			else;
		end
		S5:begin
			if(led5_cnt==time_100ms-1)
				curr_st<=S6;
			else;
		end
		S6:begin
			if(led6_cnt==time_100ms-1)
				curr_st<=S7;
			else;
		end
		S7:begin
			if(led7_cnt==time_100ms-1)
				curr_st<=S8;
			else;
		end
		S8:begin
			if(all_off_cnt==time_100ms-1)
				curr_st<=S0;
			else;
		end
		default:;
	endcase
end
//led0_cnt计数寄存器
always@(posedge clk or negedge rst_n)begin
	if(!rst_n)
		led0_cnt<=0;
	else if(curr_st==S0)
		led0_cnt<=led0_cnt+1;
	else 
		led0_cnt<=0;
end
//led1_cnt计数寄存器
always@(posedge clk or negedge rst_n)begin
	if(!rst_n)
		led1_cnt<=0;
	else if(curr_st==S1)
		led1_cnt<=led1_cnt+1;
	else 
		led1_cnt<=0;
end
//led2_cnt计数寄存器
always@(posedge clk or negedge rst_n)begin
	if(!rst_n)
		led2_cnt<=0;
	else if(curr_st==S2)
		led2_cnt<=led2_cnt+1;
	else 
		led2_cnt<=0;
end
always@(posedge clk or negedge rst_n)begin
	if(!rst_n)
		led3_cnt<=0;
	else if(curr_st==S3)
		led3_cnt<=led3_cnt+1;
	else 
		led3_cnt<=0;
end
always@(posedge clk or negedge rst_n)begin
	if(!rst_n)
		led4_cnt<=0;
	else if(curr_st==S4)
		led4_cnt<=led4_cnt+1;
	else 
		led4_cnt<=0;
end
always@(posedge clk or negedge rst_n)begin
	if(!rst_n)
		led5_cnt<=0;
	else if(curr_st==S5)
		led5_cnt<=led5_cnt+1;
	else 
		led5_cnt<=0;
end
always@(posedge clk or negedge rst_n)begin
	if(!rst_n)
		led6_cnt<=0;
	else if(curr_st==S6)
		led6_cnt<=led6_cnt+1;
	else 
		led6_cnt<=0;
end
always@(posedge clk or negedge rst_n)begin
	if(!rst_n)
		led7_cnt<=0;
	else if(curr_st==S7)
		led7_cnt<=led7_cnt+1;
	else 
		led7_cnt<=0;
end
always@(posedge clk or negedge rst_n)begin
	if(!rst_n)
		all_off_cnt<=0;
	else if(curr_st==S8)
		all_off_cnt<=all_off_cnt+1;
	else 
		all_off_cnt<=0;
end
//LED灯接口赋值操作
always@(posedge clk or negedge rst_n)begin
	if(!rst_n)
		led<=8'hff;
	else case(curr_st)
		IDLE	:led<=8'hff;
		S0		:led<=8'hfe;
		S1		:led<=8'hfc;
		S2		:led<=8'hf8;
		S3		:led<=8'hf0;
		S4		:led<=8'he0;
		S5		:led<=8'hc0;
		S6		:led<=8'h80;
		S7		:led<=8'h00;
		S8	:led<=8'hff;
		default:;
	endcase
end
endmodule

5.编写仿真测试激励文件

`timescale 1ns/1ns
module led_flow_tb;
	reg	rst_n;
	reg	clk	;
	initial	
		begin
			clk=0;
			rst_n=0;//产生复位激励信号
			#1000
			rst_n=1;//产生复位激励信号
		end
	//产生时钟激励信号
	always #10 clk<=~clk;
	//例化被仿真模块
	led_flow Uled_flow(
	.rst_n	(rst_n),
	.clk	(clk),
	.led    ()
	);
endmodule

6.Modelsim仿真

Modelsim仿真一般有两种方法

  1. 图形化界面仿真,即所有的操作都是在Modelsim软件界面上来完成,该方式的优点是,简单易学,适用于简单的项目,缺点是操作步骤繁琐。

  2. 批处理仿真,这种方式在仿真前需要编写相应的脚本文件,该方式的优点是,一键即可完成仿真,省时省力,缺点是前期需要编写脚本文件。前两讲采用的是图形化界面仿真的方式;为了更贴近工程实际,从这一讲开始,我们就采用批处理方式仿真。具体操作步骤可参考我们的视频教程
    仿真出的波形如下图所示:
    在这里插入图片描述

7.对比波形图

将第二步绘制的理论波形图与第六步Modelsim仿真出来的波形图进行对比,结果一致,说明我们的逻辑设计是正确的。如果发现比对结果不一致,就需要找到不一致的原因,最终要保证对比结果一致。通过对比,理论波形与仿真波形一致,说明功能符合设计要求。

8 添加.v文件

在这里插入图片描述

9 绑定管脚并保存约束文件(.adc)

在这里插入图片描述
在这里插入图片描述

10 编译综合生成BIT文件

在这里插入图片描述

11.下载BIT文件

在这里插入图片描述
在这里插入图片描述

下载成功后,便可以观察到开发板上的实验现象,如果实验现象与设计需求相符,那说明我们的设计是没有问题的,即可进行下一步固化配置文件。

12 固化配置文件

FPGA有一个特性,就是掉电后配置信息会丢失,所以我们需要将配置信息存储在配置芯片(FLASH)中,待开发板上电后,FPGA便会读取配置芯片中的配置信息,这样开发板掉电再上电后同样可正常工作
在这里插入图片描述

固化成功后,开发板断电再重新上电,可以观察到开发板仍然可以执行刚刚的功能。

猜你喜欢

转载自blog.csdn.net/Moon_3181961725/article/details/126778678
今日推荐