FPGA实验之串口收发整合
功能:接收一个8位二进制数,并把它传给上位机。
数据包括1个起始位,8个二进制位,1个奇校验位,1个停止位,共11位。
(1) 建立工程
(2) 编写程序
顶层模块如下:
module UART_TOP(input CLK,RST,RXD,
output TXD);
UART_send_receive U1(.CLK(CLK),
.RST(RST),
.RXD(RXD),
.call_send(call_send),//CLK:时钟信号; RST:复位信号; RXD:接收数据引脚;
.Send_Data(Send_Data),//Send_Data:数据输入信号;call_send:发送使能信号
.Send_Done(Send_Done),//Send_Done:发送完成输出信号;
.Receive_Done(Receive_Done), //Receive_Done:接收完成信号;
.Receive_error(Receive_error), //接收错误的信号
.TXD(TXD), //TXD:发送输出
.Receive_data(Receive_data)); //Receive_data:接收完成的数据
reg call_send,Send_Done,Receive_Done,Receive_error;
reg [7:0] Send_Data,Receive_data;
reg [7:0] i;
always @(posedge CLK or negedge RST) // 测试串口收发模块
if(!RST)
begincall_send<=1'b0; end
else
case(i)
0:if(Receive_error) begin i<=1'b0; end //如果接收错误,则停留在这一步,继续等待接收
elseif(Receive_Done) begin i<=i+1'b1; end //如果接收完成到达下一步,否则停留在这一步
elsei<=8'b0;
1:if(Send_Done) begin i<=i+1'b1; call_send<=1'b0;end // 将发送使能信号置1,将收到的数据发送给串口
elsebegin call_send<=1'b1;Send_Data<=Receive_data; end
2:i<=8'b0; //返回第一步
endcase
endmodule
顶层模块的目的是验证串口收发程序。
模块及端口定义:module UART_TOP(inputCLK,RST,RXD, output TXD);
发送与接收函数的例化:
UART_send_receiveU1(.CLK(CLK),
.RST(RST),
.RXD(RXD),
.call_send(call_send),//CLK:时钟信号; RST:复位信号; RXD:接收数据引脚;
.Send_Data(Send_Data),//Send_Data:数据输入信号;call_send:发送使能信号
.Send_Done(Send_Done),//Send_Done:发送完成输出信号;
.Receive_Done(Receive_Done),
.Receive_error(Receive_error),
.TXD(TXD), //Receive_Done:接收完成信号;TXD:发送输出
.Receive_data(Receive_data)); //Receive_data:接收完成的数据
相关寄存器的声明:
regcall_send,Send_Done,Receive_Done,Receive_error;
reg [7:0]Send_Data,Receive_data;
reg [7:0] i;
always测试程序:
always @(posedgeCLK or negedge RST) // 测试串口收发模块
if(!RST)
begin call_send<=1'b0;end
else
case(i)
0: if(Receive_error) begini<=1'b0; end //如果接收错误,则停留在这一步,继续等待接收
elseif(Receive_Done) begin i<=i+1'b1; end //如果接收完成到达下一步,否则停留在这一步
elsei<=8'b0;
1: if(Send_Done) begini<=i+1'b1; call_send<=1'b0;end // 将发送使能信号置1,将收到的数据发送给串口
elsebegin call_send<=1'b1;Send_Data<=Receive_data; end
2: i<=8'b0; //返回第一步
endcase
endmodule
被顶层模块例化的UART_send_receive模块 :
包括接收部分,发送部分,和检错部分
module UART_send_receive(
input CLK,RST,RXD,call_send, //CLK:时钟信号; RST:复位信号; RXD:接收数据引脚;
input [7:0] Send_Data, //Send_Data:数据输入信号;call_send:发送使能信号
output Send_Done,Receive_error,Receive_Done,TXD, //Send_Done:发送完成输出信号;
output [7:0]Receive_data ); //Receive_Done:接收完成信号;TXD:发送输出
//Receive_data:接收完成的数据
//Receive_error:向上层输出的接收错误信号
Parameter参数定义:波特率参数
//-------------------parameter----------------------//
parameter BPS115200=9'd434;//每位数据传输时间为t=1/115200 s,周期T=1/50000000,计数值为t/T=434
//parameter BPS9600=13'd5208; //每位数据传输时间为t=1/9600 s,周期T=1/50000000,计数值为t/T=5208
Reg类型参数定义
//-------------------reg----------------------//
reg [15:0]send_C1,receive_C1; //send_C1:发送计数器; receive_C1:接收计数器;
reg [7:0] send_ii,receive_ii; //send_ii:发送的步骤; receive_ii:接收的步骤
reg txd,send_done,send_odd; //txd:发送寄存器;send_done:reg类型发送完成信号; send_odd:发送的奇校验数据
reg receive_done,Receive_odd,receive_odd; //receive_done:reg类型接收完成信号;receive_odd:接收的奇校验位
reg receive_error; //reg类型的接收错误
reg [7:0]receive_data; //receive_data:接收到的数据;
UART_send_receive模块中的发送数据的部分
always @(posedge CLK or negedge RST) //发送部分
if(!RST)
begin send_C1<=16'd0; txd<=1'b1;send_ii<=0;send_done<=1'b0; end
else if(call_send)
case(send_ii)
0:if(send_C1==BPS115200-2) begin send_C1<=16'd0; send_ii<=send_ii+1'b1;end //起始位
else begin send_C1<=send_C1+1'd1; txd<=1'b0; send_odd<=^~Send_Data; end
//按位同或求奇校验,,,如果按位异或(even_data<=^Send_Data;)求偶校验
1,2,3,4,5,6,7,8:
if(send_C1==BPS115200-1)begin send_C1<=16'd0; send_ii<=send_ii+1'b1; end //数据位
else begin send_C1<=send_C1+1'd1; txd<=Send_Data[send_ii-1]; end
9:if(send_C1==BPS115200-1) begin send_C1<=16'd0; send_ii<=send_ii+1'b1;end //校验位
else begin send_C1<=send_C1+1'd1; txd<=send_odd; end
10:if(send_C1==BPS115200-1)begin send_C1<=16'd0; send_ii<=send_ii+1'b1; end // 停止位
else begin send_C1<=send_C1+1'd1; txd<=1'b1; end
11:begin send_done<=1'b1; send_ii<=send_ii+1'b1; end
12:begin send_done<=1'b0; send_ii<=1'b0; end
endcase
UART_send_receive模块中的接收数据的部分
always @(posedge CLK or negedge RST) //接收部分
if(!RST)
begin receive_C1<=16'd0; receive_ii<=1'b0; receive_done<=1'b0;receive_data<=8'b0;end
else
case(receive_ii)
0:if(!RXD) begin receive_ii<=receive_ii+1'b1; end
1:if(receive_C1==BPS115200) begin receive_C1<=16'd0;receive_ii<=receive_ii+1'b1; end //起始位,,没做处理,直接忽略
elsereceive_C1<=receive_C1+1'b1;
2,3,4,5,6,7,8,9:
begin
if(receive_C1==BPS115200-1)begin receive_C1<=16'd0; receive_ii<=receive_ii+1'b1; end //接收数据位
else receive_C1<=receive_C1+1'b1;
if(receive_C1==BPS115200>>1)begin receive_data[receive_ii-2]<=RXD; end //采样发生在一帧数据的中间
end
10: begin if(receive_C1==BPS115200-1) begin receive_C1<=16'd0;receive_ii<=receive_ii+1'b1; end //接收校验位
elsereceive_C1<=receive_C1+1'b1;
if(receive_C1==BPS115200>>1)begin receive_odd<=RXD; end//receive_odd:从RXD中接收到的校验位
Receive_odd<=^~receive_data; //Receive_odd:是接收到
end
11:if(receive_C1==BPS115200-1)begin receive_C1<=16'd0; receive_ii<=receive_ii+1'b1; end //接收停止位,依然没做处理
elsereceive_C1<=receive_C1+1'b1;
12:beginreceive_done<=1'b1;receive_ii<=receive_ii+1'b1; end //产生接收完成信号
13:beginreceive_done<=1'b0;receive_ii<=1'b0; end //产生接收完成信号
endcase
UART_send_receive模块中的检错的部分
always @(posedge CLK or negedge RST) //检测是否有接收错误,如果接收错误产生错误信号
if(!RST)
begin receive_error<=1'b0; end
else if(Receive_odd!=receive_odd) //如果接收的数据的各个位同或与接收到的校验位不同,产生错误信号
receive_error=1'b1;
else receive_error<=1'b0;
UART_send_receive信号的连接部分
assign TXD = txd; //TXD输出信号
assign Send_Done = send_done; // 发送完成信号
assign Receive_Done=receive_done; //接收完成信号
assign Receive_data = receive_data; //接收完成的数据
assign Receive_error = receive_error; //接收错误信号
(3) 仿真部分
由于之前的接收和发送都进行了Modelsim仿真,再进行收发结合的时候没有进行Modelsim仿真,直接用串口调试助手和SignalTap结合调试。
(SignalTap使用并不熟,并且FPGA资源有限(存储深度最多能选8K),所以,SignalTap只能采集到接收的完成,并不能显示发送的完成,需要进一步进行SignalTap的配置优化)。
注:工程下载链接:https://pan.baidu.com/s/1DKTZW1IxOIhC-NPXhsREDQ 密码:s7c5