fpga verilog rs232 发送模块实现

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位停止位的话,发送停止位完成后,半个停止位内再次发送会出现乱码应该是232芯片有一个要求大于1.5的,从FPGA出来后先转232一个芯片,232再转usb一个芯片,稳定起见,停止位两位。

  • 38
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yvee

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值