FPGA实现UART串口通信的代码

本文实现了FPGA与电脑的串口通信,利用quartus的ISSP工具可以实现与上位机的通信
包括了发送模块,波特率设置模块,接收模块,顶层模块,并且包含了这些模块的modelsim testbench文件
通过该实验可以进一步了解FPGA与上位机之间的通信,通过使用ISSP可以进一步了解信号的抓取,增进板上仿真的经验

uart_byte_tx

module uart_byte_tx(
	clk,
	rst,
	baud_set,
	byte_en,
	data_byte,
	tx_done,
	rs232_tx
);

input clk;
input rst;
input [2:0]baud_set;
input byte_en;
input [7:0]data_byte;

output reg tx_done;
output reg rs232_tx;

wire bps_clk;
reg [7:0]data;
reg [3:0]bps_cnt;
tx_bps_gen tx_bps_gen(
	.clk(clk),
	.rst(rst),
	.baud_set(baud_set),
	.tx_done(tx_done),
	.byte_en(byte_en),
	.bps_clk(bps_clk)
);

//数据寄存,以免数据丢失
always@(posedge clk or negedge rst)
	if(!rst)
		data <= 8'd0;
	else if(bps_clk && bps_cnt == 4'd1)
		data <= data_byte;
	else 
		data <= data;
//计数波特率时钟
always@(posedge clk or negedge rst)
	if(!rst)
		bps_cnt <= 4'd0;
	else if(bps_cnt == 4'd11)
		bps_cnt <= 4'd0;
	else if(bps_clk)
		bps_cnt <= bps_cnt + 1'd1;
	else 
		bps_cnt <= bps_cnt;
//发送数据序列机
always@(posedge clk or negedge rst)
	if(!rst)
		rs232_tx <= 1'd1;
	else
		begin
			case(bps_cnt)
				4'd1 : rs232_tx <= 1'd0;
				4'd2 : rs232_tx <= data[0];
				4'd3 : rs232_tx <= data[1];
				4'd4 : rs232_tx <= data[2];
				4'd5 : rs232_tx <= data[3];
				4'd6 : rs232_tx <= data[4];
				4'd7 : rs232_tx <= data[5];
				4'd8 : rs232_tx <= data[6];
				4'd9 : rs232_tx <= data[7];
				4'd10: rs232_tx <= 1'd1;
				default rs232_tx <= 1'd1;
			endcase 
		end
	
//产生控制信号
always@(posedge clk or negedge rst)
	if(!rst)
		tx_done <= 1'd0;
	else if(bps_cnt == 4'd11)
		tx_done <= 1'd1;
	else 
		tx_done <= 1'd0;
		
endmodule 

uart_byte_rx

module uart_byte_rx(
	clk,
	rst,
	baud_set,
	rs232_rx,
	rx_byte,
	rx_done
);

input clk;
input rst;
input [2:0]baud_set;
input rs232_rx;

output reg [7:0]rx_byte;
output reg rx_done;

reg [6:0]bps_cnt;
reg [1:0]data_tmp[7:0];
reg [1:0]start_bit;
reg [1:0]stop_bit;
wire byte_en;
wire bps_clk; 		

//过滤毛刺
reg rs232_rx0, rs232_rx1, rs232_rx2, rs232_rx3;
always@(posedge clk or negedge rst)
	if(!rst)
		begin
			rs232_rx0 <= 1'd0;
			rs232_rx1 <= 1'd0;
			rs232_rx2 <= 1'd0;
			rs232_rx3 <= 1'd0;
		end
	else 
		begin
			rs232_rx0 <= rs232_rx;
			rs232_rx1 <= rs232_rx0;
			rs232_rx2 <= rs232_rx1;
			rs232_rx3 <= rs232_rx2;
		end
// 检测下降沿
wire neg_rs232 = rs232_rx3 & rs232_rx2 & !rs232_rx1 & !rs232_rx0;

//采样数据

always@(posedge clk or negedge rst)
	if(!rst)
		bps_cnt <= 7'd0;
	else if(bps_clk)
		begin
			if(bps_cnt == 7'd89)
				bps_cnt <= 7'd0;
			else 
				bps_cnt <= bps_cnt + 1'd1;
		end
	else 
		bps_cnt <= bps_cnt;

always@(posedge clk or negedge rst)
	if(!rst)
		begin
			start_bit <= 2'd0;
			data_tmp[0] <= 2'd0;
			data_tmp[1] <= 2'd0;
			data_tmp[2] <= 2'd0;
			data_tmp[3] <= 2'd0;
			data_tmp[4] <= 2'd0;
			data_tmp[5] <= 2'd0;
			data_tmp[6] <= 2'd0;
			data_tmp[7] <= 2'd0;
			stop_bit <= 2'd0;
		end
	else if(bps_clk)
		begin
			case(bps_cnt)
				7'd0:begin
						start_bit <= 2'd0;
						data_tmp[0] <= 2'd0;
						data_tmp[1] <= 2'd0;
						data_tmp[2] <= 2'd0;
						data_tmp[3] <= 2'd0;
						data_tmp[4] <= 2'd0;
						data_tmp[5] <= 2'd0;
						data_tmp[6] <= 2'd0;
						data_tmp[7] <= 2'd0;
						stop_bit <= 2'd0;
					end
				7'd3 , 7'd4 , 7'd5 :start_bit <= start_bit + rs232_rx;
				7'd12, 7'd13, 7'd14:data_tmp[0] <= data_tmp[0] + rs232_rx;
				7'd21, 7'd22, 7'd23:data_tmp[1] <= data_tmp[1] + rs232_rx;
				7'd30, 7'd31, 7'd32:data_tmp[2] <= data_tmp[2] + rs232_rx;
				7'd39, 7'd40, 7'd41:data_tmp[3] <= data_tmp[3] + rs232_rx;
				7'd48, 7'd49, 7'd50:data_tmp[4] <= data_tmp[4] + rs232_rx;
				7'd57, 7'd58, 7'd59:data_tmp[5] <= data_tmp[5] + rs232_rx;
				7'd66, 7'd67, 7'd68:data_tmp[6] <= data_tmp[6] + rs232_rx;
				7'd75, 7'd76, 7'd77:data_tmp[7] <= data_tmp[7] + rs232_rx;
				7'd84, 7'd85, 7'd86:stop_bit <= stop_bit + rs232_rx;
				default:;
			endcase		
		end
//采样完成,产生输出信号
always@(posedge clk or negedge rst)
	if(!rst)
		rx_byte <= 8'd0;
	else if(bps_clk && bps_cnt == 7'd89)
		rx_byte <= {data_tmp[7][1],data_tmp[6][1],data_tmp[5][1],data_tmp[4][1],
						data_tmp[3][1],data_tmp[2][1],data_tmp[1][1],data_tmp[0][1]};
	else
		rx_byte <= rx_byte;
		
//产生采样时钟
rx_bps_gen rx_bps_gen(
	.clk(clk),
	.rst(rst),
	.baud_set(baud_set),
	.rx_done(rx_done),
	.byte_en(byte_en),
	.bps_clk(bps_clk)
);

assign byte_en = neg_rs232;
always@(posedge clk or negedge rst)
	if(!rst)
		rx_done <= 1'd0;
	else if(bps_clk && bps_cnt == 7'd89)
		rx_done <= 1'd1;
	else 
		rx_done <= 1'd0;
		
endmodule

rx_bps_gen

module rx_bps_gen(
	clk,
	rst,
	baud_set,
	rx_done,
	byte_en,
	bps_clk
);

parameter sys_clk = 50_000_000;

input clk;
input rst;
input [2:0]baud_set;
input rx_done;
input byte_en;
output reg bps_clk;

localparam	bps9600   = sys_clk/9600/9-1;
localparam	bps19200  = sys_clk/19200/9-1;
localparam	bps38400  = sys_clk/38400/9-1;
localparam	bps57600  = sys_clk/57600/9-1;
localparam	bps115200 = sys_clk/115200/9-1;
localparam	bps230400 = sys_clk/230400/9-1;
localparam	bps460800 = sys_clk/460800/9-1;
localparam	bps921600 = sys_clk/921600/9-1;

reg [31:0]bps_para;

always@(posedge clk or negedge rst)
	if(!rst)
		bps_para <= 32'd0;
	else begin
		case(baud_set)
			3'd0: bps_para <= bps9600  ;
			3'd1: bps_para <= bps19200 ;
			3'd2: bps_para <= bps38400 ;
			3'd3: bps_para <= bps57600 ;
			3'd4: bps_para <= bps115200;
			3'd5: bps_para <= bps230400;
			3'd6: bps_para <= bps460800;
			3'd7: bps_para <= bps921600;
			default:bps_para <= bps9600;
		endcase
	end
localparam	IDEL = 1'd0,
				RECE = 1'd1;
	
reg [9:0]cnt;
reg state;
reg bps_en;
always@(posedge clk or negedge rst)
	if(!rst)
		begin
			state <= IDEL;
			bps_en <= 1'd0;
		end
	else begin
		case(state)
			IDEL: 
				if(byte_en)
					begin
						state <= RECE;
						bps_en <= 1'd1;
					end
				else
					begin
						state <= IDEL;
						bps_en <= 1'd0;
					end
			RECE:
				if(rx_done)
					begin
						state <= IDEL;
						bps_en <= 1'd0;
					end
				else 
					begin
						state <= RECE;
						bps_en <= 1'd1;
					end
		endcase
	end

always@(posedge clk or negedge rst)
	if(!rst)
		cnt <= 10'd0;
	else if(bps_en)
		begin
			if(cnt == bps_para)
				cnt <= 10'd0;
			else 
				cnt <= cnt + 1'd1;
		end
	else 
		cnt <= 10'd0;
	
always@(posedge clk or negedge rst)
	if(!rst)
		bps_clk <= 1'd0;
	else if(cnt == 10 'd1)
		bps_clk <= 1'd1;
	else 
		bps_clk <= 1'd0;
		
		
endmodule 

tb_uart_byte_rx

`timescale 1ns/1ns
`define clk_period 20

module tb_uart_byte_rx;

reg clk;
reg rst;
reg baud_set;
reg  [7:0]data_tx;
reg byte_en;

wire tx_done;
wire rs232_tx;
wire [7:0]data_rx;
wire rx_done;

uart_byte_tx uart_byte_tx(
	.clk(clk),
	.rst(rst),
	.baud_set(baud_set),
	.byte_en(byte_en),
	.data_byte(data_tx),
	.tx_done(tx_done),
	.rs232_tx(rs232_tx)
);

uart_byte_rx uart_byte_rx(
	.clk(clk),
	.rst(rst),
	.baud_set(baud_set),
	.rs232_rx(rs232_tx),
	.rx_byte(data_rx),
	.rx_done(rx_done)
);

initial clk = 1'd1;
always#(`clk_period/2) clk = ~clk;

initial begin
	rst = 1'd0;
	baud_set = 2'd1;
	data_tx = 8'd0;
	byte_en = 1'd0;
	#(`clk_period*20);
	rst = 1'd1;
	#(`clk_period*2000);
	
	data_tx = 8'haa;
	byte_en = 1'd1;
	#(`clk_period);
	byte_en = 1'd0;
	@(posedge tx_done);
	#(`clk_period*5000);
	
	data_tx = 8'h55;
	byte_en = 1'd1;
	#(`clk_period);
	byte_en = 1'd0;
	@(posedge tx_done);
	#(`clk_period*5000);

	$stop;
end


endmodule 

tb_uart_byte_tx

`timescale 1ns/1ns
`define clk_period 20

module tb_uart_byte_tx;

reg clk;
reg rst;
reg [2:0]baud_set;
reg [7:0]data_byte;
reg byte_en;

wire tx_done;
wire rs232_tx;

uart_byte_tx uart_byte_tx(
	.clk(clk),
	.rst(rst),
	.baud_set(baud_set),
	.byte_en(byte_en),
	.data_byte(data_byte),
	.tx_done(tx_done),
	.rs232_tx(rs232_tx)
);

initial clk = 1'd1;
always#(`clk_period/2) clk = ~clk;

initial begin
	rst = 1'd0;
	baud_set = 3'd0;
	data_byte = 8'd0;
	byte_en = 1'd0;
	#(`clk_period*20);
	rst = 1'd1;
	#(`clk_period*2000);
	
	data_byte = 8'haa;
	byte_en = 1'd1;
	#(`clk_period);
	byte_en = 1'd0;
	@(posedge tx_done);
	#(`clk_period*5000);
	
	data_byte = 8'h55;
	byte_en = 1'd1;
	#(`clk_period);
	byte_en = 1'd0;
	@(posedge tx_done);
	#(`clk_period*5000);
	
	
	$stop;
end


endmodule 


uart_top

module uart_top(
	clk,
	rst,
	key_in,
	rs232_tx,
	rs232_rx
);
input clk;
input rst;
input key_in;
output rs232_tx;
input rs232_rx;

wire key_flag;
wire key_state;
key_filter key_filter(
	.clk(clk),
	.rst(rst),
	.key_in(key_in),
	.key_flag(key_flag),
	.key_state(key_state)
);

wire [2:0]baud_set;
assign baud_set = 3'd0;

wire byte_en;
assign byte_en = key_flag && !key_state;

wire [7:0]data_tx;
uart_byte_tx uart_byte_tx(
	.clk(clk),
	.rst(rst),
	.baud_set(baud_set),
	.byte_en(byte_en),
	.data_byte(data_tx),
	.tx_done(),
	.rs232_tx(rs232_tx)
);

wire [7:0]data_rx;
uart_byte_rx uart_byte_rx(
	.clk(clk),
	.rst(rst),
	.baud_set(baud_set),
	.rs232_rx(rs232_rx),
	.rx_byte(data_rx),
	.rx_done()
);

issp	issp (
	.probe ( data_rx ),
	.source ( data_tx )
	);

endmodule 

posted @ 2020-05-11 11:25  嗨喽来了  阅读(1149)  评论(0编辑  收藏  举报