• 如何让FPGA中的SPI与其他模块互动起来


    在上一篇文章《FPGA的SPI从机模块实现》中,已经实现了SPI的从机模块,如何通过SPI总线与FPGA内部其他模块进行通信,是本文的主要讨论内容。

    一. 新建FPGA内部DAC控制模块

    这里由于手上项目需求,有两块单独DAC902核心板,其中一片DAC902的输出作为另一片DAC902的基准源输入,我们分别称它们为DACref和DACsin,顾名思义一片提供基准源电压,一片输出正弦信号或者扩展成DDS信号输出。
    因此,此模块的RTL模型必须有与SPI模块通信端和外部控制DAC902的信号管脚。所以预设计这个模块为:
    module dac_reg_rw_spi(clk, nrst, rec_flag, rec_data, send_flag, sending_flag, send_data, dac_clk, dacref_clk, dacref_fudu, dacsin_output);
            input clk, nrst;  //模块系统时钟、复位
    
    
    //与spi模块交互引脚
    	input rec_flag;   //spi字节接收标志
    	input[7:0] rec_data;  //spi接收数据缓存寄存器
    	input sending_flag;  //spi模块正在发送数据标志位
    	
    //与spi模块交互引脚
    	output send_flag;   //dac控制模块存在需要发送数据标志位,主要负责触发spi发送
    	output[7:0] send_data;   //spi需要发送的数据
    
    
    //与外部dac通信引脚
    	output[11:0] dacref_fudu;  //直接输出到dacref中
    	output[11:0] dacsin_output;
    	output dac_clk;
    	output dacref_clk;

    这里假定先发送一个字节的命令,紧接着通过spi发送、接收dac控制模块所需的数据。所以定义命令字如下:

    //指令代号
    	parameter read_dacref_fudukongzhizi=8'b00000001;  //读取dacref的幅度控制字
    	parameter read_dacsin_xiangweikongzhizi=8'b00000010;  //读取dacsin的相位控制字
    	parameter read_dacsin_pinlvkongzhizi=8'b00000011;  //读取dacsin的频率控制字
    	parameter set_dacsin_pinlvkongzhizi=8'b00100001;   //写入dacsin的频率控制字
    	parameter set_dacsin_xiangweikongzhizi=8'b00100010;  //写入dacsin的相位控制字
    	parameter set_dacref_fudukongzhizi=8'b00100011;  //写入dacref的幅度控制字
    	parameter set_dac_clk_pdf=8'b00100100;  //设置dac时钟预分频
    	parameter reset_to_default=8'b11100000; //复位dac控制模块
    	parameter start_dac=8'b11100001;  //开启dac模块
    	parameter stop_dac=8'b11100010;   //停止dac模块

    由于spi属于串行接收,一次以8位传输格式,而我们的DDS模块需要32位的频率控制字、10位的相位控制字、12位的基准源幅度控制字(具体DDS原理,由于篇幅有限,这里就不再详细介绍了),因此我们需要读取这几个寄存器或者写入这几个寄存器,需要输出、接收不等的字节长度,而dds模块处于实时运行中,所以这里需要影子寄存器的介入。
    //dac配置的影子寄存器(dac运作依据的值)
    	reg[11:0] dacref_fudukongzhizi_shadow;
    	reg[31:0] dacsin_pinlvkongzhizi_shadow;
    	reg[9:0] dacsin_xiangweikongzhizi_shadow;
    	reg[3:0] dac_clk_pdf_shadow;

    开始设计dac的模块吧:
    reg[3:0] rw_reg_status;  //处理spi接收发送数据状态机
    	reg[3:0] rw_reg_status_temp;  ////处理spi接收发送数据状态机(影子寄存器)
    	reg[7:0] rec_data_temp;  //8位spi数据接收缓存
    	reg[3:0] delay_cnt;  //发送数据延时计数器
    	
    	//dac配置寄存器临时值
    	reg[31:0] dacsin_pinlvkongzhizi;  
    	reg[11:0] dacref_fudukongzhizi;
    	reg[9:0] dacsin_xiangweikongzhizi;
    	
    	reg[7:0] send_data;  //与myspi模块通信脚
    	reg send_flag;  //与myspi模块通信脚
    	reg[2:0] byte_sended_cnt;  //发送数据字节数计数器
    	reg[2:0] byte_received_cnt;  //接收数据字节数计数器
    	reg dac_start_flag;  //dac使能脚
    	reg dacref_clk;
    	
    	//spi通信处理状态机,需要注意的是,clk时钟频率必须为sck时钟频率约10倍以上,保证正确操作。
    	always @ (posedge clk or negedge nrst)
    	begin
    		if(~nrst)
    		begin
    //初始化上述寄存器
    			rw_reg_status <= 4'h0;
    			rw_reg_status_temp <= 4'h0;  //处理spi接收发送数据状态机(影子寄存器)
    			rec_data_temp <= 8'h00;
    			dacsin_pinlvkongzhizi <= 32'h00412345;
    			dacsin_xiangweikongzhizi <= 10'h123;
    			dacref_fudukongzhizi <= 12'h800;
    			delay_cnt <= 4'b0000;
    			byte_sended_cnt <= 3'b000;
    			send_flag <= 1'b0;
    			byte_received_cnt <= 3'b000;
    			dac_start_flag <= 1'b0;
    			dacref_clk <= 1'b0;
    			
    			dacref_fudukongzhizi_shadow <= 12'h800;
    			dacsin_pinlvkongzhizi_shadow <= 32'h00423456;
    			dacsin_xiangweikongzhizi_shadow <= 10'h200;
    			dac_clk_pdf_shadow <= 4'h1;
    		end
    		else
    		begin 
    			 case (rw_reg_status)
    			 4'b0000: begin  //从机接收指令
    				  if(rec_flag)
    				  begin
    					   rec_data_temp <= rec_data;
    						rw_reg_status <= 4'b0001;  //进入命令解析
    				  end
    			 end
    			 4'b0001: begin  //指令解析,跳转相应状态
    				  case (rec_data_temp)
    				  reset_to_default: begin
    					   rw_reg_status <= 4'b1110;
    				  end
    				  read_dacref_fudukongzhizi: begin
    					   rw_reg_status <= 4'b0011;  //读dacref的幅度控制字
    				  end
    				  read_dacsin_xiangweikongzhizi: begin
    					   rw_reg_status <= 4'b0010;  //读dacsin的相位控制字
    				  end
    				  read_dacsin_pinlvkongzhizi: begin
    					   rw_reg_status <= 4'b0110;  //读dacsin的频率控制字
    				  end
    				  set_dacsin_pinlvkongzhizi: begin
    					   rw_reg_status <= 4'b1101;  //设置dacsin的频率控制字
    						rw_reg_status_temp <= 4'b0101;
    				  end
    				  set_dacsin_xiangweikongzhizi: begin  //设置dacsin的相位控制字
    						rw_reg_status <= 4'b1101;
    					   rw_reg_status_temp <= 4'b0100;
    				  end
    				  set_dacref_fudukongzhizi: begin  //设置dacref的幅度控制字
    					   rw_reg_status <= 4'b1101;
    						rw_reg_status_temp <= 4'b1100;
    				  end
    				  set_dac_clk_pdf: begin  //设置dac时钟预分频值
    					   rw_reg_status <= 4'b1101;
    						rw_reg_status_temp <= 4'b1001;
    				  end
    				  start_dac: begin
    					   rw_reg_status <= 4'b1010;
    						//rw_reg_status_temp <= 4'b0000;
    				  end
    				  stop_dac: begin
    					   rw_reg_status <= 4'b1011;
    						//rw_reg_status_temp <= 4'b0000;
    				  end
    				  default: begin
    					   rw_reg_status <= 4'b1101;
    						rw_reg_status_temp <= 4'b0000;
    				  end
    				  endcase
    			 end
    			 //----------------------------------------------------
    			 4'b0011: begin  //先发送幅度控制字高八位字节然后发送低八位字节
    				  if(~sending_flag) begin  //判断spi是否处于发送状态
    					  case (byte_sended_cnt)
    					  3'b000: begin
    							send_data <= {4'b0000, dacref_fudukongzhizi_shadow[11:8]};
    							rw_reg_status_temp <= 4'b0011;
    							rw_reg_status <= 4'b0111;
    					  end
    					  3'b001: begin
    							send_data <= dacref_fudukongzhizi_shadow[7:0];
    							rw_reg_status_temp <= 4'b0011;
    							rw_reg_status <= 4'b0111;
    					  end
    					  default: begin
    							byte_sended_cnt <= 3'b000;
    							rw_reg_status_temp <= 4'b0000;
    							rw_reg_status <= 4'b0000;  //发送完成
    					  end
    					  endcase
    				  end
    				  else begin
    					  send_flag <= 1'b0;
    				  end
    			 end
    			 //----------------------------------------------------
    			 4'b0010: begin
    				  if(~sending_flag) begin  //判断spi是否处于发送状态
    					  case (byte_sended_cnt)
    					  3'b000: begin
    							send_data <= {6'b000000, dacsin_xiangweikongzhizi_shadow[9:8]};
    							rw_reg_status_temp <= 4'b0010;  //4'b0110;
    							rw_reg_status <= 4'b0111;
    					  end
    					  3'b001: begin
    							send_data <= dacsin_xiangweikongzhizi_shadow[7:0];
    							rw_reg_status_temp <= 4'b0010;  //4'b0110;
    							rw_reg_status <= 4'b0111;
    					  end
    					  default: begin
    							rw_reg_status <= 4'b0000;  //发送完成
    							rw_reg_status_temp <= 4'b0000;
    							byte_sended_cnt <= 3'b000;
    					  end
    					  endcase
    				  end
    				  else begin
    					  send_flag <= 1'b0;
    				  end
    			 end
    			 //----------------------------------------------------
    			 4'b0110: begin
    				  if(~sending_flag) begin  //判断spi模块是否处于发送状态
    					  case (byte_sended_cnt)
    					  3'b000: begin
    							send_data <= dacsin_pinlvkongzhizi_shadow[31:24];
    							rw_reg_status_temp <= 4'b0110;
    							rw_reg_status <= 4'b0111;  //4'b0100;
    					  end
    					  3'b001: begin
    							send_data <= dacsin_pinlvkongzhizi_shadow[23:16];
    							rw_reg_status_temp <= 4'b0110;
    							rw_reg_status <= 4'b0111;  //4'b0100;
    					  end
    					  3'b010: begin 
    						   send_data <= dacsin_pinlvkongzhizi_shadow[15:8];
    							rw_reg_status_temp <= 4'b0110;
    							rw_reg_status <= 4'b0111;
    					  end
    					  3'b011: begin
    						   send_data <= dacsin_pinlvkongzhizi_shadow[7:0];
    							rw_reg_status_temp <= 4'b0110;
    							rw_reg_status <= 4'b0111;
    					  end
    					  default: begin
    							rw_reg_status <= 4'b0000;  //发送完成
    							rw_reg_status_temp <= 4'b0000;
    							byte_sended_cnt <= 3'b000;
    					  end
    					  endcase
    				  end
    				  else begin
    					  send_flag <= 1'b0;
    				  end
    			 end
    //通用状态			 
    			 4'b0111: begin
    //dac控制模块向spi模块提出发送请求,即生成send_flag脉冲
    				  send_flag <= 1'b1;
    				  if(delay_cnt == 4'b0011)
    				  begin
    					   delay_cnt <= 4'b0000;
    						rw_reg_status <= rw_reg_status_temp;
    						byte_sended_cnt <= byte_sended_cnt+1;
    				  end
    				  else
    				  begin
    					   delay_cnt <= delay_cnt+1;
    				  end
    			 end
    			 //----------------------------------------------------
    			 4'b0101: begin
    				  //if(rec_flag) begin  
    					  case (byte_received_cnt)
    					  3'b000: begin
    							if(rec_flag) begin  //spi字节接收完成标志位
    								dacsin_pinlvkongzhizi[31:24] <= rec_data;
    								rw_reg_status <= 4'b1101;
    								byte_received_cnt <= 3'b001;
    							end
    					  end
    					  3'b001: begin
    							if(rec_flag) begin
    								dacsin_pinlvkongzhizi[23:16] <= rec_data;
    								rw_reg_status <= 4'b1101;
    								byte_received_cnt <= 3'b010;
    							end
    					  end
    					  3'b010: begin
    							if(rec_flag) begin
    								dacsin_pinlvkongzhizi[15:8] <= rec_data;
    								rw_reg_status <= 4'b1101;
    								byte_received_cnt <= 3'b011;
    							end
    					  end
    					  3'b011: begin
    							if(rec_flag) begin
    								dacsin_pinlvkongzhizi[7:0] <= rec_data;
    								rw_reg_status <= 4'b1101;
    								byte_received_cnt <= 3'b100;
    							end
    					  end
    					  3'b100: begin
    							dacsin_pinlvkongzhizi_shadow <= dacsin_pinlvkongzhizi;
    							byte_received_cnt <= 3'b101;
    					  end
    					  3'b101: begin
    							rw_reg_status <= 4'b1101;
    							rw_reg_status_temp <= 4'b0000;
    							byte_received_cnt <= 3'b000;
    					  end
    					  endcase
    				  //end
    			 end
    			 //----------------------------------------------------
     在spi接收到命令字时,下一个系统时钟clk上跳沿则进入此状态,此时rec_flag可能仍然是有效,所以会先进入4'b1101模块等待rec_flag标志位复位后再接收数据,其他状态其实大同小异,这里不一一描述。
    			 4'b0100: begin
    				  //if(rec_flag) begin
    					  case (byte_received_cnt)
    					  3'b000: begin
    							if(rec_flag) begin
    								dacsin_xiangweikongzhizi[9:8] <= rec_data[1:0];
    								rw_reg_status <= 4'b1101;
    								byte_received_cnt <= 3'b001;
    							end
    					  end
    					  3'b001: begin
    							if(rec_flag) begin
    								dacsin_xiangweikongzhizi[7:0] <= rec_data;
    								rw_reg_status <= 4'b1101;
    								byte_received_cnt <= 3'b010;
    							end
    					  end
    					  3'b010: begin
    							dacsin_xiangweikongzhizi_shadow <= dacsin_xiangweikongzhizi;
    							byte_received_cnt <= 3'b011;
    					  end
    					  3'b011: begin
    							rw_reg_status <= 4'b1101;  //4'b0000;
    							rw_reg_status_temp <= 4'b0000;
    							byte_received_cnt <= 3'b000;
    					  end
    					  endcase
    				  //end
    			 end
    			 //----------------------------------------------------
    			 4'b1100: begin
    				  //if(rec_flag) begin
    					  case (byte_received_cnt)
    					  3'b000: begin
    							if(rec_flag) begin
    								dacref_fudukongzhizi[11:8] <= rec_data[3:0];
    								rw_reg_status <= 4'b1101;
    								byte_received_cnt <= 3'b001;
    							end
    					  end
    					  3'b001: begin
    							if(rec_flag) begin
    								dacref_fudukongzhizi[7:0] <= rec_data;
    								rw_reg_status <= 4'b1101;
    								byte_received_cnt <= 3'b010;
    							end
    					  end
    					  3'b010: begin
    							dacref_fudukongzhizi_shadow <= dacref_fudukongzhizi;
    							byte_received_cnt <= 3'b011;
    					  end
    					  3'b011: begin
    							dacref_clk <= 1'b1;
    							if(delay_cnt == 4'b0011)
    							begin
    								delay_cnt <= 4'b0000;
    								byte_received_cnt <= 3'b111;
    						   end
    						   else
    						   begin
    								delay_cnt <= delay_cnt+1;
    						   end
    					  end
    					  3'b111: begin
    							dacref_clk <= 1'b0;
    							rw_reg_status <= 4'b1101;
    							rw_reg_status_temp <= 4'b0000;
    							byte_received_cnt <= 3'b000;
    					  end
    					  endcase
    				  //end
    			 end
    			 
    			 4'b1101: begin
    				  if(~rec_flag) begin  //字节接收完成标志位复位等待
    					   rw_reg_status <= rw_reg_status_temp;
    				  end
    			 end
    			 //----------------------------------------------------
    			 4'b1110: begin
    				  dacsin_pinlvkongzhizi <= 32'h00454321;
    				  dacsin_xiangweikongzhizi <= 10'h234;
    				  dacref_fudukongzhizi <= 12'h321;
    				  rw_reg_status_temp <= 4'b0000;
    				  rw_reg_status <= 4'b1101;
    			 end
    			 4'b1111: begin
    				  if(delay_cnt == 4'b0011)
    				  begin
    					   delay_cnt <= 4'b0000;
    						rw_reg_status <= 4'b0000;
    				  end
    				  else
    				  begin
    					   delay_cnt <= delay_cnt+1;
    				  end
    			 end
    			 //----------------------------------------------------
    			 4'b1010: begin
    				  dac_start_flag <= 1'b1;
    				  rw_reg_status <= 4'b1101;
    				  rw_reg_status_temp <= 4'b0000;
    			 end
    			 //----------------------------------------------------
    			 4'b1011: begin
    				  dac_start_flag <= 1'b0;
    				  rw_reg_status <= 4'b1101;
    				  rw_reg_status_temp <= 4'b0000;
    			 end
    			 //----------------------------------------------------
    			 4'b1001: begin
    				  if(rec_flag) begin
    					   dac_clk_pdf_shadow <= rec_data[3:0];
    						rw_reg_status <= 4'b1101;
    						rw_reg_status_temp <= 4'b0000;
    				  end
    			 end
    			 endcase
    		end
    	end

    既然dac控制模块的spi接收和发送设计好了,dds模块当然不能少,这部分就相对简单些。
    //dac时钟分频模块
    	reg dac_clk;
    	reg[3:0] dac_clk_cnt;  //分频,后面可以对dac_clk_cnt进行预分频处理
    	reg[3:0] dac_clk_pdf;  //预分频
    	always @ (posedge clk or negedge nrst)
    	begin
    		 if(~nrst)
    		 begin
    			  dac_clk <= 1'b0;
    			  dac_clk_cnt <= 4'b0;
    			  dac_clk_pdf <= 4'h1;
    		 end
    		 else begin
    			  if(dac_start_flag) begin
    				  if(dac_clk_cnt == dac_clk_pdf) begin
    						dac_clk_cnt <= 4'b0;
    						dac_clk <= ~dac_clk;
    						dac_clk_pdf <= dac_clk_pdf_shadow;
    				  end
    				  else begin
    						dac_clk_cnt <= dac_clk_cnt+1;
    				  end
    			  end
    		 end
    	end
    	
    	//dac输出模块
    	assign dacref_fudu = dacref_fudukongzhizi_shadow;  //直接输出到dacref中
    	//reg[11:0] dacsin_output;
    	reg[31:0] leijiazi;
    	reg[9:0] dac_rom_addr;
    	//assign dacsin_enable = nrst&dac_start_flag;
    	always @ (posedge clk or negedge nrst)
    	begin
    		 if(~nrst)  //dacsin失能
    		 begin
    			  leijiazi <= {dacsin_xiangweikongzhizi_shadow, 22'h000000};  //累加字存储器
    			  dac_rom_addr <= 10'h000;
    		 end
    		 else  //dacsin使能
    		 begin
    			  if(dac_start_flag) begin
    				   leijiazi <= leijiazi+dacsin_pinlvkongzhizi_shadow;
    					dac_rom_addr <= leijiazi[31:22];
    			  end
    			  else begin
    				   dac_rom_addr <= 10'h000;
    			  end
    		 end
    	end
    	
    	sin_table U3(
    	  .clka(clk),
    	  .addra(dac_rom_addr),
    	  .douta(dacsin_output)
    	);
    这里用到了名为sin_table的ROM软核,使用Block RAM组合成12位数据输出,10位数据深度(即1024个存储空间)的ROM,空间为12bits*1024。

    题外话:既然提到了核,那么想当然联想到他们的分类:软核、固核和硬核三种。

    软核:属于综合之前的RTL模型,只经过功能仿真,最后需要进行综合及布线后才能使用。但是不同的布线环境对其效果是不一样的,存在发送错误的可能性。

    固核:带有局部规划信息的网表,对时序有一定约束后的产物,只需要通过布线工具就可以使用。

    硬核:就是经过验证的设计版图,其物理版图不允许再进行修改,模块时序要求非常严格,可靠性相当高。

    二. 修改spi从机模块

    根据上面的dac控制模块,我们需要对先前的spi从机模块进行适当修改。
    module myspi(nrst, clk, ncs, mosi, miso, sck, rec_flag, rec_data, send_flag, sending_flag, send_data);  //miso主入从出,mosi主出从入
    	input clk, nrst;
    	input ncs, mosi, sck;
    	input send_flag;
    	input[7:0] send_data;
    	output[7:0] rec_data;
    	output miso;
    	output sending_flag;
    	output rec_flag;
    这样,spi模块就加入与dac控制模块的通信线路了,是不是很方便。

    三. 生成顶层模块

    这个主要是考虑fpga最终IO口输出情况,有点像将模块打包成一个模块,在外看FPGA内部模块相当于一个黑匣子,我们操作的时候则只关心FPGA留给我们的通信管脚就可以了。
    module dac_top(clk, nrst, ncs, mosi, miso, sck, dac_clk, dacref_fudu, dacsin_output, dacref_clk);
    	input clk, nrst, ncs;
    	input mosi, sck;
    	output miso;
    	
    	output dac_clk;
    	output dacref_clk;
    	output[11:0] dacref_fudu;
    	output[11:0] dacsin_output;
    	
    	wire send_flag, rec_flag, sending_flag;
    	wire[7:0] rec_data;
    	wire[7:0] send_data;
    	
    	myspi U1(
    		.clk(clk), 
    		.nrst(nrst), 
    		.ncs(ncs), 
    		.mosi(mosi), 
    		.miso(miso), 
    		.sck(sck), 
    		.rec_flag(rec_flag), 
    		.rec_data(rec_data), 
    		.send_flag(send_flag), 
    		.sending_flag(sending_flag), 
    		.send_data(send_data)
    	);
    	
    	dac_reg_rw_spi U2(
    		.clk(clk), 
    		.nrst(nrst), 
    		.rec_flag(rec_flag), 
    		.rec_data(rec_data), 
    		.send_flag(send_flag), 
    		.sending_flag(sending_flag), 
    		.send_data(send_data),
    		.dac_clk(dac_clk),
    		.dacref_fudu(dacref_fudu),
    		.dacsin_output(dacsin_output),
    		.dacref_clk(dacref_clk)
    	);
    
    endmodule

    四. ModelSim的功能验证

    module dac_top_test;
    
    	// Inputs
    	reg clk;
    	reg nrst;
    	reg ncs;
    	reg mosi;
    	reg sck;
    
    	// Outputs
    	wire miso;
    	wire dac_clk;
    	wire[11:0] dacref_fudu;
    	wire[11:0] dacsin_output;
    
    	// Instantiate the Unit Under Test (UUT)
    	dac_top uut (
    		.clk(clk), 
    		.nrst(nrst), 
    		.ncs(ncs), 
    		.mosi(mosi), 
    		.miso(miso), 
    		.sck(sck),
    		.dac_clk(dac_clk),
    		.dacref_fudu(dacref_fudu),
    		.dacsin_output(dacsin_output)
    	);
    
    	initial begin
    		// Initialize Inputs
    		clk = 0;
    		nrst = 0;
    		ncs = 1;
    		mosi = 0;
    		sck = 0;
    
    		// Wait 100 ns for global reset to finish
    		#100;
    		nrst = 1;
    		#20;
    		ncs = 0;
    		
    		#100;	         mosi = 0;  //先发送高位 00100011 写入频率控制字
    		#100; sck = 1;
    		#100; sck = 0; mosi = 0;		
    		#100; sck = 1;
    		#100; sck = 0; mosi = 1;		
    		#100; sck = 1;
    		#100; sck = 0; mosi = 0;		
    		#100; sck = 1;
    		#100; sck = 0; mosi = 0;		
    		#100; sck = 1;
    		#100; sck = 0; mosi = 0;		
    		#100; sck = 1;
    		#100; sck = 0; mosi = 1;	
    		#100; sck = 1;
    		#100; sck = 0; mosi = 1;		
    		#100; sck = 1;
    		#100; sck = 0;
    		//
    		#100;	         mosi = 0;  //发送 00001111
    		#100; sck = 1;
    		#100; sck = 0; mosi = 0;		
    		#100; sck = 1;
    		#100; sck = 0; mosi = 0;		
    		#100; sck = 1;
    		#100; sck = 0; mosi = 0;		
    		#100; sck = 1;
    		#100; sck = 0; mosi = 1;		
    		#100; sck = 1;
    		#100; sck = 0; mosi = 1;		
    		#100; sck = 1;
    		#100; sck = 0; mosi = 1;	
    		#100; sck = 1;
    		#100; sck = 0; mosi = 1;		
    		#100; sck = 1;
    		#100; sck = 0;
    		//
    		#100;	         mosi = 1;  //发送 11111110
    		#100; sck = 1;
    		#100; sck = 0; mosi = 1;		
    		#100; sck = 1;
    		#100; sck = 0; mosi = 1;		
    		#100; sck = 1;
    		#100; sck = 0; mosi = 1;		
    		#100; sck = 1;
    		#100; sck = 0; mosi = 1;		
    		#100; sck = 1;
    		#100; sck = 0; mosi = 1;		
    		#100; sck = 1;
    		#100; sck = 0; mosi = 1;	
    		#100; sck = 1;
    		#100; sck = 0; mosi = 1;		
    		#100; sck = 1;
    		#100; sck = 0;
    		//
          #100;	         mosi = 0;  //发送 00000001
    		#100; sck = 1;
    		#100; sck = 0; mosi = 0;		
    		#100; sck = 1;
    		#100; sck = 0; mosi = 0;		
    		#100; sck = 1;
    		#100; sck = 0; mosi = 0;		
    		#100; sck = 1;
    		#100; sck = 0; mosi = 0;		
    		#100; sck = 1;
    		#100; sck = 0; mosi = 0;		
    		#100; sck = 1;
    		#100; sck = 0; mosi = 0;	
    		#100; sck = 1;
    		#100; sck = 0; mosi = 1;		
    		#100; sck = 1;
    		#100; sck = 0;  
    		//
    		#100;
    		#100 sck = 1;  #100 sck = 0;
    		#100 sck = 1;  #100 sck = 0;	
    		#100 sck = 1;  #100 sck = 0;
    		#100 sck = 1;  #100 sck = 0;
    		#100 sck = 1;  #100 sck = 0;
    		#100 sck = 1;  #100 sck = 0;
    		#100 sck = 1;  #100 sck = 0;
    		#100 sck = 1;  #100 sck = 0;
    		//
    		#100;
    		#100 sck = 1;  #100 sck = 0;
    		#100 sck = 1;  #100 sck = 0;	
    		#100 sck = 1;  #100 sck = 0;
    		#100 sck = 1;  #100 sck = 0;
    		#100 sck = 1;  #100 sck = 0;
    		#100 sck = 1;  #100 sck = 0;
    		#100 sck = 1;  #100 sck = 0;
    		#100 sck = 1;  #100 sck = 0;
    		//
          #100;	         mosi = 1;  //发送 11100001  启动dac控制模块
    		#100; sck = 1;
    		#100; sck = 0; mosi = 1;		
    		#100; sck = 1;
    		#100; sck = 0; mosi = 1;		
    		#100; sck = 1;
    		#100; sck = 0; mosi = 0;		
    		#100; sck = 1;
    		#100; sck = 0; mosi = 0;		
    		#100; sck = 1;
    		#100; sck = 0; mosi = 0;		
    		#100; sck = 1;
    		#100; sck = 0; mosi = 0;	
    		#100; sck = 1;
    		#100; sck = 0; mosi = 1;		
    		#100; sck = 1;
    		#100; sck = 0; 
    		//
    		#50000;        mosi = 0;  //延时50000个时间单元后再次修改频率控制字
    		#100; sck = 1;
    		#100; sck = 0; mosi = 0;		
    		#100; sck = 1;
    		#100; sck = 0; mosi = 1;		
    		#100; sck = 1;
    		#100; sck = 0; mosi = 0;		
    		#100; sck = 1;
    		#100; sck = 0; mosi = 0;		
    		#100; sck = 1;
    		#100; sck = 0; mosi = 0;		
    		#100; sck = 1;
    		#100; sck = 0; mosi = 0;	
    		#100; sck = 1;
    		#100; sck = 0; mosi = 1;		
    		#100; sck = 1;
    		#100; sck = 0;
    		//
    		#100;	         mosi = 0;  
    		#100; sck = 1;
    		#100; sck = 0; mosi = 0;		
    		#100; sck = 1;
    		#100; sck = 0; mosi = 0;		
    		#100; sck = 1;
    		#100; sck = 0; mosi = 0;		
    		#100; sck = 1;
    		#100; sck = 0; mosi = 0;		
    		#100; sck = 1;
    		#100; sck = 0; mosi = 0;		
    		#100; sck = 1;
    		#100; sck = 0; mosi = 0;	
    		#100; sck = 1;
    		#100; sck = 0; mosi = 1;		
    		#100; sck = 1;
    		#100; sck = 0;
    		//
    		#100;	         mosi = 0;  
    		#100; sck = 1;
    		#100; sck = 0; mosi = 0;		
    		#100; sck = 1;
    		#100; sck = 0; mosi = 0;		
    		#100; sck = 1;
    		#100; sck = 0; mosi = 0;		
    		#100; sck = 1;
    		#100; sck = 0; mosi = 0;		
    		#100; sck = 1;
    		#100; sck = 0; mosi = 0;		
    		#100; sck = 1;
    		#100; sck = 0; mosi = 0;	
    		#100; sck = 1;
    		#100; sck = 0; mosi = 0;		
    		#100; sck = 1;
    		#100; sck = 0;
    		//
    		#100;	         mosi = 0;  
    		#100; sck = 1;
    		#100; sck = 0; mosi = 0;		
    		#100; sck = 1;
    		#100; sck = 0; mosi = 0;		
    		#100; sck = 1;
    		#100; sck = 0; mosi = 0;		
    		#100; sck = 1;
    		#100; sck = 0; mosi = 0;		
    		#100; sck = 1;
    		#100; sck = 0; mosi = 0;		
    		#100; sck = 1;
    		#100; sck = 0; mosi = 0;	
    		#100; sck = 1;
    		#100; sck = 0; mosi = 0;		
    		#100; sck = 1;
    		#100; sck = 0;
    		//
    		#100;	         mosi = 0;  
    		#100; sck = 1;
    		#100; sck = 0; mosi = 0;		
    		#100; sck = 1;
    		#100; sck = 0; mosi = 0;		
    		#100; sck = 1;
    		#100; sck = 0; mosi = 0;		
    		#100; sck = 1;
    		#100; sck = 0; mosi = 0;		
    		#100; sck = 1;
    		#100; sck = 0; mosi = 0;		
    		#100; sck = 1;
    		#100; sck = 0; mosi = 0;	
    		#100; sck = 1;
    		#100; sck = 0; mosi = 0;		
    		#100; sck = 1;
    		#100; sck = 0;
    	end
    	
    	always #5 clk=~clk;  //sck必须为clk的频率的十分之一或低于十分之一
          
    endmodule

    最终的实物图~~





  • 相关阅读:
    8行代码批量下载GitHub上的图片
    python经典面试算法题1.1:如何实现链表的逆序
    pandas处理excel的常用方法技巧(上)
    numpy---python数据分析
    python、C++经典算法题:打印100以内的素数
    Java中数组、集合、链表、队列的数据结构和优缺点和他们之间的区别
    Hystrix
    Java中的static关键字解析
    Spring Boot
    Springcloud和Dubbo的区别。Eureka和Ribbon和Hystrix和zuul
  • 原文地址:https://www.cnblogs.com/xhyzjiji/p/3712758.html
Copyright © 2020-2023  润新知