fpga verilog rs232 发送模块实现

RS-232是一种串行通信协议,用于在计算机和其他外部设备之间进行数据传输。RS-232定义了电气特性、信号级别、机械特性和传输速率等规范,为串行通信提供了一种标准化的接口。

RS-232通常使用DB9连接器,用于传输和接收数据、控制信号以及地线连接。

但除了235脚其它基本都省略了,一个发送一个接收还有个地。

rs232是单端传输,还有485,422 差分传输,485半双工,422 全双工,原理差不多

下面是verilog代码。

tx.v

c 复制代码
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

c 复制代码
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

c 复制代码
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一个芯片,稳定起见,停止位两位。

相关推荐
IM_DALLA17 小时前
【Verilog学习日常】—牛客网刷题—Verilog快速入门—VL21
学习·fpga开发
皇华ameya21 小时前
AMEYA360:村田电子更适合薄型设计应用场景的3.3V输入、12A输出的DCDC转换IC
fpga开发
千穹凌帝1 天前
SpinalHDL之结构(二)
开发语言·前端·fpga开发
一口一口吃成大V1 天前
FPGA随记——FPGA时序优化小经验
fpga开发
贾saisai1 天前
Xilinx系FPGA学习笔记(九)DDR3学习
笔记·学习·fpga开发
redcocal1 天前
地平线秋招
python·嵌入式硬件·算法·fpga开发·求职招聘
思尔芯S2C2 天前
高密原型验证系统解决方案(下篇)
fpga开发·soc设计·debugging·fpga原型验证·prototyping·深度调试·多fpga 调试
坚持每天写程序2 天前
xilinx vivado PULLMODE 设置思路
fpga开发
redcocal3 天前
地平线内推码 kbrfck
c++·嵌入式硬件·mcu·算法·fpga开发·求职招聘
邹莉斯4 天前
FPGA基本结构和简单原理
fpga开发·硬件工程