RS-232是一种串行通信协议,用于在计算机和其他外部设备之间进行数据传输。RS-232定义了电气特性、信号级别、机械特性和传输速率等规范,为串行通信提供了一种标准化的接口。
RS-232通常使用DB9连接器,用于传输和接收数据、控制信号以及地线连接。
但除了235脚其它基本都省略了,一个发送一个接收还有个地。
rs232是单端传输,还有485,422 差分传输,485半双工,422 全双工,原理差不多
下面是verilog代码。
tx.v
module tx (
input wire clk,
input wire rst_n,
input wire tx_begin,
input wire[7:0] tx_pdata,
output reg txd,
output reg busy
);
localparam OSC = 50_000_000;
localparam BAUD = 115200;
//localparam BAUD = 57600;
//localparam BAUD = 38400;
//localparam BAUD = 19200;
localparam NUM = OSC/BAUD - 1;
reg[16:0] clk_cnt;
reg [1:0] stage;
reg [2:0] curbit;
reg [7:0] tx_data;
reg done;
always @(posedge clk or negedge rst_n ) begin
if (!rst_n ) begin
busy <= 1'b0;
end else if (tx_begin === 1'b1 && busy === 1'b0 ) begin // busy ignore
busy <= 1'b1;
tx_data <= tx_pdata;
end else if (done)
busy <= 1'b0;
end
reg tx_clk_en;
always @(busy) begin
if(busy)
tx_clk_en <= 1'b1;
else
tx_clk_en <= 1'b0;
end
reg tx_stage_pulse;
always @(posedge clk or negedge rst_n ) begin
if (!rst_n)
clk_cnt <= 0;
else if( tx_clk_en === 1'b0 || clk_cnt === NUM)
clk_cnt <= 0;
else
clk_cnt <= clk_cnt + 1;
end
always @(posedge clk) begin
if (clk_cnt === 1)
tx_stage_pulse <= 1'b1;
else
tx_stage_pulse <= 1'b0;
end
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
txd <= 1'b1;
done <= 1'b0;
stage <= 2'd0;
end else if (busy) begin
if (tx_stage_pulse) begin
if (stage === 2'd0) begin
txd <= 1'b0;
done <= 1'b0;
stage <= 2'b1;
curbit <= 3'd0;
end else if (stage === 2'b1) begin
txd <= tx_data[curbit];
if (curbit === 3'd7)
stage <= 2'd2;
else
curbit <= curbit + 1;
end else if (stage === 2'd2) begin
txd <= 1'b1;
stage <= 2'd3;
end else if (stage === 2'd3) begin
txd <= 1'b1;
done <= 1'b1;
stage <= 2'd0;
end
end
end else begin
txd <= 1'b1;
done <= 1'b0;
stage <= 2'd0;
end
end
endmodule
测试
uart_test.v
module uart_test (
input wire clk,
input wire rst_n,
output wire txd
);
reg tx_begin;
reg[7:0] tx_data = 0;
reg[31:0] cnt;
parameter maxcnt = 32'd1500 ;
wire busy;
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
cnt <= 0;
else if (cnt == maxcnt) begin
cnt <= 0;
if(!busy)
tx_data <= (tx_data + 1) & 8'h7f ;
tx_begin <= 1'b1;
end else begin
tx_begin <= 1'b0;
cnt <= cnt+1;
end
end
tx tx1(clk,rst_n,tx_begin,tx_data,txd,busy);
endmodule
testbench
test.v
module test;
reg rst_n=1 ;
initial begin
$dumpfile("test.vcd");
$dumpvars(0, test);
#10 rst_n = !rst_n;
#30 rst_n = !rst_n;
#100000 $finish;
end
reg clk = 0;
always #1 clk = !clk;
wire txd;
uart_test uart1(clk,rst_n,txd);
endmodule
两个问题,一帧数据传输完成前,再次接到发送指令,直接丢弃,因为中间即使停止, 对方也会以为这是数据直到完成这一帧 , 有可能会打乱时序 ,或用FIFO。引出一位busy忙标志位。
二停止位,有1位,1.5位,2位的,测试了下快速发送,用1位115200 57600没有乱码,速度降下去后会出现乱码,两位停止位乱码消失,稳定起见,停止位两位。