• 【小月电子】国产安路FPGA开发板系统学习教程-LESSON9简易测试系统


    简易测试系统例程讲解

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

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

    1. 需求解读

    1.1 需求

    采用C#做一个上位机界面,通过异步串口可控制开发板上的数码管,LED灯,蜂鸣器,同时按下开发板上的按键,可在上位机界面上显示当前被按下是哪个按键。该实验即是一个最简单的工控设备,应用面非常广。

    1.2 知识背景

        串口是“串行接口”的简称,即采用串行通信方式的接口。串行通信将数据字节分成一位一位的形式在一条数据线上逐个传送,其特点是通信线路简单,但传输速度较慢。因此串口广泛应用于嵌入式、工业控制等领域中对数据传输速度要求不高的场合。
        串行通信分为两种方式:同步串行通信和异步串行通信。同步串行通信需要通信双方在同一时钟的控制下,同步传输数据;异步串行通信是指通信双方使用各自的时钟控制数据的发送和接收过程。
        UART是一种采用异步串行通信方式的通用异步收发传输器(universal asynchronous receiver-transmitter),它在发送数据时将并行数据转换成串行数据来传输,在接收数据时将接收到的串行数据转换成并行数据。
        UART串口通信需要两根信号线来实现,一根用于串口发送,另外一根负责串口接收。 UART在发送或接收过程中的一帧数据由4部分组成,起始位、数据位、 奇偶校验位和停止位,具体时序如图1所示。其中,起始位标志着一帧数据的开始,停止位标志着一帧数据的结束,数据位是一帧数据中的有效数据。校验位分为奇校验和偶校验,用于检验数据在传输过程中是否出错。奇校验时,发送方应使数据位中1的个数与校验位中1的个数之和为奇数;接收方在接收数据时,对1的个数进行检查,若不为奇数,则说明数据在传输过程中出了差错。同样,偶校验则检查1的个数是否为偶数。
        UART通信过程中的数据格式及传输速率是可设置的,为了正确的通信,收发双方应约定并遵循同样的设置。数据位可选择为5、 6、 7、 8位,其中8位数据位是最常用的, 在实际应用中一般都选择8位数据位;校验位可选择奇校验、偶校验或者无校验位;停止位可选择1位(默认),1.5或2位。串口通信的速率用波特率表示,它表示每秒传输二进制数据的位数,单位是bps( 位/秒),常用的波特率有9600、19200、38400、57600以及115200等。
        在设置好数据格式及传输速率之后,UART负责完成数据的串并转换,而信号的传输则由外部驱动电路实现。电信号的传输过程有着不同的电平标准和接口规范, 针对异步串行通信的接口标准有RS232、RS422、RS485等,它们定义了接口不同的电气特性,如RS-232是单端输入输出,而RS-422/485为差分输入输出等。
        RS232接口标准出现较早, 可实现全双工工作方式,即数据发送和接收可以同时进行。在传输距离较短时(不超过15m),RS232是串行通信最常用的接口标准,本章主要介绍针对RS-232标准的UART串口通信。
        RS-232标准的串口最常见的接口类型为DB9,样式如图2所示,工业控制领域中用到的工控机一般都配备多个串口,很多老式台式机也都配有串口。但是笔记本电脑以及较新一点的台式机都没有串口,它们一般通过USB转串口线(图3)来实现与外部设备的串口通信。
    在这里插入图片描述

    图1. 异步串口时序图

    在这里插入图片描述

    图2. DB9接头

    在这里插入图片描述

    图3. USB串口线

    DB9接口定义以及各引脚功能说明如图 16.1.4所示,我们一般只用到其中的2(RXD)、3(TXD)、5(GND)引脚,其他引脚在普通串口模式下一般不使用。
    在这里插入图片描述

    图4. DB9接口定义
    波特率9600bps:每秒传输9600bit。 传输1bit的时间为:1/9600(秒)=104167ns 也就是5208个时钟周期,需要采集1次 以上只是介绍串口相关的知识,我们XLOGIC开发板上板载了USB转TTL芯片(CH340),只用一根USB线即可与电脑进行串口通信。

    1.3 硬件设计

    这个系统我们会用到开发板上基本所有的外设,原理图就不截取出来了,大家可以直接看我们提供的开发板原理图

    1.4 接口说明

    信号名方向FPGA管脚号说明
    CLK50M输入B10时钟信号,50MHZ
    FPGA_RX输入H14串口信号输入
    FPGA_TX输出F14串口信号输出
    SMG_W0输出E12位选控制信号,低电平可导通三极管,使其给数码管位选供电
    SMG_W1输出B15位选控制信号,低电平可导通三极管,使其给数码管位选供电
    SMG_W2输出E15位选控制信号,低电平可导通三极管,使其给数码管位选供电
    SMG_W3输出H11位选控制信号,低电平可导通三极管,使其给数码管位选供电
    SMG_W4输出K16位选控制信号,低电平可导通三极管,使其给数码管位选供电
    SMG_W5输出K14位选控制信号,低电平可导通三极管,使其给数码管位选供电
    SMG_A输出F13数码管段选控制信号,低电平点亮该段
    SMG_B输出B16数码管段选控制信号,低电平点亮该段
    SMG_C输出J16数码管段选控制信号,低电平点亮该段
    SMG_D输出J13数码管段选控制信号,低电平点亮该段
    SMG_E输出G14数码管段选控制信号,低电平点亮该段
    SMG_F输出E13数码管段选控制信号,低电平点亮该段
    SMG_G输出G12数码管段选控制信号,低电平点亮该段
    SMG_DP输出J14数码管段选控制信号,低电平点亮该段
    KEY1输出E4独立按键,按下低电平
    KEY2输出B4独立按键,按下低电平
    KEY3输出C3独立按键,按下低电平
    KEY4输出D3独立按键,按下低电平
    KEY5输出E3独立按键,按下低电平
    KEY6输出H4独立按键,按下低电平
    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灯亮
    BEEP输出F14PWM方波,用于驱动无源蜂鸣器

    1.5 通信协议

    这一讲我们需要做一个测试系统,用上位机软件控制我们的开发板,那么就需要拟定控制协议。这个协议是自己定义的,只要保证上位机和下位机的程序都是按这个协议来写的程序就行,这样才能正确控制。

    1. 数码管控制协议-下发(上位机发给下位机)
      在这里插入图片描述
      2.LED灯控制协议-下发(上位机发给下位机)
      在这里插入图片描述
      3.无源蜂鸣器控制协议-下发(上位机发给下位机)
      在这里插入图片描述
      4.按键检测协议-回传(下位机发给上位机
      在这里插入图片描述
      以上便是我们该项目的通信协议,一个很简单的通信协议,起到抛砖引玉的作用,当控制系统复杂时,我们在定协议的时候需要考虑很多的问题。像我们现在这个简单的控制系统,协议非常简单,仅用于大家学习,便于让大家明白一个控制系统是如何工作的。

    2 绘制理论波形图

    在这里插入图片描述

    工程逻辑框图

    由于整个工程涉及到的模块较多,理论波形图就不绘制了。但是大家在写程序之前,一定要清楚每个模块内以及模块与模块之间的信号时序关系,这样在仿真出波形时,才能判断出我们当前的程序逻辑是否正确。不然仿真出了波形,也不知道这个波形对不对,那这个项目就没办法完成了。

    3 新建TD工程

    为了让工程看起来整洁,同时方便工程移植。我们新建4个文件夹,分别是Project,Source,Sim,Doc。
    Project — 工程文件夹,里面放的TD工程
    Source — 源代码文件夹,里面放的工程源码(.v文件或.vhd文件)
    Sim — 仿真文件夹,里面放的仿真相关的文件
    Doc — 存放相关资料,比如数据手册,需求文档等

    4 编写代码

    4.1 按键消抖模块

    ///
    //QQ:3181961725
    //TEL/WX:13540738439
    //工程师:Mr Wang
    //模块介绍:按键消抖模块,主要用来消除按键机械抖动带来的干扰
    ///
    module key_xd(
    		input clk,
    		input rst_n,
    		input key_in,
    		output reg	key_out
    		);
    reg	[3:0] curr_st;
    reg	[31:0] wait_cnt;
    reg		key_in_ff1;
    reg		key_in_ff2;
    parameter wait_time=100000;
    //for sim
    //parameter wait_time=8000;
    parameter IDLE=4'd0,
    					START=4'd1,
    					WAIT=4'd2,
    					KEY_VALID=4'd3,
    					FINISH=4'd4;
    always@(posedge clk)key_in_ff1<=key_in;
    always@(posedge clk)key_in_ff2<=key_in_ff1;
    always@(posedge clk or negedge rst_n)
    	begin
    		if(!rst_n)
    			curr_st<=IDLE;
    		else
    			case(curr_st)
    				IDLE:
    					begin
    						if(key_in_ff2==0)
    							curr_st<=START;
    						else
    							;
    					end
    				START:
    					begin
    						if(key_in_ff2==1)
    							curr_st<=IDLE;
    						else if(wait_cnt==wait_time)
    							curr_st<=WAIT;
    						else
    							;
    					end
    				WAIT:
    					begin
    						if(key_in_ff2==1)
    							curr_st<=IDLE;
    						else if(key_in_ff2==0)
    							curr_st<=KEY_VALID;
    						else
    							curr_st<=IDLE;
    					end
    				KEY_VALID:curr_st<=FINISH;
    				FINISH:
    					begin
    						if(key_in_ff2==1)
    							curr_st<=IDLE;
    						else
    							;
    					end
    				default:curr_st<=IDLE;
    			endcase
    	end
    	always@(posedge clk or negedge rst_n)
    		begin
    			if(!rst_n)
    				wait_cnt<=0;
    			else if(curr_st==START)
    				wait_cnt<=wait_cnt+1;
    			else
    				wait_cnt<=0;
    		end
    	always@(posedge clk or negedge rst_n)
    		begin
    			if(!rst_n)
    				key_out<=0;
    			else if(curr_st==KEY_VALID)
    				key_out<=1;
    			else
    				key_out<=0;
    		end
    	endmodule
    	
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88

    4.2 无源蜂鸣器驱动模块

    ///
    //QQ:3181961725
    //TEL/WX:13540738439
    //工程师:Mr Wang
    //模块介绍:产生PWM波,驱动无源蜂鸣器发声
    ///
    module alarm_ctrl(
    	input	clk,
    	input	rst_n,
    	output	reg	beep
    	);
    	reg	[15:0]	cnt=0;
    	always@(posedge clk or negedge rst_n)begin
    		if(!rst_n)
    			cnt<=0;
    		else if(cnt==10000)
    			cnt<=0;
    		else	
    			cnt<=cnt+1;
    	end
    	always@(posedge clk or negedge rst_n)begin
    		if(!rst_n)
    			beep<=0;
    		else if(cnt==0)
    			beep<=~beep;
    	end
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    4.3 异步串口接收模块

    ///
    //QQ:3181961725
    //TEL/WX:13540738439
    //工程师:Mr Wang
    //模块介绍:串口接收模块,将串行数据转换成并行数据
    ///
    module async_uart_rev(
    	input				rst_n	,//复位信号,低电平有效
    	input				clk		,//时钟信号,50MHZ
    	input				rxd		,//串行接收数据
    	output	reg	[7:0]	rev_data,//并行数据
    	output	reg			rev_dvld //并行数据有效标志
    	);
    	parameter	baud_num=5207;//1/9600*1000000000/20
    	parameter	IDLE		=4'd0;
    	parameter	START_ST    =4'd1;
    	parameter	STOP_ST     =4'd2;
    	reg	[12:0]	baud_cnt;
    	reg			baud_cnt_en;
    	wire		sample_en;
    	reg	[3:0]	sample_num;
    	reg			rxd_ff1;
    	reg			rxd_ff2;
    	reg	[3:0]	curr_st;
    	always@(posedge clk)rxd_ff2<=rxd_ff1;
    	always@(posedge clk)rxd_ff1<=rxd;
    	assign	sample_en=(baud_cnt==baud_num[12:1])?1'b1:1'b0;
    	//状态机跳转程序
    	always@(posedge clk or negedge rst_n)begin
    		if(!rst_n)
    			curr_st<=IDLE;
    		else case(curr_st)
    			IDLE:begin
    				if(rxd_ff2==0)
    					curr_st<=START_ST;
    				else;
    			end
    			START_ST:begin
    				if(sample_num==8&&sample_en)
    					curr_st<=STOP_ST;
    				else;
    			end
    			STOP_ST:begin
    				if(rxd_ff2==1&&sample_en)
    					curr_st<=IDLE;
    				else;
    			end
    			default:;
    		endcase
    	end
    	always@(posedge clk or negedge rst_n)begin
    		if(!rst_n)
    			baud_cnt<=0;
    		else if(curr_st==START_ST||curr_st==STOP_ST)begin
    			if(baud_cnt==baud_num)
    				baud_cnt<=0;
    			else 
    				baud_cnt<=baud_cnt+1;
    		end else
    			baud_cnt<=0;
    	end
    	always@(posedge clk or negedge rst_n)begin
    		if(!rst_n)	
    			sample_num<=0;
    		else if(sample_en&&sample_num==9)
    			sample_num<=0;
    		else if(sample_en)
    			sample_num<=sample_num+1;
    		else;
    	end
    	always@(posedge clk or negedge rst_n)begin
    		if(!rst_n)
    			rev_data<=0;
    		else if(sample_en)
    			case(sample_num)
    			1:rev_data[0]<=rxd_ff2;
    			2:rev_data[1]<=rxd_ff2;
    			3:rev_data[2]<=rxd_ff2;
    			4:rev_data[3]<=rxd_ff2;
    			5:rev_data[4]<=rxd_ff2;
    			6:rev_data[5]<=rxd_ff2;
    			7:rev_data[6]<=rxd_ff2;
    			8:rev_data[7]<=rxd_ff2;
    			default:;
    		endcase
    	end
    	always@(posedge clk or negedge rst_n)begin
    		if(!rst_n)	
    			rev_dvld<=0;
    		else if(sample_num==9&&sample_en)
    			rev_dvld<=1;
    		else
    			rev_dvld<=0;
    	end
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95

    4.4 异步串口发送模块

    ///
    //QQ:3181961725
    //TEL/WX:13540738439
    //工程师:Mr Wang
    //模块介绍:串口发送模块,将并行数据转换成串行数据
    ///
    module async_uart_tran(
    	input			rst_n		,//复位信号,低电平有效
    	input			clk			,//时钟,50MHZ
    	input	[7:0]	tran_data	,//输入的并行数据
    	input			tran_dvld	,//输入的并行数据有效标志
    	output	reg		txd          ,//串行输出数据
    	output			byte_txfini	
    	);
    	parameter	baud_num=5207;//1/9600*1000000000/20
    	parameter	IDLE		=4'd0;
    	parameter	DATA_ST    =4'd1;
    	parameter	START_ST    =4'd2;
    	parameter	STOP_ST     =4'd3;
    	reg	[12:0]	baud_cnt;
    	reg			baud_cnt_en;
    	wire		sample_en;
    	reg	[3:0]	sample_num;
    	reg	[3:0]	curr_st;
    	assign	byte_txfini=(curr_st==STOP_ST&&sample_en)?1'b1:1'b0;
    	assign	sample_en=(baud_cnt==baud_num)?1'b1:1'b0;
    	always@(posedge clk or negedge rst_n)begin
    		if(!rst_n)
    			curr_st<=IDLE;
    		else case(curr_st)
    			IDLE:begin
    				if(tran_dvld==1)
    					curr_st<=START_ST;
    				else;
    			end
    			START_ST:begin
    				if(sample_en==1)
    					curr_st<=DATA_ST;
    			end
    			DATA_ST:begin
    				if(sample_en&&sample_num==8)
    					curr_st<=STOP_ST;
    				else;
    			end
    			STOP_ST:begin
    				if(sample_en==1)
    					curr_st<=IDLE;
    				else;
    			end
    			default:;
    		endcase
    	end
    	always@(posedge clk or negedge rst_n)begin
    		if(!rst_n)
    			baud_cnt<=0;
    		else if(curr_st==START_ST||curr_st==DATA_ST||curr_st==STOP_ST)begin
    			if(baud_cnt==baud_num)
    				baud_cnt<=0;
    			else 
    				baud_cnt<=baud_cnt+1;
    		end else
    			baud_cnt<=0;
    	end
    	always@(posedge clk or negedge rst_n)begin
    		if(!rst_n)	
    			sample_num<=0;
    		else if(curr_st==IDLE)
    			sample_num<=0;
    		else if(sample_en)
    			sample_num<=sample_num+1;
    		else;
    	end
    	always@(posedge clk or negedge rst_n)begin
    		if(!rst_n)
    			txd<=1;
    		else if(sample_en)
    			case(sample_num)
    			0:txd<=1'b0;
    			1:txd<=tran_data[0];
    			2:txd<=tran_data[1];
    			3:txd<=tran_data[2];
    			4:txd<=tran_data[3];
    			5:txd<=tran_data[4];
    			6:txd<=tran_data[5];
    			7:txd<=tran_data[6];
    			8:txd<=tran_data[7];
    			9:txd<=1'b1;
    			default:txd<=1;
    		endcase
    	end
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91

    4.5 指令解析模块

    ///
    //QQ:3181961725
    //TEL/WX:13540738439
    //工程师:Mr Wang
    //模块介绍:将收到的指令按协议解析出来,分别控制数码管,LED灯和蜂鸣器模块
    ///
    module cmd_ctrl(
    	input				clk,
    	input				rst_n,
    	input				rev_dvld,
    	input		[7:0]	rev_data,
    	output	reg	[3:0]	smg_00,
    	output	reg	[3:0]	smg_01,
    	output	reg	[3:0]	smg_02,
    	output	reg	[3:0]	smg_03,
    	output	reg	[3:0]	smg_04,
    	output	reg	[3:0]	smg_05,
    	output	reg	[7:0]	led,
    	output	reg			beep
    	);
    	parameter	IDLE		=4'd0;
    	parameter	CMD0_ST	    =4'd1;
    	parameter	SMG00_ST    =4'd2;
    	parameter	SMG01_ST    =4'd3;
    	parameter	SMG02_ST    =4'd4;
    	parameter	SMG03_ST    =4'd5;
    	parameter	SMG04_ST    =4'd6;
    	parameter	SMG05_ST    =4'd7;
    	parameter	LED_ST      =4'd8;
    	parameter	ALARM_ST    =4'd9;
    	reg	[3:0]	curr_st;
    	always@(posedge clk or negedge rst_n)begin
    		if(!rst_n)begin
    			curr_st<=IDLE;
    		end else case(curr_st)
    			IDLE:begin
    				if(rev_dvld&&rev_data==8'haa)
    					curr_st<=CMD0_ST;
    				else;
    			end
    			CMD0_ST:begin
    				if(rev_dvld&&rev_data==8'h00)//数码管
    					curr_st<=SMG00_ST;
    				else if(rev_dvld&&rev_data==8'h01)//LED灯
    					curr_st<=LED_ST;
    				else if(rev_dvld&&rev_data==8'h02)//蜂鸣器
    					curr_st<=ALARM_ST;
    				else;
    			end
    			SMG00_ST:begin
    				if(rev_dvld)
    					curr_st<=SMG01_ST;
    				else;
    			end
    			SMG01_ST:begin
    				if(rev_dvld)
    					curr_st<=SMG02_ST;
    				else;
    			end
    			SMG02_ST:begin
    				if(rev_dvld)
    					curr_st<=SMG03_ST;
    				else;
    			end
    			SMG03_ST:begin
    				if(rev_dvld)
    					curr_st<=SMG04_ST;
    				else;
    			end
    			SMG04_ST:begin
    				if(rev_dvld)
    					curr_st<=SMG05_ST;
    				else;
    			end
    			SMG05_ST:begin
    				if(rev_dvld)
    					curr_st<=IDLE;
    				else;
    			end
    			LED_ST:begin
    				if(rev_dvld)
    					curr_st<=IDLE;
    				else;
    			end
    			ALARM_ST:begin
    				if(rev_dvld)
    					curr_st<=IDLE;
    				else;
    			end
    			default:;
    		endcase
    	end
    	always@(posedge clk or negedge rst_n)begin
    		if(!rst_n)begin
    			smg_00	<=0;
    			smg_01	<=0;
    			smg_02	<=0;
    			smg_03	<=0;
    			smg_04	<=0;
    			smg_05	<=0;
    		end else if(curr_st==SMG00_ST)begin
    			smg_00<=rev_data;
    		end else if(curr_st==SMG01_ST)begin
    			smg_01<=rev_data;
    		end else if(curr_st==SMG02_ST)begin
    			smg_02<=rev_data;
    		end else if(curr_st==SMG03_ST)begin
    			smg_03<=rev_data;
    		end else if(curr_st==SMG04_ST)begin
    			smg_04<=rev_data;
    		end else if(curr_st==SMG05_ST)begin
    			smg_05<=rev_data;
    		end else;
    	end
    	always@(posedge clk or negedge rst_n)begin
    		if(!rst_n)begin
    			led<=8'hff;
    		end else if(curr_st==LED_ST)
    			led<=rev_data;
    		else;
    	end 
    	always@(posedge clk or negedge rst_n)begin
    		if(!rst_n)
    			beep<=0;
    		else if(curr_st==ALARM_ST)
    			beep<=rev_data[0];
    		else;
    	end
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129

    4.6 通信协议生成模块

    ///
    //QQ:3181961725
    //TEL/WX:13540738439
    //工程师:Mr Wang
    //模块介绍:生成按键检测的通信协议
    ///
    `timescale 1ns/1ps
    module uart_data_gen(
    	input				clk,
    	input				rst_n,
    	input				key0,
    	input				key1,
    	input				key2,
    	input				key3,
    	input				key4,
    	input				key5,
    	input				byte_end,
    	output	reg	[ 7:0]	data,
    	output	reg			data_valid
    	);
    parameter 	idle  			= 8'd0;
    parameter 	word1 			= 8'd1;
    parameter	word1_gap		= 8'd2;
    
    reg	[ 7:0] 	curr_st	;
    reg	[ 7:0] 	word_cnt	;
    reg	[ 7:0]	title		;
    reg			byte_end_ff1;
    wire		byte_end_rise;
    wire[7:0]	data_tmp	;
    assign	byte_end_rise=byte_end&(!byte_end_ff1);	
    always@(posedge clk)byte_end_ff1<=byte_end;
    always@(posedge clk or negedge rst_n)
    	begin
    		if(!rst_n)
    			title<=8'hff;
    		else if(key0)
    			title<=8'h00;
    		else if(key1)
    			title<=8'h01;
    		else if(key2)
    			title<=8'h02;
    		else if(key3)
    			title<=8'h03;
    		else if(key4)
    			title<=8'h04;
    		else if(key5)
    			title<=8'h05;
    		else;
    	end
    always@(posedge clk or negedge rst_n)
    	begin
    		if(!rst_n)
    			curr_st<=idle;
    		else case(curr_st)
    			idle:
    				begin
    					if(key0||key1||key2||key3||key4||key5)
    						curr_st<=word1;
    					else
    						;
    				end
    			word1:
    				begin	
    					if(word_cnt==2)
    						curr_st<=word1_gap;
    					else
    						;
    				end
    			word1_gap:curr_st<=idle;
    			default:;
    		endcase			
    	end
    always@(posedge clk or negedge rst_n)
    	begin
    		if(!rst_n)
    			word_cnt<=0;
    		else if(curr_st==idle||curr_st==word1_gap)
    			word_cnt<=0;
    		else if((curr_st==word1)&byte_end)
    			word_cnt<=word_cnt+1;
    		else
    			;
    	end
    always@(posedge clk or negedge rst_n)
    	begin
    		if(!rst_n)
    			begin
    				data<=0;
    				data_valid<=0;
    			end
    		else case({curr_st,word_cnt})
    		    
    			{word1,8'h0}:begin data<=8'haa ;data_valid<=1;end
    			{word1,8'h1}:begin data<=title;data_valid<=1;end
    			default:  begin data<=8'h00;data_valid<=0;end
    		endcase
    	end	
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99

    4.7 数码管显示模块

    ///
    //QQ:3181961725
    //TEL/WX:13540738439
    //工程师:Mr Wang
    //模块介绍:数码管动态扫描
    ///
    module smg(
    	input				clk		,//时钟
    	input				rst_n	,//复位,低电平有效
    	input		[3:0] 	swan	,//十万位数
    	input		[3:0] 	wan		,//万位数
    	input		[3:0] 	qian	,//千位数
    	input		[3:0] 	bai		,//百位数
    	input		[3:0] 	shi		,//十位数
    	input		[3:0] 	ge		,//个位数
    	output 	reg	[5:0]	sm_bit	,//数码管选择输出引脚
    	output 	reg	[7:0] 	sm_seg	 //数码管段输出引脚
    	);
    	
    	reg	[ 3:0]	disp_dat;//定义显示数据寄存器
    	reg	[24:0]	count	;//定义计数寄存器
    //扫描信号产生部分
    always @(posedge clk or negedge rst_n)//定义clock上升沿触发
    begin
    	if(!rst_n)
    		count<=0;
    	else if(count == 25'd250000)
    		count <= 25'd0;						//计数器清零
    	else
    		count <= count + 1'b1;
    end	
    //数码管动态扫描显示部分
    always @(posedge clk or negedge rst_n)   					
    begin
    	if(!rst_n)
    		disp_dat<=0;
    	else case(count[15:13])//选择扫描显示数据
    		3'd0:disp_dat <= ge		;//个位
    		3'd1:disp_dat <= shi	;//十位
    		3'd2:disp_dat <= bai	;//百位
    		3'd3:disp_dat <= qian	;//千位
    		3'd4:disp_dat <= wan	;//万位
    		3'd5:disp_dat <= swan	;//十万位
    	endcase
    end
    always @(posedge clk)   			
    begin
    	case(count[15:13])			 //选择扫描显示数据
    		3'd0:sm_bit <= 6'b111110;//选择第一个数码管显示
    		3'd1:sm_bit <= 6'b111101;//选择第二个数码管显示
    		3'd2:sm_bit <= 6'b111011;//选择第三个数码管显示
    		3'd3:sm_bit <= 6'b110111;//选择第四个数码管显示
    		3'd4:sm_bit <= 6'b101111;//选择第五个数码管显示
    		3'd5:sm_bit <= 6'b011111;//选择第六个数码管显示
    	endcase	
    end
    always @(posedge clk)
    begin
    	case(disp_dat)
    		4'h0:sm_seg <= 8'hc0;	//显示0
    		4'h1:sm_seg <= 8'hf9;	//显示1
    		4'h2:sm_seg <= 8'ha4;	//显示2
    		4'h3:sm_seg <= 8'hb0;	//显示3
    		4'h4:sm_seg <= 8'h99;	//显示4
    		4'h5:sm_seg <= 8'h92;	//显示5
    		4'h6:sm_seg <= 8'h82;	//显示6
    		4'h7:sm_seg <= 8'hf8;	//显示7
    		4'h8:sm_seg <= 8'h80;	//显示8
    		4'h9:sm_seg <= 8'h90;	//显示9
    		4'ha:sm_seg <= 8'hbf;	//显示-
    		default:sm_seg <= 8'hff;//不显示
    	endcase
    end
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74

    4.8 顶层模块

    ///
    //QQ:3181961725
    //TEL/WX:13540738439
    //工程师:Mr Wang
    //模块介绍:顶层模块,例化各个功能模块,使工程看起来整洁清晰
    ///
    module ctrl_system_top(
    	input			clk			,
    	input			rst_n		,
    	input	[5:0]	key			,
    	input			uart_rxd	,
    	output			uart_txd	,
    	output	[5:0]	sm_bit		,
    	output	[7:0]	sm_seg		,
    	output	[7:0]	led			,
    	output			alarm
    	);
    wire	[7:0]	rev_data;
    wire 	[3:0]	smg_00	;
    wire 	[3:0]	smg_01  ;
    wire 	[3:0]	smg_02  ;
    wire 	[3:0]	smg_03  ;
    wire 	[3:0]	smg_04  ;
    wire 	[3:0]	smg_05  ;
    wire	[7:0]	tran_data;
    wire			beep;
    wire			beep_en;
    wire			key0_out,key1_out,key2_out,key3_out,key4_out,key5_out;
    assign	alarm=(beep_en)?beep:1'b1;
    key_xd Ukey_xd0(
    	.clk	(clk		),
    	.rst_n	(rst_n		),
    	.key_in	(key[0]		),
    	.key_out(key0_out	)
    	);
    key_xd Ukey_xd1(
    	.clk	(clk		),
    	.rst_n	(rst_n		),
    	.key_in	(key[1]		),
    	.key_out(key1_out	)
    	);
    key_xd Ukey_xd2(
    	.clk	(clk		),
    	.rst_n	(rst_n		),
    	.key_in	(key[2]		),
    	.key_out(key2_out	)
    	);
    key_xd Ukey_xd3(
    	.clk	(clk		),
    	.rst_n	(rst_n		),
    	.key_in	(key[3]		),
    	.key_out(key3_out	)
    	);
    key_xd Ukey_xd4(
    	.clk	(clk		),
    	.rst_n	(rst_n		),
    	.key_in	(key[4]		),
    	.key_out(key4_out	)
    	);
    key_xd Ukey_xd5(
    	.clk	(clk		),
    	.rst_n	(rst_n		),
    	.key_in	(key[5]		),
    	.key_out(key5_out	)
    	);
    async_uart_rev Uasync_uart_rev(
    	.rst_n		(rst_n),
    	.clk		(clk),
    	.rxd		(uart_rxd),
    	.rev_data	(rev_data),
    	.rev_dvld   (rev_dvld)
    	);
    cmd_ctrl Ucmd_ctrl(
    	.clk		(clk		),
    	.rst_n		(rst_n		),
    	.rev_dvld	(rev_dvld	),
    	.rev_data	(rev_data	),
    	.smg_00		(smg_00		),
    	.smg_01		(smg_01		),
    	.smg_02		(smg_02		),
    	.smg_03		(smg_03		),
    	.smg_04		(smg_04		),
    	.smg_05		(smg_05		),
    	.led		(led		),
    	.beep       (beep_en    )
    	);
    smg Usmg(
    	.clk		(clk		),//时钟
    	.rst_n		(rst_n		),//复位,低电平有效
    	.swan		(smg_00		),//十万位数
    	.wan		(smg_01		),//万位数
    	.qian		(smg_02		),//千位数
    	.bai		(smg_03		),//百位数
    	.shi		(smg_04		),//十位数
    	.ge			(smg_05		),//个位数
    	.sm_bit		(sm_bit		),//数码管选择输出引脚
    	.sm_seg	 	(sm_seg		)//数码管段输出引脚
    	);
    alarm_ctrl Ualarm_ctrl(
    	.clk		(clk),
    	.rst_n		(rst_n),
    	.beep       (beep)
    	);
    uart_data_gen Uuart_data_gen(
    	.clk		(clk),
    	.rst_n		(rst_n),
    	.key0		(key0_out),
    	.key1		(key1_out),
    	.key2		(key2_out),
    	.key3		(key3_out),
    	.key4		(key4_out),
    	.key5		(key5_out),
    	.byte_end	(byte_txfini),
    	.data		(tran_data),
    	.data_valid (tran_dvld)
    	);
    async_uart_tran Uasync_uart_tran(
    	.rst_n		(rst_n),//复位信号,低电平有效
    	.clk		(clk),//时钟,50MHZ
    	.tran_data	(tran_data),//输入的并行数据
    	.tran_dvld	(tran_dvld),//输入的并行数据有效标志
    	.txd        (uart_txd), //串行输出数据
    	.byte_txfini(byte_txfini)
    	);
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125

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

    我们知道,写仿真激励文件时,只关心输入信号,在该项目中,输入信号有clk,rst_n,key[5:0],uart_rxd,所以我们只需要在TB文件里对这几个信号操作即可。clk,rst_n,key[5:0],这几个信号的激励比较简单,在上几讲里都有涉及到,只是uart_rxd这个信号的激励相对来说要麻烦一些。因为,我们必须按异步串口通信的协议给这个uart_rxd赋值,相当于我们在TB文件里面要写一个串口发送模块,这样才能产生一个正确的uart_rxd激励信号。

    5.1 顶层仿真文件

    `timescale 1ns/1ns
    module async_uart_top_tb;
    	reg					clk		;
    	reg					rst_n	;
    	reg	[5:0]			key		;
    	wire				rxd		;
    	reg	[17:0]			cnt=0;
    	wire[7:0]			tran_data;
    initial
    begin
    	clk = 0;
    	rst_n=0;
    	key=6'h3f;
    	#1000
    	rst_n=1;
    end
    always #10 clk=~clk;
    always@(posedge clk)cnt<=cnt+1;
    always@(posedge clk)begin
    	if(cnt>10000&&cnt<20000)//按下KEY1
    		key<=6'b111110;
    	else
    		key<=6'b111111;
    end
    //生成通信协议数据
    uart_data_gen_sim Uuart_data_gen_sim(
    	.clk		(clk		),
    	.rst_n		(rst_n		),
    	.byte_end	(byte_txfini),
    	.data		(tran_data	),
    	.data_valid (tran_dvld	)
    	);
    //将通信协议以串口的形式发送出去
    async_uart_tran Uasync_uart_tran(
    	.rst_n		(rst_n		),
    	.clk		(clk		),
    	.tran_data	(tran_data	),
    	.tran_dvld	(tran_dvld	),
    	.txd        (rxd		),
    	.byte_txfini(byte_txfini)
    	);
    //被仿真的工程顶层文件
    ctrl_system_top Uctrl_system_top(
    	.clk			(clk	),
    	.rst_n			(rst_n	),
    	.key			(key	),
    	.uart_rxd		(rxd	),
    	.uart_txd		(),
    	.sm_bit			(),
    	.sm_seg			(),
    	.led			(),
    	.alarm          ()
    	);
    endmodule
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55

    5.2 通信协议生成模块

    该模块主要用于生成数码管控制协议,LED灯控制协议和蜂鸣器控制协议,在我们仿真时,一次只能仿真一个控制协议,如果我们仿真数码管控制协议就需要在程序中注释掉LED灯控制协议和蜂鸣器控制协议。

    `timescale 1ns/1ps
    module uart_data_gen_sim(
    	input				clk,
    	input				rst_n,
    	input				byte_end,
    	output	reg	[ 7:0]	data,
    	output	reg			data_valid
    	);
    parameter 	idle  			= 8'd0;
    parameter 	word1 			= 8'd1;
    parameter	word1_gap		= 8'd2;
    parameter	word_num		=8;//控制数码管的协议为8个字节
    //parameter	word_num		=3;//控制LED灯和蜂鸣器的协议为3个字节
    reg	[ 7:0] 	curr_st	;
    reg	[ 7:0] 	word_cnt	;
    reg	[ 7:0]	title		;
    reg			byte_end_ff1;
    wire		byte_end_rise;
    wire[7:0]	data_tmp	;
    assign	byte_end_rise=byte_end&(!byte_end_ff1);	
    always@(posedge clk)byte_end_ff1<=byte_end;
    always@(posedge clk or negedge rst_n)
    	begin
    		if(!rst_n)
    			curr_st<=idle;
    		else case(curr_st)
    			idle:curr_st<=word1;
    			word1:
    				begin	
    					if(word_cnt==word_num)
    						curr_st<=word1_gap;
    					else
    						;
    				end
    			word1_gap:;//curr_st<=idle;
    			default:;
    		endcase			
    	end
    always@(posedge clk or negedge rst_n)
    	begin
    		if(!rst_n)
    			word_cnt<=0;
    		else if(curr_st==idle||curr_st==word1_gap)
    			word_cnt<=0;
    		else if((curr_st==word1)&byte_end)
    			word_cnt<=word_cnt+1;
    		else
    			;
    	end
    always@(posedge clk or negedge rst_n)
    	begin
    		if(!rst_n)
    			begin
    				data<=0;
    				data_valid<=0;
    			end
    		else case({curr_st,word_cnt})
    		    /控制数码管/
    			{word1,8'h0}:begin data<=8'haa;data_valid<=1;end
    			{word1,8'h1}:begin data<=8'h00;data_valid<=1;end
    			{word1,8'h2}:begin data<=8'h01;data_valid<=1;end//第一位数码管显示的值
    			{word1,8'h3}:begin data<=8'h02;data_valid<=1;end//第二位数码管显示的值
    			{word1,8'h4}:begin data<=8'h03;data_valid<=1;end//第三位数码管显示的值
    			{word1,8'h5}:begin data<=8'h04;data_valid<=1;end//第四位数码管显示的值
    			{word1,8'h6}:begin data<=8'h05;data_valid<=1;end//第五位数码管显示的值
    			{word1,8'h7}:begin data<=8'h06;data_valid<=1;end//第六位数码管显示的值
    			/控制LED灯/
    			// {word1,8'h0}:begin data<=8'haa;data_valid<=1;end
    			// {word1,8'h1}:begin data<=8'h01;data_valid<=1;end
    			// {word1,8'h2}:begin data<=8'hfe;data_valid<=1;end//点亮第一个LED灯
    			/控制蜂鸣器/
    			// {word1,8'h0}:begin data<=8'haa;data_valid<=1;end
    			// {word1,8'h1}:begin data<=8'h02;data_valid<=1;end
    			// {word1,8'h2}:begin data<=8'h01;data_valid<=1;end//打开蜂鸣器
    			default:  begin data<=8'h00;data_valid<=0;end
    		endcase
    	end	
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78

    6. Modelsim仿真

    Modelsim仿真一般有两种方法,第一种是图形化界面仿真,即所有的操作都是在Modelsim软件界面上来完成,该方式的优点是,简单易学,适用于简单的项目,缺点是操作步骤繁琐。第二种是批处理仿真,这种方式在仿真前需要编写相应的脚本文件,该方式的优点是,一键即可完成仿真,省时省力,缺点是前期需要编写脚本文件。为了更贴近工程实际,从第三课开始采用批处理的方式进行仿真。

    6.1 数码管控制仿真波形如下:

    在这里插入图片描述

    通过上面的仿真波形我们可以看到,smg_00等于1,smg_01等于2…smg_05等于6,在通信协议生成模块(uart_data_gen_sim.v)中,我们给数码管赋值也是123456,仿真结果与设计相符,逻辑功能正确。

    6.2 LED灯控制

    在这里插入图片描述

    通过上面的仿真波形我们可以看到,led等于8’b11111110,在通信协议生成模块(uart_data_gen_sim.v)中,我们给LED灯赋值也是8’b11111110,仿真结果与设计相符,逻辑功能正确。

    6.3 蜂鸣器控制

    在这里插入图片描述
    通过上面的仿真波形我们可以看到,alarm输出了PWM方波信号,在通信协议生成模块(uart_data_gen_sim.v)中,我们给蜂鸣器赋值也是8’h01,即打开蜂鸣器,仿真结果也看到了有PWM信号输出,与设计相符,逻辑功能正确。

    7.对比波形图

    由于我们没有绘制理论波形,所以只需要在仿真时,确保仿真波形没问题就可以

    8 添加.v文件

    在这里插入图片描述

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

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

    10 编译综合生成BIT文件

    在这里插入图片描述

    11.下载BIT文件

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

    下载成功后,便可以与我们的上位机测试软件进行通信,具体操作步骤如下
    1)安装串口驱动
    2)将电源线一端接入电脑USB接口 ,一端接入开发板供电口
    3)下载FPGA程序
    4)打开《开发板测试平台.exe》可执行文件
    5)如果串口驱动安装成功,上位机会自动识别端口号,波特率选择9600,然后开启连接,如下图:
    在这里插入图片描述
    6)连接成功后,即可进行开发板控制,可更改数码管显示的数字,设置好以后,点击设置按钮,开发板上便显示上位机设置的数字
    在这里插入图片描述
    7)按下开发板上的按键,可显示当前按下的按键,如下图:
    在这里插入图片描述
    8)LED灯控制时,当打开开发板上的LED时,对应的按钮会变成红色,表示打开了对应的LED灯,如下图表示LED0,LED2,LED4被点亮。
    在这里插入图片描述
    9)按下蜂鸣器按钮,蜂鸣器报警,再按一次,报警关闭。
    以上测试没问题就说明我们的程序是OK的,可以固化程序。

    12 固化配置文件

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

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

  • 相关阅读:
    论文学习——降雨场次划分方法对降雨控制率的影响分析
    python使用unittest进行单元测试
    startActivityForResult废弃了,用Activity Result API吧
    【clickhouse】一个性能问题,把一个中间件从头到位翻了个遍
    大模型多跳推理有解啦,北大化繁为简,用30B模型击败百亿模型
    利用回溯解决子集II遇到的二维数组去重问题
    使用iperf3测试远程服务器之间的带宽和延迟
    「Spring Boot 系列」08. Spring Boot整合MyBatis
    DETR纯代码分享(三)coco_panoptic.py
    Zookeeper原理(data tree结构、工作原理、架构、应用场景)
  • 原文地址:https://blog.csdn.net/Moon_3181961725/article/details/126819400