基于fpga的精简协议帧实现(仿真模块利用task)

1.数据在传输过程中,需要对数据加密或者按照一定的协议进行数据传输。这次是基于uart芯片对数据进行传输。总共需要3个模块。分别是uart的发送,传输模块以及协议验证模块。需要说明的是uart的接受模块中需要产生一个数据中断位。这样在数据传输过程中,才可以对数据中断,否则会一直有乱码产生。

2.协议帧实现模块,主要使用了之前的状态机。多次采集,对应状态必须严格对比,严格转移。(这次的协议帧是16进制的55_55_55_55_55_55_55_d5_00_00)之前的模块进行了修改,主要是产生终止位。

module tx_crtl(

		input wire sclk,
		input wire rst_n,
		input wire rx_in,
		
		output reg stop_flag,   //新增数据监测停止位
		output reg flag_o,
		output reg [7:0] data_o
);

reg [12:0] cnt;
reg [3:0]  bit_cnt;
reg rx_in_1,rx_in_2;
reg rx_en;     //使能信号值有问题
reg bit_flag;
reg [7:0]tmp_data;
reg tmp_flag;

reg [15:0] cnt_clean;

parameter CNT_CLEAN=44444;//28888;
parameter	CNT=5207;
parameter   BIT_CNT=9;
parameter   bit_flag_cnt=2603;  //	产生bit采集标志位
//parameter   clean_flag=2610;


always@(posedge sclk or negedge rst_n)   //ram输入信号清零计数器
		if(!rst_n)
		cnt_clean<=16'd0;
		else if(flag_o==1'b1)			//  少写了清零条件,导致写地址一直处于清零状态
				cnt_clean<=16'd0;		
		else if(cnt_clean==CNT_CLEAN)
					cnt_clean<=cnt_clean;	// 优先级,当时产生清零标志位没有保持,而是清零导致产生无数个终端位
		else if(flag_o==1'b0)  		 	//flag_o==1'b1,当时想的就是拉高开始计数,结果发现根本不计数
			cnt_clean<=cnt_clean+1'b1;	//因为标志位拉高只有一个时钟周期,应该记拉低的时钟周期。
			

always@(posedge sclk or negedge rst_n)  //数据清零位传递给帧协议
		if(!rst_n)
		stop_flag<=1'b0;
		else if (cnt_clean==CNT_CLEAN-1)
				stop_flag<=1'b1;
		else 	stop_flag<=1'b0;

always@(posedge sclk or negedge rst_n)
		if(!rst_n)
			rx_in_1<=1'b1;
		else rx_in_1<=rx_in;
always@(posedge sclk or negedge rst_n)  //输入信号延时
		if(!rst_n)
			rx_in_2<=1'b1;
		else rx_in_2<=rx_in_1;

always@(posedge sclk or negedge rst_n)   //产生计数使能信号
		if(!rst_n)
			rx_en<=1'b0;
		else if(rx_in_1==1'b0&&rx_in_2==1'b1)
			rx_en<=1'b1;
			else if(bit_cnt==BIT_CNT&&cnt==CNT)
			 rx_en<=1'b0;
			 
always@(posedge sclk or negedge rst_n)
		if(!rst_n)	
			cnt<=13'd0;
			else if(rx_en==1'b0)
				  cnt<=13'd0;
				  else if(cnt==CNT)
						cnt<=13'd0;
				  	else if(rx_en==1'b1)
				  			cnt<=cnt+1'b1;
				 
always@(posedge sclk or negedge rst_n)   //位宽计数
		if(!rst_n)	
			bit_cnt<=4'd0;
				else if(rx_en==1'b0)	
					bit_cnt<=4'd0;
				else if(bit_cnt==BIT_CNT&&cnt==CNT)	
					bit_cnt<=4'd0;	
					else if(cnt==CNT)
						bit_cnt<=bit_cnt+1'b1;

always@(posedge sclk or negedge rst_n)   //产生bit标志位
		if(!rst_n)
			bit_flag<=1'b0;
			else if(cnt==bit_flag_cnt)	
				bit_flag<=1'b1;
				else bit_flag<=1'b0;	

always@(posedge sclk or negedge rst_n)   //数据拼接
		if(!rst_n)	
			tmp_data<=8'd0;
		else if(bit_flag==1'b1&&bit_cnt>=4'd1&&bit_cnt<=4'd8)
				tmp_data<={rx_in_2,tmp_data[7:1]}; 		//少写分号
														//else if(bit_cnt==BIT_CNT&&cnt==clean_flag)  数据不清零条件
														//		tmp_data<=8'd0;

always@(posedge sclk or negedge rst_n)   //数据拼接完成标志
		if(!rst_n)	
		 tmp_flag<=1'b0;
		 else if(bit_flag==1'b1&&bit_cnt==BIT_CNT)
		 	tmp_flag<=1'b1;
		 	else tmp_flag<=1'b0;

always@(posedge sclk or negedge rst_n)
		if(!rst_n)	
			data_o<=8'd0;
		else if(tmp_flag==1'b1)
			data_o<=tmp_data;

always@(posedge sclk or negedge rst_n)
		if(!rst_n)			
			flag_o<=1'b0;
			else flag_o<=tmp_flag;	 
endmodule

   这个模块是uart的接收模块在ucf连线的连接的是fpga的发送端,产生的stop_flag就是终止位是为了监督数据传输的准确性,其余的没变。

module	w_farme(
		
		input wire sclk,
		input wire rst_n,
		input wire flag_uart,
		input wire [7:0] data_uart,
		input wire stop_flag,
		
		output reg flag_w,
		output reg [7:0] data_w


);

reg [10:0] 	state;

parameter idle		=11'b0_0000_0000_01;
parameter h_1_55	=11'b0_0000_0000_10;
parameter h_2_55	=11'b0_0000_0001_00;
parameter h_3_55	=11'b0_0000_0010_00;
parameter h_4_55	=11'b0_0000_0100_00;
parameter h_5_55	=11'b0_0000_1000_00;
parameter h_6_55	=11'b0_0001_0000_00;
parameter h_7_55	=11'b0_0010_0000_00;
parameter h_d5		=11'b0_0100_0000_00;
parameter h_00		=11'b0_1000_0000_00;
parameter h_ok		=11'b1_0000_0000_00;

always@(posedge sclk or negedge rst_n)
		if(!rst_n)
			state<=idle	;  //
			else if(stop_flag==1)
				state<=idle	;
			else if(flag_uart==1'b1)
		 			case(state)
		 			idle  :  if(data_uart==8'h55&&state==idle)
		 						state<=h_1_55;
		 						else state<=idle;
		 			h_1_55:	 if(data_uart==8'h55&&state==h_1_55)
		 						state<=h_2_55;
		 						else state<=idle;
		 			h_2_55:	 if(data_uart==8'h55&&state==h_2_55)
		 						state<=h_3_55;
		 						else state<=idle;
		 			h_3_55:	 if(data_uart==8'h55&&state==h_3_55)
		 						state<=h_4_55;
		 						else state<=idle;
		 			h_4_55:	 if(data_uart==8'h55&&state==h_4_55)
		 						state<=h_5_55;
		 						else state<=idle;
		 			h_5_55:	 if(data_uart==8'h55&&state==h_5_55)
		 						state<=h_6_55;
		 						else state<=idle;
		 			h_6_55:	 if(data_uart==8'h55&&state==h_6_55)
		 						state<=h_7_55;
		 						else state<=idle;
		 			h_7_55:	 if(data_uart==8'hd5&&state==h_7_55)
		 						state<=h_d5;
		 						else state<=idle;
		 			h_d5:	 if(data_uart==8'h00&&state==h_d5)
		 						state<=h_00;
		 						else state<=idle;
		 			h_00:	 if(data_uart==8'h00&&state==h_00)
		 						state<=h_ok;
		 						else state<=idle;
		 			h_ok:	 //if(stop_flag==1)
		 						//state<=idle;
		 					 state<=state;
					default:;
					endcase
					

always@(posedge sclk or negedge rst_n)
		if(!rst_n)
		flag_w<=1'b0;
		else if(state==h_ok&&flag_uart==1'b1)
				flag_w<=flag_uart;
		//else	flag_w<=1'b0; 
		
always@(posedge sclk or negedge rst_n)
		if(!rst_n)
		data_w<=8'd0;
		else if(state==h_ok&&flag_uart==1'b1)
				data_w<=data_uart;
		//else	data_w<=8'd0;
						

			

endmodule

      这个模块为协议验证模块,只有协议通过才可以进行数据传输。最后两个模块是数据发生到下一模块,也就是fpga的接收端即uart的发送端。

3.仿真结果如下

            模块分析,就是每个信号都要分析,多仿真,仿真没问题只是一小部分,还有时序需要上板调试,以及ise的ila的信号抓取。

4.下面P出task的测试文件的写法。

`timescale	1ns/1ns
module	tb_top;
        reg		sclk;
        reg		rst_n;
        reg		rx;
        
        wire         tx;
        
        reg[7:0] a_mem[255:0];//a_mem是一个存储器,相当于一个ram,256个8wei变量
        
        initial   $readmemh("./data.txt", a_mem);
        	//读取sim文件夹下面的data.txt文件,并把读出的数据定义为a_mem ./表示当前 ../表示前一文件夹
        initial
        	begin
        		sclk	=	1'b1;
        		rst_n	<=	1'b0;
        		#300
        		rst_n	<=	1'b1;
        	end
        
        always	#20	sclk	=	~sclk;
        
        initial
        	begin
        		rx	<=	1'b1;
        		#2000
        		rx_byte();
        	end
        
        task	rx_byte();
        	//输入a_mem,输出data,task外部已经定义了,可以在task里面直接用,
        	//而task里面定义的不可以在外面用
        	integer	j;//定义一个整型变量
        	for(j=0;j<256;j=j+1)//for循环
        		rx_bit(a_mem[j]);//a_mem[j]是data.txt文件里面第j个8比特数据
        				//j每次取一个值,就调用一次rx_bit();
        				//一共调用256次
	endtask
        
        task	rx_bit(input  [7:0]	data);//data是a_mem[j]的值。
        	integer	i;
        	for(i=0;i<10;i=i+1)
        		begin
        			case(i)
        			0:	rx	<=	1'b0;//起始位
        			1:	rx	<=	data[0];
        			2:	rx	<=	data[1];
        			3:	rx	<=	data[2];
        			4:	rx	<=	data[3];
        			5:	rx	<=	data[4];
        			6:	rx	<=	data[5];
        			7:	rx	<=	data[6];
        			8:	rx	<=	data[7];
        			//上面8个发送的是数据位
        			9:	rx	<=	1'b1;//停止位
        			endcase
        			#400;//一个波特时间=sclk周期*波特计数器	
        		end
	endtask
	
defparam 	top_inst.tx_crtl_inst.CNT=9;
defparam    top_inst.uart_crtl_inst.CNT=9;
defparam	top_inst.tx_crtl_inst.bit_flag_cnt=4;

	
top	top_inst(

	 	.sclk	(sclk),
	 	.rst_n	(rst_n),
	
	 	.rx_in	(rx)
	
	
);
		
endmodule

              

猜你喜欢

转载自blog.csdn.net/Headogerz/article/details/81937528