FPGA 30 综合数字ADC /DAC 信号发送采集系统设计(综合项目设计)_ide

FPGA 30 综合数字ADC /DAC 信号发送采集系统设计(综合项目设计)

FPGA 30 综合数字ADC /DAC 信号发送采集系统设计(综合项目设计)_verilog_02

模块名称 : 综合数字ADC /DAC 信号发送采集系统设计

主要功能 :本实验设计了一个信号发送和采集系统的设计,在整个系统中,基于原先学习的key_filter 按键滤波模块,adc_12s022 模数转换驱动模块,dac_tlv5618 数模转换驱动模块,DAC_rom_siganl 信号rom存储器控制器模块,FIFO模块、FIFO_send_ctrl FIFO发送控制模块和uart_tx 串口发送模块构成了整个综合的实验系统。

输入信号有 : Key_in 、 Clk 、 Rst_n、 ADC_DOUT

输出信号有 :Rs232_Tx 、 ( ADC_CS_N 、ADC_DIN、ADC_SCLK) ( DAC_SCLK、DAC_DIN、DAC_CS_N)。

实现功能(设计思想/流程)是: 通过按键Key_in 按下,按键滤波以后,通过接收按键标志信号(key_flag) 和 按键状态信号(key_state) 输出给 按键控制采样模块,该模块通过判断FIFO数据是否已满、AD转换是否已经完成整这个3个信号来输出Ad_En_Conv 信号,即判断是否启动ADC 驱动模块开始电压(信号),并且内部该模块实现连续的100次采集,采集100次的数据信号,存储在中间的FIFO中,同时,本次使用的FIFO是一个单时钟,输入输出位宽相同的FIFO,在fifo_send_ctrl 模块,通过FIFO模块的FIFO_almost_empty 和 empty 信号输入给fifo_send_ctrl 模块,并且将器转换为标准的8bit发送的串口格式数据发送给uart_byte_tx 模块。此外,我们的信号也是通过fpga的rom资源来存储信号,并设计控制模块,驱动设计的dac_tlv5618 数模转换模块,并在外部的模拟信号连接到adc_128s022 的我们设定的采样通道。配合上半部分的电路连接,进而完成整个系统的设计。

1、首先实现整个系统设计图的下半部分

即:DAC信号存储控制模块的设计 DAC_rom_signal.v

module DAC_rom_signal
(
	Clk,
	Rst_n,
	DAC_State,
	
	DAC_DATA,
	Data_Start
);

	input Clk ;
	input Rst_n;
	input DAC_State;
	
	output [15:0]DAC_DATA;
	output reg Data_Start;
		
	reg [11:0]address;
	wire clock ;
	wire [11:0]q;
	
	
	DAC_rom	DAC_rom0(
		.address(address),
		.clock(clock),
		.q(q)
		
		);

 
	reg [31:0]timer_cnt ;
	reg  timer_full_flag ; 
	parameter Timer_Cnt_Full = 5_000_000 ;  // 0.01s 循环定时 // 1S 循环计时 50_000_000  3s 150_000_000 clk div parameter
	 
	reg  r_Data_Start ; // 信号延时一个时钟
	
	// 定时器脉冲信号
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		timer_cnt <= 32'd0;
	else if(timer_cnt == (Timer_Cnt_Full - 1'b1))
		timer_cnt <= 32'd0 ; //定时计数器清零
	else
		timer_cnt <= timer_cnt + 1'b1 ;
	
	// timer_full_flag
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		timer_full_flag <= 1'd0;
	else if(timer_cnt == (Timer_Cnt_Full - 1'b1))
		timer_full_flag <= 1'd1;
	else
		timer_full_flag <= 1'd0;
		
	assign  clock = timer_full_flag ;
	

	
	// reg [3:0]address ; 
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		address <= 4'd0 ;
	else if(timer_full_flag)
		address <= address +1'b1; // address 到 4095后会自动清零,相当于循环
	else
		address <= address ;
		
	
	// Data_Start 	DAC_DATA <= 1'b0;
	// 启动信号延时一个时钟周期 reg r_Data_Start ;
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		r_Data_Start <= 1'b0 ;
	else if(timer_full_flag && DAC_State)
		r_Data_Start <= 1'b1 ;
	else
		r_Data_Start <= 1'b0 ;		
		
	// 延时一个时钟节拍,保证信号可以跟新当前的DA数据
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		Data_Start <= 1'b0 ;
	else
		Data_Start <= r_Data_Start ;
	
		
	
	assign DAC_DATA = {4'b0100,q} ;  // 4'b0100 ,给通道1 发送信号



endmodule


第2步 、dac_tlv5618.v dac芯片驱动设计

module dac_tlv5618
(
	Clk,
	Rst_n,
	
	DAC_DATA,
	Start,
	Set_Done,
	
	DAC_CS_N,
	DAC_DIN,
	DAC_SCLK,
	DAC_State
);

	input Clk;
	input Rst_n;
	
	input [15:0]DAC_DATA;
	input Start;
	output reg Set_Done;
	
	
	output reg DAC_CS_N;
	output reg DAC_DIN;
	output reg DAC_SCLK;
	output DAC_State;
	
	assign DAC_State = DAC_CS_N;
	
	reg en;
	parameter DIV_PARAM = 2 ; //  clk div parameter
	reg [3:0]DIV_CNT;
	reg SCLK2X;
	reg [5:0]SCLK_GEN_CNT ;   // 状态机半周期计数个数
	
	wire trans_done ;
	// clk_div
	// 
	reg [15:0]r_DAC_DATA ;
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		r_DAC_DATA <= 16'd0;
	else if(Start)
		r_DAC_DATA <= DAC_DATA;
	else
		r_DAC_DATA <= r_DAC_DATA;
	
	
	// en singal handle
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		en <= 1'b0;
	else if(Start)
		en <= 1'b1 ;
	else if(trans_done)
		en <= 1'b0;
	else
		en <= en ;
	
	// div_clk --> 12.5Mhz
	// reg [3:0]DIV_CNT;
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		DIV_CNT <= 4'd0;
	else if(en)
		begin
			if(DIV_CNT == DIV_PARAM -1'b1)
				DIV_CNT <= 4'd0;
			else
				DIV_CNT <= DIV_CNT + 1'd1;
		end
	else
		DIV_CNT <= 4'd0;
		
	//生成2倍SCLK使能脉冲,时钟计数器 
	//reg SCLK2X;
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		SCLK2X <= 1'b0 ;
	else if(en && (DIV_CNT == (DIV_PARAM -1'b1) )) // must add en singal 
		SCLK2X <= 1'b1;
	else 
		SCLK2X <= 1'b0;
	
	//  状态机半周期计数
	//  reg [5:0]SCLK_GEN_CNT ;
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		SCLK_GEN_CNT <= 6'd0;
	else if(SCLK2X && en)
		begin
			if(SCLK_GEN_CNT == 6'd33)
				SCLK_GEN_CNT <= 6'd0;
			else
				SCLK_GEN_CNT <= SCLK_GEN_CNT +1'b1 ;
		end
	else
		SCLK_GEN_CNT  <= SCLK_GEN_CNT ;
		
	
	// state machine handle
	//  	DAC_CS_N;  DAC_DIN;   DAC_SCLK;
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		begin
		DAC_CS_N <= 1'd1;	
		DAC_DIN  <= 1'd0;
		DAC_SCLK <= 1'd1;
		end
	else if(SCLK2X && (!Set_Done)) 
		begin
		case(SCLK_GEN_CNT)

			0  :  begin  DAC_CS_N <= 1'b0 ; DAC_SCLK <= 1'b1 ; DAC_DIN <= r_DAC_DATA[15];  end
			2  :  begin  DAC_SCLK <= 1'b1 ; DAC_DIN <= r_DAC_DATA[14];  end
			4  :  begin  DAC_SCLK <= 1'b1 ; DAC_DIN <= r_DAC_DATA[13];  end
			6  :  begin  DAC_SCLK <= 1'b1 ; DAC_DIN <= r_DAC_DATA[12];  end
			8  :  begin  DAC_SCLK <= 1'b1 ; DAC_DIN <= r_DAC_DATA[11];  end
			10 :  begin  DAC_SCLK <= 1'b1 ; DAC_DIN <= r_DAC_DATA[10];  end
			12 :  begin  DAC_SCLK <= 1'b1 ; DAC_DIN <= r_DAC_DATA[9];  end
			14 :  begin  DAC_SCLK <= 1'b1 ; DAC_DIN <= r_DAC_DATA[8];  end
			16 :  begin  DAC_SCLK <= 1'b1 ; DAC_DIN <= r_DAC_DATA[7];  end
			18 :  begin  DAC_SCLK <= 1'b1 ; DAC_DIN <= r_DAC_DATA[6];  end
			20 :  begin  DAC_SCLK <= 1'b1 ; DAC_DIN <= r_DAC_DATA[5];  end
			22 :  begin  DAC_SCLK <= 1'b1 ; DAC_DIN <= r_DAC_DATA[4];  end
			24 :  begin  DAC_SCLK <= 1'b1 ; DAC_DIN <= r_DAC_DATA[3];  end
			26 :  begin  DAC_SCLK <= 1'b1 ; DAC_DIN <= r_DAC_DATA[2];  end
			28 :  begin  DAC_SCLK <= 1'b1 ; DAC_DIN <= r_DAC_DATA[1];  end
			30 :  begin  DAC_SCLK <= 1'b1 ; DAC_DIN <= r_DAC_DATA[0];  end
			32	:	begin  DAC_SCLK <= 1'b1 ; end
			33 :  begin  DAC_CS_N <= 1'b1 ; end
			1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31: begin DAC_SCLK <= 1'b0 ; end
			default: ;
		endcase
		end
	
	assign trans_done = (SCLK_GEN_CNT == 33) && SCLK2X ;
	
	// Set_Done handle
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		Set_Done <= 1'b0;
	else if(trans_done)
		Set_Done <= 1'b1;
	else
		Set_Done <= 1'b0;


endmodule

通过1、2步骤,可以实现连续信号发生器的设计。

第3部分 按键滤波模块 key_filter.v

//定义按键函数端口
module key_filter(
	Clk ,
	Rst_n ,
	key_in ,
	
	key_flag, //检测按键成功信号
	key_state //实时的信号
);

	input Clk ;
	input Rst_n ;
	input key_in ;
	
	output reg key_flag ;
	output reg key_state ;
	

	//定义状态机
	localparam
		IDEL   	= 4'b0001 ,
		FILTER0	= 4'b0010 ,
		DOWN 	 	= 4'b0100 ,
		FILTER1	= 4'b1000 ;
	

	//定义使用到的寄存器
	reg [3:0]state ;
	
	reg key_tmp0 , key_tmp1 ; // key_in 的状态寄存器
	wire pedge , nedge ;
	
		
	reg en_cnt_20ms ;
	reg [19:0]cnt_20ms ;
	reg cnt_20ms_full ;
	
	//对外部输入的异步信号key_in进行同步处理
	reg key_in_sa,key_in_sb;
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)begin
		key_in_sa <= 1'b0;
		key_in_sb <= 1'b0;
	end
	else begin
		key_in_sa <= key_in;
		key_in_sb <= key_in_sa;	
	end
	
	//获取上一个周期的 按键电平 和当前 按键电平
	//目的: 获取 按键状态判断是否是下降沿还是上升沿到来
	always@(posedge Clk or negedge Rst_n)
	if(Rst_n == 1'b0) begin
		key_tmp0 <= 1'b0 ;
		key_tmp1 <= 1'b0 ;
	end
	else begin //每次时钟上升沿到来,两个寄存器读取上一次的数据的值
		key_tmp0 <= key_in_sb;
		key_tmp1 <= key_tmp0;	
	end	
	
	// 下降沿和上升沿到来标志位信号
	assign nedge = ((~key_tmp0 ) & ( key_tmp1)) ; //判断下降沿是否到来?  
	//分析::  下降沿到来的清况是高电平-->低电平的变换过程,也就是说:
	//	key_tmp1 存的前1个时刻的电平,
	// key_tmp0 存的是当前时刻的电平,
	// 要满足该条件,也就是说, key_tmp0 <= 0 且 key_tmp1 <= 1; 此时得到 nedge = 1 ;
	assign pedge = key_tmp0 & (!key_tmp1) ; //判断上升沿是否到来?	
	
	//状态机判断
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n) //复位状态下,状态机处于空闲状态 
		begin	
			state <= IDEL ;		    //复位状态下,状态机处于空闲模式下
			en_cnt_20ms <= 1'b0 ; //消抖计数器关闭
			key_flag  <= 1'b0 ;	 //按键成功标志位清零
			key_state <= 1'b1 ;	 //默认输入按键状态高电平
		end
	else 
	   begin
	 	case(state)
			IDEL :
				begin
					key_flag <= 1'b0 ;	//空闲状态下,按键成功标志位永远为0
					if(nedge == 1'b1) begin		//按键检测到下降沿到来
						state <= FILTER0 ;//进入下一个案件滤波状态
						en_cnt_20ms <= 1 ;//开启使能计数20ms
						end
					else
					   state <= IDEL ;	//未检测到下降沿到来,信号状态保持不变
				end
			FILTER0:
			if(cnt_20ms_full == 1'b1) begin //看消除抖动20ms后,且20ms内没有检测到上升沿到来  = 20ms
					key_flag <= 1'b1;		//表示按键	已经成功按下
					key_state<= 1'b0;		//此时输入按键按下输出状态为低电平
					state <= DOWN ;		//进入下一状态
					en_cnt_20ms <= 0 ;	//20ms计数器关闭				
				end
			else if(pedge == 1'b1) begin	//没有满20ms 以内,有上升沿的到来,表明此时是抖动信号,非按键按下信号
					state <= IDEL ;
					en_cnt_20ms <= 0 ;//计数器关闭
				end
				else	//上述两者情况均为出现,则状态机保持不变
					state <= FILTER0 ;
			DOWN:
				begin 
				key_flag <= 1'b0; //检测到有按键按下,发送一个脉冲信号,由上一个状态的高电平变为低电平
					if(pedge == 1'b1) begin //上一个状态时间超过20ms,此时需要一直等待上升沿的到来(做为按键松开的标志)
						state <= FILTER1 ;	//进入到下一状态
						en_cnt_20ms <= 1'b1 ;//开启下一次20ms 延时计数
					end
					else  //没有,则保持该状态
						state <= DOWN ;	
				end		
			FILTER1:
				if(cnt_20ms_full == 1'b1) begin//表示 20ms计数又一次到来,此时按键稳定
				   key_flag <= 1'b1;		//表示上升沿的信号稳定的信号,随后到 IDEL又会设置为低电平,产生一个脉冲信号
					key_state<= 1'b1;		 //此时输入按键按下状态为低电平
					en_cnt_20ms <= 1'b0 ; //关闭20ms定时器
					state <=IDEL ;
				end
				else if(nedge)begin	// 20ms内又出现了下降沿,表示这是一次抖动
					en_cnt_20ms <= 1'b0 ;
					state <= DOWN ;
				end
				else	//20ms内状态保持不变
					state <=FILTER1 ;
			default:
				begin
					state <= IDEL ; 
					key_flag <= 1'b0;
					key_state<= 1'b1;     //默认状态时 1 高电平
					en_cnt_20ms <= 1'b0 ; //默认状态时 0 低电平
				end
		endcase
	  end

//	定时器启动 always块
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		cnt_20ms <= 20'd0;
	else if(en_cnt_20ms)
		cnt_20ms <= cnt_20ms + 1'b1;
	else // 关闭时,计时器清零
		cnt_20ms <= 20'd0;
	
	
	//定时器20ms always块 50Mhz 20ms = cnt_20ms : 1_000_000
	always@(posedge Clk or negedge Rst_n)
	if(Rst_n == 1'b0)
		cnt_20ms_full <= 0 ;
	else if(cnt_20ms == 20'd999_999)
		cnt_20ms_full <= 1'b1 ;  //计数值计满标志位
	else
		cnt_20ms_full <= 1'b0 ;	// 未挤满,输出0
		

endmodule


第4部分: ctrl_sample 通过按键按下滤波后的信号,控制ADC 驱动,完成连续的100次信号采集

// 模块功能,每次按键按下,使用控制AD 100次信号采样
// 采样的信号 存放到fifo中。

module  ctrl_sample
(
	Clk,
	Rst_n,
	key_flag ,
	key_state ,
	Ad_Conv_Done,
	Fifo_almost_full,
	
	Ad_En_Conv

);
	input Clk;
	input Rst_n;
	input key_flag ;
	input key_state ;
	input Ad_Conv_Done;
	input Fifo_almost_full;

	output reg Ad_En_Conv;
	
	parameter SAMPLE_TIMES =  100 ; //每次采样次数

	reg [6:0]sample_cnt ;
	
	// key_state key_flag
	// Ad_En_Conv ;
	reg en_flag ;
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		en_flag <= 1'b0 ;
	else if(key_flag && (!key_state))
		begin
			if(Fifo_almost_full)
				en_flag <= 1'b0;
			else
				en_flag <= 1'b1;
		end
	else if(Fifo_almost_full || (sample_cnt== (SAMPLE_TIMES-1)) )
		en_flag <= 1'b0;
	else
		en_flag <= en_flag ;
	
	// Ad_En_Conv handle
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		Ad_En_Conv <= 1'b0 ;
	else if(key_flag && (!key_state))
		begin
			if(Fifo_almost_full)
				Ad_En_Conv <= 1'b0;
			else
				Ad_En_Conv <= 1'b1;
		end
	else if(en_flag && Ad_Conv_Done)
		Ad_En_Conv <= 1'b1;
	else	
		Ad_En_Conv <= 1'b0;
			
	
	// Ad_Conv_Done
	// Ad_En_Conv
	// sample_cnt
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		sample_cnt <= 7'b0 ;
	else if(Ad_Conv_Done)
		begin
			if(sample_cnt == (SAMPLE_TIMES-1) )
				sample_cnt <=7'd0;
			else
				sample_cnt <= sample_cnt +1'b1;
		end
	else
		sample_cnt <= sample_cnt ;
	

endmodule


第5部分: ad128s022.v 芯片驱动模块,可以设置采样通道、采样频率等基本输入参数,即可驱动信号。

module ad128s022
(
			Clk,
			Rst_n,
			
			Channel,
			Data,
			
			En_Conv,
			Conv_Done,
			ADC_State,
			DIV_PARAM,
			
			ADC_SCLK,
			ADC_DOUT,
			ADC_DIN,
			ADC_CS_N	
);

			input Clk;
			input Rst_n;
			
			input  [2:0]Channel;
			output reg [11:0]Data;
			
			input En_Conv;
			output reg Conv_Done;
			output ADC_State;
			input [7:0]DIV_PARAM;
			
			output reg ADC_SCLK;
			input  ADC_DOUT;
			output reg ADC_DIN;
			output reg ADC_CS_N;	

			
			reg en ;
			reg [2:0]r_Channel;
			reg [7:0]DIV_CNT ;
			reg  SCLK2X ;
			reg [5:0]SCLK_GEN_CNT;
			reg [11:0]r_Data;
			

			
			
			//  en handle 
			always@(posedge Clk or negedge Rst_n)
			if(!Rst_n)
				en <= 1'b0;
			else if(En_Conv)
				en <= 1'b1;
			else if(Conv_Done)
				en <= 1'b0 ;
			else
				en <= en ;
			
			

			// r_Channel  we set En_Conv is a plus signal 
			always@(posedge Clk or negedge Rst_n)
			if(!Rst_n)
				r_Channel <= 3'd0;
			else if(En_Conv)
				r_Channel <= Channel;
			else
				r_Channel <= r_Channel;
			
			// 时钟分频脉冲计数
			// reg [7:0]DIV_CNT ;
			always@(posedge Clk or negedge Rst_n)
			if(!Rst_n)
				DIV_CNT <= 8'd0 ;
			else if(en)
				begin
				if(DIV_CNT == (DIV_PARAM -1) )
					DIV_CNT <= 8'd0 ;
				else	
					DIV_CNT <= DIV_CNT + 1'd1 ;
				end
			else	
				DIV_CNT <= 8'd0 ;
			
			// SCLK2X plus
			// reg  SCLK2X
			always@(posedge Clk or negedge Rst_n)
			if(!Rst_n)
				SCLK2X <= 1'b0;
			else if(DIV_CNT == (DIV_PARAM -1) )
				SCLK2X <= 1'b1 ;
			else
				SCLK2X <= 1'b0;
				
			// reg [5:0]SCLK_GEN_CNT 
			always@(posedge Clk or negedge Rst_n)
			if(!Rst_n)
				SCLK_GEN_CNT  <= 6'd0 ;
			else if(en && SCLK2X)
				begin
				if(SCLK_GEN_CNT == 6'd33)
					SCLK_GEN_CNT <=6'd0;
				else
					SCLK_GEN_CNT <= SCLK_GEN_CNT + 1'b1 ;
				end
			else
				SCLK_GEN_CNT <= SCLK_GEN_CNT ;
			//
			
			/*
			output ADC_SCLK
			input  ADC_DOUT;
			output ADC_DIN;
			output reg ADC_CS_N;	
			reg [11:0]r_Data;
			*/
			
			always@(posedge Clk or negedge Rst_n)
			if(!Rst_n)
				begin
				ADC_SCLK <= 1'b1;
				ADC_DIN  <= 1'b0;
				ADC_CS_N  <= 1'b1;
				end
			else if(en && SCLK2X)
				begin
				case(SCLK_GEN_CNT)
				0: begin ADC_CS_N <= 1'b0; ADC_SCLK <= 1'b1; ADC_DIN <= 1'b0; end
				1,3: begin ADC_SCLK <= 1'b0; end
				2,4,6,8:  begin ADC_SCLK <= 1'b1 ; end
				5:  begin ADC_SCLK <= 1'b0; ADC_DIN <= r_Channel[2]; end
				7:  begin ADC_SCLK <= 1'b0; ADC_DIN <= r_Channel[1]; end
				9:  begin ADC_SCLK <= 1'b0; ADC_DIN <= r_Channel[0]; end
				10: begin ADC_SCLK <= 1'b1; r_Data[11] <= ADC_DOUT ; end
				12: begin ADC_SCLK <= 1'b1; r_Data[10] <= ADC_DOUT ; end
				14: begin ADC_SCLK <= 1'b1; r_Data[9] <= ADC_DOUT ; end
				16: begin ADC_SCLK <= 1'b1; r_Data[8] <= ADC_DOUT ; end
				18: begin ADC_SCLK <= 1'b1; r_Data[7] <= ADC_DOUT ; end
				20: begin ADC_SCLK <= 1'b1; r_Data[6] <= ADC_DOUT ; end
				22: begin ADC_SCLK <= 1'b1; r_Data[5] <= ADC_DOUT ; end
				24: begin ADC_SCLK <= 1'b1; r_Data[4] <= ADC_DOUT ; end
				26: begin ADC_SCLK <= 1'b1; r_Data[3] <= ADC_DOUT ; end
				28: begin ADC_SCLK <= 1'b1; r_Data[2] <= ADC_DOUT ; end
				30: begin ADC_SCLK <= 1'b1; r_Data[1] <= ADC_DOUT ; end
				32: begin ADC_SCLK <= 1'b1; r_Data[0] <= ADC_DOUT ; end
				11,13,15,17,19,21,23,25,27,29,31: begin ADC_SCLK <= 1'b0;  end
				33: begin ADC_CS_N <= 1'b1; end
				default: ;
				endcase
				end	
			
		// output [11:0]Data 
		always@(posedge Clk or negedge Rst_n)
		if(!Rst_n)
			Data  <= 12'd0 ;
		else if(en && SCLK2X && (SCLK_GEN_CNT == 6'd33))
			Data <= r_Data ;
		else
			Data <= Data ;
	
		// conv_Done signal
		always@(posedge Clk or negedge Rst_n)
		if(!Rst_n)
			Conv_Done  <= 1'd0 ;
		else if(en && SCLK2X && (SCLK_GEN_CNT == 6'd33))
			Conv_Done <= 1'd1 ;
		else
			Conv_Done <= 1'd0 ;	
		
		//产生ADC工作状态指示信号,保持和CS片选信号同步即可
		assign ADC_State = ADC_CS_N ; 
			
endmodule



第6部分、FIFO模块,注:这个一般来说,是调用内部IP 核来实现的,主要是看FIFO的配置,可以看一下 FPGA22 FIFO 的实现

// megafunction wizard: %FIFO%
// GENERATION: STANDARD
// VERSION: WM1.0
// MODULE: scfifo 

// ============================================================
// File Name: AD_fifo.v
// Megafunction Name(s):
// 			scfifo
//
// Simulation Library Files(s):
// 			
// ============================================================
// ************************************************************
// THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE!
//
// 13.0.0 Build 156 04/24/2013 SJ Full Version
// ************************************************************


//Copyright (C) 1991-2013 Altera Corporation
//Your use of Altera Corporation's design tools, logic functions 
//and other software and tools, and its AMPP partner logic 
//functions, and any output files from any of the foregoing 
//(including device programming or simulation files), and any 
//associated documentation or information are expressly subject 
//to the terms and conditions of the Altera Program License 
//Subscription Agreement, Altera MegaCore Function License 
//Agreement, or other applicable license agreement, including, 
//without limitation, that your use is for the sole purpose of 
//programming logic devices manufactured by Altera and sold by 
//Altera or its authorized distributors.  Please refer to the 
//applicable agreement for further details.


// synopsys translate_off
`timescale 1 ps / 1 ps
// synopsys translate_on
module AD_fifo (
	clock,
	data,
	rdreq,
	sclr,
	wrreq,
	almost_empty,
	almost_full,
	empty,
	full,
	q,
	usedw);

	input	  clock;
	input	[11:0]  data;
	input	  rdreq;
	input	  sclr;
	input	  wrreq;
	output	  almost_empty;
	output	  almost_full;
	output	  empty;
	output	  full;
	output	[11:0]  q;
	output	[9:0]  usedw;

	wire [9:0] sub_wire0;
	wire  sub_wire1;
	wire  sub_wire2;
	wire [11:0] sub_wire3;
	wire  sub_wire4;
	wire  sub_wire5;
	wire [9:0] usedw = sub_wire0[9:0];
	wire  empty = sub_wire1;
	wire  full = sub_wire2;
	wire [11:0] q = sub_wire3[11:0];
	wire  almost_empty = sub_wire4;
	wire  almost_full = sub_wire5;

	scfifo	scfifo_component (
				.clock (clock),
				.sclr (sclr),
				.wrreq (wrreq),
				.data (data),
				.rdreq (rdreq),
				.usedw (sub_wire0),
				.empty (sub_wire1),
				.full (sub_wire2),
				.q (sub_wire3),
				.almost_empty (sub_wire4),
				.almost_full (sub_wire5),
				.aclr ());
	defparam
		scfifo_component.add_ram_output_register = "OFF",
		scfifo_component.almost_empty_value = 1,
		scfifo_component.almost_full_value = 1023,
		scfifo_component.intended_device_family = "Cyclone IV E",
		scfifo_component.lpm_numwords = 1024,
		scfifo_component.lpm_showahead = "OFF",
		scfifo_component.lpm_type = "scfifo",
		scfifo_component.lpm_width = 12,
		scfifo_component.lpm_widthu = 10,
		scfifo_component.overflow_checking = "ON",
		scfifo_component.underflow_checking = "ON",
		scfifo_component.use_eab = "ON";


endmodule


第7 部分 fifo_send_ctrl.v文件,主要实现的是将fifo 的存放数据【12位】设置一个转换【8位】输出,输出串口标准的发送信号.

module  fifo_send_ctrl
(	
	Clk,
	Rst_n,
	Tx_done ,
	Fifo_empty ,
	Fifo_q,
	
	Tx_Send_en,
	Tx_Data,
	Fifo_rdreq
);

	input Clk ;
	input Rst_n ;
	input Tx_done ;
	input Fifo_empty ;
	input [11:0]Fifo_q ;
	
	output reg Tx_Send_en ;
	output reg [7:0]Tx_Data ;
	output reg Fifo_rdreq ;
		
	//
localparam
		STATE_S0	= 5'b0_0001,
		STATE_S1 = 5'b0_0010,
		STATE_S2	= 5'b0_0100,
		STATE_S3	= 5'b0_1000,
		STATE_S4	= 5'b1_0000;

	reg[4:0]state;
	
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)begin
		state <= STATE_S0;
	end
	else begin
		case(state)
			STATE_S0:
				if(Fifo_empty == 1'b0) 
					begin 					// fifo 有data
					Fifo_rdreq <= 1'b1 ; //发送读信号
					state <= STATE_S1;
					end
				else
					state <= STATE_S0;	
			STATE_S1:
					begin
					Fifo_rdreq <= 1'b0 ;
					state <= STATE_S2;
					end
			STATE_S2:
					begin
					Tx_Send_en <= 1'b1;
					Tx_Data <= {4'b0000,Fifo_q[11:8]} ; // 先发送高8位
					state <= STATE_S3;
					end			
			STATE_S3:
				if(Tx_done == 1'b1)
					begin
					Tx_Send_en <= 1'b1;
					Tx_Data <= Fifo_q[7:0] ; //再发送低8位
					state <= STATE_S4;
					end	
				else
					begin
					Tx_Send_en <= 1'b0;
					state <= STATE_S3;
					end					
			STATE_S4:
				if(Tx_done == 1'b1)
					state <= STATE_S0;
				else if(Tx_done == 1'b0)
					begin
					Tx_Send_en <= 1'b0;
					state <= STATE_S4;
					end			
			default:state <= STATE_S1;
		endcase		
	end
	

endmodule



第8部分: uart_byte_tx .v 串口发送模块

module uart_byte_tx(
	Clk,
	Rst_n,
	data_byte,
	send_en,
	baud_set,
	
	Rs232_Tx,
	Tx_Done,
	uart_state
);

	input Clk;
	input Rst_n;
	input [7:0]data_byte;
	input send_en;
	input [2:0]baud_set;
	
	output reg Rs232_Tx;
	output reg Tx_Done;
	output reg uart_state;
	
	reg bps_clk;	//波特率时钟
	
	reg [15:0]div_cnt;//分频计数器
	
	reg [15:0]bps_DR;//分频计数最大值
	
	reg [3:0]bps_cnt;//波特率时钟计数器
	
	reg [7:0]r_data_byte;
	
	localparam START_BIT = 1'b0;
	localparam STOP_BIT = 1'b1;
	
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		uart_state <= 1'b0;
	else if(send_en)
		uart_state <= 1'b1;
	else if(bps_cnt == 4'd11)
		uart_state <= 1'b0;
	else
		uart_state <= uart_state;
	
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		r_data_byte <= 8'd0;
	else if(send_en)
		r_data_byte <= data_byte;
	else
		r_data_byte <= r_data_byte;
	
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		bps_DR <= 16'd5207;
	else begin
		case(baud_set)
			0:bps_DR <= 16'd5207;
			1:bps_DR <= 16'd2603;
			2:bps_DR <= 16'd1301;
			3:bps_DR <= 16'd867;
			4:bps_DR <= 16'd433;
			default:bps_DR <= 16'd5207;			
		endcase
	end	
	
	//counter
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		div_cnt <= 16'd0;
	else if(uart_state)begin
		if(div_cnt == bps_DR)
			div_cnt <= 16'd0;
		else
			div_cnt <= div_cnt + 1'b1;
	end
	else
		div_cnt <= 16'd0;
	
	// bps_clk gen
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		bps_clk <= 1'b0;
	else if(div_cnt == 16'd1)
		bps_clk <= 1'b1;
	else
		bps_clk <= 1'b0;
	
	//bps counter
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)	
		bps_cnt <= 4'd0;
	else if(bps_cnt == 4'd11)
		bps_cnt <= 4'd0;
	else if(bps_clk)
		bps_cnt <= bps_cnt + 1'b1;
	else
		bps_cnt <= bps_cnt;
		
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		Tx_Done <= 1'b0;
	else if(bps_cnt == 4'd11)
		Tx_Done <= 1'b1;
	else
		Tx_Done <= 1'b0;
		
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		Rs232_Tx <= 1'b1;
	else begin
		case(bps_cnt)
			0:Rs232_Tx <= 1'b1;
			1:Rs232_Tx <= START_BIT;
			2:Rs232_Tx <= r_data_byte[0];
			3:Rs232_Tx <= r_data_byte[1];
			4:Rs232_Tx <= r_data_byte[2];
			5:Rs232_Tx <= r_data_byte[3];
			6:Rs232_Tx <= r_data_byte[4];
			7:Rs232_Tx <= r_data_byte[5];
			8:Rs232_Tx <= r_data_byte[6];
			9:Rs232_Tx <= r_data_byte[7];
			10:Rs232_Tx <= STOP_BIT;
			default:Rs232_Tx <= 1'b1;
		endcase
	end	

endmodule

第九部分: 顶层设计文件,就是模块核模块之间的连接

// 实验内容:
// ① 通过按键控制AD采集模块
// ② 按键按下,ad 进行采样100 次,操作
// ③ ad 采样的数据存取到fifo 中
// ④ 读取fifo中的数据,将数据通过串口模块发送,直到fifo 的数据全部读取完毕为止
// ⑤ 读取的数据是12位,串口模块发送需要先变成标准的2个8位数据发送,通过电脑上的串口调试助手显示发送的数据
// 信号发生器模块: 【内部有一个 DA_rom 数据模块】 ,每次间隔0.01S,发送一次模拟数据到,模拟信号发送通道1,发送出去
// 信号采样时间现在本工程暂时无法控制,下一个工程【27_ADC_DAC_system】将会完善改功能
module  AD_DA_Top
(
	 Clk ,
	 Rst_n ,
	 key_in ,

	 ADC_DOUT ,
	 ADC_SCLK ,
	 ADC_DIN  ,
	 ADC_CS_N ,
	
	 Rs232_Tx ,
	
	 DAC_CS_N ,
	 DAC_DIN  ,
	 DAC_SCLK
	
);


	input Clk ;
	input Rst_n ;
	input key_in ;

	input ADC_DOUT ;
	output ADC_SCLK;
	output ADC_DIN;
	output ADC_CS_N;
	
	output Rs232_Tx;

	// 信号源
	output  DAC_CS_N;
	output  DAC_DIN;
	output  DAC_SCLK;
	
	
	wire key_flag ;
	wire key_state ;
	wire Ad_En_Conv;
	wire Conv_Done;
	wire Fifo_empty;
	wire Fifo_almost_full;
	
	wire Tx_Done;
	wire Tx_Send_en;
	wire [7:0]Tx_Data;
	wire [11:0]fifo_dtae;
	wire [11:0]Fifo_q;
	wire Fifo_rdreq;
	
	wire [15:0]DAC_DATA ;
	wire Start ;
	wire DAC_State;

key_filter	key_filter_0(
		.Clk(Clk) ,
		.Rst_n(Rst_n) ,
		.key_in(key_in) ,
		
		.key_flag(key_flag), //检测按键成功信号
		.key_state(key_state) //实时的信号
	);
	

ctrl_sample ctrl_sample0
	( 
		.Clk(Clk),
		.Rst_n(Rst_n),
		.key_flag(key_flag) ,
		.key_state(key_state) ,
		.Ad_Conv_Done(Conv_Done),
		.Fifo_almost_full(Fifo_almost_full),
		
		.Ad_En_Conv(Ad_En_Conv)

	);
	

ad128s022 ad128s022_0
(
			.Clk(Clk),
			.Rst_n(Rst_n),
			
			.Channel(3'd5),
			.Data(fifo_dtae),
			
			.En_Conv(Ad_En_Conv),
			.Conv_Done(Conv_Done),
			.ADC_State(), // 和 ADC_CS_N  状态保持一致
			.DIV_PARAM(8'd13),
			
			.ADC_SCLK(ADC_SCLK),
			.ADC_DOUT(ADC_DOUT),
			.ADC_DIN(ADC_DIN),
			.ADC_CS_N(ADC_CS_N)	
);	

	AD_fifo	AD_fifo_0 (
		.clock(Clk),
		.data(fifo_dtae),
		.rdreq(Fifo_rdreq),
		.sclr(!Rst_n), 
		.wrreq(Conv_Done),
		.almost_empty(),
		.almost_full(Fifo_almost_full),
		.empty(Fifo_empty),
		.full(),
		.q(Fifo_q),
		.usedw()
		);
	
	
	
fifo_send_ctrl	fifo_send_ctrl_0
	(	
		.Clk(Clk),
		.Rst_n(Rst_n),
		.Tx_done(Tx_Done) ,
		.Fifo_empty(Fifo_empty) ,
		.Fifo_q(Fifo_q),
		
		.Tx_Send_en(Tx_Send_en),
		.Tx_Data(Tx_Data),
		.Fifo_rdreq(Fifo_rdreq)
	);

	
uart_byte_tx	uart_byte_tx_0(
		.Clk(Clk),
		.Rst_n(Rst_n),
		.data_byte(Tx_Data),
		.send_en(Tx_Send_en),
		.baud_set(3'd4),	 // 115200bps
		
		.Rs232_Tx(Rs232_Tx),
		.Tx_Done(Tx_Done),
		.uart_state()
	);

		
		DAC_rom_signal DAC_rom_signal_0
		(
			.Clk(Clk),
			.Rst_n(Rst_n),
			.DAC_State(DAC_State),
			.DAC_DATA(DAC_DATA),
			.Data_Start(Start)
		);
		
		dac_tlv5618 dac_tlv5618_0
		(
			.Clk(Clk),
			.Rst_n(Rst_n),
			
			.DAC_DATA(DAC_DATA),
			.Start(Start),
			.Set_Done(),
			
			.DAC_CS_N(DAC_CS_N),
			.DAC_DIN(DAC_DIN),
			.DAC_SCLK(DAC_SCLK),
			.DAC_State(DAC_State)
		);

endmodule

注: 本次作为一个综合实验,主要是对原先学习的知识做一个系统的设计,将现阶段所学的内容整合在一块,同时也需要知道真正在做fpga项目的时候,基本上都是先做系统模块化数字电路设计,后面模块再去写模块代码,做模块验证,最后根据顶层文件直接连接,最后综合和测试即可。