英特尔FPGA实训 day 10

今天完成了对串口通信的实现,发送端代码,接收端代码的书写,同时还完成了仿真文件的书写。

收获:

值得注意的就是,rx,tx在实际操作的时候要分清楚,芯片的rx引脚接的是其他设备的tx,而芯片的tx引脚就是接的其他设备的rx。这点一定要分清楚,否则很容易错。

其他的就是个人简单体会。

在这个实训中,我学习了利用FPGA通过串口通信与外部设备进行数据交互的基础知识和技能,其中串口通信代码的实现任务是其中的一个主要部分。
首先,我了解了串口通信的基本原理。通过串口通信,数据被以比特为单位传输,其中传输速率由波特率确定。UART是通用异步收发传输协议,它是在无需时钟或时序信号的情况下实现通信的一种串行通信协议。为此,我需要了解如何设置FPGA串口通信的参数,包括波特率、数据位和校验位等等。
其次,我学习了如何使用FPGA编写串口通信的控制代码。在该实训中,我使用了VHDL和Verilog编写了控制FPGA从外部设备接收数据的代码,并且了解了数据如何被解析和存储到FPGA的存储器中,以及如何发送FPGA生成的数据给外部设备。
最后,我还了解了调试工具的使用方法,以便调试我的代码。通过使用调试器,我可以检查代码的执行情况,解决程序中可能存在的错误,提高代码的效率和正确性。
总的来说,这个实训的串口通信任务对我的FPGA编程和硬件设计技能提高有很大的帮助。我熟练地掌握了如何设置FPGA串口通信的参数和编写串口通信的控制代码,并且从中获得了实践经验,使我能够更加深入地理解数字电路和FPGA技术。

最后附上今天的代码:

共用波特率参数模块

`define SYS_FRQ 50_000_000
`define BAUD_115200

`ifdef BAUD_9600
	`define BAUD_MAX 9600
`elsif BAUD_19200
	`define BAUD_MAX 19200
`elsif BAUD_38400
	`define BAUD_MAX 38400
`elsif BAUD_57600
	`define BAUD_MAX 57600
`elsif BAUD_115200
	`define BAUD_MAX 115200
`else
	`define BAUD_MAX 9600
`endif
	

串口发端:

`include "param.v"
module uart_tx(
	input wire 			clk	,
	input wire 			rst_n	,
	input wire 			tx_req,//发送请求
	input wire [7:0] 	tx_din,//并行数据输入
	
	output reg        tx_dout,//串行数据输出
	output wire       dout_vld//并转串完成标志
	

);
reg [12:0] cnt_bps		;//波特率计数寄存器	
wire       add_cnt_bps	;//波特率计数开始
wire       end_cnt_bps  ;//波特率计数结束

reg [3:0]  cnt_bit      ;//比特计数寄存器
wire       add_cnt_bit  ;//比特计数开始
wire       end_cnt_bit  ;//比特计数结束

reg        tx_flag      ;//发送标志

reg [9:0]  tx_data      ;

//波特率计数器设计
always @(posedge clk or negedge rst_n)begin
	if(!rst_n)begin
		cnt_bps <= 13'd0;
	end 
	else if(add_cnt_bps)begin
		if(end_cnt_bps)begin
			cnt_bps <= 13'd0;
		end 
		else begin
			cnt_bps <= cnt_bps + 1'd1;
		end 
	end 
	else begin
		cnt_bps <= cnt_bps;
	end 
end 

assign add_cnt_bps = tx_flag;
assign end_cnt_bps = add_cnt_bps && cnt_bps == (`SYS_FRQ/`BAUD_MAX) - 1'd1;

always @(posedge clk or negedge rst_n)begin
	if(!rst_n)begin
		cnt_bit <= 4'd0;
	end 
	else if(add_cnt_bit)begin
		if(end_cnt_bit)begin
			cnt_bit <= 4'd0;
		end 
		else begin
			cnt_bit <= cnt_bit + 1'd1;
		end 
	end 
	else begin
		cnt_bit <= cnt_bit;
	end 
end 

assign add_cnt_bit = end_cnt_bps;
assign end_cnt_bit = add_cnt_bit && cnt_bit == 9;

//发送标志tx_flag
always @(posedge clk or negedge rst_n)begin
	if(!rst_n)begin
		tx_flag <= 1'b0;
	end 
	else if(tx_req)begin
		tx_flag <= 1'b1;
	end 
	else if(end_cnt_bit)begin
		tx_flag <= 1'b0;
	end 
	else begin
		tx_flag <= tx_flag;
	end 
end 


//数据缓存,tx_data
always @(posedge clk or negedge rst_n)begin
	if(!rst_n)begin
		tx_data <= 10'b0;
	end 
	else if(tx_req)begin
		tx_data <= {1'b1, tx_din, 1'b0};
	end
	else begin
		tx_data <= tx_data;
	end 
end 

//tx_dout数据串行输出
always @(posedge clk or negedge rst_n)begin
	if(!rst_n)begin
		tx_dout <= 1'b1;
	end 
	else if(tx_flag && cnt_bps == 1)begin
		tx_dout <= tx_data[cnt_bit];
	end 
	else begin
		tx_dout <= tx_dout;
	end 
end 

//dout_vld约束
assign dout_vld = ~tx_flag;

endmodule 

串口发端仿真代码:

`timescale 1ns/1ns
module uart_tx_tb();
reg clk;
reg rst_n;
reg tx_req;
reg [7:0] 	tx_din;
wire        tx_dout;
wire       dout_vld;

always #(10) clk = ~clk;//每隔10ns翻转一次

initial begin//初始化信号
	clk 	= 1'b0     ;//时钟信号初始化为0
	rst_n   = 1'b0     ;//复位信号初始化为0
	#(10)         ;//等待10ns
	rst_n   = 1'b1     ;//复位信号拉高电平
    tx_req  = 1'b1;
    tx_din  = 8'b00001111;
    #(100_000);
    tx_req  = 1'b0;
	 $stop;
end 

uart_tx u_uart_tx_tb(
	.clk(clk)	,
	.rst_n(rst_n)	,
	.tx_req(tx_req),//发送请求
	.tx_din(tx_din),//并行数据输入
	
	.tx_dout(tx_dout),//串行数据输出
	.dout_vld(dout_vld)//并转串完成标志
	
);
endmodule

串口收端:

`include "param.v"
module uart_rx(
	input wire 			clk		,
	input wire 			rst_n		,
	input wire 			rx_din	,//串行数据输入
	
	output wire [7:0] rx_dout	,//并行数据输出
	output reg 		   dout_vld//串转并完成标志
);

reg [12:0] cnt_bps		;//波特率计数寄存器
wire       add_cnt_bps	;//波特率计数开始
wire       end_cnt_bps	;//波特率计数结束

reg [3:0]  cnt_bit      ;//比特计数寄存器
wire       add_cnt_bit  ;//比特计数开始
wire       end_cnt_bit  ;//比特计数结束

reg 			rx_din_r0;//同步
reg 			rx_din_r1;//打拍
wire     	nedge		;//下降沿

reg      	rx_flag;//接受标志

reg [9:0] 	rx_data;//寄存数据包


//波特率计数器设计
always @(posedge clk or negedge rst_n)begin
	if(!rst_n)begin
		cnt_bps <= 13'd0;
	end 
	else if(add_cnt_bps)begin
		if(end_cnt_bps)begin
			cnt_bps <= 13'd0;
		end 
		else begin
			cnt_bps <= cnt_bps + 1'd1;
		end 
	end 
	else begin
		cnt_bps <= cnt_bps;
	end 
end 

assign add_cnt_bps = rx_flag;
assign end_cnt_bps = add_cnt_bps && cnt_bps == (`SYS_FRQ / `BAUD_MAX) - 1'd1;

//比特计数器设计
always @(posedge clk or negedge rst_n)begin
	if(!rst_n)begin
		cnt_bit <= 4'd0;
	end 
	else if(add_cnt_bit)begin
		if(end_cnt_bit)begin
			cnt_bit <= 4'd0;
		end
		else begin
			cnt_bit <= cnt_bit + 1'd1;
		end 
	end 
	else begin
		cnt_bit <= cnt_bit;
	end 
end 

assign add_cnt_bit = end_cnt_bps;
assign end_cnt_bit = add_cnt_bit && cnt_bit == 4'd10 - 1'd1;

//起始位位置检测
always @(posedge clk or negedge rst_n)begin
	if(!rst_n)begin
		rx_din_r0 <= 1'b1;
		rx_din_r1 <= 1'b1;
	end 
	else begin
		rx_din_r0 <= rx_din;
		rx_din_r1 <= rx_din_r0;
	end 
end 

assign nedge = ~rx_din_r0 && rx_din_r1;

//接受标志rx_flag约束
always @(posedge clk or negedge rst_n)begin
	if(!rst_n)begin
		rx_flag <= 1'b0;
	end 
	else if(nedge)begin
		rx_flag <= 1'b1;
	end 
	else if(end_cnt_bit)begin
		rx_flag <= 1'b0;
	end
	else begin
		rx_flag <= rx_flag;
	end 

end 

//缓存接受到的数据
always @(posedge clk or negedge rst_n)begin
	if(!rst_n)begin
		rx_data <= 10'b0;
	end 
	else if(rx_flag && cnt_bps == (`SYS_FRQ/`BAUD_MAX) >> 1)begin
		rx_data[cnt_bit] = rx_din_r0;
	end 
	else begin
		rx_data <= rx_data;
	end 

end 

assign rx_dout = rx_data[8:1];

//串转并完成标志dout_vld约束
always @(posedge clk or negedge rst_n)begin
	if(!rst_n)begin
		dout_vld <= 1'b0;
	end 
	else if(end_cnt_bit)begin
		dout_vld <= 1'b1;
	end 
	else begin
		dout_vld <= 1'b0;
	end 
end 

endmodule 

串口收端仿真代码:

`timescale 1ns/1ns
module uart_rx_tb();
reg clk;
reg rst_n;
reg rx_din;
wire [7:0] 	rx_dout;
wire       dout_vld;

always #(10) clk = ~clk;//每隔10ns翻转一次

initial begin//初始化信号
	clk 	= 1'b0     ;//时钟信号初始化为0
	rst_n   = 1'b0     ;//复位信号初始化为0
	#(10)         ;//等待10ns
	rst_n   = 1'b1     ;//复位信号拉高电平
	rx_din  = 1'b0;
    #(8681);
	rx_din  = 1'b0;
    #(8681);
	rx_din  = 1'b0;
    #(8681);
	rx_din  = 1'b0;
    #(8681);
	rx_din  = 1'b0;
    #(8681);
	rx_din  = 1'b1;
    #(8681);
    rx_din  = 1'b1;
    #(8681);
	rx_din  = 1'b1;
    #(8681);
	rx_din  = 1'b1;
    #(8681);
	rx_din  = 1'b1;
	#(8681);
	 $stop;
end 

uart_rx u_uart_rx_tb(
	.clk(clk)	,
	.rst_n(rst_n)	,
	.rx_din(rx_din),
	.rx_dout(rx_dout),
	.dout_vld(dout_vld)
	
);
endmodule

串口收发顶层文件:

module uart(
	input wire 	clk	,
	input wire 	rst_n	,
	input wire 	rx		,
	output wire tx     //串行输出
);

wire [7:0] rx_byte		;
wire       rx_byte_vld	;

uart_rx u_uart_rx(
.clk		(clk),
.rst_n		(rst_n),
.rx_din	(rx),//串行数据输入
	
.rx_dout	(rx_byte),//并行数据输出
.dout_vld(rx_byte_vld)//串转并完成标志
);


uart_tx u_uart_tx(
.clk	(clk),
.rst_n	(rst_n),
.tx_req(rx_byte_vld),//发送请求
.tx_din(rx_byte),//并行数据输入
	
.tx_dout(tx),//串行数据输出
//.dout_vld()//并转串完成标志
	

);

endmodule 

 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值