FPGAはRS 232通信プロトコルを実現する
5186 ワード
テストにより、このコードは実行可能である(シリアルアシスタントでコードの正確性を検証できる)
/****************************RS 232最上位ファイルソース*************************************/
/******************RS 232受信ソースコード**********************************/
/*********************RS 232送信データソース**********************************/
/****************************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