FPGAはRS 232通信プロトコルを実現する

5186 ワード

テストにより、このコードは実行可能である(シリアルアシスタントでコードの正確性を検証できる)
/****************************RS 232最上位ファイルソース*************************************/
module RS232_top
(
	input clk_50M,
	input rst_n,
	input RS232_rxd,
	output RS232_txd
);

//fuwei :PIN_M1
//shizhong: PIN_R9
//txd:PIN_G5
//rxd:PIN_A8
parameter CLK_FREQ = 50_000_000;
parameter RS232_BPS = 115200;

wire rs232_en_w;
wire [7:0] rs232_data_w;


RS232_recv #(
	.CLK_FREQ(CLK_FREQ),
	.RS232_BPS(RS232_BPS))	
u_RS232_recv(
	.clk_50M(clk_50M),
	.rst_n(rst_n),
	
	.rxd(RS232_rxd),
	.done(rs232_en_w),
	.data(rs232_data_w)//rs232_data_w
);


RS232_send #(
	.CLK_FREQ(CLK_FREQ),
	.RS232_BPS(RS232_BPS))	
u_RS232_send(
	.clk_50M(clk_50M),
	.rst_n(rst_n),
	
	.en(rs232_en_w),
	.txd(RS232_txd),
	.data(rs232_data_w)//rs232_data_w
);

endmodule 

/******************RS 232受信ソースコード**********************************/
module RS232_recv(
	input clk_50M,
	input rst_n,
	
	input rxd,
	output reg done,
	output reg [7:0]data
);

parameter CLK_FREQ = 50_000_000;
parameter RS232_BPS = 115200;
localparam BPS_CNT = 434;


reg rxd_d0;
reg rxd_d1;
reg [15:0]clk_cnt;
reg [3:0] rx_cnt;
reg rx_flag;
reg [7:0] rxdata;

wire start_flag;

/**************main code************************
/**********************************************/


// , 
assign start_flag = rxd_d1 & (~rxd_d0);

// 
always@(posedge clk_50M, negedge rst_n)
begin
	if(~rst_n) begin
		rxd_d0 <= 1'b0;
		rxd_d1 <= 1'b0;
	end
	else begin 
		rxd_d0 <= rxd;
		rxd_d1 <= rxd_d0;
	end
end


always@(posedge clk_50M, negedge rst_n)
begin
	if(~rst_n) begin
		rx_flag <= 1'b0;
	end
	else begin 
		if(start_flag)
		rx_flag <= 1'b1;
		else if ((rx_cnt==4'd9) && (clk_cnt == BPS_CNT/2))
			rx_flag <= 1'b0;
		else 
			rx_flag <= rx_flag;
	end
end


// , 
always@(posedge clk_50M, negedge rst_n)
begin
	if(~rst_n) begin
		clk_cnt <= 16'd0;
		rx_cnt <= 4'd0;
	end
	else if(rx_flag) begin 
		if(clk_cnt < BPS_CNT-1) begin
			clk_cnt <= clk_cnt + 1'b1;
			rx_cnt <= rx_cnt;
		end
		else begin
			clk_cnt <= 16'd0;
			rx_cnt <= rx_cnt + 1'b1;
		end
	end
	else begin
		clk_cnt <= 16'd0;
		rx_cnt <= 4'd0;
	end
end


// 
always@(posedge clk_50M, negedge rst_n)
begin
	if(~rst_n) begin
		rxdata <= 8'd0;
	end
	else if(rx_flag) begin 
		if(clk_cnt == BPS_CNT/2)begin
			case (rx_cnt)
			4'd1:rxdata[0] <= rxd_d1;
			4'd2:rxdata[1] <= rxd_d1;
			4'd3:rxdata[2] <= rxd_d1;
			4'd4:rxdata[3] <= rxd_d1;
			4'd5:rxdata[4] <= rxd_d1;
			4'd6:rxdata[5] <= rxd_d1;
			4'd7:rxdata[6] <= rxd_d1;
			4'd8:rxdata[7] <= rxd_d1;
			default: ;
			endcase
		end
		else
			rxdata <= rxdata;
	end
	else 
		rxdata <= 8'd0;
end


// 
always@(posedge clk_50M, negedge rst_n)
begin
	if(~rst_n) begin
		data <= 8'd0;
		done <= 1'b0;
	end
	else if(rx_cnt == 4'd9) begin 
		data <= rxdata;
		done <= 1'b1;
	end
	else begin
		data <= 8'd0;
		done <= 1'b0;
	end
end

endmodule

/*********************RS 232送信データソース**********************************/
module RS232_send(
	input clk_50M,
	input rst_n,
	
	input en,
	input [7:0]data,
	output reg txd
);

parameter CLK_FREQ = 50_000_000;
parameter RS232_BPS = 115200;
localparam BPS_CNT = 434;


reg en_d0;
reg en_d1;
reg [15:0]clk_cnt;
reg [3:0] tx_cnt;
reg tx_flag;
reg [7:0] tx_data;

wire en_flag;

/********************main code************************/
// en , 
assign en_flag = (~en_d1) & en_d0;

// en 
always@(posedge clk_50M, negedge rst_n)
begin
	if(~rst_n)begin
		en_d0 <= 1'b0;
		en_d1 <= 1'b0;
	end
	else begin
		en_d0 <= en;
		en_d1 <= en_d0;
	end
end

// en_flag , , 
always@(posedge clk_50M, negedge rst_n)
begin
	if(~rst_n)begin
		tx_flag <= 1'b0;
		tx_data <= 8'd0;
	end
	else if(en_flag) begin
		tx_flag <= 1'b1;
		tx_data <= data;
	end
	else if((tx_cnt==9) && (clk_cnt == BPS_CNT/2))begin
		tx_flag <= 1'b0;
		tx_data <= 8'd0;
	end
	else begin
		tx_flag <= tx_flag;
		tx_data <= tx_data;
	end
end


// , 
always@(posedge clk_50M, negedge rst_n)
begin
	if(~rst_n)begin
		clk_cnt <= 16'd0;
		tx_cnt <= 4'd0;
	end
	else if(tx_flag) begin
		if (clk_cnt < BPS_CNT -1)begin
			clk_cnt <= clk_cnt + 1'b1;
			tx_cnt <= tx_cnt;
		end
		else begin
			clk_cnt <= 16'd0;
			tx_cnt <= tx_cnt + 1'b1;
		end
	end
	else begin
		clk_cnt <= 16'd0;
		tx_cnt <= 4'd0;
	end
end


// 
always@(posedge clk_50M, negedge rst_n)
begin
	if(~rst_n)begin
		txd <= 1'b1;
	end
	else if(tx_flag) begin
		case(tx_cnt)
			4'd0: txd <= 1'b0;	// 
			4'd1: txd <= tx_data[0];
			4'd2: txd <= tx_data[1];
			4'd3: txd <= tx_data[2];
			4'd4: txd <= tx_data[3];
			4'd5: txd <= tx_data[4];
			4'd6: txd <= tx_data[5];
			4'd7: txd <= tx_data[6];
			4'd8: txd <= tx_data[7];
			4'd9: txd <= 1'b1;
			default: ;
		endcase
	end
	else begin
		txd <= 1'b1;
	end
end

endmodule