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