1. 实验内容

本实验通过一个简单的LED灯数字设计初步了解数字设计的基本思想,了解FPGA设计的基本流程,熟悉仿真软件ModelSim和综合编译工具Quartus II的使用方法和流程。要求通过FPGA来控制开发平台的核心板上8个LED灯的亮和灭,循环点亮核心板上的8个LED灯,每个LED点亮的时间为200毫秒。

2. 实验原理

图6-1给出了开发平台的核心板上LED灯的连接图。从图中可以看出,LED灯的正极连接到了3.3V,负极通过一个下拉电阻连接到了FPGA的管脚。为了点亮LED灯,连接负极的FPGA管脚必须拉低;为了熄灭LED灯,连接负极的FPGA管脚必须拉高。
|图6 1 LED连接图 为了使LED灯点亮的时间为200ms,那么连接到相应LED负极的FPGA管脚必须拉低200ms。由于核心板上的时钟是50MHz,如果拉低时间为200ms,则需要拉低的时钟周期数为:50,000,000*0.2=10,000,000。为此,需要一个24位(224=16,777,216>10,000,000)的计数器对点亮的时钟周期进行计数,计数器初始值为0,当计数到10,000,000时,则熄灭当前点亮的LED灯,点亮下一个LED灯。 为了分别控制每个LED灯,定义一个8位的寄存器,寄存器中的每一位分别控制一个LED灯,如果寄存器中的某一位设为0,则点亮相应的LED灯;如果某一位设为1,则熄灭相应的LED灯。 在仿真时需要注意的是,由于计数器的计数值非常大,为10,000,000,循环一次要10,000,000个时钟周期,仿真的时间会很长。在仿真的观测时间内很难看到计数器循环一次,所以在仿真时可以降低计数器的计数值,例如计数到10,减少仿真时间,在观测时间内至少应该看到计数器循环一次。

3. 程序设计

为了实现对8个LED灯的控制,设计了状态机State,状态机在不同的状态控制不同LED灯点亮。State有8个状态,每个状态停留200毫秒(图6-2)。
图6 2  State状态机转移图 为了控制状态机在每个状态的停留时间,定义了计数器counter,counter从0~10,000,000循环计数,当计数器循环一次,状态State变迁一次。 整个功能由程序Ledcore.v实现,实现模块ledcore的信号定义如下:

input clk, reset;	//时钟输入clk,同步复位输入reset。
	output reg [7:0] led;  //输出信号,控制LED灯的亮灭。
	reg [2:0] state;   //状态机State定义,7个状态需要3位。
	reg [23:0] counter; //计数器counter定义,24位。

计数机循环计数,到10,000,000-1时归零:

always @(posedge clk)
		if(!reset)
			counter<= 24'b0;
			else
			if(counter == `COUNTER_NUMBER - 1 ) //`COUNTER_NUMBER在文件头定义,在仿真和实际运行时可以使用不同的值。
				counter <= 24'b0;
			else
				counter<= counter+1'b1;

状态机控制逻辑,当计数器循环一次,状态机变迁一次:

always @(posedge clk)
		if(!reset)
			state <= 3'b000;
		else
			if(counter == 24'd0) 
			    state <= state + 1'b1;

组合逻辑,State的不同状态控制不同的Led灯点亮:

always @(state)
			case(state)
				3'b0000 : led = 8'b1111_1110;
				3'b0001 : led = 8'b1111_1101;
				3'b0010 : led = 8'b1111_1011;
				3'b0011 : led = 8'b1111_0111;
				3'b0100 : led = 8'b1110_1111;
				3'b0101 : led = 8'b1101_1111;
				3'b0110 : led = 8'b1011_1111;
				3'b0111 : led = 8'b0111_1111;
			Endcase



4. 仿真结果

在程序仿真之前要设计Testbench,本实验的Testbench设计较为简单,只需要产生时钟和复位,ledtest.v是本程序的Testbench:

module test();
	reg clk,reset;	//需要给led_core产生的时钟和复位。
	wire [7:0] led; //led用于观测输出结果。
 
	led_core led_core( clk, reset ,led );
	initial begin
		clk = 0;
		reset = 0;
		#40 reset = 1; //产生复位。
	end
	always #10 clk=~clk;  //产生时钟。
endmodule

图6-3是用modelsim仿真得到的结果。从图中可以看出,在程序运行的时刻,reset为高时,输出信号LED[7..0]中始终有一个信号为低电平,表示相应的灯亮。由于程序中计数器循环一次的时间太长,所以仿真时不容易看到状态的变化,所以仿真时可以降低计数器的计数值。本例中计数到10时清零。可以看出,计数器计到10时,State的状态转换一次。
图6 3  modelsim仿真结果

5. 演示程序文件说明

文件名功能
led_core.v主程序
ledtest.v仿真Testbench
ledsim.mpfModelSim仿真项目



6. 演示程序使用

演示设备:核心板。
演示方法:将演示程序下载到开发系统后,可以观察到开发系统核心板上的LED灯按顺序依次点亮,reset为复位键。



7 时序波形