FPGA串口接收与发送详解( part 3 )
作者:互联网
之前的part1~2已经详解完了单个数据的串口接收与发送,链接如下:
FPGA串口接收与发送 详解 (part 1 )_居安士的博客-CSDN博客
FPGA串口接收与发送详解( part 2 )_居安士的博客-CSDN博客
我们在实际使用串口进行数据传输的时候,不会只能传输一个字节的单个数据,而是以数据帧的形式进行发送,下面就介绍一下,如何打包数据帧,以及数据帧如何发送与接收
目录
一、打包数据帧
数据帧,就是数据链路层的协议数据单元,它包括三部分:帧头,数据部分,帧尾。
其中,帧头和帧尾包含一些必要的控制信息,比如同步信息、地址信息、差错控制信息等;
数据部分则包含网络层传下来的数据
其中,AA 55就是帧头,00FF是帧尾,ADDR是地址,DATA是数据
一帧数据的接收,一共4个地址2个数据,帧头AA 55,帧尾00 FF,通过接收PC端的数据,将数据部分包含的地址和数据解析出来
一帧数据的发送,发送AA 55 4个地址 2个数据 00 FF
(上面的帧格式都是我自己定义的,而非固定格式,大家可以根据自己需要进行修改)
二、一帧数据的接收
一帧数据的接收是通过接收PC端的数据,将数据部分包含的地址和数据解析出来
输入的是单个的8位并行数据[7:0]dout,以及单个数据接收完毕使能信号dout_en
输出的是写数据[15:0]wr_data,写地址[31:0]wr_addr,写使能wr_en
接收一帧数据步骤:
(1)定义写数据[15:0]wr_data,写地址[31:0]wr_addr
(2)定义一帧数据的缓存寄存器(10个),让帧头,数据,帧尾缓存进去:通过把[8:0]dout移位10次得到dout9~dout0
(3)定义状态机,分为初始,写判断,写3个状态
(4) 初始状态:把读写地址和数据清零
写判断:根据协议判断是不是写
写:把dout4—dout7存入写地址,dout2—dout3存入写数据
(5)设置清零clean,在dout存入地址/数据完成之后,清掉地址/数据
module uart_RX(
input clk_25m,
input reset,
input [7:0] dout,//单个的8位并行数据
input dout_en,//单个数据接收完毕使能信号
output reg [15:0] wr_data, //写数据
output reg [31:0] wr_addr,//写地址
output reg wr_en//写使能
);
/*定义一帧数据的缓存寄存器(10个)*/
reg [7:0] dout0;
reg [7:0] dout1;
reg [7:0] dout2;
reg [7:0] dout3;
reg [7:0] dout4;
reg [7:0] dout5;
reg [7:0] dout6;
reg [7:0] dout7;
reg [7:0] dout8;
reg [7:0] dout9;
reg clean;//定义清除信号
always@(posedge clk_25m)begin
if(reset||clean)begin
dout0<=8'd0;
dout1<=8'd0;
dout2<=8'd0;
dout3<=8'd0;
dout4<=8'd0;
dout5<=8'd0;
dout6<=8'd0;
dout7<=8'd0;
dout8<=8'd0;
dout9<=8'd0;
end
else if(dout_en)begin//来一个dout_en移位一次
dout0<=dout;
dout1<=dout0;
dout2<=dout1;
dout3<=dout2;
dout4<=dout3;
dout5<=dout4;
dout6<=dout5;
dout7<=dout6;
dout8<=dout7;
dout9<=dout8;
end
end
/*接收一帧数据*/
parameter S0=4'd0;//初始状态
parameter S1=4'd1;//写判断
parameter S2=4'd2;//读
reg [2:0] state;
always@(posedge clk_25m)begin
if(reset)begin
clean<=1'd0;
wr_data<=16'd0;
wr_addr<=32'd0;
wr_en <=1'd0;
state <=S0;
end
else begin
case(state)
S0:begin
clean <=1'd0;
wr_data<=16'd0;
wr_addr<=32'd0;
wr_en <=1'd0;
state <=S1;
end
S1:begin
if(dout9==8'hAA&&dout8==8'h55&&dout1==8'h00&&dout0==8'hFF)begin
wr_en <=1'd1;//判断帧头帧尾
state <=S2;
end
else begin
wr_en <=1'd0;
state <=S1;
end
end
S2:begin
clean <=1'd1;
wr_data<={dout2,dout3};//从低位到高位
wr_addr<={dout4,dout5,dout6,dout7};//从低位到高位排列
state <=S0;
end
endcase
end
end
endmodule
三、一帧数据的发送
一帧数据的发送需要发送AA 55 4个地址 2个数据 00 FF
输入4个地址[31:0]send_addr,2个数据[15:0]send_data
输出单个数据[7:0]din,单个数据发送使能din_en
目的是把串行send_addr和串行send_data解析出并行数据[7:0]din
此外,定义帧发送使能send_en,发送帧状态send_state
一帧数据发送步骤:
(1)定义10个寄存器data0~data9,在开始发送后,把协议与10个寄存器对应
(2)定义发送数据个数send_num,把波特率结束的下降沿作为一个数据发送完的标志baud_finish_falg
(3)状态机:
初始状态:din_en=0,din清零,send_state=0
启动状态:在帧发送使能send_en=1时,产生单个数据发送使能信号din_en=1,发送帧状态send_state=1
发送状态:每baud_finish_falg一下,计数send_num一次
停止状态:send_num=10停止,din_en=0,send_en=0,send_state=0
(4)对应din
写case(send_num)
send_num=0时,发送第0位;send_num=1时,发送第1位…send_num=9时,发送第9位
module uart_TX(
input clk_25m,
input reset,
input send_en,//发送帧使能
input TX_start,
input [15:0] send_data,
input [31:0] send_addr,
output reg din_en ,//发送使能信号
output reg [7:0]din ,//发送的8位数据
output reg send_state //发送帧状态(是否发送完成)
);
/*定义10个寄存器*/
reg [7:0] data9;//定义10个寄存器
reg [7:0] data8;
reg [7:0] data7;
reg [7:0] data6;
reg [7:0] data5;
reg [7:0] data4;
reg [7:0] data3;
reg [7:0] data2;
reg [7:0] data1;
reg [7:0] data0;
always@(posedge clk_25m)begin//缓存数据
if(reset)begin
data9<=8'd0;
data8<=8'd0;
data7<=8'd0;
data6<=8'd0;
data5<=8'd0;
data4<=8'd0;
data3<=8'd0;
data2<=8'd0;
data1<=8'd0;
data0<=8'd0;
end
else if(send_en&&!send_state) begin//发送帧使能=1&&不在发送状态
data9<=8'hAA;
data8<=8'h55;
data7<=send_addr[31:24];
data6<=send_addr[23:16];
data5<=send_addr[15:8];
data4<=send_addr[7:0];
data3<=send_data[15:8];
data2<=send_data[7:0];
data1<=8'h00;
data0<=8'hFF;
end
else begin
data9<=data9;
data8<=data8;
data7<=data7;
data6<=data6;
data5<=data5;
data4<=data4;
data3<=data3;
data2<=data2;
data1<=data1;
data0<=data0;
end
end
/*把波特率结束的下降沿作为一个数据发送完的标志*/
reg TX_start_dly;
wire baud_finish_flag;//定义一个数据发送完成的标志
always@(posedge clk_25m)begin//buad_start延时一拍
if(reset)begin
TX_start_dly<=1'd0;
end
else begin
TX_start_dly<=TX_start;
end
end
assign baud_finish_flag=!TX_start&&TX_start_dly;//下降沿检测
/*发送数据状态机*/
parameter S0=4'd0;//初始状态
parameter S1=4'd1;//启动状态
parameter S2=4'd2;//发送状态
parameter S3=4'd3;//完成状态
reg [2:0]state;
reg [3:0] send_num;//定义发送数据个数
reg clean;//定义清除信号
always@(posedge clk_25m)begin
if(reset)begin
send_state<=1'd0;
send_num <=4'd0;
din_en <=1'd0 ;
state<=S0;
end
else begin
clean<=1'd0;
case(state)
S0:begin
if(send_en)begin//产生单个数据发送使能信号din_en
state<=S1;
din_en <=1'd1 ;
send_state <=1'd1 ;//帧状态=1
end
else begin
din_en <=1'd0 ;
send_state<=1'd0;
send_num <=4'd0;
state<=S0;
end
end
S1:begin
din_en <=1'b0;
send_state<=send_state;
if(baud_finish_flag)begin//发完一个数据计数一次send_num
send_state <=1'd2 ;
send_num<=send_num+4'd1;
end
else begin
send_state <=1'd1 ;
send_num<=send_num;
end
end
S2:begin
if(send_num==4'd10)begin
next_state=S0;
clean<=1'd1;
send_num<=4'd0;
send_state<=1'd0 ;
end
else begin
next_state=S2;
clean<=1'd0;
send_num<=send_num;
send_state<=1'd1 ;
end
end
endcase
end
end
/*发送din*/
always @(posedge clk_25m)begin
if(reset)begin
din<=8'hFF;
end
else begin
case(send_num)
4'd0:din<=data9;
4'd1:din<=data8;
4'd2:din<=data7;
4'd3:din<=data6;
4'd4:din<=data5;
4'd5:din<=data4;
4'd6:din<=data3;
4'd7:din<=data2;
4'd8:din<=data1;
4'd9:din<=data0;
default:din<=8'hFF;
endcase
end
end
endmodule
标签:en,一帧,FPGA,send,发送,part,串口,数据,reg 来源: https://blog.csdn.net/weixin_46188211/article/details/123488569