基于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; parameterBIT_CNT=9; parameterbit_flag_cnt=2603; // 产生bit采集标志位 //parameterclean_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; elsestop_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

【基于fpga的精简协议帧实现(仿真模块利用task)】这个模块是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:; endcasealways@(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.仿真结果如下
基于fpga的精简协议帧实现(仿真模块利用task)
文章图片

模块分析,就是每个信号都要分析,多仿真,仿真没问题只是一小部分,还有时序需要上板调试,以及ise的ila的信号抓取。
4.下面P出task的测试文件的写法。
`timescale 1ns/1ns module tb_top; regsclk; regrst_n; regrx; wiretx; 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; endalways #20 sclk = ~sclk; initial begin rx <= 1'b1; #2000 rx_byte(); endtask 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次 endtasktask 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 defparamtop_inst.tx_crtl_inst.CNT=9; defparamtop_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


    推荐阅读